mirror of
https://github.com/MCV-Software/TWBlue.git
synced 2025-08-25 17:39:23 +00:00
Compare commits
142 Commits
new-docume
...
v2023.4.13
Author | SHA1 | Date | |
---|---|---|---|
bea4096d16 | |||
6135412d4b | |||
![]() |
16d855ac56 | ||
![]() |
bfb705c18e | ||
77b2486877 | |||
![]() |
1a2a2fb3e2 | ||
![]() |
a2660dd410 | ||
058ca1347a | |||
10e23b039b | |||
00a5ad9e59 | |||
db4607f17e | |||
65aea3c43c | |||
972b851b93 | |||
0764679164 | |||
c6796874c2 | |||
5f07f3b9d0 | |||
52267562bc | |||
972b880931 | |||
1fa1313434 | |||
96dc99a93b | |||
8acebc290b | |||
![]() |
74fe437684 | ||
![]() |
05b7e9fce4 | ||
8940825509 | |||
5af336fdcc | |||
![]() |
8bfb7ef003 | ||
a57ea752d6 | |||
3f0ee5650b | |||
d320daa6a1 | |||
ae5515b6e1 | |||
d01856f436 | |||
![]() |
5749b4c8e3 | ||
eec4b34f44 | |||
059e83a765 | |||
476df9cfdb | |||
866da8425c | |||
![]() |
e9ae5b228b | ||
![]() |
4a420bf1e0 | ||
![]() |
025d0467ae | ||
![]() |
727096ca91 | ||
e31369e49a | |||
f3fd1087b4 | |||
e9dc02e868 | |||
68c5b9affe | |||
09650f588a | |||
310ba003c9 | |||
d0fcf88b31 | |||
d0e18178c6 | |||
ad8667a13c | |||
63ae496c39 | |||
45cffd6a0b | |||
7c959088e0 | |||
fda5250a52 | |||
98aba2a4c4 | |||
24e91235f3 | |||
ef2e63e195 | |||
7d7a9d72c4 | |||
fcfbae4964 | |||
aca51a2fb9 | |||
b4ea6ffcbe | |||
f69af7aaa1 | |||
a8c5fc8589 | |||
f87ced817f | |||
3be01013f4 | |||
fd176f92d3 | |||
97d4fea563 | |||
b35f2e0fed | |||
b3851cde95 | |||
4b232d527c | |||
12b4c8ac23 | |||
d89c5150f8 | |||
d17e9ecdac | |||
76d0866780 | |||
![]() |
706616717e | ||
7c47d6171a | |||
![]() |
b743d7af09 | ||
d4219f1705 | |||
![]() |
e25d007149 | ||
![]() |
fcb8edbda2 | ||
![]() |
a6ca588115 | ||
18a7a42b5a | |||
460cea702b | |||
b14c77b730 | |||
1e5c7512e4 | |||
d76dbe318c | |||
![]() |
4d4901b029 | ||
![]() |
07128d2e4a | ||
c45ba5e705 | |||
![]() |
795cb33efc | ||
98bcb9d279 | |||
![]() |
06cbe0a3b5 | ||
e4f2793aaf | |||
43ae43ce26 | |||
![]() |
7082a5f3ec | ||
c278fba4c7 | |||
cfc8221825 | |||
![]() |
32c1ed225e | ||
![]() |
d3b15fcefa | ||
7ec96c47d6 | |||
97812ec8b0 | |||
d1ca3c9fb2 | |||
![]() |
492352bc27 | ||
![]() |
6328c252f7 | ||
![]() |
e1a46f338a | ||
![]() |
f7e09a05b2 | ||
![]() |
c7116916ba | ||
![]() |
f1fbe858e9 | ||
![]() |
fc5a1060be | ||
![]() |
5951276033 | ||
![]() |
2d761c423f | ||
![]() |
434e2878a7 | ||
![]() |
89cdba5910 | ||
![]() |
e9a885784f | ||
![]() |
3a968e49aa | ||
![]() |
c6417962a9 | ||
![]() |
2f55eca575 | ||
![]() |
1cd66e7f10 | ||
![]() |
0ddb4e6f32 | ||
![]() |
39aac0a3e7 | ||
![]() |
45ab6d953b | ||
![]() |
fdd0d566ad | ||
![]() |
c606fedda5 | ||
9b0ecdf928 | |||
![]() |
f5e1ff39be | ||
![]() |
5dff35fd02 | ||
![]() |
a5104fd76a | ||
![]() |
423b63e486 | ||
![]() |
25c6db7dd8 | ||
ca40103df7 | |||
250b248d25 | |||
efd11b90fb | |||
2a90e7be25 | |||
32a86f1bb4 | |||
b0fa59cc01 | |||
b8647c29ea | |||
1eb9aefbf1 | |||
d4ebfac317 | |||
3680349b59 | |||
ec68c7ccae | |||
4bf155b421 | |||
e63479a261 | |||
ae0dcc7b21 |
32
.github/workflows/update-translations.yml
vendored
Normal file
32
.github/workflows/update-translations.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: Update translation files
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "35 0 * * 0"
|
||||
|
||||
permissions: write-all
|
||||
|
||||
jobs:
|
||||
|
||||
update_catalogs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.10"
|
||||
cache: 'pip'
|
||||
- name: Install dependencies
|
||||
run: pip install babel
|
||||
- name: Extract messages
|
||||
run: pybabel extract -o twblue.pot --msgid-bugs-address "manuel@manuelcortez.net" --copyright-holder "MCV software" --input-dirs .
|
||||
working-directory: 'src'
|
||||
- name: Update catalogs
|
||||
run: pybabel update --input-file twblue.pot --domain twblue --output-dir locales
|
||||
working-directory: 'src'
|
||||
- uses: stefanzweifel/git-auto-commit-action@v4
|
||||
with:
|
||||
commit_message: Updated translation catalogs
|
||||
repository: src/locales
|
@@ -32,7 +32,6 @@ twblue32:
|
||||
- cd ..\src
|
||||
- '&$env:PYTHON ..\doc\generator.py'
|
||||
- '&$env:PYTHON write_version_data.py'
|
||||
- New-Item "appkeys.py" -ItemType File -Value "twitter_api_key='$TWITTER_API_KEY'`ntwitter_api_secret='$TWITTER_API_SECRET'"
|
||||
- '&$env:PYTHON setup.py build'
|
||||
- cd ..
|
||||
- mkdir artifacts
|
||||
@@ -120,7 +119,7 @@ twblueWin7:
|
||||
- cd ..
|
||||
- move src/twblue.zip artifacts/twblue_windows7_x86.zip
|
||||
only:
|
||||
- next-gen
|
||||
- tags
|
||||
artifacts:
|
||||
paths:
|
||||
- artifacts
|
||||
|
49
README.md
49
README.md
@@ -1,35 +1,16 @@
|
||||
TWBlue -
|
||||
TWBlue
|
||||
======
|
||||
|
||||
[](https://ci.appveyor.com/project/manuelcortez/twblue)
|
||||
|
||||
TW Blue is an app designed to use Twitter simply and efficiently while using minimal system resources.
|
||||
With this app you’ll have access to twitter features such as:
|
||||
TWBlue is a free and open source application that allows you to interact with the main features of mastodon from the comfort of a windows software, with 2 different interfaces specially designed for screen reader users.
|
||||
|
||||
* Create, reply to, like, retweet and delete tweets,
|
||||
* Send and delete direct messages,
|
||||
* See your friends and followers,
|
||||
* Follow, unfollow, block and report users as spam,
|
||||
* Open a user’s timeline, which will allow you to get that user’s tweets separately,
|
||||
* Open URLs when attached to a tweet or direct message,
|
||||
* Play audio tweets
|
||||
* and more!
|
||||
|
||||
See [TWBlue's webpage](http://twblue.es) for more details.
|
||||
See [TWBlue's webpage](https://twblue.es) for more details.
|
||||
|
||||
## Running TWBlue from source
|
||||
|
||||
This document describes how to run tw blue from source and how to build a binary version which doesn't need Python and the other dependencies to run.
|
||||
|
||||
### Generating application keys
|
||||
|
||||
In order to communicate with Twitter, you will need to generate a set of API keys in their [developer portal](https://developer.twitter.com/en/portal/dashboard) (If you haven't signed up, [visit this site to register as a developer](https://developer.twitter.com/en/docs/twitter-api/getting-started/getting-access-to-the-twitter-api)) and create a module called appkeys.py, within the src directory, with the following content, replacing the example values with your set of API keys:
|
||||
|
||||
```
|
||||
twitter_api_key='xxxxxxxxxx'
|
||||
twitter_api_secret='xxxxxxxxxx'
|
||||
```
|
||||
|
||||
### Required dependencies.
|
||||
|
||||
Although most dependencies can be found in the windows-dependencies directory, we provide links to their official websites. If you are cloning with git, don't forget to initialize and update the submodules to get the windows-dependencies folder. You can use these two commands to perform this task from git bash:
|
||||
@@ -83,15 +64,7 @@ This dependency has been built using pure basic 4.61. Its source can be found at
|
||||
|
||||
* [NSIS,](http://nsis.sourceforge.net/) version 3.04
|
||||
|
||||
#### Dependencies required to build the portableApps.com format archive
|
||||
|
||||
* [NSIS Portable,](http://portableapps.com/apps/development/nsis_portable) version 3.03
|
||||
* [PortableApps.com Launcher,](http://portableapps.com/apps/development/portableapps.com_launcher) version 2.2.1
|
||||
* [PortableApps.com Installer,](http://portableapps.com/apps/development/portableapps.com_installer) version 3.5.11
|
||||
|
||||
Important! Install these 3 apps into the same folder, otherwise you won't be able to build the pa.c version. For example: D:\portableApps\NSISPortable, D:\PortableApps\PortableApps.com installer, ...
|
||||
|
||||
#### Dependencies to make the spell checker multilingual ####
|
||||
#### Dependencies to make the spell checker multilingual
|
||||
|
||||
In order to add the support for spell checking in more languages than english you need to add some additional dictionaries to pyenchant. These are located on the dictionaries folder under windows-dependencies. Simply copy them to the share/enchant/myspell folder located in your enchant installation. They will be automatically copied when building a binary version.
|
||||
|
||||
@@ -136,16 +109,8 @@ If you want to install TWBlue on your computer, you must create the installer fi
|
||||
|
||||
### How to generate a translation template
|
||||
|
||||
Run the gen_pot.bat file, located in the tools directory. Your python installation must be in your path environment variable. The pot file will appear in the tools directory.
|
||||
To manage translations in TWBlue, you can install the [Babel package.](https://pypi.org/project/Babel/) You can extract message catalogs and generate the main template file with the following command:
|
||||
|
||||
### How to build the portableApps.com archive
|
||||
|
||||
If you want to have TWBlue on your PortableApps.com platform, follow these steps:
|
||||
|
||||
* Navigate to the src directory, and create a binary version for x86: C:\python37\python setup.py build
|
||||
* Move the dist directory to the misc\pa.c format\app folder in this repo, and rename it to twblue
|
||||
* Repeat these steps with Python for x64: C:\python37x64\python setup.py build
|
||||
* Move the new dist directory to the misc\pa.c format\app folder, and rename it to twblue64
|
||||
* Run the PortableApps.com Launcher Generator, and follow the wizard. Choose the pa.c format folder and continue to generate the launcher. If the wizard is completed, you will see a file named TWBlue portable.exe inside the pa.c format folder.
|
||||
* Run the PortableApps.com Installer, and follow the wizard. As in the above step, choose the pa.c format folder. When it completes, you will see a file named TWBluePortable_x.y.paf.exe inside the misc folder, where x.y is the version number.
|
||||
pybabel extract -o twblue.pot --msgid-bugs-address "manuel@manuelcortez.net" --copyright-holder "MCV software" --input-dirs ..\src
|
||||
|
||||
Take into account, though, that we use [weblate](https://weblate.mcvsoftware.com) to track translation work for TWBlue. If you wish to be part of our translation team, please open an issue so we can create an account for you in Weblate.
|
@@ -2,6 +2,54 @@ TWBlue Changelog
|
||||
|
||||
## changes in this version
|
||||
|
||||
During the development of the current TWBlue version, Twitter has cut out access from their API, meaning TWBlue will no longer be able to communicate with Twitter. This is the end of the support of TWBlue for Twitter sessions. No new sessions will be available for this social network, and we will focus in adding more features to our Mastodon support and writing support for more websites and networks. Thank you everyone who have been using TWBlue to manage your Twitter accounts since 2013.
|
||||
|
||||
* TWBlue should be able to display variables within templates (for example, now it is possible to send a template inside a post's text). Before, it was removing $variables so it was difficult to show how to edit templates from the client. ([#515](https://github.com/MCV-Software/TWBlue/issues/515))
|
||||
* Mastodon:
|
||||
* it is possible to add descriptions for all media available on Mastodon (audio, photos, video and Givs). ([#516](https://github.com/MCV-Software/TWBlue/issues/516))
|
||||
* TWBlue can now perform OCR in attached images.
|
||||
* It is possible to add aliases to mastodon users. Also, the "manage user aliases" setting, located on the application menu within the menu bar can be used to add, edit or remove aliases.
|
||||
* Implemented "Hide emojis on usernames" in both GUI and invisible interface.
|
||||
* Added an experimental feature to recover from connection errors. When making a post, if the post cannot be published due to any kind of error, TWBlue will bring up the dialog where the post was composed, so you can give the post a second chance or save the post's text. This feature should work for threads, posts with attachments, polls and replies. ([#527,](https://github.com/MCV-Software/TWBlue/issues/527) [#526,](https://github.com/MCV-Software/TWBlue/issues/526) [#377,](https://github.com/MCV-Software/TWBlue/issues/377) [#137,](https://github.com/MCV-Software/TWBlue/issues/137) [#108](https://github.com/MCV-Software/TWBlue/issues/108))
|
||||
* When playing media items, TWBlue will prefer remote URL streams and fall back to instance cached stream URL'S.
|
||||
* Fixed an error on mentions buffer that was making TWBlue unable to load posts if there were mentions from a blocked or deleted account.
|
||||
* Fixed an error when loading timelines during startup where TWBlue was unable to change the buffer title properly.
|
||||
|
||||
## Changes on version 2023.2.6
|
||||
|
||||
This release focuses on fixing some important bugs that have been reported in the previous version. Particularly, TWBlue should be able to authorize on some instances that have blocked the Mastodon.py library, and should be able to avoid repeatedly calling some endpoints that cause excessive connections for some instances. Additionally, it is possible to disable Streaming from the account options in Mastodon. This can be especially useful if TWBlue keeps making a lot of API calls for some instances.
|
||||
|
||||
* Fixed the update system.
|
||||
* Fixed a bug when attempting to switch between different accounts using the invisible interface, if the focused account is not an active session.
|
||||
* Mastodon:
|
||||
* Improved the way TWBlue counts characters in Mastodon. Now it counts only the username part in a remote user (@domain is not counted against character limit), adds content warning text to character count, also emojis and CJK characters are counted as 1 as opposed to 2. ([#511](https://github.com/MCV-Software/TWBlue/issues/511))
|
||||
* Added notification when a user joins an instance. This notification is only available for administrators.
|
||||
* Added option to disable Streaming in the account options. This can be useful if TWBlue, for some reason, repeatedly calls the instance API.
|
||||
* Improved the code that works with the Streaming API to reduce the number of reconnection attempts TWBlue performs.
|
||||
* Fixed media uploads for audio, video and gifvs. ([#513](https://github.com/MCV-Software/TWBlue/issues/513))
|
||||
|
||||
## Changes in version 2023.2.3
|
||||
|
||||
In this version, TWBlue will no longer support Twitter sessions starting on February 9, due to Twitter's policies prohibiting third-party clients, in addition to the shutdown of the free access to the Twitter API. All Twitter sessions that are active on TWBlue will stop working as of February 9, when the free API access will finally be shut down. It will not be possible to display or add Twitter sessions from the Session manager. From the TWBlue team, we will continue working to improve our support for Mastodon instances and add other social networks in the near future. If you want to keep in touch with the project, you can follow us in our mastodon account, at [@twblue@maaw.social.](https://maaw.social/@twblue)
|
||||
|
||||
* In the graphical interface, TWBlue will update menu items, in the menu bar, depending on whether you are focusing a Twitter or Mastodon session. This makes it possible for TWBlue to display the correct terms in each social network. Take into account that there might be unavailable items for the currently active session.
|
||||
* in the keystroke editor for the invisible interface, TWBlue displays the available shortcuts for the currently active session. Descriptions of those keystrokes are also different for Twitter and mastodon sessions to use correct terms for both networks.
|
||||
* In the invisible interface, TWBlue will skip sessions that have not been started when using the keyboard shortcut to switch between different accounts.
|
||||
* Fixed a bug when deleting a session in the session manager dialog. Sessions can now be deleted correctly.
|
||||
* Mastodon:
|
||||
* Added basic support to notifications buffer. This buffer shows mastodon notifications in real time. Every notification is attached to a kind of object (posts, users, relationships or polls). At the moment, the only supported action for notification is dismissing, which allows you to remove the notification from the buffer (take into account, though, that mention notifications will remove also the mention in its corresponding buffer, due to the way TWBlue reads mentions from mastodon instances).
|
||||
* Fixed an issue that was preventing TWBlue to create more than one user timeline during startup.
|
||||
* Fixed getting more items in mentions buffer. ([#508](https://github.com/mcv-software/twblue/issues/508))
|
||||
* TWBlue will display properly new paragraphs in mastodon posts.
|
||||
* In the session manager, Mastodon sessions are now displayed including the instance to avoid confusion.
|
||||
* TWBlue will now read default visibility preferences when posting new statuses, and display sensitive content. These preferences can be set on the mastodon instance, in the account's preferences section. If you wish to change TWBlue's behavior and have it not read those preferences from your instance, but instead set the default public visibility and hide sensitive content, you can uncheck the Read preferences from instance checkbox in the account options.
|
||||
* If a mastodon instance is not active or there are errors during login, TWBlue will report it in the log file and will continue with other sessions.
|
||||
* When replying to someone in a public post, TWBlue will default to "unlisted" as its visibility setting. This is done so replies will not clutter local and federated timelines. This setting might be changed when writing the reply, though. ([#504,](https://github.com/MCV-Software/TWBlue/issues/504))
|
||||
* TWBlue uses its own user agent in Mastodon sessions, so it will be easier to identify the client for instance admins.
|
||||
* TWBlue will check if the streaming API endpoints are available before attempting to start Streaming for the current session. Before, TWBlue caused load issues in misconfigured mastodon instances where the streaming API were not available.
|
||||
|
||||
## Changes in version 2022.12.13
|
||||
|
||||
* per popular request, We will generate a 32-bit portable version of TWBlue available for Windows 7 operating systems. This version will not be supported in our automatic updater, so in case of using such version, you would need to download it manually every time there is a new update. TWBlue will continue to be available for Windows 7 as long as it is possible to build it using Python 3.7.
|
||||
* Fixed a couple of bugs that were making TWBlue unable to be opened in some computers, related to our translator module and some COM objects handled incorrectly.
|
||||
* Fixed an issue that was making TWBlue unable to open in certain computers due to errors related to Win32 API'S.
|
||||
|
@@ -10,7 +10,6 @@ from importlib import reload
|
||||
# Languages already translated or translating the documentation.
|
||||
documentation_languages = ["en", "es", "fr", "de", "it", "gl", "ja", "ru", "ro", "eu", "ca", "da", "sr"]
|
||||
|
||||
|
||||
# Changelog translated languages.
|
||||
changelog_languages = ["en", "ca", "de", "es", "eu", "fr", "gl", "ja", "ro", "ru", "sr"]
|
||||
|
||||
@@ -29,8 +28,13 @@ def get_translations(name):
|
||||
langs = changelog_languages
|
||||
for l in langs:
|
||||
if l != "en":
|
||||
_ = gettext.translation(name, os.path.join(paths.app_path(), "locales"), languages=[l])
|
||||
translations[l] = _
|
||||
try:
|
||||
_ = gettext.translation(name, os.path.join(paths.app_path(), "locales"), languages=[l])
|
||||
translations[l] = _
|
||||
print(l, name)
|
||||
except FileNotFoundError:
|
||||
_ = gettext.NullTranslations()
|
||||
translations[l] = _
|
||||
else:
|
||||
_ = gettext.NullTranslations()
|
||||
translations[l] = _
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
BIN
doc/locales/sr/LC_MESSAGES/twblue-changelog.mo
Normal file
BIN
doc/locales/sr/LC_MESSAGES/twblue-changelog.mo
Normal file
Binary file not shown.
1945
doc/locales/sr/LC_MESSAGES/twblue-changelog.po
Normal file
1945
doc/locales/sr/LC_MESSAGES/twblue-changelog.po
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,6 @@ oauthlib
|
||||
requests-oauthlib
|
||||
requests-toolbelt
|
||||
pypubsub
|
||||
geopy
|
||||
arrow
|
||||
python-dateutil
|
||||
winpaths
|
||||
@@ -29,7 +28,6 @@ pywin32
|
||||
certifi
|
||||
backports.functools_lru_cache
|
||||
cx_freeze
|
||||
tweepy
|
||||
twitter-text-parser
|
||||
mastodon.py
|
||||
pyenchant
|
||||
|
@@ -1,60 +0,0 @@
|
||||
[twitter]
|
||||
user_key = string(default="")
|
||||
user_secret = string(default="")
|
||||
user_name = string(default="")
|
||||
ignored_clients = list(default=list())
|
||||
|
||||
[general]
|
||||
relative_times = boolean(default=True)
|
||||
max_api_calls = integer(default=1)
|
||||
max_tweets_per_call = integer(default=100)
|
||||
reverse_timelines = boolean(default=False)
|
||||
announce_stream_status = boolean(default=True)
|
||||
retweet_mode = string(default="ask")
|
||||
persist_size = integer(default=0)
|
||||
load_cache_in_memory=boolean(default=True)
|
||||
show_screen_names = boolean(default=False)
|
||||
hide_emojis = boolean(default=False)
|
||||
buffer_order = list(default=list('home','mentions', 'dm', 'sent_dm', 'sent_tweets','favorites','followers','friends','blocks','muted'))
|
||||
|
||||
[sound]
|
||||
volume = float(default=1.0)
|
||||
input_device = string(default="Default")
|
||||
output_device = string(default="Default")
|
||||
session_mute = boolean(default=False)
|
||||
current_soundpack = string(default="FreakyBlue")
|
||||
indicate_audio = boolean(default=True)
|
||||
indicate_geo = boolean(default=True)
|
||||
indicate_img = boolean(default=True)
|
||||
sndup_api_key = string(default="")
|
||||
|
||||
[other_buffers]
|
||||
timelines = list(default=list())
|
||||
tweet_searches = list(default=list())
|
||||
lists = list(default=list())
|
||||
favourites_timelines = list(default=list())
|
||||
followers_timelines = list(default=list())
|
||||
friends_timelines = list(default=list())
|
||||
trending_topic_buffers = list(default=list())
|
||||
muted_buffers = list(default=list())
|
||||
autoread_buffers = list(default=list(mentions, direct_messages, events))
|
||||
|
||||
[mysc]
|
||||
spelling_language = string(default="")
|
||||
save_followers_in_autocompletion_db = boolean(default=False)
|
||||
save_friends_in_autocompletion_db = boolean(default=False)
|
||||
ocr_language = string(default="")
|
||||
|
||||
[reporting]
|
||||
braille_reporting = boolean(default=True)
|
||||
speech_reporting = boolean(default=True)
|
||||
|
||||
[templates]
|
||||
tweet = string(default="$display_name, $text $image_descriptions $date. $source")
|
||||
dm = string(default="$sender_display_name, $text $date")
|
||||
dm_sent = string(default="Dm to $recipient_display_name, $text $date")
|
||||
person = string(default="$display_name (@$screen_name). $followers followers, $following following, $tweets tweets. Joined Twitter $created_at.")
|
||||
|
||||
[filters]
|
||||
|
||||
[user-aliases]
|
@@ -2,13 +2,13 @@
|
||||
name = 'TWBlue'
|
||||
short_name='twblue'
|
||||
update_url = 'https://twblue.es/updates/updates.php'
|
||||
mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/updates.json'
|
||||
mirror_update_url = 'https://raw.githubusercontent.com/mcv-software/TWBlue/next-gen/updates/updates.json'
|
||||
authors = ["Manuel Cortéz", "José Manuel Delicado"]
|
||||
authorEmail = "manuel@manuelcortez.net"
|
||||
copyright = "Copyright (C) 2013-2022, MCV Software."
|
||||
copyright = "Copyright (C) 2013-2023, MCV Software."
|
||||
description = name+" is an app designed to use Twitter simply and efficiently while using minimal system resources. This app provides access to most Twitter features."
|
||||
translators = ["Manuel Cortéz (English)", "Mohammed Al Shara, Hatoun Felemban (Arabic)", "Francisco Torres (Catalan)", "Manuel cortéz (Spanish)", "Sukil Etxenike Arizaleta (Basque)", "Jani Kinnunen (finnish)", "Corentin Bacqué-Cazenave (Français)", "Juan Buño (Galician)", "Steffen Schultz (German)", "Zvonimir Stanečić (Croatian)", "Robert Osztolykan (Hungarian)", "Christian Leo Mameli (Italian)", "Riku (Japanese)", "Paweł Masarczyk (Polish)", "Odenilton Júnior Santos (Portuguese)", "Florian Ionașcu, Nicușor Untilă (Romanian)", "Natalia Hedlund, Valeria Kuznetsova (Russian)", "Aleksandar Đurić (Serbian)", "Burak Yüksek (Turkish)"]
|
||||
url = "https://twblue.es"
|
||||
report_bugs_url = "https://github.com/mcvsoftware/twblue/issues"
|
||||
report_bugs_url = "https://github.com/MCV-Software/TWBlue/issues"
|
||||
supported_languages = []
|
||||
version = "11"
|
||||
|
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import base as base
|
||||
from . import twitter as twitter
|
||||
from . import mastodon as mastodon
|
@@ -2,4 +2,5 @@
|
||||
from .base import BaseBuffer
|
||||
from .mentions import MentionsBuffer
|
||||
from .conversations import ConversationBuffer, ConversationListBuffer
|
||||
from .users import UserBuffer
|
||||
from .users import UserBuffer
|
||||
from .notifications import NotificationsBuffer
|
@@ -9,6 +9,7 @@ import config
|
||||
import sound
|
||||
import languageHandler
|
||||
import logging
|
||||
from mastodon import MastodonNotFoundError
|
||||
from audio_services import youtube_utils
|
||||
from controller.buffers.base import base
|
||||
from controller.mastodon import messages
|
||||
@@ -16,9 +17,11 @@ from sessions.mastodon import compose, utils, templates
|
||||
from mysc.thread_utils import call_threaded
|
||||
from pubsub import pub
|
||||
from extra import ocr
|
||||
from wxUI import buffers, dialogs, commonMessageDialogs
|
||||
from wxUI import buffers, commonMessageDialogs
|
||||
from wxUI.dialogs.mastodon import menus
|
||||
from wxUI.dialogs.mastodon import dialogs as mastodon_dialogs
|
||||
from wxUI.dialogs.mastodon.postDialogs import attachedPoll
|
||||
from wxUI.dialogs import urlList
|
||||
|
||||
log = logging.getLogger("controller.buffers.mastodon.base")
|
||||
|
||||
@@ -72,15 +75,23 @@ class BaseBuffer(base.Buffer):
|
||||
post.message.destroy()
|
||||
|
||||
def get_formatted_message(self):
|
||||
return self.compose_function(self.get_item(), self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])[1]
|
||||
safe = True
|
||||
if self.session.settings["general"]["read_preferences_from_instance"]:
|
||||
safe = self.session.expand_spoilers == False
|
||||
return self.compose_function(self.get_item(), self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)[1]
|
||||
|
||||
def get_message(self):
|
||||
post = self.get_item()
|
||||
if post == None:
|
||||
return
|
||||
template = self.session.settings["templates"]["post"]
|
||||
|
||||
t = templates.render_post(post, template, relative_times=self.session.settings["general"]["relative_times"], offset_hours=self.session.db["utc_offset"])
|
||||
# If template is set to hide sensitive media by default, let's change it according to user preferences.
|
||||
if self.session.settings["general"]["read_preferences_from_instance"] == True:
|
||||
if self.session.expand_spoilers == True and "$safe_text" in template:
|
||||
template = template.replace("$safe_text", "$text")
|
||||
elif self.session.expand_spoilers == False and "$text" in template:
|
||||
template = template.replace("$text", "$safe_text")
|
||||
t = templates.render_post(post, template, self.session.settings, relative_times=self.session.settings["general"]["relative_times"], offset_hours=self.session.db["utc_offset"])
|
||||
return t
|
||||
|
||||
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False):
|
||||
@@ -108,6 +119,7 @@ class BaseBuffer(base.Buffer):
|
||||
if hasattr(self, "finished_timeline") and self.finished_timeline == False:
|
||||
if "-timeline" in self.name:
|
||||
self.username = self.session.db[self.name][0]["account"].username
|
||||
pub.sendMessage("core.change_buffer_title", name=self.session.get_name(), buffer=self.name, title=_("Timeline for {}").format(self.username))
|
||||
self.finished_timeline = True
|
||||
self.put_items_on_list(number_of_items)
|
||||
if number_of_items > 0 and self.name != "sent_posts" and self.name != "sent_direct_messages" and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True:
|
||||
@@ -124,7 +136,10 @@ class BaseBuffer(base.Buffer):
|
||||
else:
|
||||
post = self.session.db[self.name][0]
|
||||
output.speak(_("New post in {0}").format(self.get_buffer_name()))
|
||||
output.speak(" ".join(self.compose_function(post, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])))
|
||||
safe = True
|
||||
if self.session.settings["general"]["read_preferences_from_instance"]:
|
||||
safe = self.session.expand_spoilers == False
|
||||
output.speak(" ".join(self.compose_function(post, self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)))
|
||||
elif number_of_items > 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False:
|
||||
output.speak(_("{0} new posts in {1}.").format(number_of_items, self.get_buffer_name()))
|
||||
|
||||
@@ -150,13 +165,16 @@ class BaseBuffer(base.Buffer):
|
||||
self.session.db[self.name] = items_db
|
||||
selection = self.buffer.list.get_selected()
|
||||
log.debug("Retrieved %d items from cursored search in function %s." % (len(elements), self.function))
|
||||
safe = True
|
||||
if self.session.settings["general"]["read_preferences_from_instance"]:
|
||||
safe = self.session.expand_spoilers == False
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
for i in elements:
|
||||
post = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])
|
||||
post = self.compose_function(i, self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
||||
self.buffer.list.insert_item(True, *post)
|
||||
else:
|
||||
for i in elements:
|
||||
post = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])
|
||||
post = self.compose_function(i, self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
||||
self.buffer.list.insert_item(False, *post)
|
||||
self.buffer.list.select_item(selection)
|
||||
output.speak(_(u"%s items retrieved") % (str(len(elements))), True)
|
||||
@@ -185,27 +203,33 @@ class BaseBuffer(base.Buffer):
|
||||
if number_of_items == 0 and self.session.settings["general"]["persist_size"] == 0: return
|
||||
log.debug("The list contains %d items " % (self.buffer.list.get_count(),))
|
||||
log.debug("Putting %d items on the list" % (number_of_items,))
|
||||
safe = True
|
||||
if self.session.settings["general"]["read_preferences_from_instance"]:
|
||||
safe = self.session.expand_spoilers == False
|
||||
if self.buffer.list.get_count() == 0:
|
||||
for i in list_to_use:
|
||||
post = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])
|
||||
post = self.compose_function(i, self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
||||
self.buffer.list.insert_item(False, *post)
|
||||
self.buffer.set_position(self.session.settings["general"]["reverse_timelines"])
|
||||
elif self.buffer.list.get_count() > 0 and number_of_items > 0:
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
items = list_to_use[len(list_to_use)-number_of_items:]
|
||||
for i in items:
|
||||
post = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])
|
||||
post = self.compose_function(i, self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
||||
self.buffer.list.insert_item(False, *post)
|
||||
else:
|
||||
items = list_to_use[0:number_of_items]
|
||||
items.reverse()
|
||||
for i in items:
|
||||
post = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])
|
||||
post = self.compose_function(i, self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
||||
self.buffer.list.insert_item(True, *post)
|
||||
log.debug("Now the list contains %d items " % (self.buffer.list.get_count(),))
|
||||
|
||||
def add_new_item(self, item):
|
||||
post = self.compose_function(item, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])
|
||||
safe = True
|
||||
if self.session.settings["general"]["read_preferences_from_instance"]:
|
||||
safe = self.session.expand_spoilers == False
|
||||
post = self.compose_function(item, self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
self.buffer.list.insert_item(False, *post)
|
||||
else:
|
||||
@@ -214,7 +238,10 @@ class BaseBuffer(base.Buffer):
|
||||
output.speak(" ".join(post[:2]), speech=self.session.settings["reporting"]["speech_reporting"], braille=self.session.settings["reporting"]["braille_reporting"])
|
||||
|
||||
def update_item(self, item, position):
|
||||
post = self.compose_function(item, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])
|
||||
safe = True
|
||||
if self.session.settings["general"]["read_preferences_from_instance"]:
|
||||
safe = self.session.expand_spoilers == False
|
||||
post = self.compose_function(item, self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
||||
self.buffer.list.list.SetItem(position, 1, post[1])
|
||||
|
||||
def bind_events(self):
|
||||
@@ -298,6 +325,9 @@ class BaseBuffer(base.Buffer):
|
||||
else:
|
||||
title = _("Reply to {}").format(item.account.username)
|
||||
caption = _("Write your reply here")
|
||||
# Set unlisted by default, so we will not clutter other user's buffers with replies.
|
||||
# see https://github.com/MCV-Software/TWBlue/issues/504
|
||||
visibility = "unlisted"
|
||||
if item.reblog != None:
|
||||
users = ["@{} ".format(user.acct) for user in item.reblog.mentions if user.id != self.session.db["user_id"]]
|
||||
if item.reblog.account.acct != item.account.acct and "@{} ".format(item.reblog.account.acct) not in users:
|
||||
@@ -350,7 +380,7 @@ class BaseBuffer(base.Buffer):
|
||||
|
||||
def share_item(self, *args, **kwargs):
|
||||
if self.can_share() == False:
|
||||
return output.speak(_("This action is not supported on conversation posts."))
|
||||
return output.speak(_("This action is not supported on conversations."))
|
||||
post = self.get_item()
|
||||
id = post.id
|
||||
if self.session.settings["general"]["boost_mode"] == "ask":
|
||||
@@ -387,7 +417,7 @@ class BaseBuffer(base.Buffer):
|
||||
if len(urls) == 1:
|
||||
url=urls[0]
|
||||
elif len(urls) > 1:
|
||||
urls_list = dialogs.urlList.urlList()
|
||||
urls_list = urlList.urlList()
|
||||
urls_list.populate_list(urls)
|
||||
if urls_list.get_response() == widgetUtils.OK:
|
||||
url=urls_list.get_string()
|
||||
@@ -408,7 +438,7 @@ class BaseBuffer(base.Buffer):
|
||||
if len(urls) == 1:
|
||||
url=urls[0]
|
||||
elif len(urls) > 1:
|
||||
urls_list = dialogs.urlList.urlList()
|
||||
urls_list = urlList.urlList()
|
||||
urls_list.populate_list(urls)
|
||||
if urls_list.get_response() == widgetUtils.OK:
|
||||
url=urls_list.get_string()
|
||||
@@ -439,6 +469,7 @@ class BaseBuffer(base.Buffer):
|
||||
self.buffer.list.remove_item(index)
|
||||
except Exception as e:
|
||||
self.session.sound.play("error.ogg")
|
||||
log.exception("")
|
||||
self.session.db[self.name] = items
|
||||
|
||||
def user_details(self):
|
||||
@@ -472,7 +503,11 @@ class BaseBuffer(base.Buffer):
|
||||
item = self.get_item()
|
||||
if item.reblog != None:
|
||||
item = item.reblog
|
||||
item = self.session.api.status(item.id)
|
||||
try:
|
||||
item = self.session.api.status(item.id)
|
||||
except MastodonNotFoundError:
|
||||
output.speak(_("No status found with that ID"))
|
||||
return
|
||||
if item.favourited == False:
|
||||
call_threaded(self.session.api_call, call_name="status_favourite", preexec_message=_("Adding to favorites..."), _sound="favourite.ogg", id=item.id)
|
||||
else:
|
||||
@@ -482,7 +517,11 @@ class BaseBuffer(base.Buffer):
|
||||
item = self.get_item()
|
||||
if item.reblog != None:
|
||||
item = item.reblog
|
||||
item = self.session.api.status(item.id)
|
||||
try:
|
||||
item = self.session.api.status(item.id)
|
||||
except MastodonNotFoundError:
|
||||
output.speak(_("No status found with that ID"))
|
||||
return
|
||||
if item.bookmarked == False:
|
||||
call_threaded(self.session.api_call, call_name="status_bookmark", preexec_message=_("Adding to bookmarks..."), _sound="favourite.ogg", id=item.id)
|
||||
else:
|
||||
@@ -491,11 +530,86 @@ class BaseBuffer(base.Buffer):
|
||||
def view_item(self):
|
||||
post = self.get_item()
|
||||
# Update object so we can retrieve newer stats
|
||||
post = self.session.api.status(id=post.id)
|
||||
try:
|
||||
post = self.session.api.status(id=post.id)
|
||||
except MastodonNotFoundError:
|
||||
output.speak(_("No status found with that ID"))
|
||||
return
|
||||
# print(post)
|
||||
msg = messages.viewPost(post, offset_hours=self.session.db["utc_offset"], item_url=self.get_item_url())
|
||||
|
||||
def ocr_image(self):
|
||||
post = self.get_item()
|
||||
media_list = []
|
||||
pass
|
||||
if post.reblog != None:
|
||||
post = post.reblog
|
||||
for media in post.get("media_attachments"):
|
||||
if media.get("type", "") == "image":
|
||||
media_list.append(media)
|
||||
if len(media_list) > 1:
|
||||
image_list = [_(u"Picture {0}").format(i+1,) for i in range(0, len(media_list))]
|
||||
dialog = urlList.urlList(title=_(u"Select the picture"))
|
||||
dialog.populate_list(image_list)
|
||||
if dialog.get_response() == widgetUtils.OK:
|
||||
img = media_list[dialog.get_item()]
|
||||
else:
|
||||
return
|
||||
elif len(media_list) == 1:
|
||||
img = media_list[0]
|
||||
else:
|
||||
return
|
||||
if self.session.settings["mysc"]["ocr_language"] != "":
|
||||
ocr_lang = self.session.settings["mysc"]["ocr_language"]
|
||||
else:
|
||||
ocr_lang = ocr.OCRSpace.short_langs.index(post.language)
|
||||
ocr_lang = ocr.OCRSpace.OcrLangs[ocr_lang]
|
||||
if img["remote_url"] != None:
|
||||
url = img["remote_url"]
|
||||
else:
|
||||
url = img["url"]
|
||||
api = ocr.OCRSpace.OCRSpaceAPI()
|
||||
try:
|
||||
text = api.OCR_URL(url)
|
||||
except ocr.OCRSpace.APIError as er:
|
||||
output.speak(_(u"Unable to extract text"))
|
||||
return
|
||||
viewer = messages.text(title=_("OCR Result"), text=text["ParsedText"])
|
||||
response = viewer.message.ShowModal()
|
||||
viewer.message.Destroy()
|
||||
|
||||
def vote(self):
|
||||
post = self.get_item()
|
||||
if not hasattr(post, "poll") or post.poll == None:
|
||||
return
|
||||
poll = post.poll
|
||||
try:
|
||||
poll = self.session.api.poll(id=poll.id)
|
||||
except MastodonNotFoundError:
|
||||
output.speak(_("this poll no longer exists."))
|
||||
return
|
||||
if poll.expired:
|
||||
output.speak(_("This poll has already expired."))
|
||||
return
|
||||
if poll.voted:
|
||||
output.speak(_("You have already voted on this poll."))
|
||||
return
|
||||
options = poll.options
|
||||
dlg = attachedPoll(poll_options=[option.title for option in options], multiple=poll.multiple)
|
||||
answer = dlg.ShowModal()
|
||||
options = dlg.get_selected()
|
||||
dlg.Destroy()
|
||||
if answer != wx.ID_OK:
|
||||
return
|
||||
poll = self.session.api_call(call_name="poll_vote", id=poll.id, choices=options, preexec_message=_("Sending vote..."))
|
||||
|
||||
def post_from_error(self, visibility, reply_to, data):
|
||||
title = _("Post")
|
||||
caption = _("Write your post here")
|
||||
post = messages.post(session=self.session, title=title, caption=caption)
|
||||
post.set_post_data(visibility=visibility, data=data)
|
||||
response = post.message.ShowModal()
|
||||
if response == wx.ID_OK:
|
||||
post_data = post.get_data()
|
||||
call_threaded(self.session.send_post, posts=post_data, reply_to=reply_to, visibility=post.get_visibility())
|
||||
if hasattr(post.message, "destroy"):
|
||||
post.message.destroy()
|
||||
|
@@ -4,6 +4,7 @@ import logging
|
||||
import wx
|
||||
import widgetUtils
|
||||
import output
|
||||
from mastodon import MastodonNotFoundError
|
||||
from controller.mastodon import messages
|
||||
from controller.buffers.mastodon.base import BaseBuffer
|
||||
from mysc.thread_utils import call_threaded
|
||||
@@ -27,7 +28,7 @@ class ConversationListBuffer(BaseBuffer):
|
||||
return self.session.db[self.name][index]
|
||||
|
||||
def get_formatted_message(self):
|
||||
return self.compose_function(self.get_conversation(), self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])[1]
|
||||
return self.compose_function(self.get_conversation(), self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])[1]
|
||||
|
||||
def get_message(self):
|
||||
conversation = self.get_conversation()
|
||||
@@ -35,7 +36,7 @@ class ConversationListBuffer(BaseBuffer):
|
||||
return
|
||||
template = self.session.settings["templates"]["conversation"]
|
||||
post_template = self.session.settings["templates"]["post"]
|
||||
t = templates.render_conversation(conversation=conversation, template=template, post_template=post_template, relative_times=self.session.settings["general"]["relative_times"], offset_hours=self.session.db["utc_offset"])
|
||||
t = templates.render_conversation(conversation=conversation, template=template, post_template=post_template, settings=self.session.settings, relative_times=self.session.settings["general"]["relative_times"], offset_hours=self.session.db["utc_offset"])
|
||||
return t
|
||||
|
||||
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False):
|
||||
@@ -88,11 +89,11 @@ class ConversationListBuffer(BaseBuffer):
|
||||
log.debug("Retrieved %d items from cursored search in function %s." % (len(elements), self.function))
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
for i in elements:
|
||||
conversation = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])
|
||||
conversation = self.compose_function(i, self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])
|
||||
self.buffer.list.insert_item(True, *conversation)
|
||||
else:
|
||||
for i in elements:
|
||||
conversation = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])
|
||||
conversation = self.compose_function(i, self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])
|
||||
self.buffer.list.insert_item(False, *conversation)
|
||||
self.buffer.list.select_item(selection)
|
||||
output.speak(_(u"%s items retrieved") % (str(len(elements))), True)
|
||||
@@ -200,7 +201,11 @@ class ConversationBuffer(BaseBuffer):
|
||||
self.execution_time = current_time
|
||||
log.debug("Starting stream for buffer %s, account %s and type %s" % (self.name, self.account, self.type))
|
||||
log.debug("args: %s, kwargs: %s" % (self.args, self.kwargs))
|
||||
self.post = self.session.api.status(id=self.post.id)
|
||||
try:
|
||||
self.post = self.session.api.status(id=self.post.id)
|
||||
except MastodonNotFoundError:
|
||||
output.speak(_("No status found with that ID"))
|
||||
return
|
||||
# toDo: Implement reverse timelines properly here.
|
||||
try:
|
||||
results = []
|
||||
|
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import time
|
||||
import logging
|
||||
import output
|
||||
from controller.buffers.mastodon.base import BaseBuffer
|
||||
from sessions.mastodon import utils
|
||||
|
||||
@@ -8,6 +9,11 @@ log = logging.getLogger("controller.buffers.mastodon.mentions")
|
||||
|
||||
class MentionsBuffer(BaseBuffer):
|
||||
|
||||
def get_item(self):
|
||||
index = self.buffer.list.get_selected()
|
||||
if index > -1 and self.session.db.get(self.name) != None and len(self.session.db[self.name]) > index:
|
||||
return self.session.db[self.name][index]["status"]
|
||||
|
||||
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False):
|
||||
current_time = time.time()
|
||||
if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory==True:
|
||||
@@ -17,13 +23,14 @@ class MentionsBuffer(BaseBuffer):
|
||||
count = self.session.settings["general"]["max_posts_per_call"]
|
||||
min_id = None
|
||||
try:
|
||||
items = getattr(self.session.api, self.function)(min_id=min_id, limit=count, exclude_types=["follow", "favourite", "reblog", "poll", "follow_request"], *self.args, **self.kwargs)
|
||||
items = getattr(self.session.api, self.function)(min_id=min_id, limit=count, types=["mention"], *self.args, **self.kwargs)
|
||||
items.reverse()
|
||||
results = [item.status for item in items if item.get("status") and item.type == "mention"]
|
||||
except Exception as e:
|
||||
log.exception("Error %s" % (str(e)))
|
||||
return
|
||||
number_of_items = self.session.order_buffer(self.name, results)
|
||||
# Attempt to remove items with no statuses attached to them as it might happen when blocked accounts have notifications.
|
||||
items = [item for item in items if item.status != None]
|
||||
number_of_items = self.session.order_buffer(self.name, items)
|
||||
log.debug("Number of items retrieved: %d" % (number_of_items,))
|
||||
self.put_items_on_list(number_of_items)
|
||||
if number_of_items > 0 and self.name != "sent_posts" and self.name != "sent_direct_messages" and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True:
|
||||
@@ -40,11 +47,12 @@ class MentionsBuffer(BaseBuffer):
|
||||
else:
|
||||
max_id = self.session.db[self.name][-1].id
|
||||
try:
|
||||
items = getattr(self.session.api, self.function)(max_id=max_id, limit=self.session.settings["general"]["max_posts_per_call"], exclude_types=["follow", "favourite", "reblog", "poll", "follow_request"], *self.args, **self.kwargs)
|
||||
items = [item.status for item in items if item.get("status") and item.type == "mention"]
|
||||
items = getattr(self.session.api, self.function)(max_id=max_id, limit=self.session.settings["general"]["max_posts_per_call"], types=["mention"], *self.args, **self.kwargs)
|
||||
except Exception as e:
|
||||
log.exception("Error %s" % (str(e)))
|
||||
return
|
||||
# Attempt to remove items with no statuses attached to them as it might happen when blocked accounts have notifications.
|
||||
items = [item for item in items if item.status != None]
|
||||
items_db = self.session.db[self.name]
|
||||
for i in items:
|
||||
if utils.find_item(i, self.session.db[self.name]) == None:
|
||||
@@ -56,13 +64,55 @@ class MentionsBuffer(BaseBuffer):
|
||||
self.session.db[self.name] = items_db
|
||||
selection = self.buffer.list.get_selected()
|
||||
log.debug("Retrieved %d items from cursored search in function %s." % (len(elements), self.function))
|
||||
safe = True
|
||||
if self.session.settings["general"]["read_preferences_from_instance"]:
|
||||
safe = self.session.expand_spoilers == False
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
for i in elements:
|
||||
post = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])
|
||||
post = self.compose_function(i.status, self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
||||
self.buffer.list.insert_item(True, *post)
|
||||
else:
|
||||
for i in elements:
|
||||
post = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])
|
||||
post = self.compose_function(i.status, self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
||||
self.buffer.list.insert_item(False, *post)
|
||||
self.buffer.list.select_item(selection)
|
||||
output.speak(_(u"%s items retrieved") % (str(len(elements))), True)
|
||||
output.speak(_(u"%s items retrieved") % (str(len(elements))), True)
|
||||
|
||||
def put_items_on_list(self, number_of_items):
|
||||
list_to_use = self.session.db[self.name]
|
||||
if number_of_items == 0 and self.session.settings["general"]["persist_size"] == 0: return
|
||||
log.debug("The list contains %d items " % (self.buffer.list.get_count(),))
|
||||
log.debug("Putting %d items on the list" % (number_of_items,))
|
||||
safe = True
|
||||
if self.session.settings["general"]["read_preferences_from_instance"]:
|
||||
safe = self.session.expand_spoilers == False
|
||||
if self.buffer.list.get_count() == 0:
|
||||
for i in list_to_use:
|
||||
post = self.compose_function(i.status, self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
||||
self.buffer.list.insert_item(False, *post)
|
||||
self.buffer.set_position(self.session.settings["general"]["reverse_timelines"])
|
||||
elif self.buffer.list.get_count() > 0 and number_of_items > 0:
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
items = list_to_use[len(list_to_use)-number_of_items:]
|
||||
for i in items:
|
||||
post = self.compose_function(i.status, self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
||||
self.buffer.list.insert_item(False, *post)
|
||||
else:
|
||||
items = list_to_use[0:number_of_items]
|
||||
items.reverse()
|
||||
for i in items:
|
||||
post = self.compose_function(i.status, self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
||||
self.buffer.list.insert_item(True, *post)
|
||||
log.debug("Now the list contains %d items " % (self.buffer.list.get_count(),))
|
||||
|
||||
def add_new_item(self, item):
|
||||
safe = True
|
||||
if self.session.settings["general"]["read_preferences_from_instance"]:
|
||||
safe = self.session.expand_spoilers == False
|
||||
post = self.compose_function(item.status, self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
self.buffer.list.insert_item(False, *post)
|
||||
else:
|
||||
self.buffer.list.insert_item(True, *post)
|
||||
if self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False:
|
||||
output.speak(" ".join(post[:2]), speech=self.session.settings["reporting"]["speech_reporting"], braille=self.session.settings["reporting"]["braille_reporting"])
|
||||
|
66
src/controller/buffers/mastodon/notifications.py
Normal file
66
src/controller/buffers/mastodon/notifications.py
Normal file
@@ -0,0 +1,66 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import time
|
||||
import logging
|
||||
import widgetUtils
|
||||
import output
|
||||
from controller.buffers.mastodon.base import BaseBuffer
|
||||
from sessions.mastodon import compose, templates
|
||||
from wxUI import buffers
|
||||
from wxUI.dialogs.mastodon import dialogs as mastodon_dialogs
|
||||
|
||||
log = logging.getLogger("controller.buffers.mastodon.notifications")
|
||||
|
||||
class NotificationsBuffer(BaseBuffer):
|
||||
|
||||
def get_message(self):
|
||||
notification = self.get_item()
|
||||
if notification == None:
|
||||
return
|
||||
template = self.session.settings["templates"]["notification"]
|
||||
post_template = self.session.settings["templates"]["post"]
|
||||
t = templates.render_notification(notification, template, post_template, self.session.settings, relative_times=self.session.settings["general"]["relative_times"], offset_hours=self.session.db["utc_offset"])
|
||||
return t
|
||||
|
||||
def create_buffer(self, parent, name):
|
||||
self.buffer = buffers.mastodon.notificationsPanel(parent, name)
|
||||
|
||||
def onFocus(self, *args, **kwargs):
|
||||
item = self.get_item()
|
||||
if self.session.settings["general"]["relative_times"] == True:
|
||||
original_date = arrow.get(self.session.db[self.name][self.buffer.list.get_selected()].created_at)
|
||||
ts = original_date.humanize(locale=languageHandler.getLanguage())
|
||||
self.buffer.list.list.SetItem(self.buffer.list.get_selected(), 1, ts)
|
||||
|
||||
def bind_events(self):
|
||||
widgetUtils.connect_event(self.buffer.list.list, widgetUtils.KEYPRESS, self.get_event)
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.post_status, self.buffer.post)
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.destroy_status, self.buffer.dismiss)
|
||||
|
||||
def fav(self):
|
||||
pass
|
||||
|
||||
def unfav(self):
|
||||
pass
|
||||
|
||||
def vote(self):
|
||||
pass
|
||||
|
||||
def can_share(self):
|
||||
return False
|
||||
|
||||
def destroy_status(self, *args, **kwargs):
|
||||
index = self.buffer.list.get_selected()
|
||||
item = self.session.db[self.name][index]
|
||||
answer = mastodon_dialogs.delete_notification_dialog()
|
||||
if answer == False:
|
||||
return
|
||||
items = self.session.db[self.name]
|
||||
try:
|
||||
self.session.api.notifications_dismiss(id=item.id)
|
||||
items.pop(index)
|
||||
self.buffer.list.remove_item(index)
|
||||
output.speak(_("Notification dismissed."))
|
||||
except Exception as e:
|
||||
self.session.sound.play("error.ogg")
|
||||
log.exception("")
|
||||
self.session.db[self.name] = items
|
@@ -4,6 +4,7 @@ import logging
|
||||
import wx
|
||||
import widgetUtils
|
||||
import output
|
||||
from pubsub import pub
|
||||
from mysc.thread_utils import call_threaded
|
||||
from controller.buffers.mastodon.base import BaseBuffer
|
||||
from controller.mastodon import messages
|
||||
@@ -22,7 +23,7 @@ class UserBuffer(BaseBuffer):
|
||||
if user == None:
|
||||
return
|
||||
template = self.session.settings["templates"]["person"]
|
||||
t = templates.render_user(user=user, template=template, relative_times=self.session.settings["general"]["relative_times"], offset_hours=self.session.db["utc_offset"])
|
||||
t = templates.render_user(user=user, template=template, settings=self.session.settings, relative_times=self.session.settings["general"]["relative_times"], offset_hours=self.session.db["utc_offset"])
|
||||
return t
|
||||
|
||||
def bind_events(self):
|
||||
@@ -88,6 +89,11 @@ class UserBuffer(BaseBuffer):
|
||||
if hasattr(self, "finished_timeline") and self.finished_timeline == False:
|
||||
if "-followers" in self.name or "-following" in self.name:
|
||||
self.username = self.session.api.account(id=self.kwargs.get("id")).username
|
||||
if "-followers" in self.name:
|
||||
title=_("Followers for {}").format(self.username)
|
||||
else:
|
||||
title=_("Following for {}").format(self.username)
|
||||
pub.sendMessage("core.change_buffer_title", name=self.session.get_name(), buffer=self.name, title=title)
|
||||
self.finished_timeline = True
|
||||
self.put_items_on_list(number_of_items)
|
||||
if number_of_items > 0 and self.name != "sent_posts" and self.name != "sent_direct_messages" and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True:
|
||||
@@ -123,11 +129,11 @@ class UserBuffer(BaseBuffer):
|
||||
log.debug("Retrieved %d items from cursored search in function %s." % (len(elements), self.function))
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
for i in elements:
|
||||
post = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])
|
||||
post = self.compose_function(i, self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])
|
||||
self.buffer.list.insert_item(True, *post)
|
||||
else:
|
||||
for i in elements:
|
||||
post = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])
|
||||
post = self.compose_function(i, self.session.db, self.session.settings, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"])
|
||||
self.buffer.list.insert_item(False, *post)
|
||||
self.buffer.list.select_item(selection)
|
||||
output.speak(_(u"%s items retrieved") % (str(len(elements))), True)
|
||||
|
@@ -1,7 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from .base import BaseBuffer
|
||||
from .directMessages import DirectMessagesBuffer, SentDirectMessagesBuffer
|
||||
from .list import ListBuffer
|
||||
from .people import PeopleBuffer
|
||||
from .trends import TrendsBuffer
|
||||
from .search import SearchBuffer, SearchPeopleBuffer, ConversationBuffer
|
@@ -1,663 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import time
|
||||
import wx
|
||||
import widgetUtils
|
||||
import arrow
|
||||
import webbrowser
|
||||
import output
|
||||
import config
|
||||
import sound
|
||||
import languageHandler
|
||||
import logging
|
||||
from audio_services import youtube_utils
|
||||
from controller.buffers.base import base
|
||||
from sessions.twitter import compose, utils, reduce, templates
|
||||
from mysc.thread_utils import call_threaded
|
||||
from tweepy.errors import TweepyException
|
||||
from tweepy.cursor import Cursor
|
||||
from pubsub import pub
|
||||
from extra import ocr
|
||||
from sessions.twitter.long_tweets import twishort, tweets
|
||||
from wxUI import buffers, dialogs, commonMessageDialogs, menus
|
||||
from controller.twitter import user, messages
|
||||
|
||||
log = logging.getLogger("controller.buffers")
|
||||
|
||||
def _tweets_exist(function):
|
||||
""" A decorator to execute a function only if the selected buffer contains at least one item."""
|
||||
def function_(self, *args, **kwargs):
|
||||
if self.buffer.list.get_count() > 0:
|
||||
function(self, *args, **kwargs)
|
||||
return function_
|
||||
|
||||
class BaseBuffer(base.Buffer):
|
||||
def __init__(self, parent, function, name, sessionObject, account, sound=None, bufferType=None, compose_func="compose_tweet", *args, **kwargs):
|
||||
super(BaseBuffer, self).__init__(parent, function, *args, **kwargs)
|
||||
log.debug("Initializing buffer %s, account %s" % (name, account,))
|
||||
if bufferType != None:
|
||||
self.buffer = getattr(buffers.twitter, bufferType)(parent, name)
|
||||
else:
|
||||
self.buffer = buffers.twitter.basePanel(parent, name)
|
||||
self.invisible = True
|
||||
self.name = name
|
||||
self.type = self.buffer.type
|
||||
self.session = sessionObject
|
||||
self.compose_function = getattr(compose, compose_func)
|
||||
log.debug("Compose_function: %s" % (self.compose_function,))
|
||||
self.account = account
|
||||
self.buffer.account = account
|
||||
self.bind_events()
|
||||
self.sound = sound
|
||||
if "-timeline" in self.name or "-favorite" in self.name:
|
||||
self.finished_timeline = False
|
||||
# Add a compatibility layer for username based timelines from config.
|
||||
# ToDo: Remove this in some new versions of the client, when user ID timelines become mandatory.
|
||||
try:
|
||||
int(self.kwargs["user_id"])
|
||||
except ValueError:
|
||||
self.is_screen_name = True
|
||||
self.kwargs["screen_name"] = self.kwargs["user_id"]
|
||||
self.kwargs.pop("user_id")
|
||||
|
||||
def get_buffer_name(self):
|
||||
""" Get buffer name from a set of different techniques."""
|
||||
# firstly let's take the easier buffers.
|
||||
basic_buffers = dict(home_timeline=_(u"Home"), mentions=_(u"Mentions"), direct_messages=_(u"Direct messages"), sent_direct_messages=_(u"Sent direct messages"), sent_tweets=_(u"Sent tweets"), favourites=_(u"Likes"), followers=_(u"Followers"), friends=_(u"Friends"), blocked=_(u"Blocked users"), muted=_(u"Muted users"))
|
||||
if self.name in list(basic_buffers.keys()):
|
||||
return basic_buffers[self.name]
|
||||
# Check user timelines
|
||||
elif hasattr(self, "username"):
|
||||
if "-timeline" in self.name:
|
||||
return _(u"{username}'s timeline").format(username=self.username,)
|
||||
elif "-favorite" in self.name:
|
||||
return _(u"{username}'s likes").format(username=self.username,)
|
||||
elif "-followers" in self.name:
|
||||
return _(u"{username}'s followers").format(username=self.username,)
|
||||
elif "-friends" in self.name:
|
||||
return _(u"{username}'s friends").format(username=self.username,)
|
||||
log.error("Error getting name for buffer %s" % (self.name,))
|
||||
return _(u"Unknown buffer")
|
||||
|
||||
def post_status(self, *args, **kwargs):
|
||||
title = _("Tweet")
|
||||
caption = _("Write the tweet here")
|
||||
tweet = messages.tweet(self.session, title, caption, "")
|
||||
response = tweet.message.ShowModal()
|
||||
if response == wx.ID_OK:
|
||||
tweet_data = tweet.get_tweet_data()
|
||||
call_threaded(self.session.send_tweet, *tweet_data)
|
||||
if hasattr(tweet.message, "destroy"):
|
||||
tweet.message.destroy()
|
||||
|
||||
def get_formatted_message(self):
|
||||
if self.type == "dm" or self.name == "direct_messages":
|
||||
return self.compose_function(self.get_right_tweet(), self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)[1]
|
||||
return self.get_message()
|
||||
|
||||
def get_message(self):
|
||||
template = self.session.settings["templates"]["tweet"]
|
||||
tweet = self.get_right_tweet()
|
||||
t = templates.render_tweet(tweet, template, self.session, relative_times=self.session.settings["general"]["relative_times"], offset_seconds=self.session.db["utc_offset"])
|
||||
return t
|
||||
|
||||
def get_full_tweet(self):
|
||||
tweet = self.get_right_tweet()
|
||||
tweetsList = []
|
||||
tweet_id = tweet.id
|
||||
message = None
|
||||
if hasattr(tweet, "message"):
|
||||
message = tweet.message
|
||||
try:
|
||||
tweet = self.session.twitter.get_status(id=tweet_id, include_ext_alt_text=True, tweet_mode="extended")
|
||||
tweet.full_text = utils.expand_urls(tweet.full_text, tweet.entities)
|
||||
except TweepyException as e:
|
||||
utils.twitter_error(e)
|
||||
return
|
||||
if message != None:
|
||||
tweet.message = message
|
||||
l = tweets.is_long(tweet)
|
||||
while l != False:
|
||||
tweetsList.append(tweet)
|
||||
try:
|
||||
tweet = self.session.twitter.get_status(id=l, include_ext_alt_text=True, tweet_mode="extended")
|
||||
tweet.full_text = utils.expand_urls(tweet.full_text, tweet.entities)
|
||||
except TweepyException as e:
|
||||
utils.twitter_error(e)
|
||||
return
|
||||
l = tweets.is_long(tweet)
|
||||
if l == False:
|
||||
tweetsList.append(tweet)
|
||||
return (tweet, tweetsList)
|
||||
|
||||
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False):
|
||||
# starts stream every 3 minutes.
|
||||
current_time = time.time()
|
||||
if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory==True:
|
||||
self.execution_time = current_time
|
||||
log.debug("Starting stream for buffer %s, account %s and type %s" % (self.name, self.account, self.type))
|
||||
log.debug("args: %s, kwargs: %s" % (self.args, self.kwargs))
|
||||
if self.name != "direct_messages":
|
||||
val = self.session.call_paged(self.function, self.name, *self.args, **self.kwargs)
|
||||
else:
|
||||
# 50 results are allowed per API call, so let's assume max value can be 50.
|
||||
# reference: https://developer.twitter.com/en/docs/twitter-api/v1/direct-messages/sending-and-receiving/api-reference/list-events
|
||||
if self.session.settings["general"]["max_tweets_per_call"] > 50:
|
||||
count = 50
|
||||
else:
|
||||
count = self.session.settings["general"]["max_tweets_per_call"]
|
||||
# try to retrieve the cursor for the current buffer.
|
||||
try:
|
||||
val = getattr(self.session.twitter, self.function)(return_cursors=True, count=count, *self.args, **self.kwargs)
|
||||
if type(val) == tuple:
|
||||
val, cursor = val
|
||||
if type(cursor) == tuple:
|
||||
cursor = cursor[1]
|
||||
cursors = self.session.db["cursors"]
|
||||
cursors[self.name] = cursor
|
||||
self.session.db["cursors"] = cursors
|
||||
results = [i for i in val]
|
||||
val = results
|
||||
val.reverse()
|
||||
log.debug("Retrieved %d items from the cursored search on function %s." %(len(val), self.function))
|
||||
user_ids = [item.message_create["sender_id"] for item in val]
|
||||
self.session.save_users(user_ids)
|
||||
except TweepyException as e:
|
||||
log.exception("Error %s" % (str(e)))
|
||||
return
|
||||
number_of_items = self.session.order_buffer(self.name, val)
|
||||
log.debug("Number of items retrieved: %d" % (number_of_items,))
|
||||
self.put_items_on_list(number_of_items)
|
||||
if hasattr(self, "finished_timeline") and self.finished_timeline == False:
|
||||
if "-timeline" in self.name:
|
||||
self.username = self.session.get_user(self.kwargs.get("user_id")).screen_name
|
||||
elif "-favorite" in self.name:
|
||||
self.username = self.session.get_user(self.kwargs.get("user_id")).screen_name
|
||||
self.finished_timeline = True
|
||||
if number_of_items > 0 and self.name != "sent_tweets" and self.name != "sent_direct_messages" and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True:
|
||||
self.session.sound.play(self.sound)
|
||||
# Autoread settings
|
||||
if avoid_autoreading == False and mandatory == True and number_of_items > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]:
|
||||
self.auto_read(number_of_items)
|
||||
return number_of_items
|
||||
|
||||
def auto_read(self, number_of_items):
|
||||
if number_of_items == 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False:
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
tweet = self.session.db[self.name][-1]
|
||||
else:
|
||||
tweet = self.session.db[self.name][0]
|
||||
output.speak(_(u"New tweet in {0}").format(self.get_buffer_name()))
|
||||
output.speak(" ".join(self.compose_function(tweet, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)))
|
||||
elif number_of_items > 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False:
|
||||
output.speak(_(u"{0} new tweets in {1}.").format(number_of_items, self.get_buffer_name()))
|
||||
|
||||
def get_more_items(self):
|
||||
elements = []
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
last_id = self.session.db[self.name][0].id
|
||||
else:
|
||||
last_id = self.session.db[self.name][-1].id
|
||||
try:
|
||||
items = getattr(self.session.twitter, self.function)(max_id=last_id, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs)
|
||||
except TweepyException as e:
|
||||
log.exception("Error %s" % (str(e)))
|
||||
return
|
||||
if items == None:
|
||||
return
|
||||
items_db = self.session.db[self.name]
|
||||
self.session.add_users_from_results(items)
|
||||
for i in items:
|
||||
if utils.is_allowed(i, self.session.settings, self.name) == True and utils.find_item(i, self.session.db[self.name]) == None:
|
||||
i = reduce.reduce_tweet(i)
|
||||
i = self.session.check_quoted_status(i)
|
||||
i = self.session.check_long_tweet(i)
|
||||
elements.append(i)
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
items_db.insert(0, i)
|
||||
else:
|
||||
items_db.append(i)
|
||||
self.session.db[self.name] = items_db
|
||||
selection = self.buffer.list.get_selected()
|
||||
log.debug("Retrieved %d items from cursored search in function %s." % (len(elements), self.function))
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
for i in elements:
|
||||
tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)
|
||||
self.buffer.list.insert_item(True, *tweet)
|
||||
else:
|
||||
for i in items:
|
||||
tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)
|
||||
self.buffer.list.insert_item(False, *tweet)
|
||||
self.buffer.list.select_item(selection)
|
||||
output.speak(_(u"%s items retrieved") % (str(len(elements))), True)
|
||||
|
||||
def remove_buffer(self, force=False):
|
||||
if "-timeline" in self.name:
|
||||
if force == False:
|
||||
dlg = commonMessageDialogs.remove_buffer()
|
||||
else:
|
||||
dlg = widgetUtils.YES
|
||||
if dlg == widgetUtils.YES:
|
||||
if self.name[:-9] in self.session.settings["other_buffers"]["timelines"]:
|
||||
self.session.settings["other_buffers"]["timelines"].remove(self.name[:-9])
|
||||
self.session.settings.write()
|
||||
if self.name in self.session.db:
|
||||
self.session.db.pop(self.name)
|
||||
return True
|
||||
elif dlg == widgetUtils.NO:
|
||||
return False
|
||||
elif "favorite" in self.name:
|
||||
if force == False:
|
||||
dlg = commonMessageDialogs.remove_buffer()
|
||||
else:
|
||||
dlg = widgetUtils.YES
|
||||
if dlg == widgetUtils.YES:
|
||||
if self.name[:-9] in self.session.settings["other_buffers"]["favourites_timelines"]:
|
||||
self.session.settings["other_buffers"]["favourites_timelines"].remove(self.name[:-9])
|
||||
if self.name in self.session.db:
|
||||
self.session.db.pop(self.name)
|
||||
self.session.settings.write()
|
||||
return True
|
||||
elif dlg == widgetUtils.NO:
|
||||
return False
|
||||
else:
|
||||
output.speak(_(u"This buffer is not a timeline; it can't be deleted."), True)
|
||||
return False
|
||||
|
||||
def remove_tweet(self, id):
|
||||
if type(self.session.db[self.name]) == dict: return
|
||||
items = self.session.db[self.name]
|
||||
for i in range(0, len(items)):
|
||||
if items[i].id == id:
|
||||
items.pop(i)
|
||||
self.remove_item(i)
|
||||
self.session.db[self.name] = items
|
||||
|
||||
def put_items_on_list(self, number_of_items):
|
||||
list_to_use = self.session.db[self.name]
|
||||
if number_of_items == 0 and self.session.settings["general"]["persist_size"] == 0: return
|
||||
log.debug("The list contains %d items " % (self.buffer.list.get_count(),))
|
||||
log.debug("Putting %d items on the list" % (number_of_items,))
|
||||
if self.buffer.list.get_count() == 0:
|
||||
for i in list_to_use:
|
||||
tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)
|
||||
self.buffer.list.insert_item(False, *tweet)
|
||||
self.buffer.set_position(self.session.settings["general"]["reverse_timelines"])
|
||||
elif self.buffer.list.get_count() > 0 and number_of_items > 0:
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
items = list_to_use[len(list_to_use)-number_of_items:]
|
||||
for i in items:
|
||||
tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)
|
||||
self.buffer.list.insert_item(False, *tweet)
|
||||
else:
|
||||
items = list_to_use[0:number_of_items]
|
||||
items.reverse()
|
||||
for i in items:
|
||||
tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)
|
||||
self.buffer.list.insert_item(True, *tweet)
|
||||
log.debug("Now the list contains %d items " % (self.buffer.list.get_count(),))
|
||||
|
||||
def add_new_item(self, item):
|
||||
tweet = self.compose_function(item, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
self.buffer.list.insert_item(False, *tweet)
|
||||
else:
|
||||
self.buffer.list.insert_item(True, *tweet)
|
||||
if self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False:
|
||||
output.speak(" ".join(tweet[:2]), speech=self.session.settings["reporting"]["speech_reporting"], braille=self.session.settings["reporting"]["braille_reporting"])
|
||||
|
||||
def bind_events(self):
|
||||
log.debug("Binding events...")
|
||||
self.buffer.set_focus_function(self.onFocus)
|
||||
widgetUtils.connect_event(self.buffer.list.list, widgetUtils.KEYPRESS, self.get_event)
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.post_status, self.buffer.tweet)
|
||||
# if self.type == "baseBuffer":
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.share_item, self.buffer.retweet)
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.send_message, self.buffer.dm)
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.reply, self.buffer.reply)
|
||||
widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_ITEM_RIGHT_CLICK, self.show_menu)
|
||||
widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_KEY_DOWN, self.show_menu_by_key)
|
||||
|
||||
def show_menu(self, ev, pos=0, *args, **kwargs):
|
||||
if self.buffer.list.get_count() == 0: return
|
||||
if self.name == "sent_tweets" or self.name == "direct_messages":
|
||||
menu = menus.sentPanelMenu()
|
||||
elif self.name == "direct_messages":
|
||||
menu = menus.dmPanelMenu()
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.send_message, menuitem=menu.reply)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.user_actions, menuitem=menu.userActions)
|
||||
else:
|
||||
menu = menus.basePanelMenu()
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.reply, menuitem=menu.reply)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.user_actions, menuitem=menu.userActions)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.share_item, menuitem=menu.retweet)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.fav, menuitem=menu.fav)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.unfav, menuitem=menu.unfav)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.url_, menuitem=menu.openUrl)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.audio, menuitem=menu.play)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.copy, menuitem=menu.copy)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.destroy_status, menuitem=menu.remove)
|
||||
if hasattr(menu, "openInBrowser"):
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.open_in_browser, menuitem=menu.openInBrowser)
|
||||
if pos != 0:
|
||||
self.buffer.PopupMenu(menu, pos)
|
||||
else:
|
||||
self.buffer.PopupMenu(menu, ev.GetPosition())
|
||||
|
||||
def view(self, *args, **kwargs):
|
||||
pub.sendMessage("execute-action", action="view_item")
|
||||
|
||||
def copy(self, *args, **kwargs):
|
||||
pub.sendMessage("execute-action", action="copy_to_clipboard")
|
||||
|
||||
def user_actions(self, *args, **kwargs):
|
||||
pub.sendMessage("execute-action", action="follow")
|
||||
|
||||
def fav(self, *args, **kwargs):
|
||||
pub.sendMessage("execute-action", action="add_to_favourites")
|
||||
|
||||
def unfav(self, *args, **kwargs):
|
||||
pub.sendMessage("execute-action", action="remove_from_favourites")
|
||||
|
||||
def delete_item_(self, *args, **kwargs):
|
||||
pub.sendMessage("execute-action", action="delete_item")
|
||||
|
||||
def url_(self, *args, **kwargs):
|
||||
self.url()
|
||||
|
||||
def show_menu_by_key(self, ev):
|
||||
if self.buffer.list.get_count() == 0:
|
||||
return
|
||||
if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU:
|
||||
self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition())
|
||||
|
||||
def get_tweet(self):
|
||||
if hasattr(self.session.db[self.name][self.buffer.list.get_selected()], "retweeted_status"):
|
||||
tweet = self.session.db[self.name][self.buffer.list.get_selected()].retweeted_status
|
||||
else:
|
||||
tweet = self.session.db[self.name][self.buffer.list.get_selected()]
|
||||
return tweet
|
||||
|
||||
def get_right_tweet(self):
|
||||
tweet = self.session.db[self.name][self.buffer.list.get_selected()]
|
||||
return tweet
|
||||
|
||||
def can_share(self):
|
||||
tweet = self.get_right_tweet()
|
||||
user = self.session.get_user(tweet.user)
|
||||
is_protected = user.protected
|
||||
return is_protected==False
|
||||
|
||||
@_tweets_exist
|
||||
def reply(self, *args, **kwargs):
|
||||
tweet = self.get_right_tweet()
|
||||
user = self.session.get_user(tweet.user)
|
||||
screen_name = user.screen_name
|
||||
id = tweet.id
|
||||
users = utils.get_all_mentioned(tweet, self.session.db, field="screen_name")
|
||||
ids = utils.get_all_mentioned(tweet, self.session.db, field="id")
|
||||
# Build the window title
|
||||
if len(users) < 1:
|
||||
title=_("Reply to {arg0}").format(arg0=screen_name)
|
||||
else:
|
||||
title=_("Reply")
|
||||
message = messages.reply(self.session, title, _("Reply to %s") % (screen_name,), "", users=users, ids=ids)
|
||||
if message.message.ShowModal() == widgetUtils.OK:
|
||||
if config.app["app-settings"]["remember_mention_and_longtweet"]:
|
||||
if len(users) > 0:
|
||||
config.app["app-settings"]["mention_all"] = message.message.mention_all.GetValue()
|
||||
config.app.write()
|
||||
tweet_data = dict(text=message.message.text.GetValue(), attachments=message.attachments, poll_options=message.poll_options, poll_period=message.poll_period)
|
||||
call_threaded(self.session.reply, in_reply_to_status_id=id, text=message.message.text.GetValue(), attachments=message.attachments, exclude_reply_user_ids=message.get_ids())
|
||||
if hasattr(message.message, "destroy"): message.message.destroy()
|
||||
self.session.settings.write()
|
||||
|
||||
@_tweets_exist
|
||||
def send_message(self, *args, **kwargs):
|
||||
tweet = self.get_right_tweet()
|
||||
if self.type == "dm":
|
||||
screen_name = self.session.get_user(tweet.message_create["sender_id"]).screen_name
|
||||
users = [screen_name]
|
||||
elif self.type == "people":
|
||||
screen_name = tweet.screen_name
|
||||
users = [screen_name]
|
||||
else:
|
||||
screen_name = self.session.get_user(tweet.user).screen_name
|
||||
users = utils.get_all_users(tweet, self.session)
|
||||
dm = messages.dm(self.session, _("Direct message to %s") % (screen_name,), _("New direct message"), users)
|
||||
if dm.message.ShowModal() == widgetUtils.OK:
|
||||
screen_name = dm.message.cb.GetValue()
|
||||
user = self.session.get_user_by_screen_name(screen_name)
|
||||
recipient_id = user
|
||||
text = dm.message.text.GetValue()
|
||||
if len(dm.attachments) > 0:
|
||||
attachment = dm.attachments[0]
|
||||
else:
|
||||
attachment = None
|
||||
call_threaded(self.session.direct_message, text=text, recipient=recipient_id, attachment=attachment)
|
||||
if hasattr(dm.message, "destroy"): dm.message.destroy()
|
||||
|
||||
@_tweets_exist
|
||||
def share_item(self, *args, **kwargs):
|
||||
if self.can_share() == False:
|
||||
return output.speak(_("This action is not supported on protected accounts."))
|
||||
tweet = self.get_right_tweet()
|
||||
id = tweet.id
|
||||
if self.session.settings["general"]["retweet_mode"] == "ask":
|
||||
answer = commonMessageDialogs.retweet_question(self.buffer)
|
||||
if answer == widgetUtils.YES:
|
||||
self._retweet_with_comment(tweet, id)
|
||||
elif answer == widgetUtils.NO:
|
||||
self._direct_retweet(id)
|
||||
elif self.session.settings["general"]["retweet_mode"] == "direct":
|
||||
self._direct_retweet(id)
|
||||
else:
|
||||
self._retweet_with_comment(tweet, id)
|
||||
|
||||
def _retweet_with_comment(self, tweet, id):
|
||||
if hasattr(tweet, "retweeted_status"):
|
||||
tweet = tweet.retweeted_status
|
||||
retweet = messages.tweet(session=self.session, title=_("Quote"), caption=_("Add your comment to the tweet"), thread_mode=False)
|
||||
if retweet.message.ShowModal() == widgetUtils.OK:
|
||||
text = retweet.message.text.GetValue()
|
||||
tweet_data = dict(text=text, attachments=retweet.attachments, poll_period=retweet.poll_period, poll_options=retweet.poll_options)
|
||||
tweet_data.update(quote_tweet_id=id)
|
||||
call_threaded(self.session.send_tweet, *[tweet_data])
|
||||
if hasattr(retweet.message, "destroy"):
|
||||
retweet.message.Destroy()
|
||||
|
||||
def _direct_retweet(self, id):
|
||||
item = self.session.api_call(call_name="retweet", _sound="retweet_send.ogg", id=id)
|
||||
|
||||
def onFocus(self, *args, **kwargs):
|
||||
tweet = self.get_tweet()
|
||||
if self.session.settings["general"]["relative_times"] == True:
|
||||
# fix this:
|
||||
original_date = arrow.get(self.session.db[self.name][self.buffer.list.get_selected()].created_at, locale="en")
|
||||
ts = original_date.humanize(locale=languageHandler.getLanguage())
|
||||
self.buffer.list.list.SetItem(self.buffer.list.get_selected(), 2, ts)
|
||||
if self.session.settings['sound']['indicate_audio'] and utils.is_audio(tweet):
|
||||
self.session.sound.play("audio.ogg")
|
||||
if self.session.settings['sound']['indicate_geo'] and utils.is_geocoded(tweet):
|
||||
self.session.sound.play("geo.ogg")
|
||||
if self.session.settings['sound']['indicate_img'] and utils.is_media(tweet):
|
||||
self.session.sound.play("image.ogg")
|
||||
can_share = self.can_share()
|
||||
pub.sendMessage("toggleShare", shareable=can_share)
|
||||
self.buffer.retweet.Enable(can_share)
|
||||
|
||||
def audio(self, url='', *args, **kwargs):
|
||||
if sound.URLPlayer.player.is_playing():
|
||||
return sound.URLPlayer.stop_audio()
|
||||
tweet = self.get_tweet()
|
||||
if tweet == None: return
|
||||
urls = utils.find_urls(tweet, twitter_media=True)
|
||||
if len(urls) == 1:
|
||||
url=urls[0]
|
||||
elif len(urls) > 1:
|
||||
urls_list = dialogs.urlList.urlList()
|
||||
urls_list.populate_list(urls)
|
||||
if urls_list.get_response() == widgetUtils.OK:
|
||||
url=urls_list.get_string()
|
||||
if hasattr(urls_list, "destroy"): urls_list.destroy()
|
||||
if url != '':
|
||||
# try:
|
||||
sound.URLPlayer.play(url, self.session.settings["sound"]["volume"])
|
||||
# except:
|
||||
# log.error("Exception while executing audio method.")
|
||||
|
||||
# @_tweets_exist
|
||||
def url(self, url='', announce=True, *args, **kwargs):
|
||||
if url == '':
|
||||
tweet = self.get_tweet()
|
||||
urls = utils.find_urls(tweet)
|
||||
if len(urls) == 1:
|
||||
url=urls[0]
|
||||
elif len(urls) > 1:
|
||||
urls_list = dialogs.urlList.urlList()
|
||||
urls_list.populate_list(urls)
|
||||
if urls_list.get_response() == widgetUtils.OK:
|
||||
url=urls_list.get_string()
|
||||
if hasattr(urls_list, "destroy"): urls_list.destroy()
|
||||
if url != '':
|
||||
if announce:
|
||||
output.speak(_(u"Opening URL..."), True)
|
||||
webbrowser.open_new_tab(url)
|
||||
|
||||
def clear_list(self):
|
||||
dlg = commonMessageDialogs.clear_list()
|
||||
if dlg == widgetUtils.YES:
|
||||
self.session.db[self.name] = []
|
||||
self.buffer.list.clear()
|
||||
|
||||
@_tweets_exist
|
||||
def destroy_status(self, *args, **kwargs):
|
||||
index = self.buffer.list.get_selected()
|
||||
if self.type == "events" or self.type == "people" or self.type == "empty" or self.type == "account": return
|
||||
answer = commonMessageDialogs.delete_tweet_dialog(None)
|
||||
if answer == widgetUtils.YES:
|
||||
items = self.session.db[self.name]
|
||||
try:
|
||||
if self.name == "direct_messages" or self.name == "sent_direct_messages":
|
||||
self.session.twitter.delete_direct_message(id=self.get_right_tweet().id)
|
||||
items.pop(index)
|
||||
else:
|
||||
self.session.twitter.destroy_status(id=self.get_right_tweet().id)
|
||||
items.pop(index)
|
||||
self.buffer.list.remove_item(index)
|
||||
except TweepyException:
|
||||
self.session.sound.play("error.ogg")
|
||||
self.session.db[self.name] = items
|
||||
|
||||
@_tweets_exist
|
||||
def user_details(self):
|
||||
tweet = self.get_right_tweet()
|
||||
if self.type == "dm":
|
||||
users = [self.session.get_user(tweet.message_create["sender_id"]).screen_name]
|
||||
elif self.type == "people":
|
||||
users = [tweet.screen_name]
|
||||
else:
|
||||
users = utils.get_all_users(tweet, self.session)
|
||||
dlg = dialogs.utils.selectUserDialog(title=_(u"User details"), users=users)
|
||||
if dlg.get_response() == widgetUtils.OK:
|
||||
user.profileController(session=self.session, user=dlg.get_user())
|
||||
if hasattr(dlg, "destroy"): dlg.destroy()
|
||||
|
||||
def get_quoted_tweet(self, tweet):
|
||||
quoted_tweet = self.session.twitter.get_status(id=tweet.id)
|
||||
quoted_tweet.text = utils.find_urls_in_text(quoted_tweet.text, quoted_tweet.entities)
|
||||
l = tweets.is_long(quoted_tweet)
|
||||
id = tweets.get_id(l)
|
||||
original_tweet = self.session.twitter.get_status(id=id)
|
||||
original_tweet.text = utils.find_urls_in_text(original_tweet.text, original_tweet.entities)
|
||||
return compose.compose_quoted_tweet(quoted_tweet, original_tweet, self.session.db, self.session.settings["general"]["relative_times"])
|
||||
|
||||
def get_item_url(self):
|
||||
tweet = self.get_tweet()
|
||||
url = "https://twitter.com/{screen_name}/status/{tweet_id}".format(screen_name=self.session.get_user(tweet.user).screen_name, tweet_id=tweet.id)
|
||||
return url
|
||||
|
||||
def open_in_browser(self, *args, **kwargs):
|
||||
url = self.get_item_url()
|
||||
output.speak(_(u"Opening item in web browser..."))
|
||||
webbrowser.open(url)
|
||||
|
||||
def add_to_favorites(self):
|
||||
id = self.get_tweet().id
|
||||
call_threaded(self.session.api_call, call_name="create_favorite", _sound="favourite.ogg", id=id)
|
||||
|
||||
def remove_from_favorites(self):
|
||||
id = self.get_tweet().id
|
||||
call_threaded(self.session.api_call, call_name="destroy_favorite", id=id)
|
||||
|
||||
def toggle_favorite(self):
|
||||
id = self.get_tweet().id
|
||||
tweet = self.session.twitter.get_status(id=id, include_ext_alt_text=True, tweet_mode="extended")
|
||||
if tweet.favorited == False:
|
||||
call_threaded(self.session.api_call, call_name="create_favorite", _sound="favourite.ogg", id=id)
|
||||
else:
|
||||
call_threaded(self.session.api_call, call_name="destroy_favorite", id=id)
|
||||
|
||||
def view_item(self):
|
||||
if self.type == "dm" or self.name == "direct_messages":
|
||||
non_tweet = self.get_formatted_message()
|
||||
item = self.get_right_tweet()
|
||||
original_date = arrow.get(int(item.created_timestamp))
|
||||
date = original_date.shift(seconds=self.session.db["utc_offset"]).format(_(u"MMM D, YYYY. H:m"), locale=languageHandler.getLanguage())
|
||||
msg = messages.viewTweet(non_tweet, [], False, date=date)
|
||||
else:
|
||||
tweet, tweetsList = self.get_full_tweet()
|
||||
msg = messages.viewTweet(tweet, tweetsList, utc_offset=self.session.db["utc_offset"], item_url=self.get_item_url())
|
||||
|
||||
def reverse_geocode(self, geocoder):
|
||||
try:
|
||||
tweet = self.get_tweet()
|
||||
if tweet.coordinates != None:
|
||||
x = tweet.coordinates["coordinates"][0]
|
||||
y = tweet.coordinates["coordinates"][1]
|
||||
address = geocoder.reverse_geocode(y, x, language = languageHandler.curLang)
|
||||
return address
|
||||
else:
|
||||
output.speak(_("There are no coordinates in this tweet"))
|
||||
# except GeocoderError:
|
||||
# output.speak(_(u"There are no results for the coordinates in this tweet"))
|
||||
except ValueError:
|
||||
output.speak(_(u"Error decoding coordinates. Try again later."))
|
||||
except KeyError:
|
||||
pass
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def ocr_image(self):
|
||||
tweet = self.get_tweet()
|
||||
media_list = []
|
||||
if hasattr(tweet, "entities") and tweet.entities.get("media") != None:
|
||||
[media_list.append(i) for i in tweet.entities["media"] if i not in media_list]
|
||||
elif hasattr(tweet, "retweeted_status") and tweet.retweeted_status.get("media") != None:
|
||||
[media_list.append(i) for i in tweet.retweeted_status.entities["media"] if i not in media_list]
|
||||
elif hasattr(tweet, "quoted_status") and tweet.quoted_status.entities.get("media") != None:
|
||||
[media_list.append(i) for i in tweet.quoted_status.entities["media"] if i not in media_list]
|
||||
if len(media_list) > 1:
|
||||
image_list = [_(u"Picture {0}").format(i,) for i in range(0, len(media_list))]
|
||||
dialog = dialogs.urlList.urlList(title=_(u"Select the picture"))
|
||||
if dialog.get_response() == widgetUtils.OK:
|
||||
img = media_list[dialog.get_item()]
|
||||
else:
|
||||
return
|
||||
elif len(media_list) == 1:
|
||||
img = media_list[0]
|
||||
else:
|
||||
output.speak(_(u"Invalid buffer"))
|
||||
return
|
||||
if self.session.settings["mysc"]["ocr_language"] != "":
|
||||
ocr_lang = self.session.settings["mysc"]["ocr_language"]
|
||||
else:
|
||||
ocr_lang = ocr.OCRSpace.short_langs.index(tweet.lang)
|
||||
ocr_lang = ocr.OCRSpace.OcrLangs[ocr_lang]
|
||||
api = ocr.OCRSpace.OCRSpaceAPI()
|
||||
try:
|
||||
text = api.OCR_URL(img["media_url"], lang=ocr_lang)
|
||||
except ocr.OCRSpace.APIError as er:
|
||||
output.speak(_(u"Unable to extract text"))
|
||||
return
|
||||
msg = messages.viewTweet(text["ParsedText"], [], False)
|
@@ -1,164 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import widgetUtils
|
||||
import arrow
|
||||
import webbrowser
|
||||
import output
|
||||
import config
|
||||
import languageHandler
|
||||
import logging
|
||||
from sessions.twitter import compose, utils, templates
|
||||
from mysc.thread_utils import call_threaded
|
||||
from tweepy.errors import TweepyException
|
||||
from pubsub import pub
|
||||
from wxUI import commonMessageDialogs
|
||||
from controller.twitter import messages
|
||||
from . import base
|
||||
|
||||
log = logging.getLogger("controller.buffers.twitter.dmBuffer")
|
||||
|
||||
class DirectMessagesBuffer(base.BaseBuffer):
|
||||
|
||||
def get_more_items(self):
|
||||
# 50 results are allowed per API call, so let's assume max value can be 50.
|
||||
# reference: https://developer.twitter.com/en/docs/twitter-api/v1/direct-messages/sending-and-receiving/api-reference/list-events
|
||||
if self.session.settings["general"]["max_tweets_per_call"] > 50:
|
||||
count = 50
|
||||
else:
|
||||
count = self.session.settings["general"]["max_tweets_per_call"]
|
||||
total = 0
|
||||
# try to retrieve the cursor for the current buffer.
|
||||
cursor = self.session.db["cursors"].get(self.name)
|
||||
try:
|
||||
items = getattr(self.session.twitter, self.function)(return_cursors=True, cursor=cursor, count=count, *self.args, **self.kwargs)
|
||||
if type(items) == tuple:
|
||||
items, cursor = items
|
||||
if type(cursor) == tuple:
|
||||
cursor = cursor[1]
|
||||
cursors = self.session.db["cursors"]
|
||||
cursors[self.name] = cursor
|
||||
self.session.db["cursors"] = cursors
|
||||
results = [i for i in items]
|
||||
items = results
|
||||
log.debug("Retrieved %d items for cursored search in function %s" % (len(items), self.function))
|
||||
except TweepyException as e:
|
||||
log.exception("Error %s" % (str(e)))
|
||||
return
|
||||
if items == None:
|
||||
return
|
||||
sent = []
|
||||
received = []
|
||||
sent_dms = self.session.db["sent_direct_messages"]
|
||||
received_dms = self.session.db["direct_messages"]
|
||||
for i in items:
|
||||
if int(i.message_create["sender_id"]) == self.session.db["user_id"]:
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
sent_dms.insert(0, i)
|
||||
sent.append(i)
|
||||
else:
|
||||
sent_dms.append(i)
|
||||
sent.insert(0, i)
|
||||
else:
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
received_dms.insert(0, i)
|
||||
received.append(i)
|
||||
else:
|
||||
received_dms.append(i)
|
||||
received.insert(0, i)
|
||||
total = total+1
|
||||
self.session.db["direct_messages"] = received_dms
|
||||
self.session.db["sent_direct_messages"] = sent_dms
|
||||
user_ids = [item.message_create["sender_id"] for item in items]
|
||||
self.session.save_users(user_ids)
|
||||
pub.sendMessage("twitter.more_sent_dms", data=sent, account=self.session.db["user_name"])
|
||||
selected = self.buffer.list.get_selected()
|
||||
if self.session.settings["general"]["reverse_timelines"] == True:
|
||||
for i in received:
|
||||
if int(i.message_create["sender_id"]) == self.session.db["user_id"]:
|
||||
continue
|
||||
tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)
|
||||
self.buffer.list.insert_item(True, *tweet)
|
||||
self.buffer.list.select_item(selected)
|
||||
else:
|
||||
for i in received:
|
||||
if int(i.message_create["sender_id"]) == self.session.db["user_id"]:
|
||||
continue
|
||||
tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)
|
||||
self.buffer.list.insert_item(True, *tweet)
|
||||
output.speak(_(u"%s items retrieved") % (total), True)
|
||||
|
||||
def reply(self, *args, **kwargs):
|
||||
return self.send_message()
|
||||
|
||||
def onFocus(self, *args, **kwargs):
|
||||
tweet = self.get_tweet()
|
||||
if self.session.settings["general"]["relative_times"] == True:
|
||||
# fix this:
|
||||
original_date = arrow.get(int(tweet.created_timestamp))
|
||||
ts = original_date.humanize(locale=languageHandler.getLanguage())
|
||||
self.buffer.list.list.SetItem(self.buffer.list.get_selected(), 2, ts)
|
||||
if self.session.settings['sound']['indicate_audio'] and utils.is_audio(tweet):
|
||||
self.session.sound.play("audio.ogg")
|
||||
if self.session.settings['sound']['indicate_img'] and utils.is_media(tweet):
|
||||
self.session.sound.play("image.ogg")
|
||||
|
||||
def clear_list(self):
|
||||
dlg = commonMessageDialogs.clear_list()
|
||||
if dlg == widgetUtils.YES:
|
||||
self.session.db[self.name] = []
|
||||
self.buffer.list.clear()
|
||||
|
||||
def auto_read(self, number_of_items):
|
||||
if number_of_items == 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False:
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
tweet = self.session.db[self.name][-1]
|
||||
else:
|
||||
tweet = self.session.db[self.name][0]
|
||||
output.speak(_(u"New direct message"))
|
||||
output.speak(" ".join(self.compose_function(tweet, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)))
|
||||
elif number_of_items > 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False:
|
||||
output.speak(_(u"{0} new direct messages.").format(number_of_items,))
|
||||
|
||||
def open_in_browser(self, *args, **kwargs):
|
||||
output.speak(_(u"This action is not supported in the buffer yet."))
|
||||
|
||||
def get_message(self):
|
||||
template = self.session.settings["templates"]["dm"]
|
||||
dm = self.get_right_tweet()
|
||||
t = templates.render_dm(dm, template, self.session, relative_times=self.session.settings["general"]["relative_times"], offset_seconds=self.session.db["utc_offset"])
|
||||
return t
|
||||
|
||||
class SentDirectMessagesBuffer(DirectMessagesBuffer):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SentDirectMessagesBuffer, self).__init__(*args, **kwargs)
|
||||
if ("sent_direct_messages" in self.session.db) == False:
|
||||
self.session.db["sent_direct_messages"] = []
|
||||
|
||||
def get_more_items(self):
|
||||
output.speak(_(u"Getting more items cannot be done in this buffer. Use the direct messages buffer instead."))
|
||||
|
||||
def start_stream(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def put_more_items(self, items):
|
||||
if self.session.settings["general"]["reverse_timelines"] == True:
|
||||
for i in items:
|
||||
tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)
|
||||
self.buffer.list.insert_item(False, *tweet)
|
||||
else:
|
||||
for i in items:
|
||||
tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)
|
||||
self.buffer.list.insert_item(False, *tweet)
|
||||
|
||||
def get_message(self):
|
||||
template = self.session.settings["templates"]["dm_sent"]
|
||||
dm = self.get_right_tweet()
|
||||
t = templates.render_dm(dm, template, self.session, relative_times=self.session.settings["general"]["relative_times"], offset_seconds=self.session.db["utc_offset"])
|
||||
return t
|
||||
|
||||
def view_item(self):
|
||||
non_tweet = self.get_formatted_message()
|
||||
item = self.get_right_tweet()
|
||||
original_date = arrow.get(int(item.created_timestamp))
|
||||
date = original_date.shift(seconds=self.session.db["utc_offset"]).format(_(u"MMM D, YYYY. H:m"), locale=languageHandler.getLanguage())
|
||||
msg = messages.viewTweet(non_tweet, [], False, date=date)
|
@@ -1,39 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import widgetUtils
|
||||
import logging
|
||||
from tweepy.cursor import Cursor
|
||||
from wxUI import dialogs, commonMessageDialogs
|
||||
from . import base
|
||||
|
||||
log = logging.getLogger("controller.buffers.twitter.listBuffer")
|
||||
|
||||
class ListBuffer(base.BaseBuffer):
|
||||
def __init__(self, parent, function, name, sessionObject, account, sound=None, bufferType=None, list_id=None, *args, **kwargs):
|
||||
super(ListBuffer, self).__init__(parent, function, name, sessionObject, account, sound=None, bufferType=None, *args, **kwargs)
|
||||
self.users = []
|
||||
self.list_id = list_id
|
||||
self.kwargs["list_id"] = list_id
|
||||
|
||||
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False):
|
||||
self.get_user_ids()
|
||||
super(ListBuffer, self).start_stream(mandatory, play_sound, avoid_autoreading)
|
||||
|
||||
def get_user_ids(self):
|
||||
for i in Cursor(self.session.twitter.get_list_members, list_id=self.list_id, include_entities=False, skip_status=True, count=5000).items():
|
||||
if i.id not in self.users:
|
||||
self.users.append(i.id)
|
||||
|
||||
def remove_buffer(self, force=False):
|
||||
if force == False:
|
||||
dlg = commonMessageDialogs.remove_buffer()
|
||||
else:
|
||||
dlg = widgetUtils.YES
|
||||
if dlg == widgetUtils.YES:
|
||||
if self.name[:-5] in self.session.settings["other_buffers"]["lists"]:
|
||||
self.session.settings["other_buffers"]["lists"].remove(self.name[:-5])
|
||||
if self.name in self.session.db:
|
||||
self.session.db.pop(self.name)
|
||||
self.session.settings.write()
|
||||
return True
|
||||
elif dlg == widgetUtils.NO:
|
||||
return False
|
@@ -1,254 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import time
|
||||
import widgetUtils
|
||||
import webbrowser
|
||||
import output
|
||||
import config
|
||||
import logging
|
||||
from mysc.thread_utils import call_threaded
|
||||
from tweepy.errors import TweepyException
|
||||
from pubsub import pub
|
||||
from controller.twitter import user, messages
|
||||
from sessions.twitter import compose, templates
|
||||
from wxUI import commonMessageDialogs, menus
|
||||
from . import base
|
||||
|
||||
log = logging.getLogger("controller.buffers.twitter.peopleBuffer")
|
||||
|
||||
def _tweets_exist(function):
|
||||
""" A decorator to execute a function only if the selected buffer contains at least one item."""
|
||||
def function_(self, *args, **kwargs):
|
||||
if self.buffer.list.get_count() > 0:
|
||||
function(self, *args, **kwargs)
|
||||
return function_
|
||||
|
||||
class PeopleBuffer(base.BaseBuffer):
|
||||
def __init__(self, parent, function, name, sessionObject, account, bufferType=None, *args, **kwargs):
|
||||
super(PeopleBuffer, self).__init__(parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs)
|
||||
log.debug("Initializing buffer %s, account %s" % (name, account,))
|
||||
self.compose_function = compose.compose_followers_list
|
||||
log.debug("Compose_function: %s" % (self.compose_function,))
|
||||
self.get_tweet = self.get_right_tweet
|
||||
self.url = self.interact
|
||||
if "-followers" in self.name or "-friends" in self.name:
|
||||
self.finished_timeline = False
|
||||
# Add a compatibility layer for username based timelines from config.
|
||||
# ToDo: Remove this in some new versions of the client, when user ID timelines become mandatory.
|
||||
try:
|
||||
int(self.kwargs["user_id"])
|
||||
except ValueError:
|
||||
self.is_screen_name = True
|
||||
self.kwargs["screen_name"] = self.kwargs["user_id"]
|
||||
self.kwargs.pop("user_id")
|
||||
|
||||
def remove_buffer(self, force=True):
|
||||
if "-followers" in self.name:
|
||||
if force == False:
|
||||
dlg = commonMessageDialogs.remove_buffer()
|
||||
else:
|
||||
dlg = widgetUtils.YES
|
||||
if dlg == widgetUtils.YES:
|
||||
if self.name[:-10] in self.session.settings["other_buffers"]["followers_timelines"]:
|
||||
self.session.settings["other_buffers"]["followers_timelines"].remove(self.name[:-10])
|
||||
if self.name in self.session.db:
|
||||
self.session.db.pop(self.name)
|
||||
self.session.settings.write()
|
||||
return True
|
||||
elif dlg == widgetUtils.NO:
|
||||
return False
|
||||
elif "-friends" in self.name:
|
||||
if force == False:
|
||||
dlg = commonMessageDialogs.remove_buffer()
|
||||
else:
|
||||
dlg = widgetUtils.YES
|
||||
if dlg == widgetUtils.YES:
|
||||
if self.name[:-8] in self.session.settings["other_buffers"]["friends_timelines"]:
|
||||
self.session.settings["other_buffers"]["friends_timelines"].remove(self.name[:-8])
|
||||
if self.name in self.session.db:
|
||||
self.session.db.pop(self.name)
|
||||
self.session.settings.write()
|
||||
return True
|
||||
elif dlg == widgetUtils.NO:
|
||||
return False
|
||||
else:
|
||||
output.speak(_(u"This buffer is not a timeline; it can't be deleted."), True)
|
||||
return False
|
||||
|
||||
def onFocus(self, ev):
|
||||
pass
|
||||
|
||||
def get_message(self):
|
||||
template = self.session.settings["templates"]["person"]
|
||||
user = self.get_right_tweet()
|
||||
t = templates.render_person(user, template, self.session, relative_times=True, offset_seconds=self.session.db["utc_offset"])
|
||||
return t
|
||||
|
||||
def delete_item(self): pass
|
||||
|
||||
@_tweets_exist
|
||||
def reply(self, *args, **kwargs):
|
||||
tweet = self.get_right_tweet()
|
||||
screen_name = tweet.screen_name
|
||||
message = messages.tweet(session=self.session, title=_("Mention"), caption=_("Mention to %s") % (screen_name,), text="@%s " % (screen_name,), thread_mode=False)
|
||||
if message.message.ShowModal() == widgetUtils.OK:
|
||||
tweet_data = message.get_tweet_data()
|
||||
call_threaded(self.session.send_tweet, *tweet_data)
|
||||
if hasattr(message.message, "destroy"):
|
||||
message.message.destroy()
|
||||
|
||||
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False):
|
||||
# starts stream every 3 minutes.
|
||||
current_time = time.time()
|
||||
if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory==True:
|
||||
self.execution_time = current_time
|
||||
log.debug("Starting stream for %s buffer, %s account" % (self.name, self.account,))
|
||||
log.debug("args: %s, kwargs: %s" % (self.args, self.kwargs))
|
||||
try:
|
||||
val = getattr(self.session.twitter, self.function)(return_cursors=True, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs)
|
||||
if type(val) == tuple:
|
||||
val, cursor = val
|
||||
if type(cursor) == tuple:
|
||||
cursor = cursor[1]
|
||||
cursors = self.session.db["cursors"]
|
||||
cursors[self.name] = cursor
|
||||
self.session.db["cursors"] = cursors
|
||||
results = [i for i in val]
|
||||
val = results
|
||||
val.reverse()
|
||||
log.debug("Retrieved %d items from cursored search in function %s" % (len(val), self.function))
|
||||
except TweepyException as e:
|
||||
log.exception("Error %s" % (str(e)))
|
||||
return
|
||||
number_of_items = self.session.order_people(self.name, val)
|
||||
log.debug("Number of items retrieved: %d" % (number_of_items,))
|
||||
self.put_items_on_list(number_of_items)
|
||||
if hasattr(self, "finished_timeline") and self.finished_timeline == False:
|
||||
self.username = self.session.api_call("get_user", **self.kwargs).screen_name
|
||||
self.finished_timeline = True
|
||||
if number_of_items > 0 and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True:
|
||||
self.session.sound.play(self.sound)
|
||||
# Autoread settings
|
||||
if avoid_autoreading == False and mandatory == True and number_of_items > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]:
|
||||
self.auto_read(number_of_items)
|
||||
return number_of_items
|
||||
|
||||
def get_more_items(self):
|
||||
try:
|
||||
cursor = self.session.db["cursors"].get(self.name)
|
||||
items = getattr(self.session.twitter, self.function)(return_cursors=True, users=True, cursor=cursor, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs)
|
||||
if type(items) == tuple:
|
||||
items, cursor = items
|
||||
if type(cursor) == tuple:
|
||||
cursor = cursor[1]
|
||||
cursors = self.session.db["cursors"]
|
||||
cursors[self.name] = cursor
|
||||
self.session.db["cursors"] = cursors
|
||||
results = [i for i in items]
|
||||
items = results
|
||||
log.debug("Retrieved %d items from cursored search in function %s" % (len(items), self.function))
|
||||
except TweepyException as e:
|
||||
log.exception("Error %s" % (str(e)))
|
||||
return
|
||||
if items == None:
|
||||
return
|
||||
items_db = self.session.db[self.name]
|
||||
for i in items:
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
items_db.insert(0, i)
|
||||
else:
|
||||
items_db.append(i)
|
||||
self.session.db[self.name] = items_db
|
||||
selected = self.buffer.list.get_selected()
|
||||
if self.session.settings["general"]["reverse_timelines"] == True:
|
||||
for i in items:
|
||||
tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session)
|
||||
self.buffer.list.insert_item(True, *tweet)
|
||||
self.buffer.list.select_item(selected)
|
||||
else:
|
||||
for i in items:
|
||||
tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session)
|
||||
self.buffer.list.insert_item(True, *tweet)
|
||||
output.speak(_(u"%s items retrieved") % (len(items)), True)
|
||||
|
||||
def put_items_on_list(self, number_of_items):
|
||||
log.debug("The list contains %d items" % (self.buffer.list.get_count(),))
|
||||
# log.debug("Putting %d items on the list..." % (number_of_items,))
|
||||
if self.buffer.list.get_count() == 0:
|
||||
for i in self.session.db[self.name]:
|
||||
tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session)
|
||||
self.buffer.list.insert_item(False, *tweet)
|
||||
self.buffer.set_position(self.session.settings["general"]["reverse_timelines"])
|
||||
# self.buffer.set_list_position()
|
||||
elif self.buffer.list.get_count() > 0:
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
for i in self.session.db[self.name][len(self.session.db[self.name])-number_of_items:]:
|
||||
tweet = self.compose_function(i, self.session.db)
|
||||
self.buffer.list.insert_item(False, *tweet)
|
||||
else:
|
||||
items = self.session.db[self.name][0:number_of_items]
|
||||
items.reverse()
|
||||
for i in items:
|
||||
tweet = self.compose_function(i, self.session.db)
|
||||
self.buffer.list.insert_item(True, *tweet)
|
||||
log.debug("now the list contains %d items" % (self.buffer.list.get_count(),))
|
||||
|
||||
def get_right_tweet(self):
|
||||
tweet = self.session.db[self.name][self.buffer.list.get_selected()]
|
||||
return tweet
|
||||
|
||||
def add_new_item(self, item):
|
||||
tweet = self.compose_function(item, self.session.db, self.session.settings["general"]["relative_times"], self.session)
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
self.buffer.list.insert_item(False, *tweet)
|
||||
else:
|
||||
self.buffer.list.insert_item(True, *tweet)
|
||||
if self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False:
|
||||
output.speak(" ".join(tweet))
|
||||
|
||||
def clear_list(self):
|
||||
dlg = commonMessageDialogs.clear_list()
|
||||
if dlg == widgetUtils.YES:
|
||||
self.session.db[self.name] = []
|
||||
self.session.db["cursors"][self.name] = -1
|
||||
self.buffer.list.clear()
|
||||
|
||||
def interact(self):
|
||||
user.profileController(self.session, user=self.get_right_tweet().screen_name)
|
||||
|
||||
def show_menu(self, ev, pos=0, *args, **kwargs):
|
||||
menu = menus.peoplePanelMenu()
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.send_message, menuitem=menu.reply)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.user_actions, menuitem=menu.userActions)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.details, menuitem=menu.details)
|
||||
# widgetUtils.connect_event(menu, widgetUtils.MENU, self.lists, menuitem=menu.lists)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.copy, menuitem=menu.copy)
|
||||
if hasattr(menu, "openInBrowser"):
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.open_in_browser, menuitem=menu.openInBrowser)
|
||||
if pos != 0:
|
||||
self.buffer.PopupMenu(menu, pos)
|
||||
else:
|
||||
self.buffer.PopupMenu(menu, ev.GetPosition())
|
||||
|
||||
def details(self, *args, **kwargs):
|
||||
pub.sendMessage("execute-action", action="user_details")
|
||||
|
||||
def auto_read(self, number_of_items):
|
||||
if number_of_items == 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False:
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
tweet = self.session.db[self.name][-1]
|
||||
else:
|
||||
tweet = self.session.db[self.name][0]
|
||||
output.speak(" ".join(self.compose_function(tweet, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)))
|
||||
elif number_of_items > 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False:
|
||||
output.speak(_(u"{0} new followers.").format(number_of_items))
|
||||
|
||||
def get_item_url(self, *args, **kwargs):
|
||||
tweet = self.get_tweet()
|
||||
url = "https://twitter.com/{screen_name}".format(screen_name=tweet.screen_name)
|
||||
return url
|
||||
|
||||
def view_item(self):
|
||||
item_url = self.get_item_url()
|
||||
non_tweet = self.get_formatted_message()
|
||||
msg = messages.viewTweet(non_tweet, [], False, item_url=item_url)
|
@@ -1,187 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import time
|
||||
import locale
|
||||
import widgetUtils
|
||||
import logging
|
||||
from tweepy.errors import TweepyException
|
||||
from wxUI import commonMessageDialogs
|
||||
from . import base, people
|
||||
|
||||
log = logging.getLogger("controller.buffers.twitter.searchBuffer")
|
||||
|
||||
class SearchBuffer(base.BaseBuffer):
|
||||
|
||||
def remove_buffer(self, force=False):
|
||||
if force == False:
|
||||
dlg = commonMessageDialogs.remove_buffer()
|
||||
else:
|
||||
dlg = widgetUtils.YES
|
||||
if dlg == widgetUtils.YES:
|
||||
if self.name[:-11] in self.session.settings["other_buffers"]["tweet_searches"]:
|
||||
self.session.settings["other_buffers"]["tweet_searches"].remove(self.name[:-11])
|
||||
self.session.settings.write()
|
||||
if self.name in self.session.db:
|
||||
self.session.db.pop(self.name)
|
||||
return True
|
||||
elif dlg == widgetUtils.NO:
|
||||
return False
|
||||
|
||||
class SearchPeopleBuffer(people.PeopleBuffer):
|
||||
""" This is identical to a normal peopleBufferController, except that uses the page parameter instead of a cursor."""
|
||||
def __init__(self, parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs):
|
||||
super(SearchPeopleBuffer, self).__init__(parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs)
|
||||
if ("page" in self.kwargs) == False:
|
||||
self.page = 1
|
||||
else:
|
||||
self.page = self.kwargs.pop("page")
|
||||
|
||||
def get_more_items(self, *args, **kwargs):
|
||||
# Add 1 to the page parameter, put it in kwargs and calls to get_more_items in the parent buffer.
|
||||
self.page = self.page +1
|
||||
self.kwargs["page"] = self.page
|
||||
super(SearchPeopleBuffer, self).get_more_items(*args, **kwargs)
|
||||
# remove the parameter again to make sure start_stream won't fetch items for this page indefinitely.
|
||||
self.kwargs.pop("page")
|
||||
|
||||
def remove_buffer(self, force=False):
|
||||
if force == False:
|
||||
dlg = commonMessageDialogs.remove_buffer()
|
||||
else:
|
||||
dlg = widgetUtils.YES
|
||||
if dlg == widgetUtils.YES:
|
||||
if self.name[:-11] in self.session.settings["other_buffers"]["tweet_searches"]:
|
||||
self.session.settings["other_buffers"]["tweet_searches"].remove(self.name[:-11])
|
||||
self.session.settings.write()
|
||||
if self.name in self.session.db:
|
||||
self.session.db.pop(self.name)
|
||||
return True
|
||||
elif dlg == widgetUtils.NO:
|
||||
return False
|
||||
|
||||
class ConversationBuffer(SearchBuffer):
|
||||
last_thread_id = None
|
||||
last_reply_id = None
|
||||
|
||||
def __init__(self, tweet, *args, **kwargs):
|
||||
self.tweet = tweet
|
||||
super(ConversationBuffer, self).__init__(*args, **kwargs)
|
||||
|
||||
def start_stream(self, start=False, mandatory=False, play_sound=True, avoid_autoreading=False):
|
||||
current_time = time.time()
|
||||
if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory == True:
|
||||
self.execution_time = current_time
|
||||
log.debug("Retrieving conversation. Last thread ID is {}, last reply ID is {}".format(self.last_thread_id, self.last_reply_id))
|
||||
results = self.get_replies(self.tweet)
|
||||
log.debug("Retrieved {} items before filters.".format(len(results)))
|
||||
number_of_items = self.session.order_buffer(self.name, results)
|
||||
log.debug("Number of items retrieved: %d" % (number_of_items,))
|
||||
self.put_items_on_list(number_of_items)
|
||||
if number_of_items > 0 and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True:
|
||||
self.session.sound.play(self.sound)
|
||||
# Autoread settings
|
||||
if avoid_autoreading == False and mandatory == True and number_of_items > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]:
|
||||
self.auto_read(number_of_items)
|
||||
return number_of_items
|
||||
|
||||
def remove_buffer(self, force=False):
|
||||
if force == False:
|
||||
dlg = commonMessageDialogs.remove_buffer()
|
||||
else:
|
||||
dlg = widgetUtils.YES
|
||||
if dlg == widgetUtils.YES:
|
||||
if self.name in self.session.db:
|
||||
self.session.db.pop(self.name)
|
||||
return True
|
||||
elif dlg == widgetUtils.NO:
|
||||
return False
|
||||
|
||||
def get_replies(self, tweet):
|
||||
""" Try to retrieve the whole conversation for the passed object by using a mix between calls to API V1.1 and V2 """
|
||||
# firstly we would try to retrieve the whole thread, then we will get replies.
|
||||
# this makes us to waste two search API calls, but there's no better option to retrieve the whole thread including replies, unfortunately.
|
||||
thread_results = []
|
||||
reply_results = []
|
||||
# try to fetch conversation_id of the tweet initiating the buffer.
|
||||
try:
|
||||
tweet = self.session.twitter_v2.get_tweet(id=self.tweet.id, user_auth=True, tweet_fields=["conversation_id", "author_id"])
|
||||
thread_results.append(tweet.data)
|
||||
except TweepyException as e:
|
||||
log.exception("Error attempting to retrieve tweet conversation ID")
|
||||
thread_results.append(self.tweet)
|
||||
# Return earlier cause we can't do anything if we cannot fetch the object from twitter.
|
||||
return thread_results
|
||||
# If tweet contains a conversation_id param, let's retrieve the original tweet which started the conversation so we will have the whole reference for later.
|
||||
if hasattr(tweet.data, "conversation_id") and tweet.data.conversation_id != None:
|
||||
conversation_id = tweet.data.conversation_id
|
||||
original_tweet = self.session.twitter_v2.get_tweet(id=tweet.data.conversation_id, user_auth=True, tweet_fields=["conversation_id", "author_id"])
|
||||
thread_results.insert(0, original_tweet.data)
|
||||
else:
|
||||
conversation_id = tweet.data.id
|
||||
# find all tweets replying to the original thread only. Those tweets are sent by the same author who originally posted the first tweet.
|
||||
try:
|
||||
term = "conversation_id:{} from:{} to:{}".format(conversation_id, original_tweet.data.author_id, original_tweet.data.author_id)
|
||||
thread_tweets = self.session.twitter_v2.search_recent_tweets(term, user_auth=True, max_results=98, since_id=self.last_thread_id, tweet_fields=["in_reply_to_user_id", "author_id", "conversation_id"])
|
||||
if thread_tweets.data != None:
|
||||
thread_results.extend(thread_tweets.data)
|
||||
# Search only replies to conversation_id.
|
||||
term = "conversation_id:{}".format(conversation_id, original_tweet.data.author_id)
|
||||
reply_tweets = self.session.twitter_v2.search_recent_tweets(term, user_auth=True, max_results=50, since_id=self.last_reply_id, tweet_fields=["in_reply_to_user_id", "author_id", "conversation_id"])
|
||||
if reply_tweets.data != None:
|
||||
reply_results.extend(reply_tweets.data)
|
||||
except TweepyException as e:
|
||||
log.exception("There was an error when attempting to retrieve the whole conversation for buffer {}".format(self.buffer.name))
|
||||
# convert v2 tweets in normal, V1.1 tweets so we don't have to deal with those kind of objects in our infrastructure.
|
||||
# ToDo: Remove this last step once we support natively all objects fetched via Twitter API V2.
|
||||
results = []
|
||||
ids = [tweet.id for tweet in thread_results]
|
||||
if len(ids) > 0:
|
||||
try:
|
||||
thread_results = self.session.twitter.lookup_statuses(ids, include_ext_alt_text=True, tweet_mode="extended")
|
||||
thread_results.sort(key=lambda x: x.id)
|
||||
self.last_thread_id = thread_results[-1].id
|
||||
results.extend(thread_results)
|
||||
except TweepyException as e:
|
||||
log.exception("There was an error attempting to retrieve tweets for Twitter API V1.1, in conversation buffer {}".format(self.name))
|
||||
return []
|
||||
ids = [tweet.id for tweet in reply_results]
|
||||
if len(ids) > 0:
|
||||
try:
|
||||
reply_results = self.session.twitter.lookup_statuses(ids, include_ext_alt_text=True, tweet_mode="extended")
|
||||
reply_results.sort(key=lambda x: x.id)
|
||||
self.last_reply_id = reply_results[-1].id
|
||||
results.extend(reply_results)
|
||||
except TweepyException as e:
|
||||
log.exception("There was an error attempting to retrieve tweets for Twitter API V1.1, in conversation buffer {}".format(self.name))
|
||||
results.sort(key=lambda x: x.id)
|
||||
return results
|
||||
|
||||
def get_replies_v1(self, tweet):
|
||||
try:
|
||||
tweet = self.session.twitter.get_status(id=tweet.id, tweet_mode="extended")
|
||||
except:
|
||||
log.exception("Error getting tweet for making a conversation buffer.")
|
||||
return []
|
||||
results = []
|
||||
results.append(tweet)
|
||||
if hasattr(tweet, "in_reply_to_status_id") and tweet.in_reply_to_status_id != None:
|
||||
while tweet.in_reply_to_status_id != None:
|
||||
original_tweet = self.session.twitter.get_status(id=tweet.in_reply_to_status_id, tweet_mode="extended")
|
||||
results.insert(0, original_tweet)
|
||||
tweet = original_tweet
|
||||
try:
|
||||
term = "from:{} to:{}".format(tweet.user.screen_name, tweet.user.screen_name)
|
||||
thread_tweets = self.session.twitter.search_tweets(term, count=100, since_id=tweet.id, tweet_mode="extended")
|
||||
results.extend(thread_tweets)
|
||||
except TweepyException as e:
|
||||
log.exception("There was an error when attempting to retrieve the whole conversation for buffer {}".format(self.buffer.name))
|
||||
|
||||
try:
|
||||
term = "to:{}".format(tweet.user.screen_name)
|
||||
reply_tweets = self.session.twitter.search_tweets(term, count=100, since_id=tweet.id, tweet_mode="extended")
|
||||
ids = [t.id for t in results]
|
||||
reply_tweets = [t for t in reply_tweets if hasattr(t, "in_reply_to_status_id") and t.in_reply_to_status_id in ids]
|
||||
results.extend(reply_tweets)
|
||||
except TweepyException as e:
|
||||
log.exception("There was an error when attempting to retrieve the whole conversation for buffer {}".format(self.buffer.name))
|
||||
results.sort(key=lambda x: x.id)
|
||||
return results
|
@@ -1,144 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import time
|
||||
import wx
|
||||
import widgetUtils
|
||||
import output
|
||||
import logging
|
||||
from mysc.thread_utils import call_threaded
|
||||
from tweepy.errors import TweepyException
|
||||
from pubsub import pub
|
||||
from wxUI import buffers, commonMessageDialogs, menus
|
||||
from controller.twitter import user, messages
|
||||
from controller.buffers import base
|
||||
|
||||
log = logging.getLogger("controller.buffers.twitter.trends")
|
||||
|
||||
class TrendsBuffer(base.Buffer):
|
||||
def __init__(self, parent, name, sessionObject, account, trendsFor, *args, **kwargs):
|
||||
super(TrendsBuffer, self).__init__(parent=parent, sessionObject=sessionObject)
|
||||
self.trendsFor = trendsFor
|
||||
self.session = sessionObject
|
||||
self.account = account
|
||||
self.invisible = True
|
||||
self.buffer = buffers.twitter.trendsPanel(parent, name)
|
||||
self.buffer.account = account
|
||||
self.type = self.buffer.type
|
||||
self.bind_events()
|
||||
self.sound = "trends_updated.ogg"
|
||||
self.trends = []
|
||||
self.name = name
|
||||
self.buffer.name = name
|
||||
self.compose_function = self.compose_function_
|
||||
self.get_formatted_message = self.get_message
|
||||
self.reply = self.search_topic
|
||||
|
||||
|
||||
def post_status(self, *args, **kwargs):
|
||||
title = _("Tweet")
|
||||
caption = _("Write the tweet here")
|
||||
tweet = messages.tweet(self.session, title, caption, "")
|
||||
response = tweet.message.ShowModal()
|
||||
if response == wx.ID_OK:
|
||||
tweet_data = tweet.get_tweet_data()
|
||||
call_threaded(self.session.send_tweet, *tweet_data)
|
||||
if hasattr(tweet.message, "destroy"):
|
||||
tweet.message.destroy()
|
||||
|
||||
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False):
|
||||
# starts stream every 3 minutes.
|
||||
current_time = time.time()
|
||||
if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory == True:
|
||||
self.execution_time = current_time
|
||||
try:
|
||||
data = self.session.twitter.get_place_trends(id=self.trendsFor)
|
||||
except TweepyException as err:
|
||||
log.exception("Error %s" % (str(err)))
|
||||
if not hasattr(self, "name_"):
|
||||
self.name_ = data[0]["locations"][0]["name"]
|
||||
pub.sendMessage("buffer-title-changed", buffer=self)
|
||||
self.trends = data[0]["trends"]
|
||||
self.put_items_on_the_list()
|
||||
if self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True:
|
||||
self.session.sound.play(self.sound)
|
||||
|
||||
def put_items_on_the_list(self):
|
||||
selected_item = self.buffer.list.get_selected()
|
||||
self.buffer.list.clear()
|
||||
for i in self.trends:
|
||||
tweet = self.compose_function(i)
|
||||
self.buffer.list.insert_item(False, *tweet)
|
||||
self.buffer.set_position(self.session.settings["general"]["reverse_timelines"])
|
||||
|
||||
def compose_function_(self, trend):
|
||||
return [trend["name"]]
|
||||
|
||||
def bind_events(self):
|
||||
log.debug("Binding events...")
|
||||
self.buffer.list.list.Bind(wx.EVT_CHAR_HOOK, self.get_event)
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.tweet_about_this_trend, self.buffer.tweetTrendBtn)
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.post_status, self.buffer.tweet)
|
||||
widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_ITEM_RIGHT_CLICK, self.show_menu)
|
||||
widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_KEY_DOWN, self.show_menu_by_key)
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.search_topic, self.buffer.search_topic)
|
||||
|
||||
def get_message(self):
|
||||
return self.compose_function(self.trends[self.buffer.list.get_selected()])[0]
|
||||
|
||||
def remove_buffer(self, force=False):
|
||||
if force == False:
|
||||
dlg = commonMessageDialogs.remove_buffer()
|
||||
else:
|
||||
dlg = widgetUtils.YES
|
||||
if dlg == widgetUtils.YES:
|
||||
if self.name[:-3] in self.session.settings["other_buffers"]["trending_topic_buffers"]:
|
||||
self.session.settings["other_buffers"]["trending_topic_buffers"].remove(self.name[:-3])
|
||||
self.session.settings.write()
|
||||
if self.name in self.session.db:
|
||||
self.session.db.pop(self.name)
|
||||
return True
|
||||
elif dlg == widgetUtils.NO:
|
||||
return False
|
||||
|
||||
def url(self, *args, **kwargs):
|
||||
self.tweet_about_this_trend()
|
||||
|
||||
def search_topic(self, *args, **kwargs):
|
||||
topic = self.trends[self.buffer.list.get_selected()]["name"]
|
||||
pub.sendMessage("search", term=topic)
|
||||
|
||||
def show_menu(self, ev, pos=0, *args, **kwargs):
|
||||
menu = menus.trendsPanelMenu()
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.search_topic, menuitem=menu.search_topic)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.tweet_about_this_trend, menuitem=menu.tweetThisTrend)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.copy, menuitem=menu.copy)
|
||||
if pos != 0:
|
||||
self.buffer.PopupMenu(menu, pos)
|
||||
else:
|
||||
self.buffer.PopupMenu(menu, ev.GetPosition())
|
||||
|
||||
def view(self, *args, **kwargs):
|
||||
pub.sendMessage("execute-action", action="view_item")
|
||||
|
||||
def copy(self, *args, **kwargs):
|
||||
pub.sendMessage("execute-action", action="copy_to_clipboard")
|
||||
|
||||
def tweet_about_this_trend(self, *args, **kwargs):
|
||||
if self.buffer.list.get_count() == 0: return
|
||||
title = _("Tweet")
|
||||
caption = _("Write the tweet here")
|
||||
tweet = messages.tweet(session=self.session, title=title, caption=caption, text=self.get_message()+ " ")
|
||||
tweet.message.SetInsertionPoint(len(tweet.message.GetValue()))
|
||||
if tweet.message.ShowModal() == widgetUtils.OK:
|
||||
tweet_data = tweet.get_tweet_data()
|
||||
call_threaded(self.session.send_tweet, *tweet_data)
|
||||
if hasattr(tweet.message, "destroy"): tweet.message.destroy()
|
||||
|
||||
def show_menu_by_key(self, ev):
|
||||
if self.buffer.list.get_count() == 0:
|
||||
return
|
||||
if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU:
|
||||
self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition())
|
||||
|
||||
def open_in_browser(self, *args, **kwargs):
|
||||
output.speak(_(u"This action is not supported in the buffer, yet."))
|
@@ -13,8 +13,6 @@ import application
|
||||
import sound
|
||||
import output
|
||||
from pubsub import pub
|
||||
from tweepy.errors import TweepyException, Forbidden
|
||||
from geopy.geocoders import Nominatim
|
||||
from extra import SoundsTutorial
|
||||
from update import updater
|
||||
from wxUI import view, dialogs, commonMessageDialogs, sysTrayIcon
|
||||
@@ -25,14 +23,11 @@ from mysc import restart
|
||||
from mysc import localization
|
||||
from mysc.thread_utils import call_threaded
|
||||
from mysc.repeating_timer import RepeatingTimer
|
||||
from controller.twitter import handler as TwitterHandler
|
||||
from controller.mastodon import handler as MastodonHandler
|
||||
from . import settings, userAlias
|
||||
|
||||
log = logging.getLogger("mainController")
|
||||
|
||||
geocoder = Nominatim(user_agent="TWBlue")
|
||||
|
||||
class Controller(object):
|
||||
|
||||
""" Main Controller for TWBlue. It manages the main window and sessions."""
|
||||
@@ -110,35 +105,19 @@ class Controller(object):
|
||||
pub.subscribe(self.toggle_share_settings, "toggleShare")
|
||||
pub.subscribe(self.invisible_shorcuts_changed, "invisible-shorcuts-changed")
|
||||
pub.subscribe(self.create_account_buffer, "core.create_account")
|
||||
|
||||
# Twitter specific events.
|
||||
pub.subscribe(self.buffer_title_changed, "buffer-title-changed")
|
||||
pub.subscribe(self.manage_sent_dm, "twitter.sent_dm")
|
||||
pub.subscribe(self.update_sent_dms, "twitter.sent_dms_updated")
|
||||
pub.subscribe(self.more_dms, "twitter.more_sent_dms")
|
||||
pub.subscribe(self.manage_sent_tweets, "twitter.sent_tweet")
|
||||
pub.subscribe(self.manage_new_tweet, "twitter.new_tweet")
|
||||
pub.subscribe(self.manage_friend, "twitter.friend")
|
||||
pub.subscribe(self.manage_unfollowing, "twitter.unfollowing")
|
||||
pub.subscribe(self.manage_favourite, "twitter.favourite")
|
||||
pub.subscribe(self.manage_unfavourite, "twitter.unfavourite")
|
||||
pub.subscribe(self.manage_blocked_user, "twitter.blocked_user")
|
||||
pub.subscribe(self.manage_unblocked_user, "twitter.unblocked_user")
|
||||
pub.subscribe(self.restart_streaming, "twitter.restart_streaming")
|
||||
pub.subscribe(self.change_buffer_title, "core.change_buffer_title")
|
||||
|
||||
# Mastodon specific events.
|
||||
pub.subscribe(self.mastodon_new_item, "mastodon.new_item")
|
||||
pub.subscribe(self.mastodon_updated_item, "mastodon.updated_item")
|
||||
pub.subscribe(self.mastodon_new_conversation, "mastodon.conversation_received")
|
||||
pub.subscribe(self.mastodon_error_post, "mastodon.error_post")
|
||||
|
||||
# connect application events to GUI
|
||||
widgetUtils.connect_event(self.view, widgetUtils.CLOSE_EVENT, self.exit_)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.show_hide, menuitem=self.view.show_hide)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.search, menuitem=self.view.menuitem_search)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.list_manager, menuitem=self.view.lists)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.get_trending_topics, menuitem=self.view.trends)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.filter, menuitem=self.view.filter)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.manage_filters, menuitem=self.view.manage_filters)
|
||||
# widgetUtils.connect_event(self.view, widgetUtils.MENU, self.list_manager, menuitem=self.view.lists)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.find, menuitem=self.view.find)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.accountConfiguration, menuitem=self.view.account_settings)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.configuration, menuitem=self.view.prefs)
|
||||
@@ -152,17 +131,14 @@ class Controller(object):
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.edit_keystrokes, menuitem=self.view.keystroke_editor)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.post_tweet, self.view.compose)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.post_reply, self.view.reply)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.post_retweet, self.view.retweet)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.post_retweet, self.view.share)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.add_to_favourites, self.view.fav)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.remove_from_favourites, self.view.unfav)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_item, self.view.view)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_reverse_geocode, menuitem=self.view.view_coordinates)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.delete, self.view.delete)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.follow, menuitem=self.view.follow)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.send_dm, self.view.dm)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_user_lists, menuitem=self.view.viewLists)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.get_more_items, menuitem=self.view.load_previous_items)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_user_lists, menuitem=self.view.viewLists)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.clear_buffer, menuitem=self.view.clear)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.remove_buffer, self.view.deleteTl)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.check_for_updates, self.view.check_for_updates)
|
||||
@@ -170,8 +146,6 @@ class Controller(object):
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.visit_website, menuitem=self.view.visit_website)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.get_soundpacks, menuitem=self.view.get_soundpacks)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.manage_accounts, self.view.manage_accounts)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.update_profile, menuitem=self.view.updateProfile)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.user_details, menuitem=self.view.details)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.toggle_autoread, menuitem=self.view.autoread)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.toggle_buffer_mute, self.view.mute_buffer)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.open_timeline, self.view.timeline)
|
||||
@@ -184,17 +158,15 @@ class Controller(object):
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_documentation, self.view.doc)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_changelog, self.view.changelog)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.add_alias, self.view.addAlias)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.add_to_list, self.view.addToList)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.remove_from_list, self.view.removeFromList)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.update_buffer, self.view.update_buffer)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.manage_aliases, self.view.manageAliases)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.report_error, self.view.reportError)
|
||||
|
||||
def set_systray_icon(self):
|
||||
self.systrayIcon = sysTrayIcon.SysTrayIcon()
|
||||
widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.post_tweet, menuitem=self.systrayIcon.tweet)
|
||||
widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.post_tweet, menuitem=self.systrayIcon.post)
|
||||
widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.configuration, menuitem=self.systrayIcon.global_settings)
|
||||
widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.accountConfiguration, menuitem=self.systrayIcon.account_settings)
|
||||
widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.update_profile, menuitem=self.systrayIcon.update_profile)
|
||||
widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.show_hide, menuitem=self.systrayIcon.show_hide)
|
||||
widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.check_for_updates, menuitem=self.systrayIcon.check_for_updates)
|
||||
widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.view_documentation, menuitem=self.systrayIcon.doc)
|
||||
@@ -214,9 +186,7 @@ class Controller(object):
|
||||
def get_handler(self, type):
|
||||
handler = self.handlers.get(type)
|
||||
if handler == None:
|
||||
if type == "twitter":
|
||||
handler = TwitterHandler.Handler()
|
||||
elif type == "mastodon":
|
||||
if type == "mastodon":
|
||||
handler = MastodonHandler.Handler()
|
||||
self.handlers[type]=handler
|
||||
return handler
|
||||
@@ -234,6 +204,8 @@ class Controller(object):
|
||||
self.accounts = []
|
||||
# This saves the current account (important in invisible mode)
|
||||
self.current_account = ""
|
||||
# this saves current menu bar layout.
|
||||
self.menubar_current_handler = ""
|
||||
# Handlers are special objects as they manage the mapping of available features and events in different social networks.
|
||||
self.handlers = dict()
|
||||
self.view.prepare()
|
||||
@@ -259,9 +231,9 @@ class Controller(object):
|
||||
if sessions.sessions[i].is_logged == False:
|
||||
self.create_ignored_session_buffer(sessions.sessions[i])
|
||||
continue
|
||||
# Valid types currently are twitter and mastodon (Work in progress)
|
||||
# Valid types currently are mastodon (Work in progress)
|
||||
# More can be added later.
|
||||
valid_session_types = ["twitter", "mastodon"]
|
||||
valid_session_types = ["mastodon"]
|
||||
if sessions.sessions[i].type in valid_session_types:
|
||||
handler = self.get_handler(type=sessions.sessions[i].type)
|
||||
handler.create_buffers(sessions.sessions[i], controller=self)
|
||||
@@ -282,8 +254,9 @@ class Controller(object):
|
||||
if config.app["app-settings"]["speak_ready_msg"] == True:
|
||||
output.speak(_(u"Ready"))
|
||||
self.started = True
|
||||
self.streams_checker_function = RepeatingTimer(60, self.check_streams)
|
||||
self.streams_checker_function.start()
|
||||
if len(self.accounts) > 0:
|
||||
b = self.get_first_buffer(self.accounts[0])
|
||||
self.update_menus(handler=self.get_handler(b.session.type))
|
||||
|
||||
def create_ignored_session_buffer(self, session):
|
||||
pub.sendMessage("core.create_account", name=session.get_name(), session_id=session.session_id)
|
||||
@@ -300,7 +273,6 @@ class Controller(object):
|
||||
session.start_streaming()
|
||||
|
||||
def create_account_buffer(self, name, session_id, logged=False):
|
||||
self.accounts.append(name)
|
||||
account = buffers.base.AccountBuffer(self.view.nb, name, name, session_id)
|
||||
if logged == False:
|
||||
account.logged = logged
|
||||
@@ -401,21 +373,6 @@ class Controller(object):
|
||||
return output.speak(page.get_message(), True)
|
||||
output.speak(_(u"{0} not found.").format(string,), True)
|
||||
|
||||
def filter(self, *args, **kwargs):
|
||||
buffer = self.get_current_buffer()
|
||||
if not hasattr(buffer.buffer, "list"):
|
||||
output.speak(_(u"No session is currently in focus. Focus a session with the next or previous session shortcut."), True)
|
||||
return
|
||||
handler = self.get_handler(type=buffer.session.type)
|
||||
if handler != None and hasattr(handler, "filter"):
|
||||
return handler.filter(buffer=buffer)
|
||||
|
||||
def manage_filters(self, *args, **kwargs):
|
||||
buffer = self.get_best_buffer()
|
||||
handler = self.get_handler(type=buffer.session.type)
|
||||
if handler != None and hasattr(handler, "manage_filters"):
|
||||
return handler.manage_filters(session=buffer.session)
|
||||
|
||||
def seekLeft(self, *args, **kwargs):
|
||||
try:
|
||||
sound.URLPlayer.seek(-5000)
|
||||
@@ -429,7 +386,8 @@ class Controller(object):
|
||||
output.speak("Unable to seek.",True)
|
||||
|
||||
def edit_keystrokes(self, *args, **kwargs):
|
||||
editor = keystrokeEditor.KeystrokeEditor()
|
||||
buffer = self.get_best_buffer()
|
||||
editor = keystrokeEditor.KeystrokeEditor(buffer.session.type)
|
||||
if editor.changed == True:
|
||||
config.keymap.write()
|
||||
register = False
|
||||
@@ -451,31 +409,6 @@ class Controller(object):
|
||||
buffer = self.get_best_buffer()
|
||||
SoundsTutorial.soundsTutorial(buffer.session)
|
||||
|
||||
def view_user_lists(self, *args, **kwargs):
|
||||
buffer = self.get_best_buffer()
|
||||
handler = self.get_handler(type=buffer.session.type)
|
||||
if handler != None and hasattr(handler, "view_user_lists"):
|
||||
return handler.view_user_lists(buffer=buffer)
|
||||
|
||||
def add_to_list(self, *args, **kwargs):
|
||||
buffer = self.get_best_buffer()
|
||||
handler = self.get_handler(type=buffer.session.type)
|
||||
if handler != None and hasattr(handler, "add_to_list"):
|
||||
return handler.add_to_list(controller=self, buffer=buffer)
|
||||
|
||||
def remove_from_list(self, *args, **kwargs):
|
||||
buffer = self.get_best_buffer()
|
||||
handler = self.get_handler(type=buffer.session.type)
|
||||
if handler != None and hasattr(handler, "remove_from_list"):
|
||||
return handler.remove_from_list(controller=self, buffer=buffer)
|
||||
|
||||
def list_manager(self, *args, **kwargs):
|
||||
buffer = self.get_best_buffer()
|
||||
handler = self.get_handler(type=buffer.session.type)
|
||||
if handler != None and hasattr(handler, "list_manager"):
|
||||
lists_buffer_position = self.view.search("lists", buffer.session.get_name())
|
||||
return handler.list_manager(session=buffer.session, lists_buffer_position=lists_buffer_position)
|
||||
|
||||
def configuration(self, *args, **kwargs):
|
||||
""" Opens the global settings dialogue."""
|
||||
d = settings.globalSettingsController()
|
||||
@@ -521,10 +454,6 @@ class Controller(object):
|
||||
for item in sessions.sessions:
|
||||
if sessions.sessions[item].logged == False:
|
||||
continue
|
||||
if hasattr(sessions.sessions[item], "stop_streaming"):
|
||||
log.debug("Disconnecting streaming endpoint for session" + sessions.sessions[item].session_id)
|
||||
sessions.sessions[item].stop_streaming()
|
||||
log.debug("Disconnecting streams for %s session" % (sessions.sessions[item].session_id,))
|
||||
sessions.sessions[item].sound.cleaner.cancel()
|
||||
log.debug("Saving database for " + sessions.sessions[item].session_id)
|
||||
sessions.sessions[item].save_persistent_data()
|
||||
@@ -532,9 +461,6 @@ class Controller(object):
|
||||
pidpath = os.path.join(os.getenv("temp"), "{}.pid".format(application.name))
|
||||
if os.path.exists(pidpath):
|
||||
os.remove(pidpath)
|
||||
if hasattr(self, "streams_checker_function"):
|
||||
log.debug("Stopping stream checker...")
|
||||
self.streams_checker_function.cancel()
|
||||
widgetUtils.exit_application()
|
||||
|
||||
def follow(self, *args, **kwargs):
|
||||
@@ -588,6 +514,11 @@ class Controller(object):
|
||||
if hasattr(buffer, "toggle_favorite"):
|
||||
return buffer.toggle_favorite()
|
||||
|
||||
def vote(self, *args, **kwargs):
|
||||
buffer = self.get_current_buffer()
|
||||
if hasattr(buffer, "vote"):
|
||||
return buffer.vote()
|
||||
|
||||
def view_item(self, *args, **kwargs):
|
||||
buffer = self.get_current_buffer()
|
||||
if hasattr(buffer, "view_item"):
|
||||
@@ -631,19 +562,6 @@ class Controller(object):
|
||||
self.view.Show()
|
||||
self.showing = True
|
||||
|
||||
def get_trending_topics(self, *args, **kwargs):
|
||||
buffer = self.get_best_buffer()
|
||||
handler = self.get_handler(type=buffer.session.type)
|
||||
if handler != None and hasattr(handler, "get_trending_topics"):
|
||||
return handler.get_trending_topics(controller=self, session=buffer.session)
|
||||
|
||||
def view_reverse_geocode(self, event=None):
|
||||
buffer = self.get_current_buffer()
|
||||
if hasattr(buffer, "reverse_geocode"):
|
||||
address = buffer.reverse_geocode()
|
||||
if address != None:
|
||||
dlg = commonMessageDialogs.view_geodata(address[0].__str__())
|
||||
|
||||
def get_more_items(self, *args, **kwargs):
|
||||
buffer = self.get_current_buffer()
|
||||
if hasattr(buffer, "get_more_items"):
|
||||
@@ -676,8 +594,15 @@ class Controller(object):
|
||||
|
||||
def buffer_changed(self, *args, **kwargs):
|
||||
buffer = self.get_current_buffer()
|
||||
if buffer.account != self.current_account:
|
||||
old_account = self.current_account
|
||||
new_account = buffer.account
|
||||
if new_account != old_account:
|
||||
self.current_account = buffer.account
|
||||
new_first_buffer = self.get_first_buffer(new_account)
|
||||
if new_first_buffer != None and new_first_buffer.session.type != self.menubar_current_handler:
|
||||
handler = self.get_handler(new_first_buffer.session.type)
|
||||
self.menubar_current_handler = new_first_buffer.session.type
|
||||
self.update_menus(handler)
|
||||
if not hasattr(buffer, "session") or buffer.session == None:
|
||||
return
|
||||
muted = autoread = False
|
||||
@@ -688,6 +613,19 @@ class Controller(object):
|
||||
self.view.check_menuitem("mute_buffer", muted)
|
||||
self.view.check_menuitem("autoread", autoread)
|
||||
|
||||
def update_menus(self, handler):
|
||||
if hasattr(handler, "menus"):
|
||||
for m in list(handler.menus.keys()):
|
||||
if hasattr(self.view, m):
|
||||
menu_item = getattr(self.view, m)
|
||||
if handler.menus[m] == None:
|
||||
menu_item.Enable(False)
|
||||
else:
|
||||
menu_item.Enable(True)
|
||||
menu_item.SetItemLabel(handler.menus[m])
|
||||
if hasattr(handler, "item_menu"):
|
||||
self.view.menubar.SetMenuLabel(1, handler.item_menu)
|
||||
|
||||
def fix_wrong_buffer(self):
|
||||
buf = self.get_best_buffer()
|
||||
if buf == None:
|
||||
@@ -776,7 +714,10 @@ class Controller(object):
|
||||
output.speak(msg, True)
|
||||
|
||||
def next_account(self, *args, **kwargs):
|
||||
index = self.accounts.index(self.current_account)
|
||||
try:
|
||||
index = self.accounts.index(self.current_account)
|
||||
except ValueError:
|
||||
index = -1
|
||||
if index+1 == len(self.accounts):
|
||||
index = 0
|
||||
else:
|
||||
@@ -801,7 +742,10 @@ class Controller(object):
|
||||
output.speak(msg, True)
|
||||
|
||||
def previous_account(self, *args, **kwargs):
|
||||
index = self.accounts.index(self.current_account)
|
||||
try:
|
||||
index = self.accounts.index(self.current_account)
|
||||
except ValueError:
|
||||
index = 0
|
||||
if index-1 < 0:
|
||||
index = len(self.accounts)-1
|
||||
else:
|
||||
@@ -916,70 +860,6 @@ class Controller(object):
|
||||
if message != None:
|
||||
output.speak(message, speech=session.settings["reporting"]["speech_reporting"], braille=session.settings["reporting"]["braille_reporting"])
|
||||
|
||||
def manage_sent_dm(self, data, session_name):
|
||||
buffer = self.search_buffer("sent_direct_messages", session_name)
|
||||
if buffer == None:
|
||||
return
|
||||
play_sound = "dm_sent.ogg"
|
||||
if "sent_direct_messages" not in buffer.session.settings["other_buffers"]["muted_buffers"]:
|
||||
self.notify(buffer.session, play_sound=play_sound)
|
||||
buffer.add_new_item(data)
|
||||
|
||||
def manage_sent_tweets(self, data, session_name):
|
||||
buffer = self.search_buffer("sent_tweets", session_name)
|
||||
if buffer == None:
|
||||
return
|
||||
data = buffer.session.check_quoted_status(data)
|
||||
data = buffer.session.check_long_tweet(data)
|
||||
if data == False: # Long tweet deleted from twishort.
|
||||
return
|
||||
items = buffer.session.db[buffer.name]
|
||||
if buffer.session.settings["general"]["reverse_timelines"] == False:
|
||||
items.append(data)
|
||||
else:
|
||||
items.insert(0, data)
|
||||
buffer.session.db[buffer.name] = items
|
||||
buffer.add_new_item(data)
|
||||
|
||||
def manage_friend(self, data, session_name):
|
||||
buffer = self.search_buffer("friends", session_name)
|
||||
if buffer == None:
|
||||
return
|
||||
buffer.add_new_item(data)
|
||||
|
||||
def manage_unfollowing(self, item, session_name):
|
||||
buffer = self.search_buffer("friends", session_name)
|
||||
if buffer == None:
|
||||
return
|
||||
buffer.remove_item(item)
|
||||
|
||||
def manage_favourite(self, data, session_name):
|
||||
buffer = self.search_buffer("favourites", session_name)
|
||||
if buffer == None:
|
||||
return
|
||||
play_sound = "favourite.ogg"
|
||||
if "favourites" not in buffer.session.settings["other_buffers"]["muted_buffers"]:
|
||||
self.notify(buffer.session, play_sound=play_sound)
|
||||
buffer.add_new_item(data)
|
||||
|
||||
def manage_unfavourite(self, item, session_name):
|
||||
buffer = self.search_buffer("favourites", session_name)
|
||||
if buffer == None:
|
||||
return
|
||||
buffer.remove_item(item)
|
||||
|
||||
def manage_blocked_user(self, data, session_name):
|
||||
buffer = self.search_buffer("blocked", session_name)
|
||||
if buffer == None:
|
||||
return
|
||||
buffer.add_new_item(data)
|
||||
|
||||
def manage_unblocked_user(self, item, session_name):
|
||||
buffer = self.search_buffer("blocked", session_name)
|
||||
if buffer == None:
|
||||
return
|
||||
buffer.remove_item(item)
|
||||
|
||||
def start_buffers(self, session):
|
||||
log.debug("starting buffers... Session %s" % (session.session_id,))
|
||||
handler = self.get_handler(type=session.type)
|
||||
@@ -991,17 +871,6 @@ class Controller(object):
|
||||
for i in sessions.sessions:
|
||||
self.set_buffer_positions(i)
|
||||
|
||||
def check_connection(self):
|
||||
if self.started == False:
|
||||
return
|
||||
for i in sessions.sessions:
|
||||
try:
|
||||
if sessions.sessions[i].is_logged == False:
|
||||
continue
|
||||
sessions.sessions[i].check_connection()
|
||||
except: # We shouldn't allow this function to die.
|
||||
pass
|
||||
|
||||
def invisible_shorcuts_changed(self, registered):
|
||||
if registered == True:
|
||||
km = self.create_invisible_keyboard_shorcuts()
|
||||
@@ -1057,21 +926,11 @@ class Controller(object):
|
||||
for i in sm.removed_sessions:
|
||||
if sessions.sessions[i].logged == True:
|
||||
self.logout_account(sessions.sessions[i].session_id)
|
||||
self.destroy_buffer(sessions.sessions[i].settings["twitter"]["user_name"], sessions.sessions[i].settings["twitter"]["user_name"])
|
||||
self.accounts.remove(sessions.sessions[i].settings["twitter"]["user_name"])
|
||||
self.destroy_buffer(sessions.sessions[i].get_name(), sessions.sessions[i].get_name())
|
||||
if sessions.sessions[i].get_name() in self.accounts:
|
||||
self.accounts.remove(sessions.sessions[i].get_name())
|
||||
sessions.sessions.pop(i)
|
||||
|
||||
def update_profile(self, *args, **kwargs):
|
||||
buffer = self.get_best_buffer()
|
||||
handler = self.get_handler(type=buffer.session.type)
|
||||
if hasattr(handler, "update_profile"):
|
||||
return handler.update_profile(session=buffer.session)
|
||||
|
||||
def user_details(self, *args, **kwargs):
|
||||
buffer = self.get_current_buffer()
|
||||
if hasattr(buffer, "user_details"):
|
||||
buffer.user_details()
|
||||
|
||||
def toggle_autoread(self, *args, **kwargs):
|
||||
buffer = self.get_current_buffer()
|
||||
if hasattr(buffer, "session") and buffer.session == None:
|
||||
@@ -1136,16 +995,6 @@ class Controller(object):
|
||||
i.start_stream(mandatory=True)
|
||||
except Exception as err:
|
||||
log.exception("Error %s starting buffer %s on account %s, with args %r and kwargs %r." % (str(err), i.name, i.account, i.args, i.kwargs))
|
||||
# Determine if this error was caused by a block applied to the current user (IE permission errors).
|
||||
if type(err) == Forbidden:
|
||||
buff = self.view.search(i.name, i.account)
|
||||
i.remove_buffer(force=True)
|
||||
commonMessageDialogs.blocked_timeline()
|
||||
if self.get_current_buffer() == i:
|
||||
self.right()
|
||||
self.view.delete_buffer(buff)
|
||||
self.buffers.remove(i)
|
||||
del i
|
||||
|
||||
def update_buffer(self, *args, **kwargs):
|
||||
bf = self.get_current_buffer()
|
||||
@@ -1160,16 +1009,12 @@ class Controller(object):
|
||||
def buffer_title_changed(self, buffer):
|
||||
if buffer.name.endswith("-timeline"):
|
||||
title = _(u"Timeline for {}").format(buffer.username,)
|
||||
elif buffer.name.endswith("-favorite"):
|
||||
title = _(u"Likes for {}").format(buffer.username,)
|
||||
elif buffer.name.endswith("-followers"):
|
||||
title = _(u"Followers for {}").format(buffer.username,)
|
||||
elif buffer.name.endswith("-friends"):
|
||||
title = _(u"Friends for {}").format(buffer.username,)
|
||||
elif buffer.name.endswith("-following"):
|
||||
title = _(u"Following for {}").format(buffer.username,)
|
||||
elif buffer.name.endswith("_tt"):
|
||||
title = _("Trending topics for %s") % (buffer.name_)
|
||||
buffer_index = self.view.search(buffer.name, buffer.account)
|
||||
self.view.set_page_title(buffer_index, title)
|
||||
|
||||
@@ -1178,54 +1023,12 @@ class Controller(object):
|
||||
if hasattr(buffer, "ocr_image"):
|
||||
return buffer.ocr_image()
|
||||
|
||||
def update_sent_dms(self, total, session_name):
|
||||
sent_dms = self.search_buffer("sent_direct_messages", session_name)
|
||||
if sent_dms != None:
|
||||
sent_dms.put_items_on_list(total)
|
||||
|
||||
def more_dms(self, data, account):
|
||||
sent_dms = self.search_buffer("sent_direct_messages", account)
|
||||
if sent_dms != None:
|
||||
sent_dms.put_more_items(data)
|
||||
|
||||
def save_data_in_db(self):
|
||||
for i in sessions.sessions:
|
||||
sessions.sessions[i].save_persistent_data()
|
||||
|
||||
def manage_new_tweet(self, data, session_name, _buffers):
|
||||
sound_to_play = None
|
||||
for buff in _buffers:
|
||||
buffer = self.search_buffer(buff, session_name)
|
||||
if buffer == None or buffer.session.get_name() != session_name:
|
||||
return
|
||||
buffer.add_new_item(data)
|
||||
if buff == "home_timeline": sound_to_play = "tweet_received.ogg"
|
||||
elif buff == "mentions": sound_to_play = "mention_received.ogg"
|
||||
elif buff == "sent_tweets": sound_to_play = "tweet_send.ogg"
|
||||
elif "timeline" in buff: sound_to_play = "tweet_timeline.ogg"
|
||||
else: sound_to_play = None
|
||||
if sound_to_play != None and buff not in buffer.session.settings["other_buffers"]["muted_buffers"]:
|
||||
self.notify(buffer.session, sound_to_play)
|
||||
|
||||
def toggle_share_settings(self, shareable=True):
|
||||
self.view.retweet.Enable(shareable)
|
||||
|
||||
def check_streams(self):
|
||||
if self.started == False:
|
||||
return
|
||||
for i in sessions.sessions:
|
||||
try:
|
||||
if sessions.sessions[i].is_logged == False: continue
|
||||
sessions.sessions[i].check_streams()
|
||||
except TweepyException: # We shouldn't allow this function to die.
|
||||
pass
|
||||
|
||||
def restart_streaming(self, session):
|
||||
for s in sessions.sessions:
|
||||
if sessions.sessions[s].session_id == session:
|
||||
log.debug("Restarting stream in session %s" % (session))
|
||||
sessions.sessions[s].stop_streaming()
|
||||
sessions.sessions[s].start_streaming()
|
||||
self.view.share.Enable(shareable)
|
||||
|
||||
def mastodon_new_item(self, item, session_name, _buffers):
|
||||
sound_to_play = None
|
||||
@@ -1239,6 +1042,7 @@ class Controller(object):
|
||||
elif buff == "direct_messages": sound_to_play = "dm_received.ogg"
|
||||
elif buff == "sent": sound_to_play = "tweet_send.ogg"
|
||||
elif buff == "followers" or buff == "following": sound_to_play = "update_followers.ogg"
|
||||
elif buff == "notifications": sound_to_play = "new_event.ogg"
|
||||
elif "timeline" in buff: sound_to_play = "tweet_timeline.ogg"
|
||||
else: sound_to_play = None
|
||||
if sound_to_play != None and buff not in buffer.session.settings["other_buffers"]["muted_buffers"]:
|
||||
@@ -1265,4 +1069,19 @@ class Controller(object):
|
||||
# if number_of_items > 0:
|
||||
# sound_to_play = "dm_received.ogg"
|
||||
# if "direct_messages" not in buffer.session.settings["other_buffers"]["muted_buffers"]:
|
||||
# self.notify(buffer.session, sound_to_play)
|
||||
# self.notify(buffer.session, sound_to_play)
|
||||
|
||||
def mastodon_error_post(self, name, reply_to, visibility, posts):
|
||||
home = self.search_buffer("home_timeline", name)
|
||||
if home != None:
|
||||
wx.CallAfter(home.post_from_error, visibility=visibility, reply_to=reply_to, data=posts)
|
||||
|
||||
def change_buffer_title(self, name, buffer, title):
|
||||
buffer_index = self.view.search(buffer, name)
|
||||
if buffer_index != None and buffer_index > -1:
|
||||
self.view.set_page_title(buffer_index, title)
|
||||
|
||||
def report_error(self, *args, **kwargs):
|
||||
"""Redirects the user to the issue page on github"""
|
||||
log.debug("Redirecting the user to report an error...")
|
||||
webbrowser.open_new_tab(application.report_bugs_url)
|
||||
|
@@ -1,13 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import wx
|
||||
import logging
|
||||
import output
|
||||
from pubsub import pub
|
||||
from mysc import restart
|
||||
from wxUI.dialogs.mastodon import dialogs
|
||||
from wxUI.dialogs.mastodon import search as search_dialogs
|
||||
from wxUI.dialogs.mastodon import dialogs
|
||||
from wxUI.dialogs import userAliasDialogs
|
||||
from wxUI import commonMessageDialogs
|
||||
from sessions.twitter import utils
|
||||
from . import userActions, settings
|
||||
|
||||
log = logging.getLogger("controller.mastodon.handler")
|
||||
@@ -16,10 +16,45 @@ class Handler(object):
|
||||
|
||||
def __init__(self):
|
||||
super(Handler, self).__init__()
|
||||
# Structure to hold names for menu bar items.
|
||||
# empty names mean the item will be Disabled.
|
||||
self.menus = dict(
|
||||
# In application menu.
|
||||
updateProfile=None,
|
||||
menuitem_search=_("&Search"),
|
||||
lists=None,
|
||||
manageAliases=_("Manage user aliases"),
|
||||
# In item menu.
|
||||
compose=_("&Post"),
|
||||
reply=_("Re&ply"),
|
||||
share=_("&Boost"),
|
||||
fav=_("&Add to favorites"),
|
||||
unfav=_("Remove from favorites"),
|
||||
view=_("&Show post"),
|
||||
view_conversation=_("View conversa&tion"),
|
||||
ocr=_("Read text in picture"),
|
||||
delete=_("&Delete"),
|
||||
# In user menu.
|
||||
follow=_("&Actions..."),
|
||||
timeline=_("&View timeline..."),
|
||||
dm=_("Direct me&ssage"),
|
||||
addAlias=_("Add a&lias"),
|
||||
addToList=None,
|
||||
removeFromList=None,
|
||||
details=None,
|
||||
favs=None,
|
||||
# In buffer Menu.
|
||||
trends=None,
|
||||
filter=None,
|
||||
manage_filters=None
|
||||
)
|
||||
# Name for the "tweet" menu in the menu bar.
|
||||
self.item_menu = _("&Post")
|
||||
|
||||
def create_buffers(self, session, createAccounts=True, controller=None):
|
||||
session.get_user_info()
|
||||
name = session.get_name()
|
||||
controller.accounts.append(name)
|
||||
if createAccounts == True:
|
||||
pub.sendMessage("core.create_account", name=name, session_id=session.session_id, logged=True)
|
||||
root_position =controller.view.search(name, name)
|
||||
@@ -48,14 +83,16 @@ class Handler(object):
|
||||
pub.sendMessage("createBuffer", buffer_type="UserBuffer", session_type=session.type, buffer_title=_("Muted users"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, compose_func="compose_user", function="mutes", name="muted", sessionObject=session, account=name))
|
||||
elif i == 'blocked':
|
||||
pub.sendMessage("createBuffer", buffer_type="UserBuffer", session_type=session.type, buffer_title=_("Blocked users"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, compose_func="compose_user", function="blocks", name="blocked", sessionObject=session, account=name))
|
||||
elif i == 'notifications':
|
||||
pub.sendMessage("createBuffer", buffer_type="NotificationsBuffer", session_type=session.type, buffer_title=_("Notifications"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, compose_func="compose_notification", function="notifications", name="notifications", sessionObject=session, account=name))
|
||||
pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Timelines"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, name="timelines", account=name))
|
||||
timelines_position =controller.view.search("timelines", name)
|
||||
for i in session.settings["other_buffers"]["timelines"]:
|
||||
pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=i, parent_tab=timelines_position, start=False, kwargs=dict(parent=controller.view.nb, function="account_statuses", name="%s-timeline".format(i), sessionObject=session, account=name, sound="tweet_timeline.ogg", id=i))
|
||||
pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_("Timeline for {}").format(i), parent_tab=timelines_position, start=False, kwargs=dict(parent=controller.view.nb, function="account_statuses", name="{}-timeline".format(i), sessionObject=session, account=name, sound="tweet_timeline.ogg", id=i))
|
||||
for i in session.settings["other_buffers"]["followers_timelines"]:
|
||||
pub.sendMessage("createBuffer", buffer_type="UserBuffer", session_type=session.type, buffer_title=_("Followers for {}").format(i), parent_tab=timelines_position, start=False, kwargs=dict(parent=controller.view.nb, compose_func="compose_user", function="account_followers", name="%s-followers" % (i,), sessionObject=session, account=name, sound="new_event.ogg", id=i))
|
||||
pub.sendMessage("createBuffer", buffer_type="UserBuffer", session_type=session.type, buffer_title=_("Followers for {}").format(i), parent_tab=timelines_position, start=False, kwargs=dict(parent=controller.view.nb, compose_func="compose_user", function="account_followers", name="{}-followers".format(i,), sessionObject=session, account=name, sound="new_event.ogg", id=i))
|
||||
for i in session.settings["other_buffers"]["following_timelines"]:
|
||||
pub.sendMessage("createBuffer", buffer_type="UserBuffer", session_type=session.type, buffer_title=_("Following for {}").format(i), parent_tab=timelines_position, start=False, kwargs=dict(parent=controller.view.nb, compose_func="compose_user", function="account_following", name="%s-following" % (i,), sessionObject=session, account=name, sound="new_event.ogg", id=i))
|
||||
pub.sendMessage("createBuffer", buffer_type="UserBuffer", session_type=session.type, buffer_title=_("Following for {}").format(i), parent_tab=timelines_position, start=False, kwargs=dict(parent=controller.view.nb, compose_func="compose_user", function="account_following", name="{}-following".format(i,), sessionObject=session, account=name, sound="new_event.ogg", id=i))
|
||||
# pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Lists"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, name="lists", name))
|
||||
# lists_position =controller.view.search("lists", session.db["user_name"])
|
||||
# for i in session.settings["other_buffers"]["lists"]:
|
||||
@@ -138,45 +175,45 @@ class Handler(object):
|
||||
users = [user.acct for user in item.mentions if user.id != buffer.session.db["user_id"]]
|
||||
if item.account.acct not in users and item.account.id != buffer.session.db["user_id"]:
|
||||
users.insert(0, item.account.acct)
|
||||
u = userActions.UserTimeline(buffer.session, users)
|
||||
if u.dialog.ShowModal() == wx.ID_OK:
|
||||
action = u.process_action()
|
||||
if action == None:
|
||||
return
|
||||
user = u.user
|
||||
if action == "posts":
|
||||
if user.statuses_count == 0:
|
||||
dialogs.no_posts()
|
||||
return
|
||||
if user.id in buffer.session.settings["other_buffers"]["timelines"]:
|
||||
commonMessageDialogs.timeline_exist()
|
||||
return
|
||||
timelines_position =controller.view.search("timelines", buffer.session.get_name())
|
||||
pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=buffer.session.type, buffer_title=_("Timeline for {}").format(user.username,), parent_tab=timelines_position, start=True, kwargs=dict(parent=controller.view.nb, function="account_statuses", name="%s-timeline" % (user.id,), sessionObject=buffer.session, account=buffer.session.get_name(), sound="tweet_timeline.ogg", id=user.id))
|
||||
buffer.session.settings["other_buffers"]["timelines"].append(user.id)
|
||||
buffer.session.sound.play("create_timeline.ogg")
|
||||
elif action == "followers":
|
||||
if user.followers_count == 0:
|
||||
dialogs.no_followers()
|
||||
return
|
||||
if user.id in buffer.session.settings["other_buffers"]["followers_timelines"]:
|
||||
commonMessageDialogs.timeline_exist()
|
||||
return
|
||||
timelines_position =controller.view.search("timelines", buffer.session.get_name())
|
||||
pub.sendMessage("createBuffer", buffer_type="UserBuffer", session_type=buffer.session.type, buffer_title=_("Followers for {}").format(user.username,), parent_tab=timelines_position, start=True, kwargs=dict(parent=controller.view.nb, compose_func="compose_user", function="account_followers", name="%s-followers" % (user.id,), sessionObject=buffer.session, account=buffer.session.get_name(), sound="new_event.ogg", id=user.id))
|
||||
buffer.session.settings["other_buffers"]["followers_timelines"].append(user.id)
|
||||
buffer.session.sound.play("create_timeline.ogg")
|
||||
elif action == "following":
|
||||
if user.following_count == 0:
|
||||
dialogs.no_following()
|
||||
return
|
||||
if user.id in buffer.session.settings["other_buffers"]["following_timelines"]:
|
||||
commonMessageDialogs.timeline_exist()
|
||||
return
|
||||
timelines_position =controller.view.search("timelines", buffer.session.get_name())
|
||||
pub.sendMessage("createBuffer", buffer_type="UserBuffer", session_type=buffer.session.type, buffer_title=_("Following for {}").format(user.username,), parent_tab=timelines_position, start=True, kwargs=dict(parent=controller.view.nb, compose_func="compose_user", function="account_following", name="%s-followers" % (user.id,), sessionObject=buffer.session, account=buffer.session.get_name(), sound="new_event.ogg", id=user.id))
|
||||
buffer.session.settings["other_buffers"]["following_timelines"].append(user.id)
|
||||
buffer.session.sound.play("create_timeline.ogg")
|
||||
u = userActions.UserTimeline(buffer.session, users)
|
||||
if u.dialog.ShowModal() == wx.ID_OK:
|
||||
action = u.process_action()
|
||||
if action == None:
|
||||
return
|
||||
user = u.user
|
||||
if action == "posts":
|
||||
if user.statuses_count == 0:
|
||||
dialogs.no_posts()
|
||||
return
|
||||
if user.id in buffer.session.settings["other_buffers"]["timelines"]:
|
||||
commonMessageDialogs.timeline_exist()
|
||||
return
|
||||
timelines_position =controller.view.search("timelines", buffer.session.get_name())
|
||||
pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=buffer.session.type, buffer_title=_("Timeline for {}").format(user.username,), parent_tab=timelines_position, start=True, kwargs=dict(parent=controller.view.nb, function="account_statuses", name="%s-timeline" % (user.id,), sessionObject=buffer.session, account=buffer.session.get_name(), sound="tweet_timeline.ogg", id=user.id))
|
||||
buffer.session.settings["other_buffers"]["timelines"].append(user.id)
|
||||
buffer.session.sound.play("create_timeline.ogg")
|
||||
elif action == "followers":
|
||||
if user.followers_count == 0:
|
||||
dialogs.no_followers()
|
||||
return
|
||||
if user.id in buffer.session.settings["other_buffers"]["followers_timelines"]:
|
||||
commonMessageDialogs.timeline_exist()
|
||||
return
|
||||
timelines_position =controller.view.search("timelines", buffer.session.get_name())
|
||||
pub.sendMessage("createBuffer", buffer_type="UserBuffer", session_type=buffer.session.type, buffer_title=_("Followers for {}").format(user.username,), parent_tab=timelines_position, start=True, kwargs=dict(parent=controller.view.nb, compose_func="compose_user", function="account_followers", name="%s-followers" % (user.id,), sessionObject=buffer.session, account=buffer.session.get_name(), sound="new_event.ogg", id=user.id))
|
||||
buffer.session.settings["other_buffers"]["followers_timelines"].append(user.id)
|
||||
buffer.session.sound.play("create_timeline.ogg")
|
||||
elif action == "following":
|
||||
if user.following_count == 0:
|
||||
dialogs.no_following()
|
||||
return
|
||||
if user.id in buffer.session.settings["other_buffers"]["following_timelines"]:
|
||||
commonMessageDialogs.timeline_exist()
|
||||
return
|
||||
timelines_position =controller.view.search("timelines", buffer.session.get_name())
|
||||
pub.sendMessage("createBuffer", buffer_type="UserBuffer", session_type=buffer.session.type, buffer_title=_("Following for {}").format(user.username,), parent_tab=timelines_position, start=True, kwargs=dict(parent=controller.view.nb, compose_func="compose_user", function="account_following", name="%s-followers" % (user.id,), sessionObject=buffer.session, account=buffer.session.get_name(), sound="new_event.ogg", id=user.id))
|
||||
buffer.session.settings["other_buffers"]["following_timelines"].append(user.id)
|
||||
buffer.session.sound.play("create_timeline.ogg")
|
||||
buffer.session.settings.write()
|
||||
|
||||
def account_settings(self, buffer, controller):
|
||||
@@ -188,3 +225,33 @@ class Handler(object):
|
||||
buffer.session.settings.write()
|
||||
buffer.session.save_persistent_data()
|
||||
restart.restart_program()
|
||||
|
||||
def add_alias(self, buffer):
|
||||
if not hasattr(buffer, "get_item"):
|
||||
return
|
||||
item = buffer.get_item()
|
||||
if buffer.type == "user":
|
||||
users = [item.acct]
|
||||
elif buffer.type == "baseBuffer":
|
||||
if item.reblog != None:
|
||||
users = [user.acct for user in item.reblog.mentions if user.id != buffer.session.db["user_id"]]
|
||||
if item.reblog.account.acct not in users and item.account.id != buffer.session.db["user_id"]:
|
||||
users.insert(0, item.reblog.account.acct)
|
||||
else:
|
||||
users = [user.acct for user in item.mentions if user.id != buffer.session.db["user_id"]]
|
||||
if item.account.acct not in users:
|
||||
users.insert(0, item.account.acct)
|
||||
dlg = userAliasDialogs.addAliasDialog(_("Add an user alias"), users)
|
||||
if dlg.get_response() == wx.ID_OK:
|
||||
user, alias = dlg.get_user()
|
||||
if user == "" or alias == "":
|
||||
return
|
||||
try:
|
||||
full_user = buffer.session.api.account_lookup(user)
|
||||
except Exception as e:
|
||||
log.exception("Error adding alias to user {}.".format(user))
|
||||
return
|
||||
buffer.session.settings["user-aliases"][str(full_user.id)] = alias
|
||||
buffer.session.settings.write()
|
||||
output.speak(_("Alias has been set correctly for {}.").format(user))
|
||||
pub.sendMessage("alias-added")
|
@@ -1,14 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import re
|
||||
import wx
|
||||
import widgetUtils
|
||||
import config
|
||||
import output
|
||||
from controller.twitter import messages
|
||||
from twitter_text import parse_tweet, config
|
||||
from controller import messages
|
||||
from sessions.mastodon import templates
|
||||
from wxUI.dialogs.mastodon import postDialogs
|
||||
|
||||
class post(messages.basicTweet):
|
||||
def character_count(post_text, post_cw, character_limit=500):
|
||||
# We will use text for counting character limit only.
|
||||
full_text = post_text+post_cw
|
||||
# find remote users as Mastodon doesn't count the domain in char limit.
|
||||
users = re.findall("@[\w\.-]+@[\w\.-]+", full_text)
|
||||
for user in users:
|
||||
domain = user.split("@")[-1]
|
||||
full_text = full_text.replace("@"+domain, "")
|
||||
options = config.config.get("defaults")
|
||||
options.update(max_weighted_tweet_length=character_limit, default_weight=100)
|
||||
parsed = parse_tweet(full_text, options=options)
|
||||
return parsed.weightedLength
|
||||
|
||||
class post(messages.basicMessage):
|
||||
def __init__(self, session, title, caption, text="", *args, **kwargs):
|
||||
# take max character limit from session as this might be different for some instances.
|
||||
self.max = session.char_limit
|
||||
@@ -19,6 +34,7 @@ class post(messages.basicTweet):
|
||||
self.message.text.SetInsertionPoint(len(self.message.text.GetValue()))
|
||||
widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck)
|
||||
widgetUtils.connect_event(self.message.text, widgetUtils.ENTERED_TEXT, self.text_processor)
|
||||
widgetUtils.connect_event(self.message.spoiler, widgetUtils.ENTERED_TEXT, self.text_processor)
|
||||
widgetUtils.connect_event(self.message.translate, widgetUtils.BUTTON_PRESSED, self.translate)
|
||||
widgetUtils.connect_event(self.message.add, widgetUtils.BUTTON_PRESSED, self.on_attach)
|
||||
widgetUtils.connect_event(self.message.remove_attachment, widgetUtils.BUTTON_PRESSED, self.remove_attachment)
|
||||
@@ -48,8 +64,32 @@ class post(messages.basicTweet):
|
||||
self.add_post(event=None, update_gui=False)
|
||||
return self.thread
|
||||
|
||||
def set_post_data(self, visibility, data):
|
||||
if len(data) == 0:
|
||||
return
|
||||
if len(data) > 1:
|
||||
self.thread = data[:-1]
|
||||
for p in self.thread:
|
||||
self.message.add_item(item=[p.get("text") or "", len(p.get("attachments") or [])], list_type="post")
|
||||
post = data[-1]
|
||||
self.attachments = post.get("attachments") or []
|
||||
self.message.text.SetValue(post.get("text") or "")
|
||||
self.message.sensitive.SetValue(post.get("sensitive") or False)
|
||||
self.message.spoiler.SetValue(post.get("spoiler_text") or "")
|
||||
visibility_settings = dict(public=0, unlisted=1, private=2, direct=3)
|
||||
self.message.visibility.SetSelection(visibility_settings.get(visibility))
|
||||
self.message.on_sensitivity_changed()
|
||||
for attachment in self.attachments:
|
||||
self.message.add_item(item=[attachment["file"], attachment["type"], attachment["description"]])
|
||||
self.text_processor()
|
||||
|
||||
def text_processor(self, *args, **kwargs):
|
||||
super(post, self).text_processor(*args, **kwargs)
|
||||
text = self.message.text.GetValue()
|
||||
cw = self.message.spoiler.GetValue()
|
||||
results = character_count(text, cw, character_limit=self.max)
|
||||
self.message.SetTitle(_("%s - %s of %d characters") % (self.title, results, self.max))
|
||||
if results > self.max:
|
||||
self.session.sound.play("max_length.ogg")
|
||||
if len(self.thread) > 0:
|
||||
if hasattr(self.message, "posts"):
|
||||
self.message.posts.Enable(True)
|
||||
@@ -127,9 +167,9 @@ class post(messages.basicTweet):
|
||||
break
|
||||
if can_attach == False or big_media_present == True:
|
||||
return self.message.unable_to_attach_file()
|
||||
video = self.message.get_video()
|
||||
video, description = self.message.get_video()
|
||||
if video != None:
|
||||
videoInfo = {"type": "video", "file": video, "description": ""}
|
||||
videoInfo = {"type": "video", "file": video, "description": description}
|
||||
self.attachments.append(videoInfo)
|
||||
self.message.add_item(item=[os.path.basename(videoInfo["file"]), videoInfo["type"], videoInfo["description"]])
|
||||
self.text_processor()
|
||||
@@ -145,9 +185,9 @@ class post(messages.basicTweet):
|
||||
break
|
||||
if can_attach == False or big_media_present == True:
|
||||
return self.message.unable_to_attach_file()
|
||||
audio = self.message.get_audio()
|
||||
audio, description = self.message.get_audio()
|
||||
if audio != None:
|
||||
audioInfo = {"type": "audio", "file": audio, "description": ""}
|
||||
audioInfo = {"type": "audio", "file": audio, "description": description}
|
||||
self.attachments.append(audioInfo)
|
||||
self.message.add_item(item=[os.path.basename(audioInfo["file"]), audioInfo["type"], audioInfo["description"]])
|
||||
self.text_processor()
|
||||
@@ -185,6 +225,11 @@ class post(messages.basicTweet):
|
||||
visibility_settings = ["public", "unlisted", "private", "direct"]
|
||||
return visibility_settings[self.message.visibility.GetSelection()]
|
||||
|
||||
def set_visibility(self, setting):
|
||||
visibility_settings = ["public", "unlisted", "private", "direct"]
|
||||
visibility_setting = visibility_settings.index(setting)
|
||||
self.message.visibility.SetSelection(setting)
|
||||
|
||||
class viewPost(post):
|
||||
def __init__(self, post, offset_hours=0, date="", item_url=""):
|
||||
if post.reblog != None:
|
||||
@@ -224,4 +269,12 @@ class viewPost(post):
|
||||
def share(self, *args, **kwargs):
|
||||
if hasattr(self, "item_url"):
|
||||
output.copy(self.item_url)
|
||||
output.speak(_("Link copied to clipboard."))
|
||||
output.speak(_("Link copied to clipboard."))
|
||||
|
||||
class text(messages.basicMessage):
|
||||
def __init__(self, title, text="", *args, **kwargs):
|
||||
self.title = title
|
||||
self.message = postDialogs.viewText(title=title, text=text, *args, **kwargs)
|
||||
self.message.text.SetInsertionPoint(len(self.message.text.GetValue()))
|
||||
widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck)
|
||||
widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate)
|
@@ -9,7 +9,7 @@ import output
|
||||
from collections import OrderedDict
|
||||
from wxUI import commonMessageDialogs
|
||||
from wxUI.dialogs.mastodon import configuration
|
||||
from extra.autocompletionUsers import scan, manage
|
||||
#from extra.autocompletionUsers import scan, manage
|
||||
from extra.ocr import OCRSpace
|
||||
from controller.settings import globalSettingsController
|
||||
from . templateEditor import EditTemplate
|
||||
@@ -31,7 +31,9 @@ class accountSettingsController(globalSettingsController):
|
||||
self.dialog.create_general_account()
|
||||
# widgetUtils.connect_event(self.dialog.general.userAutocompletionScan, widgetUtils.BUTTON_PRESSED, self.on_autocompletion_scan)
|
||||
# widgetUtils.connect_event(self.dialog.general.userAutocompletionManage, widgetUtils.BUTTON_PRESSED, self.on_autocompletion_manage)
|
||||
self.dialog.set_value("general", "disable_streaming", self.config["general"]["disable_streaming"])
|
||||
self.dialog.set_value("general", "relative_time", self.config["general"]["relative_times"])
|
||||
self.dialog.set_value("general", "read_preferences_from_instance", self.config["general"]["read_preferences_from_instance"])
|
||||
self.dialog.set_value("general", "show_screen_names", self.config["general"]["show_screen_names"])
|
||||
self.dialog.set_value("general", "hide_emojis", self.config["general"]["hide_emojis"])
|
||||
self.dialog.set_value("general", "itemsPerApiCall", self.config["general"]["max_posts_per_call"])
|
||||
@@ -111,6 +113,11 @@ class accountSettingsController(globalSettingsController):
|
||||
self.needs_restart = True
|
||||
log.debug("Triggered app restart due to change in relative times.")
|
||||
self.config["general"]["relative_times"] = self.dialog.get_value("general", "relative_time")
|
||||
if self.config["general"]["disable_streaming"] != self.dialog.get_value("general", "disable_streaming"):
|
||||
self.needs_restart = True
|
||||
log.debug("Triggered app restart due to change in streaming settings.")
|
||||
self.config["general"]["disable_streaming"] = self.dialog.get_value("general", "disable_streaming")
|
||||
self.config["general"]["read_preferences_from_instance"] = self.dialog.get_value("general", "read_preferences_from_instance")
|
||||
self.config["general"]["show_screen_names"] = self.dialog.get_value("general", "show_screen_names")
|
||||
self.config["general"]["hide_emojis"] = self.dialog.get_value("general", "hide_emojis")
|
||||
self.config["general"]["max_posts_per_call"] = self.dialog.get_value("general", "itemsPerApiCall")
|
||||
|
@@ -3,7 +3,7 @@ import re
|
||||
import wx
|
||||
from typing import List
|
||||
from sessions.mastodon.templates import post_variables, conversation_variables, person_variables
|
||||
from wxUI.dialogs.twitterDialogs import templateDialogs
|
||||
from wxUI.dialogs import templateDialogs
|
||||
|
||||
class EditTemplate(object):
|
||||
def __init__(self, template: str, type: str) -> None:
|
||||
|
@@ -6,7 +6,7 @@ from wxUI.dialogs.mastodon import userActions as userActionsDialog
|
||||
from wxUI.dialogs.mastodon import userTimeline as userTimelineDialog
|
||||
from pubsub import pub
|
||||
from mastodon import MastodonError, MastodonNotFoundError
|
||||
from extra.autocompletionUsers import completion
|
||||
#from extra.autocompletionUsers import completion
|
||||
|
||||
log = logging.getLogger("controller.mastodon.userActions")
|
||||
|
||||
|
41
src/controller/messages.py
Normal file
41
src/controller/messages.py
Normal file
@@ -0,0 +1,41 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import widgetUtils
|
||||
import output
|
||||
from extra import translator, SpellChecker
|
||||
|
||||
class basicMessage(object):
|
||||
def translate(self, event=None):
|
||||
dlg = translator.gui.translateDialog()
|
||||
if dlg.get_response() == widgetUtils.OK:
|
||||
text_to_translate = self.message.text.GetValue()
|
||||
language_dict = translator.translator.available_languages()
|
||||
for k in language_dict:
|
||||
if language_dict[k] == dlg.dest_lang.GetStringSelection():
|
||||
dst = k
|
||||
msg = translator.translator.translate(text=text_to_translate, target=dst)
|
||||
self.message.text.ChangeValue(msg)
|
||||
self.message.text.SetInsertionPoint(len(self.message.text.GetValue()))
|
||||
self.text_processor()
|
||||
self.message.text.SetFocus()
|
||||
output.speak(_(u"Translated"))
|
||||
else:
|
||||
return
|
||||
|
||||
def text_processor(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def spellcheck(self, event=None):
|
||||
text = self.message.text.GetValue()
|
||||
checker = SpellChecker.spellchecker.spellChecker(text, "")
|
||||
if hasattr(checker, "fixed_text"):
|
||||
self.message.text.ChangeValue(checker.fixed_text)
|
||||
self.text_processor()
|
||||
self.message.text.SetFocus()
|
||||
|
||||
def remove_attachment(self, *args, **kwargs):
|
||||
attachment = self.message.attachments.GetFocusedItem()
|
||||
if attachment > -1 and len(self.attachments) > attachment:
|
||||
self.attachments.pop(attachment)
|
||||
self.message.remove_item(list_type="attachment")
|
||||
self.text_processor()
|
||||
self.message.text.SetFocus()
|
@@ -1 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
@@ -1,76 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import time
|
||||
import widgetUtils
|
||||
import application
|
||||
from wxUI.dialogs import filterDialogs
|
||||
from wxUI import commonMessageDialogs
|
||||
|
||||
class filter(object):
|
||||
def __init__(self, buffer, filter_title=None, if_word_exists=None, in_lang=None, regexp=None, word=None, in_buffer=None):
|
||||
self.buffer = buffer
|
||||
self.dialog = filterDialogs.filterDialog(languages=[i["name"] for i in application.supported_languages])
|
||||
if self.dialog.get_response() == widgetUtils.OK:
|
||||
title = self.dialog.get("title")
|
||||
contains = self.dialog.get("contains")
|
||||
term = self.dialog.get("term")
|
||||
regexp = self.dialog.get("regexp")
|
||||
allow_rts = self.dialog.get("allow_rts")
|
||||
allow_quotes = self.dialog.get("allow_quotes")
|
||||
allow_replies = self.dialog.get("allow_replies")
|
||||
load_language = self.dialog.get("load_language")
|
||||
ignore_language = self.dialog.get("ignore_language")
|
||||
lang_option = None
|
||||
if ignore_language:
|
||||
lang_option = False
|
||||
elif load_language:
|
||||
lang_option = True
|
||||
langs = self.dialog.get_selected_langs()
|
||||
langcodes = []
|
||||
for i in application.supported_languages:
|
||||
if i["name"] in langs:
|
||||
langcodes.append(i["code"])
|
||||
d = dict(in_buffer=self.buffer.name, word=term, regexp=regexp, in_lang=lang_option, languages=langcodes, if_word_exists=contains, allow_rts=allow_rts, allow_quotes=allow_quotes, allow_replies=allow_replies)
|
||||
if title in self.buffer.session.settings["filters"]:
|
||||
return commonMessageDialogs.existing_filter()
|
||||
self.buffer.session.settings["filters"][title] = d
|
||||
self.buffer.session.settings.write()
|
||||
|
||||
class filterManager(object):
|
||||
|
||||
def __init__(self, session):
|
||||
self.session = session
|
||||
self.dialog = filterDialogs.filterManagerDialog()
|
||||
self.insert_filters(self.session.settings["filters"])
|
||||
if self.dialog.filters.get_count() == 0:
|
||||
self.dialog.edit.Enable(False)
|
||||
self.dialog.delete.Enable(False)
|
||||
else:
|
||||
widgetUtils.connect_event(self.dialog.edit, widgetUtils.BUTTON_PRESSED, self.edit_filter)
|
||||
widgetUtils.connect_event(self.dialog.delete, widgetUtils.BUTTON_PRESSED, self.delete_filter)
|
||||
response = self.dialog.get_response()
|
||||
|
||||
def insert_filters(self, filters):
|
||||
self.dialog.filters.clear()
|
||||
for f in list(filters.keys()):
|
||||
filterName = f
|
||||
buffer = filters[f]["in_buffer"]
|
||||
if filters[f]["if_word_exists"] == "True" and filters[f]["word"] != "":
|
||||
filter_by_word = "True"
|
||||
else:
|
||||
filter_by_word = "False"
|
||||
filter_by_lang = ""
|
||||
if filters[f]["in_lang"] != "None":
|
||||
filter_by_lang = "True"
|
||||
b = [f, buffer, filter_by_word, filter_by_lang]
|
||||
self.dialog.filters.insert_item(False, *b)
|
||||
|
||||
def edit_filter(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def delete_filter(self, *args, **kwargs):
|
||||
filter_title = self.dialog.filters.get_text_column(self.dialog.filters.get_selected(), 0)
|
||||
response = commonMessageDialogs.delete_filter()
|
||||
if response == widgetUtils.YES:
|
||||
self.session.settings["filters"].pop(filter_title)
|
||||
self.session.settings.write()
|
||||
self.insert_filters(self.session.settings["filters"])
|
@@ -1,340 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import logging
|
||||
import widgetUtils
|
||||
import output
|
||||
from pubsub import pub
|
||||
from tweepy.errors import TweepyException, Forbidden
|
||||
from mysc import restart
|
||||
from sessions.twitter import utils, compose
|
||||
from controller import userSelector
|
||||
from wxUI import dialogs, commonMessageDialogs
|
||||
from . import filters, lists, settings, userActions, trendingTopics, user
|
||||
|
||||
log = logging.getLogger("controller.twitter.handler")
|
||||
|
||||
class Handler(object):
|
||||
|
||||
def __init__(self):
|
||||
super(Handler, self).__init__()
|
||||
|
||||
def create_buffers(self, session, createAccounts=True, controller=None):
|
||||
session.get_user_info()
|
||||
name = session.get_name()
|
||||
if createAccounts == True:
|
||||
pub.sendMessage("core.create_account", name=name, session_id=session.session_id, logged=True)
|
||||
root_position =controller.view.search(name, name)
|
||||
for i in session.settings['general']['buffer_order']:
|
||||
if i == 'home':
|
||||
pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_("Home"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, function="home_timeline", name="home_timeline", sessionObject=session, account=session.get_name(), sound="tweet_received.ogg", include_ext_alt_text=True, tweet_mode="extended"))
|
||||
elif i == 'mentions':
|
||||
pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_("Mentions"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, function="mentions_timeline", name="mentions", sessionObject=session, account=session.get_name(), sound="mention_received.ogg", include_ext_alt_text=True, tweet_mode="extended"))
|
||||
elif i == 'dm':
|
||||
pub.sendMessage("createBuffer", buffer_type="DirectMessagesBuffer", session_type=session.type, buffer_title=_("Direct messages"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, function="get_direct_messages", name="direct_messages", sessionObject=session, account=session.get_name(), bufferType="dmPanel", compose_func="compose_direct_message", sound="dm_received.ogg"))
|
||||
elif i == 'sent_dm':
|
||||
pub.sendMessage("createBuffer", buffer_type="SentDirectMessagesBuffer", session_type=session.type, buffer_title=_("Sent direct messages"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, function=None, name="sent_direct_messages", sessionObject=session, account=session.get_name(), bufferType="dmPanel", compose_func="compose_direct_message"))
|
||||
elif i == 'sent_tweets':
|
||||
pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_("Sent tweets"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, function="user_timeline", name="sent_tweets", sessionObject=session, account=session.get_name(), screen_name=session.db["user_name"], include_ext_alt_text=True, tweet_mode="extended"))
|
||||
elif i == 'favorites':
|
||||
pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_("Likes"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, function="get_favorites", name="favourites", sessionObject=session, account=session.get_name(), sound="favourite.ogg", include_ext_alt_text=True, tweet_mode="extended"))
|
||||
elif i == 'followers':
|
||||
pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Followers"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, function="get_followers", name="followers", sessionObject=session, account=session.get_name(), sound="update_followers.ogg", screen_name=session.db["user_name"]))
|
||||
elif i == 'friends':
|
||||
pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Following"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, function="get_friends", name="friends", sessionObject=session, account=session.get_name(), screen_name=session.db["user_name"]))
|
||||
elif i == 'blocks':
|
||||
pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Blocked users"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, function="get_blocks", name="blocked", sessionObject=session, account=session.get_name()))
|
||||
elif i == 'muted':
|
||||
pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Muted users"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, function="get_mutes", name="muted", sessionObject=session, account=session.get_name()))
|
||||
pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Timelines"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, name="timelines", account=name))
|
||||
timelines_position =controller.view.search("timelines", name)
|
||||
for i in session.settings["other_buffers"]["timelines"]:
|
||||
pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_(u"Timeline for {}").format(i,), parent_tab=timelines_position, start=False, kwargs=dict(parent=controller.view.nb, function="user_timeline", name="%s-timeline" % (i,), sessionObject=session, account=session.get_name(), sound="tweet_timeline.ogg", bufferType=None, user_id=i, include_ext_alt_text=True, tweet_mode="extended"))
|
||||
pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Likes timelines"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, name="favs_timelines", account=name))
|
||||
favs_timelines_position =controller.view.search("favs_timelines", name)
|
||||
for i in session.settings["other_buffers"]["favourites_timelines"]:
|
||||
pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_("Likes for {}").format(i,), parent_tab=favs_timelines_position, start=False, kwargs=dict(parent=controller.view.nb, function="get_favorites", name="%s-favorite" % (i,), sessionObject=session, account=name, bufferType=None, sound="favourites_timeline_updated.ogg", user_id=i, include_ext_alt_text=True, tweet_mode="extended"))
|
||||
pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Followers timelines"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, name="followers_timelines", account=session.get_name()))
|
||||
followers_timelines_position =controller.view.search("followers_timelines", name)
|
||||
for i in session.settings["other_buffers"]["followers_timelines"]:
|
||||
pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Followers for {}").format(i,), parent_tab=followers_timelines_position, start=False, kwargs=dict(parent=controller.view.nb, function="get_followers", name="%s-followers" % (i,), sessionObject=session, account=session.get_name(), sound="new_event.ogg", user_id=i))
|
||||
pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Following timelines"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, name="friends_timelines", account=name))
|
||||
friends_timelines_position =controller.view.search("friends_timelines", name)
|
||||
for i in session.settings["other_buffers"]["friends_timelines"]:
|
||||
pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_(u"Friends for {}").format(i,), parent_tab=friends_timelines_position, start=False, kwargs=dict(parent=controller.view.nb, function="get_friends", name="%s-friends" % (i,), sessionObject=session, account=session.get_name(), sound="new_event.ogg", user_id=i))
|
||||
pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Lists"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, name="lists", account=name))
|
||||
lists_position =controller.view.search("lists", name)
|
||||
for i in session.settings["other_buffers"]["lists"]:
|
||||
pub.sendMessage("createBuffer", buffer_type="ListBuffer", session_type=session.type, buffer_title=_(u"List for {}").format(i), parent_tab=lists_position, start=False, kwargs=dict(parent=controller.view.nb, function="list_timeline", name="%s-list" % (i,), sessionObject=session, account=session.get_name(), bufferType=None, sound="list_tweet.ogg", list_id=utils.find_list(i, session.db["lists"]), include_ext_alt_text=True, tweet_mode="extended"))
|
||||
pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Searches"), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, name="searches", account=name))
|
||||
searches_position =controller.view.search("searches", name)
|
||||
for i in session.settings["other_buffers"]["tweet_searches"]:
|
||||
pub.sendMessage("createBuffer", buffer_type="SearchBuffer", session_type=session.type, buffer_title=_(u"Search for {}").format(i), parent_tab=searches_position, start=False, kwargs=dict(parent=controller.view.nb, function="search_tweets", name="%s-searchterm" % (i,), sessionObject=session, account=session.get_name(), bufferType="searchPanel", sound="search_updated.ogg", q=i, include_ext_alt_text=True, tweet_mode="extended"))
|
||||
for i in session.settings["other_buffers"]["trending_topic_buffers"]:
|
||||
pub.sendMessage("createBuffer", buffer_type="TrendsBuffer", session_type=session.type, buffer_title=_("Trending topics for %s") % (i), parent_tab=root_position, start=False, kwargs=dict(parent=controller.view.nb, name="%s_tt" % (i,), sessionObject=session, account=session.get_name(), trendsFor=i, sound="trends_updated.ogg"))
|
||||
|
||||
def filter(self, buffer):
|
||||
# Let's prevent filtering of some buffers (people buffers, direct messages, events and sent items).
|
||||
if (buffer.name == "direct_messages" or buffer.name == "sent_tweets") or buffer.type == "people":
|
||||
output.speak(_("Filters cannot be applied on this buffer"))
|
||||
return
|
||||
new_filter = filters.filter(buffer)
|
||||
|
||||
def manage_filters(self, session):
|
||||
manage_filters = filters.filterManager(session)
|
||||
|
||||
def view_user_lists(self, buffer):
|
||||
if not hasattr(buffer, "get_right_tweet"):
|
||||
return
|
||||
tweet = buffer.get_right_tweet()
|
||||
if buffer.type == "people":
|
||||
users = [tweet.screen_name]
|
||||
elif buffer.type == "dm":
|
||||
users = [buffer.session.get_user(tweet.message_create["sender_id"]).screen_name]
|
||||
else:
|
||||
users = utils.get_all_users(tweet, buffer.session)
|
||||
selector = userSelector.userSelector(users=users, session_id=buffer.session.session_id)
|
||||
user = selector.get_user()
|
||||
if user == None:
|
||||
return
|
||||
l = lists.listsController(buffer.session, user=user)
|
||||
|
||||
def add_to_list(self, controller, buffer):
|
||||
if not hasattr(buffer, "get_right_tweet"):
|
||||
return
|
||||
tweet = buffer.get_right_tweet()
|
||||
if buffer.type == "people":
|
||||
users = [tweet.screen_name]
|
||||
elif buffer.type == "dm":
|
||||
users = [buffer.session.get_user(tweet.message_create["sender_id"]).screen_name]
|
||||
else:
|
||||
users = utils.get_all_users(tweet, buffer.session)
|
||||
selector = userSelector.userSelector(users=users, session_id=buffer.session.session_id)
|
||||
user = selector.get_user()
|
||||
if user == None:
|
||||
return
|
||||
dlg = dialogs.lists.addUserListDialog()
|
||||
dlg.populate_list([compose.compose_list(item) for item in buffer.session.db["lists"]])
|
||||
if dlg.get_response() == widgetUtils.OK:
|
||||
try:
|
||||
list = buffer.session.twitter.add_list_member(list_id=buffer.session.db["lists"][dlg.get_item()].id, screen_name=user)
|
||||
older_list = utils.find_item(buffer.session.db["lists"][dlg.get_item()].id, buffer.session.db["lists"])
|
||||
listBuffer = controller.search_buffer("%s-list" % (buffer.session.db["lists"][dlg.get_item()].name.lower()), buff.session.get_name())
|
||||
if listBuffer != None:
|
||||
listBuffer.get_user_ids()
|
||||
buffer.session.db["lists"].pop(older_list)
|
||||
buffer.session.db["lists"].append(list)
|
||||
except TweepyException as e:
|
||||
log.exception("error %s" % (str(e)))
|
||||
output.speak("error %s" % (str(e)))
|
||||
|
||||
def remove_from_list(self, controller, buffer):
|
||||
if not hasattr(buffer, "get_right_tweet"):
|
||||
return
|
||||
tweet = buffer.get_right_tweet()
|
||||
if buffer.type == "people":
|
||||
users = [tweet.screen_name]
|
||||
elif buffer.type == "dm":
|
||||
users = [buffer.session.get_user(tweet.message_create["sender_id"]).screen_name]
|
||||
else:
|
||||
users = utils.get_all_users(tweet, buffer.session)
|
||||
selector = userSelector.userSelector(users=users, session_id=buffer.session.session_id)
|
||||
user = selector.get_user()
|
||||
if user == None:
|
||||
return
|
||||
dlg = dialogs.lists.removeUserListDialog()
|
||||
dlg.populate_list([compose.compose_list(item) for item in buffer.session.db["lists"]])
|
||||
if dlg.get_response() == widgetUtils.OK:
|
||||
try:
|
||||
list = buffer.session.twitter.remove_list_member(list_id=buffer.session.db["lists"][dlg.get_item()].id, screen_name=user)
|
||||
older_list = utils.find_item(buffer.session.db["lists"][dlg.get_item()].id, buffer.session.db["lists"])
|
||||
listBuffer = controller.search_buffer("%s-list" % (buffer.session.db["lists"][dlg.get_item()].name.lower()), buffer.session.get_name())
|
||||
if listBuffer != None:
|
||||
listBuffer.get_user_ids()
|
||||
buffer.session.db["lists"].pop(older_list)
|
||||
buffer.session.db["lists"].append(list)
|
||||
except TweepyException as e:
|
||||
output.speak("error %s" % (str(e)))
|
||||
log.exception("error %s" % (str(e)))
|
||||
|
||||
def list_manager(self, session, lists_buffer_position):
|
||||
return lists.listsController(session=session, lists_buffer_position=lists_buffer_position)
|
||||
|
||||
def account_settings(self, buffer, controller):
|
||||
d = settings.accountSettingsController(buffer, controller)
|
||||
if d.response == widgetUtils.OK:
|
||||
d.save_configuration()
|
||||
if d.needs_restart == True:
|
||||
commonMessageDialogs.needs_restart()
|
||||
buffer.session.settings.write()
|
||||
buffer.session.save_persistent_data()
|
||||
restart.restart_program()
|
||||
|
||||
def follow(self, buffer):
|
||||
if not hasattr(buffer, "get_right_tweet"):
|
||||
return
|
||||
tweet = buffer.get_right_tweet()
|
||||
if buffer.type == "people":
|
||||
users = [tweet.screen_name]
|
||||
elif buffer.type == "dm":
|
||||
users = [buffer.session.get_user(tweet.message_create["sender_id"]).screen_name]
|
||||
else:
|
||||
users = utils.get_all_users(tweet, buffer.session)
|
||||
u = userActions.userActionsController(buffer, users)
|
||||
|
||||
def add_alias(self, buffer):
|
||||
if not hasattr(buffer, "get_right_tweet"):
|
||||
return
|
||||
tweet = buffer.get_right_tweet()
|
||||
if buffer.type == "people":
|
||||
users = [tweet.screen_name]
|
||||
elif buffer.type == "dm":
|
||||
users = [buffer.session.get_user(tweet.message_create["sender_id"]).screen_name]
|
||||
else:
|
||||
users = utils.get_all_users(tweet, buffer.session)
|
||||
dlg = dialogs.userAliasDialogs.addAliasDialog(_("Add an user alias"), users)
|
||||
if dlg.get_response() == widgetUtils.OK:
|
||||
user, alias = dlg.get_user()
|
||||
if user == "" or alias == "":
|
||||
return
|
||||
user_id = buffer.session.get_user_by_screen_name(user)
|
||||
buffer.session.settings["user-aliases"][str(user_id)] = alias
|
||||
buffer.session.settings.write()
|
||||
output.speak(_("Alias has been set correctly for {}.").format(user))
|
||||
pub.sendMessage("alias-added")
|
||||
|
||||
# ToDo: explore how to play sound & save config differently.
|
||||
# currently, TWBlue will play the sound and save the config for the timeline even if the buffer did not load or something else.
|
||||
def open_timeline(self, controller, buffer, default="tweets"):
|
||||
if not hasattr(buffer, "get_right_tweet"):
|
||||
return
|
||||
tweet = buffer.get_right_tweet()
|
||||
if buffer.type == "people":
|
||||
users = [tweet.screen_name]
|
||||
elif buffer.type == "dm":
|
||||
users = [buffer.session.get_user(tweet.message_create["sender_id"]).screen_name]
|
||||
else:
|
||||
users = utils.get_all_users(tweet, buffer.session)
|
||||
dlg = dialogs.userSelection.selectUserDialog(users=users, default=default)
|
||||
if dlg.get_response() == widgetUtils.OK:
|
||||
usr = utils.if_user_exists(buffer.session.twitter, dlg.get_user())
|
||||
if usr != None:
|
||||
if usr == dlg.get_user():
|
||||
commonMessageDialogs.suspended_user()
|
||||
return
|
||||
if usr.protected == True:
|
||||
if usr.following == False:
|
||||
commonMessageDialogs.no_following()
|
||||
return
|
||||
tl_type = dlg.get_action()
|
||||
if tl_type == "tweets":
|
||||
if usr.statuses_count == 0:
|
||||
commonMessageDialogs.no_tweets()
|
||||
return
|
||||
if usr.id_str in buffer.session.settings["other_buffers"]["timelines"]:
|
||||
commonMessageDialogs.timeline_exist()
|
||||
return
|
||||
timelines_position =controller.view.search("timelines", buffer.session.get_name())
|
||||
pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=buffer.session.type, buffer_title=_("Timeline for {}").format(usr.screen_name,), parent_tab=timelines_position, start=True, kwargs=dict(parent=controller.view.nb, function="user_timeline", name="%s-timeline" % (usr.id_str,), sessionObject=buffer.session, account=buffer.session.get_name(), sound="tweet_timeline.ogg", bufferType=None, user_id=usr.id_str, include_ext_alt_text=True, tweet_mode="extended"))
|
||||
buffer.session.settings["other_buffers"]["timelines"].append(usr.id_str)
|
||||
buffer.session.sound.play("create_timeline.ogg")
|
||||
elif tl_type == "favourites":
|
||||
if usr.favourites_count == 0:
|
||||
commonMessageDialogs.no_favs()
|
||||
return
|
||||
if usr.id_str in buffer.session.settings["other_buffers"]["favourites_timelines"]:
|
||||
commonMessageDialogs.timeline_exist()
|
||||
return
|
||||
favs_timelines_position =controller.view.search("favs_timelines", buffer.session.get_name())
|
||||
pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=buffer.session.type, buffer_title=_("Likes for {}").format(usr.screen_name,), parent_tab=favs_timelines_position, start=True, kwargs=dict(parent=controller.view.nb, function="get_favorites", name="%s-favorite" % (usr.id_str,), sessionObject=buffer.session, account=buffer.session.get_name(), bufferType=None, sound="favourites_timeline_updated.ogg", user_id=usr.id_str, include_ext_alt_text=True, tweet_mode="extended"))
|
||||
buffer.session.settings["other_buffers"]["favourites_timelines"].append(usr.id_str)
|
||||
buffer.session.sound.play("create_timeline.ogg")
|
||||
elif tl_type == "followers":
|
||||
if usr.followers_count == 0:
|
||||
commonMessageDialogs.no_followers()
|
||||
return
|
||||
if usr.id_str in buffer.session.settings["other_buffers"]["followers_timelines"]:
|
||||
commonMessageDialogs.timeline_exist()
|
||||
return
|
||||
followers_timelines_position =controller.view.search("followers_timelines", buffer.session.get_name())
|
||||
pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=buffer.session.type, buffer_title=_("Followers for {}").format(usr.screen_name,), parent_tab=followers_timelines_position, start=True, kwargs=dict(parent=controller.view.nb, function="get_followers", name="%s-followers" % (usr.id_str,), sessionObject=buffer.session, account=buffer.session.get_name(), sound="new_event.ogg", user_id=usr.id_str))
|
||||
buffer.session.settings["other_buffers"]["followers_timelines"].append(usr.id_str)
|
||||
buffer.session.sound.play("create_timeline.ogg")
|
||||
elif tl_type == "friends":
|
||||
if usr.friends_count == 0:
|
||||
commonMessageDialogs.no_friends()
|
||||
return
|
||||
if usr.id_str in buffer.session.settings["other_buffers"]["friends_timelines"]:
|
||||
commonMessageDialogs.timeline_exist()
|
||||
return
|
||||
friends_timelines_position =controller.view.search("friends_timelines", buffer.session.get_name())
|
||||
pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=buffer.session.type, buffer_title=_("Friends for {}").format(usr.screen_name,), parent_tab=friends_timelines_position, start=True, kwargs=dict(parent=controller.view.nb, function="get_friends", name="%s-friends" % (usr.id_str,), sessionObject=buffer.session, account=buffer.session.get_name(), sound="new_event.ogg", user_id=usr.id_str))
|
||||
buffer.session.settings["other_buffers"]["friends_timelines"].append(usr.id_str)
|
||||
buffer.session.sound.play("create_timeline.ogg")
|
||||
else:
|
||||
commonMessageDialogs.user_not_exist()
|
||||
buffer.session.settings.write()
|
||||
|
||||
def open_conversation(self, controller, buffer):
|
||||
tweet = buffer.get_right_tweet()
|
||||
if hasattr(tweet, "retweeted_status") and tweet.retweeted_status != None:
|
||||
tweet = tweet.retweeted_status
|
||||
user = buffer.session.get_user(tweet.user).screen_name
|
||||
searches_position =controller.view.search("searches", buffer.session.get_name())
|
||||
pub.sendMessage("createBuffer", buffer_type="ConversationBuffer", session_type=buffer.session.type, buffer_title=_(u"Conversation with {0}").format(user), parent_tab=searches_position, start=True, kwargs=dict(tweet=tweet, parent=controller.view.nb, function="search_tweets", name="%s-searchterm" % (tweet.id,), sessionObject=buffer.session, account=buffer.session.get_name(), bufferType="searchPanel", sound="search_updated.ogg", since_id=tweet.id, q="@{0}".format(user)))
|
||||
|
||||
def get_trending_topics(self, controller, session):
|
||||
trends = trendingTopics.trendingTopicsController(session)
|
||||
if trends.dialog.get_response() == widgetUtils.OK:
|
||||
woeid = trends.get_woeid()
|
||||
if woeid in session.settings["other_buffers"]["trending_topic_buffers"]:
|
||||
return
|
||||
root_position =controller.view.search(session.get_name(), session.get_name())
|
||||
pub.sendMessage("createBuffer", buffer_type="TrendsBuffer", session_type=session.type, buffer_title=_("Trending topics for %s") % (trends.get_string()), parent_tab=root_position, start=True, kwargs=dict(parent=controller.view.nb, name="%s_tt" % (woeid,), sessionObject=session, account=session.get_name(), trendsFor=woeid, sound="trends_updated.ogg"))
|
||||
session.settings["other_buffers"]["trending_topic_buffers"].append(str(woeid))
|
||||
session.settings.write()
|
||||
|
||||
def start_buffer(self, controller, buffer):
|
||||
if hasattr(buffer, "finished_timeline") and buffer.finished_timeline == False:
|
||||
change_title = True
|
||||
else:
|
||||
change_title = False
|
||||
try:
|
||||
if "mentions" in buffer.name or "direct_messages" in buffer.name:
|
||||
buffer.start_stream()
|
||||
else:
|
||||
buffer.start_stream(play_sound=False)
|
||||
except TweepyException as err:
|
||||
log.exception("Error %s starting buffer %s on account %s, with args %r and kwargs %r." % (str(err), buffer.name, buffer.account, buffer.args, buffer.kwargs))
|
||||
# Determine if this error was caused by a block applied to the current user (IE permission errors).
|
||||
if type(err) == Forbidden:
|
||||
buff = controller.view.search(buffer.name, buffer.account)
|
||||
buffer.remove_buffer(force=True)
|
||||
commonMessageDialogs.blocked_timeline()
|
||||
if controller.get_current_buffer() == buffer:
|
||||
controller.right()
|
||||
controller.view.delete_buffer(buff)
|
||||
controller.buffers.remove(buffer)
|
||||
del buffer
|
||||
if change_title:
|
||||
pub.sendMessage("buffer-title-changed", buffer=buffer)
|
||||
|
||||
def update_profile(self, session):
|
||||
r = user.profileController(session)
|
||||
|
||||
def search(self, controller, session, value):
|
||||
log.debug("Creating a new search...")
|
||||
dlg = dialogs.search.searchDialog(value)
|
||||
if dlg.get_response() == widgetUtils.OK and dlg.get("term") != "":
|
||||
term = dlg.get("term")
|
||||
searches_position =controller.view.search("searches", session.get_name())
|
||||
if dlg.get("tweets") == True:
|
||||
if term not in session.settings["other_buffers"]["tweet_searches"]:
|
||||
session.settings["other_buffers"]["tweet_searches"].append(term)
|
||||
session.settings.write()
|
||||
args = {"lang": dlg.get_language(), "result_type": dlg.get_result_type()}
|
||||
pub.sendMessage("createBuffer", buffer_type="SearchBuffer", session_type=session.type, buffer_title=_("Search for {}").format(term), parent_tab=searches_position, start=True, kwargs=dict(parent=controller.view.nb, function="search_tweets", name="%s-searchterm" % (term,), sessionObject=session, account=session.get_name(), bufferType="searchPanel", sound="search_updated.ogg", q=term, include_ext_alt_text=True, tweet_mode="extended"))
|
||||
else:
|
||||
log.error("A buffer for the %s search term is already created. You can't create a duplicate buffer." % (term,))
|
||||
return
|
||||
elif dlg.get("users") == True:
|
||||
pub.sendMessage("createBuffer", buffer_type="SearchPeopleBuffer", session_type=session.type, buffer_title=_("Search for {}").format(term), parent_tab=searches_position, start=True, kwargs=dict(parent=controller.view.nb, function="search_users", name="%s-searchUser" % (term,), sessionObject=session, account=session.get_name(), bufferType=None, sound="search_updated.ogg", q=term))
|
||||
dlg.Destroy()
|
@@ -1,117 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import widgetUtils
|
||||
import output
|
||||
import logging
|
||||
from wxUI.dialogs import lists
|
||||
from tweepy.errors import TweepyException
|
||||
from sessions.twitter import compose, utils
|
||||
from pubsub import pub
|
||||
|
||||
log = logging.getLogger("controller.listsController")
|
||||
|
||||
class listsController(object):
|
||||
def __init__(self, session, user=None, lists_buffer_position=0):
|
||||
super(listsController, self).__init__()
|
||||
self.session = session
|
||||
self.lists_buffer_position = lists_buffer_position
|
||||
if user == None:
|
||||
self.dialog = lists.listViewer()
|
||||
self.dialog.populate_list(self.get_all_lists())
|
||||
widgetUtils.connect_event(self.dialog.createBtn, widgetUtils.BUTTON_PRESSED, self.create_list)
|
||||
widgetUtils.connect_event(self.dialog.editBtn, widgetUtils.BUTTON_PRESSED, self.edit_list)
|
||||
widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.remove_list)
|
||||
widgetUtils.connect_event(self.dialog.view, widgetUtils.BUTTON_PRESSED, self.open_list_as_buffer)
|
||||
widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.remove_list)
|
||||
else:
|
||||
self.dialog = lists.userListViewer(user)
|
||||
self.dialog.populate_list(self.get_user_lists(user))
|
||||
widgetUtils.connect_event(self.dialog.createBtn, widgetUtils.BUTTON_PRESSED, self.subscribe)
|
||||
widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.unsubscribe)
|
||||
self.dialog.get_response()
|
||||
|
||||
def get_all_lists(self):
|
||||
return [compose.compose_list(item) for item in self.session.db["lists"]]
|
||||
|
||||
def get_user_lists(self, user):
|
||||
self.lists = self.session.twitter.get_lists(reverse=True, screen_name=user)
|
||||
return [compose.compose_list(item) for item in self.lists]
|
||||
|
||||
def create_list(self, *args, **kwargs):
|
||||
dialog = lists.createListDialog()
|
||||
if dialog.get_response() == widgetUtils.OK:
|
||||
name = dialog.get("name")
|
||||
description = dialog.get("description")
|
||||
p = dialog.get("public")
|
||||
if p == True:
|
||||
mode = "public"
|
||||
else:
|
||||
mode = "private"
|
||||
try:
|
||||
new_list = self.session.twitter.create_list(name=name, description=description, mode=mode)
|
||||
self.session.db["lists"].append(new_list)
|
||||
self.dialog.lista.insert_item(False, *compose.compose_list(new_list))
|
||||
except TweepyException as e:
|
||||
output.speak("error %s" % (str(e)))
|
||||
log.exception("error %s" % (str(e)))
|
||||
dialog.destroy()
|
||||
|
||||
def edit_list(self, *args, **kwargs):
|
||||
if self.dialog.lista.get_count() == 0: return
|
||||
list = self.session.db["lists"][self.dialog.get_item()]
|
||||
dialog = lists.editListDialog(list)
|
||||
if dialog.get_response() == widgetUtils.OK:
|
||||
name = dialog.get("name")
|
||||
description = dialog.get("description")
|
||||
p = dialog.get("public")
|
||||
if p == True:
|
||||
mode = "public"
|
||||
else:
|
||||
mode = "private"
|
||||
try:
|
||||
self.session.twitter.update_list(list_id=list.id, name=name, description=description, mode=mode)
|
||||
self.session.get_lists()
|
||||
self.dialog.populate_list(self.get_all_lists(), True)
|
||||
except TweepyException as e:
|
||||
output.speak("error %s" % (str(e)))
|
||||
log.exception("error %s" % (str(e)))
|
||||
dialog.destroy()
|
||||
|
||||
def remove_list(self, *args, **kwargs):
|
||||
if self.dialog.lista.get_count() == 0: return
|
||||
list = self.session.db["lists"][self.dialog.get_item()].id
|
||||
if lists.remove_list() == widgetUtils.YES:
|
||||
try:
|
||||
self.session.twitter.destroy_list(list_id=list)
|
||||
self.session.db["lists"].pop(self.dialog.get_item())
|
||||
self.dialog.lista.remove_item(self.dialog.get_item())
|
||||
except TweepyException as e:
|
||||
output.speak("error %s" % (str(e)))
|
||||
log.exception("error %s" % (str(e)))
|
||||
|
||||
def open_list_as_buffer(self, *args, **kwargs):
|
||||
if self.dialog.lista.get_count() == 0: return
|
||||
list = self.session.db["lists"][self.dialog.get_item()]
|
||||
pub.sendMessage("createBuffer", buffer_type="ListBuffer", session_type=self.session.type, buffer_title=_("List for {}").format(list.name), parent_tab=self.lists_buffer_position, start=True, kwargs=dict(function="list_timeline", name="%s-list" % (list.name,), sessionObject=self.session, account=self.session.get_name(), bufferType=None, sound="list_tweet.ogg", list_id=list.id, include_ext_alt_text=True, tweet_mode="extended"))
|
||||
self.session.settings["other_buffers"]["lists"].append(list.name)
|
||||
self.session.settings.write()
|
||||
|
||||
def subscribe(self, *args, **kwargs):
|
||||
if self.dialog.lista.get_count() == 0: return
|
||||
list_id = self.lists[self.dialog.get_item()].id
|
||||
try:
|
||||
list = self.session.twitter.subscribe_list(list_id=list_id)
|
||||
item = utils.find_item(list.id, self.session.db["lists"])
|
||||
self.session.db["lists"].append(list)
|
||||
except TweepyException as e:
|
||||
output.speak("error %s" % (str(e)))
|
||||
log.exception("error %s" % (str(e)))
|
||||
|
||||
def unsubscribe(self, *args, **kwargs):
|
||||
if self.dialog.lista.get_count() == 0: return
|
||||
list_id = self.lists[self.dialog.get_item()].id
|
||||
try:
|
||||
list = self.session.twitter.unsubscribe_list(list_id=list_id)
|
||||
self.session.db["lists"].remove(list)
|
||||
except TweepyException as e:
|
||||
output.speak("error %s" % (str(e)))
|
||||
log.exception("error %s" % (str(e)))
|
@@ -1,382 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import arrow
|
||||
import languageHandler
|
||||
import wx
|
||||
import widgetUtils
|
||||
import output
|
||||
import sound
|
||||
import config
|
||||
from pubsub import pub
|
||||
from twitter_text.parse_tweet import parse_tweet
|
||||
from wxUI.dialogs import twitterDialogs, urlList
|
||||
from wxUI import commonMessageDialogs
|
||||
from extra import translator, SpellChecker
|
||||
from extra.AudioUploader import audioUploader
|
||||
from extra.autocompletionUsers import completion
|
||||
from sessions.twitter import utils
|
||||
|
||||
class basicTweet(object):
|
||||
""" This class handles the tweet main features. Other classes should derive from this class."""
|
||||
def __init__(self, session, title, caption, text="", messageType="tweet", max=280, *args, **kwargs):
|
||||
super(basicTweet, self).__init__()
|
||||
self.max = max
|
||||
self.title = title
|
||||
self.session = session
|
||||
self.message = getattr(twitterDialogs, messageType)(title=title, caption=caption, message=text, max_length=max, *args, **kwargs)
|
||||
self.message.text.SetValue(text)
|
||||
self.message.text.SetInsertionPoint(len(self.message.text.GetValue()))
|
||||
widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck)
|
||||
widgetUtils.connect_event(self.message.add_audio, widgetUtils.BUTTON_PRESSED, self.attach)
|
||||
widgetUtils.connect_event(self.message.text, widgetUtils.ENTERED_TEXT, self.text_processor)
|
||||
widgetUtils.connect_event(self.message.translate, widgetUtils.BUTTON_PRESSED, self.translate)
|
||||
if hasattr(self.message, "add"):
|
||||
widgetUtils.connect_event(self.message.add, widgetUtils.BUTTON_PRESSED, self.on_attach)
|
||||
self.attachments = []
|
||||
|
||||
def translate(self, event=None):
|
||||
dlg = translator.gui.translateDialog()
|
||||
if dlg.get_response() == widgetUtils.OK:
|
||||
text_to_translate = self.message.text.GetValue()
|
||||
language_dict = translator.translator.available_languages()
|
||||
for k in language_dict:
|
||||
if language_dict[k] == dlg.dest_lang.GetStringSelection():
|
||||
dst = k
|
||||
msg = translator.translator.translate(text=text_to_translate, target=dst)
|
||||
self.message.text.ChangeValue(msg)
|
||||
self.message.text.SetInsertionPoint(len(self.message.text.GetValue()))
|
||||
self.text_processor()
|
||||
self.message.text.SetFocus()
|
||||
output.speak(_(u"Translated"))
|
||||
else:
|
||||
return
|
||||
|
||||
def text_processor(self, *args, **kwargs):
|
||||
text = self.message.text.GetValue()
|
||||
results = parse_tweet(text)
|
||||
self.message.SetTitle(_("%s - %s of %d characters") % (self.title, results.weightedLength, self.max))
|
||||
if results.weightedLength > self.max:
|
||||
self.session.sound.play("max_length.ogg")
|
||||
|
||||
def spellcheck(self, event=None):
|
||||
text = self.message.text.GetValue()
|
||||
checker = SpellChecker.spellchecker.spellChecker(text, "")
|
||||
if hasattr(checker, "fixed_text"):
|
||||
self.message.text.ChangeValue(checker.fixed_text)
|
||||
self.text_processor()
|
||||
self.message.text.SetFocus()
|
||||
|
||||
def attach(self, *args, **kwargs):
|
||||
def completed_callback(dlg):
|
||||
url = dlg.uploaderFunction.get_url()
|
||||
pub.unsubscribe(dlg.uploaderDialog.update, "uploading")
|
||||
dlg.uploaderDialog.destroy()
|
||||
if "sndup.net/" in url:
|
||||
self.message.text.ChangeValue(self.message.text.GetValue()+url+" #audio")
|
||||
self.text_processor()
|
||||
else:
|
||||
commonMessageDialogs.common_error(url)
|
||||
dlg.cleanup()
|
||||
dlg = audioUploader.audioUploader(self.session.settings, completed_callback)
|
||||
self.message.text.SetFocus()
|
||||
|
||||
def can_attach(self):
|
||||
if len(self.attachments) == 0:
|
||||
return True
|
||||
elif len(self.attachments) == 1 and (self.attachments[0]["type"] == "video" or self.attachments[0]["type"] == "gif"):
|
||||
return False
|
||||
elif len(self.attachments) < 4:
|
||||
return True
|
||||
return False
|
||||
|
||||
def on_attach(self, *args, **kwargs):
|
||||
can_attach = self.can_attach()
|
||||
menu = self.message.attach_menu(can_attach)
|
||||
self.message.Bind(wx.EVT_MENU, self.on_attach_image, self.message.add_image)
|
||||
self.message.Bind(wx.EVT_MENU, self.on_attach_video, self.message.add_video)
|
||||
if hasattr(self.message, "add_poll"):
|
||||
self.message.Bind(wx.EVT_MENU, self.on_attach_poll, self.message.add_poll)
|
||||
self.message.PopupMenu(menu, self.message.add.GetPosition())
|
||||
|
||||
def on_attach_image(self, *args, **kwargs):
|
||||
can_attach = self.can_attach()
|
||||
video_or_gif_present = False
|
||||
for a in self.attachments:
|
||||
if a["type"] == "video" or a["type"] == "gif":
|
||||
video_or_gif = True
|
||||
break
|
||||
if can_attach == False or video_or_gif_present == True:
|
||||
return self.message.unable_to_attach_file()
|
||||
image, description = self.message.get_image()
|
||||
if image != None:
|
||||
if image.endswith("gif"):
|
||||
image_type = "gif"
|
||||
else:
|
||||
image_type = "photo"
|
||||
imageInfo = {"type": image_type, "file": image, "description": description}
|
||||
if len(self.attachments) > 0 and image_type == "gif":
|
||||
return self.message.unable_to_attach_file()
|
||||
self.attachments.append(imageInfo)
|
||||
self.message.add_item(item=[os.path.basename(imageInfo["file"]), imageInfo["type"], imageInfo["description"]])
|
||||
self.text_processor()
|
||||
|
||||
def on_attach_video(self, *args, **kwargs):
|
||||
if len(self.attachments) > 0:
|
||||
return self.message.unable_to_attach_file()
|
||||
video = self.message.get_video()
|
||||
if video != None:
|
||||
videoInfo = {"type": "video", "file": video, "description": ""}
|
||||
if len(self.attachments) > 0:
|
||||
return self.message.unable_to_attach_file()
|
||||
self.attachments.append(videoInfo)
|
||||
self.message.add_item(item=[os.path.basename(videoInfo["file"]), videoInfo["type"], videoInfo["description"]])
|
||||
self.text_processor()
|
||||
|
||||
def on_attach_poll(self, *args, **kwargs):
|
||||
dlg = twitterDialogs.poll()
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
self.poll_options = dlg.get_options()
|
||||
self.poll_period = 60*24*dlg.period.GetValue()
|
||||
dlg.Destroy()
|
||||
|
||||
def remove_attachment(self, *args, **kwargs):
|
||||
attachment = self.message.attachments.GetFocusedItem()
|
||||
if attachment > -1 and len(self.attachments) > attachment:
|
||||
self.attachments.pop(attachment)
|
||||
self.message.remove_item(list_type="attachment")
|
||||
self.text_processor()
|
||||
self.message.text.SetFocus()
|
||||
|
||||
class tweet(basicTweet):
|
||||
def __init__(self, session, title, caption, text="", max=280, messageType="tweet", *args, **kwargs):
|
||||
self.thread = []
|
||||
self.poll_options = None
|
||||
self.poll_period = None
|
||||
super(tweet, self).__init__(session, title, caption, text, messageType, max, *args, **kwargs)
|
||||
widgetUtils.connect_event(self.message.autocomplete_users, widgetUtils.BUTTON_PRESSED, self.autocomplete_users)
|
||||
if hasattr(self.message, "add_tweet"):
|
||||
widgetUtils.connect_event(self.message.add_tweet, widgetUtils.BUTTON_PRESSED, self.add_tweet)
|
||||
widgetUtils.connect_event(self.message.remove_tweet, widgetUtils.BUTTON_PRESSED, self.remove_tweet)
|
||||
widgetUtils.connect_event(self.message.remove_attachment, widgetUtils.BUTTON_PRESSED, self.remove_attachment)
|
||||
self.text_processor()
|
||||
|
||||
def autocomplete_users(self, *args, **kwargs):
|
||||
c = completion.autocompletionUsers(self.message, self.session.session_id)
|
||||
c.show_menu()
|
||||
|
||||
def add_tweet(self, event, update_gui=True, *args, **kwargs):
|
||||
text = self.message.text.GetValue()
|
||||
attachments = self.attachments[::]
|
||||
tweetdata = dict(text=text, attachments=attachments, poll_options=self.poll_options, poll_period=self.poll_period)
|
||||
self.thread.append(tweetdata)
|
||||
self.attachments = []
|
||||
self.poll_options = None
|
||||
self.poll_period = None
|
||||
if update_gui:
|
||||
self.message.reset_controls()
|
||||
self.message.add_item(item=[text, len(attachments)], list_type="tweet")
|
||||
self.message.text.SetFocus()
|
||||
self.text_processor()
|
||||
|
||||
def get_tweet_data(self):
|
||||
self.add_tweet(event=None, update_gui=False)
|
||||
return self.thread
|
||||
|
||||
def text_processor(self, *args, **kwargs):
|
||||
super(tweet, self).text_processor(*args, **kwargs)
|
||||
if len(self.thread) > 0:
|
||||
if hasattr(self.message, "tweets"):
|
||||
self.message.tweets.Enable(True)
|
||||
self.message.remove_tweet.Enable(True)
|
||||
else:
|
||||
self.message.tweets.Enable(False)
|
||||
self.message.remove_tweet.Enable(False)
|
||||
if len(self.attachments) > 0:
|
||||
self.message.attachments.Enable(True)
|
||||
self.message.remove_attachment.Enable(True)
|
||||
else:
|
||||
self.message.attachments.Enable(False)
|
||||
self.message.remove_attachment.Enable(False)
|
||||
if hasattr(self.message, "add_tweet"):
|
||||
if len(self.message.text.GetValue()) > 0 or len(self.attachments) > 0:
|
||||
self.message.add_tweet.Enable(True)
|
||||
else:
|
||||
self.message.add_tweet.Enable(False)
|
||||
|
||||
def remove_tweet(self, *args, **kwargs):
|
||||
tweet = self.message.tweets.GetFocusedItem()
|
||||
if tweet > -1 and len(self.thread) > tweet:
|
||||
self.thread.pop(tweet)
|
||||
self.message.remove_item(list_type="tweet")
|
||||
self.text_processor()
|
||||
self.message.text.SetFocus()
|
||||
|
||||
|
||||
class reply(tweet):
|
||||
def __init__(self, session, title, caption, text, users=[], ids=[]):
|
||||
super(reply, self).__init__(session, title, caption, text, messageType="reply", users=users)
|
||||
self.ids = ids
|
||||
self.users = users
|
||||
if len(users) > 0:
|
||||
widgetUtils.connect_event(self.message.mention_all, widgetUtils.CHECKBOX, self.mention_all)
|
||||
self.message.mention_all.Enable(True)
|
||||
if config.app["app-settings"]["remember_mention_and_longtweet"]:
|
||||
self.message.mention_all.SetValue(config.app["app-settings"]["mention_all"])
|
||||
self.mention_all()
|
||||
self.message.text.SetInsertionPoint(len(self.message.text.GetValue()))
|
||||
self.text_processor()
|
||||
|
||||
def text_processor(self, *args, **kwargs):
|
||||
super(tweet, self).text_processor(*args, **kwargs)
|
||||
if len(self.attachments) > 0:
|
||||
self.message.attachments.Enable(True)
|
||||
self.message.remove_attachment.Enable(True)
|
||||
else:
|
||||
self.message.attachments.Enable(False)
|
||||
self.message.remove_attachment.Enable(False)
|
||||
|
||||
def mention_all(self, *args, **kwargs):
|
||||
if self.message.mention_all.GetValue() == True:
|
||||
for i in self.message.checkboxes:
|
||||
i.SetValue(True)
|
||||
i.Hide()
|
||||
else:
|
||||
for i in self.message.checkboxes:
|
||||
i.SetValue(False)
|
||||
i.Show()
|
||||
|
||||
def get_ids(self):
|
||||
excluded_ids = []
|
||||
for i in range(0, len(self.message.checkboxes)):
|
||||
if self.message.checkboxes[i].GetValue() == False:
|
||||
excluded_ids.append(self.ids[i])
|
||||
return excluded_ids
|
||||
|
||||
def get_people(self):
|
||||
people = ""
|
||||
for i in range(0, len(self.message.checkboxes)):
|
||||
if self.message.checkboxes[i].GetValue() == True:
|
||||
people = people + "{0} ".format(self.message.checkboxes[i].GetLabel(),)
|
||||
return people
|
||||
|
||||
class dm(basicTweet):
|
||||
def __init__(self, session, title, caption, users):
|
||||
super(dm, self).__init__(session, title, caption, messageType="dm", max=10000, users=users)
|
||||
widgetUtils.connect_event(self.message.autocomplete_users, widgetUtils.BUTTON_PRESSED, self.autocomplete_users)
|
||||
self.text_processor()
|
||||
widgetUtils.connect_event(self.message.cb, widgetUtils.ENTERED_TEXT, self.user_changed)
|
||||
|
||||
def user_changed(self, *args, **kwargs):
|
||||
self.title = _("Direct message to %s") % (self.message.cb.GetValue())
|
||||
self.text_processor()
|
||||
|
||||
def autocomplete_users(self, *args, **kwargs):
|
||||
c = completion.autocompletionUsers(self.message, self.session.session_id)
|
||||
c.show_menu("dm")
|
||||
|
||||
def text_processor(self, *args, **kwargs):
|
||||
super(dm, self).text_processor(*args, **kwargs)
|
||||
if len(self.attachments) > 0:
|
||||
self.message.attachments.Enable(True)
|
||||
self.message.remove_attachment.Enable(True)
|
||||
else:
|
||||
self.message.attachments.Enable(False)
|
||||
self.message.remove_attachment.Enable(False)
|
||||
|
||||
def can_attach(self):
|
||||
if len(self.attachments) == 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
class viewTweet(basicTweet):
|
||||
def __init__(self, tweet, tweetList, is_tweet=True, utc_offset=0, date="", item_url=""):
|
||||
""" This represents a tweet displayer. However it could be used for showing something wich is not a tweet, like a direct message or an event.
|
||||
param tweet: A dictionary that represents a full tweet or a string for non-tweets.
|
||||
param tweetList: If is_tweet is set to True, this could be a list of quoted tweets.
|
||||
param is_tweet: True or false, depending wether the passed object is a tweet or not."""
|
||||
if is_tweet == True:
|
||||
self.title = _(u"Tweet")
|
||||
image_description = []
|
||||
text = ""
|
||||
for i in range(0, len(tweetList)):
|
||||
# tweets with message keys are longer tweets, the message value is the full messaje taken from twishort.
|
||||
if hasattr(tweetList[i], "message") and tweetList[i].is_quote_status == False:
|
||||
value = "message"
|
||||
else:
|
||||
value = "full_text"
|
||||
if hasattr(tweetList[i], "retweeted_status") and tweetList[i].is_quote_status == False:
|
||||
if not hasattr(tweetList[i], "message"):
|
||||
text = text + "rt @%s: %s\n" % (tweetList[i].retweeted_status.user.screen_name, tweetList[i].retweeted_status.full_text)
|
||||
else:
|
||||
text = text + "rt @%s: %s\n" % (tweetList[i].retweeted_status.user.screen_name, getattr(tweetList[i], value))
|
||||
else:
|
||||
text = text + " @%s: %s\n" % (tweetList[i].user.screen_name, getattr(tweetList[i], value))
|
||||
# tweets with extended_entities could include image descriptions.
|
||||
if hasattr(tweetList[i], "extended_entities") and "media" in tweetList[i].extended_entities:
|
||||
for z in tweetList[i].extended_entities["media"]:
|
||||
if "ext_alt_text" in z and z["ext_alt_text"] != None:
|
||||
image_description.append(z["ext_alt_text"])
|
||||
if hasattr(tweetList[i], "retweeted_status") and hasattr(tweetList[i].retweeted_status, "extended_entities") and "media" in tweetList[i].retweeted_status["extended_entities"]:
|
||||
for z in tweetList[i].retweeted_status.extended_entities["media"]:
|
||||
if "ext_alt_text" in z and z["ext_alt_text"] != None:
|
||||
image_description.append(z["ext_alt_text"])
|
||||
# set rt and likes counters.
|
||||
rt_count = str(tweet.retweet_count)
|
||||
favs_count = str(tweet.favorite_count)
|
||||
# Gets the client from where this tweet was made.
|
||||
source = tweet.source
|
||||
original_date = arrow.get(tweet.created_at, locale="en")
|
||||
date = original_date.shift(seconds=utc_offset).format(_(u"MMM D, YYYY. H:m"), locale=languageHandler.getLanguage())
|
||||
if text == "":
|
||||
if hasattr(tweet, "message"):
|
||||
value = "message"
|
||||
else:
|
||||
value = "full_text"
|
||||
if hasattr(tweet, "retweeted_status"):
|
||||
if not hasattr(tweet, "message"):
|
||||
text = "rt @%s: %s" % (tweet.retweeted_status.user.screen_name, tweet.retweeted_status.full_text)
|
||||
else:
|
||||
text = "rt @%s: %s" % (tweet.retweeted_status.user.screen_name, getattr(tweet, value))
|
||||
else:
|
||||
text = getattr(tweet, value)
|
||||
text = self.clear_text(text)
|
||||
if hasattr(tweet, "extended_entities") and "media" in tweet.extended_entities:
|
||||
for z in tweet.extended_entities["media"]:
|
||||
if "ext_alt_text" in z and z["ext_alt_text"] != None:
|
||||
image_description.append(z["ext_alt_text"])
|
||||
if hasattr(tweet, "retweeted_status") and hasattr(tweet.retweeted_status, "extended_entities") and "media" in tweet.retweeted_status.extended_entities:
|
||||
for z in tweet.retweeted_status.extended_entities["media"]:
|
||||
if "ext_alt_text" in z and z["ext_alt_text"] != None:
|
||||
image_description.append(z["ext_alt_text"])
|
||||
self.message = twitterDialogs.viewTweet(text, rt_count, favs_count, source, date)
|
||||
results = parse_tweet(text)
|
||||
self.message.set_title(results.weightedLength)
|
||||
[self.message.set_image_description(i) for i in image_description]
|
||||
else:
|
||||
self.title = _(u"View item")
|
||||
text = tweet
|
||||
self.message = twitterDialogs.viewNonTweet(text, date)
|
||||
widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck)
|
||||
if item_url != "":
|
||||
self.message.enable_button("share")
|
||||
widgetUtils.connect_event(self.message.share, widgetUtils.BUTTON_PRESSED, self.share)
|
||||
self.item_url = item_url
|
||||
widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate)
|
||||
self.message.ShowModal()
|
||||
|
||||
# We won't need text_processor in this dialog, so let's avoid it.
|
||||
def text_processor(self):
|
||||
pass
|
||||
|
||||
def clear_text(self, text):
|
||||
text = utils.StripChars(text)
|
||||
urls = utils.find_urls_in_text(text)
|
||||
for i in urls:
|
||||
if "https://twitter.com/" in i:
|
||||
text = text.replace(i, "\n")
|
||||
return text
|
||||
|
||||
def share(self, *args, **kwargs):
|
||||
if hasattr(self, "item_url"):
|
||||
output.copy(self.item_url)
|
||||
output.speak(_("Link copied to clipboard."))
|
@@ -1,247 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import threading
|
||||
import logging
|
||||
import sound_lib
|
||||
import paths
|
||||
import widgetUtils
|
||||
import output
|
||||
from collections import OrderedDict
|
||||
from wxUI import commonMessageDialogs
|
||||
from extra.autocompletionUsers import scan, manage
|
||||
from extra.ocr import OCRSpace
|
||||
from controller.settings import globalSettingsController
|
||||
from . templateEditor import EditTemplate
|
||||
|
||||
log = logging.getLogger("Settings")
|
||||
|
||||
class accountSettingsController(globalSettingsController):
|
||||
def __init__(self, buffer, window):
|
||||
self.user = buffer.session.db["user_name"]
|
||||
self.buffer = buffer
|
||||
self.window = window
|
||||
self.config = buffer.session.settings
|
||||
super(accountSettingsController, self).__init__()
|
||||
|
||||
def create_config(self):
|
||||
self.dialog.create_general_account()
|
||||
widgetUtils.connect_event(self.dialog.general.userAutocompletionScan, widgetUtils.BUTTON_PRESSED, self.on_autocompletion_scan)
|
||||
widgetUtils.connect_event(self.dialog.general.userAutocompletionManage, widgetUtils.BUTTON_PRESSED, self.on_autocompletion_manage)
|
||||
self.dialog.set_value("general", "relative_time", self.config["general"]["relative_times"])
|
||||
self.dialog.set_value("general", "show_screen_names", self.config["general"]["show_screen_names"])
|
||||
self.dialog.set_value("general", "hide_emojis", self.config["general"]["hide_emojis"])
|
||||
self.dialog.set_value("general", "itemsPerApiCall", self.config["general"]["max_tweets_per_call"])
|
||||
self.dialog.set_value("general", "reverse_timelines", self.config["general"]["reverse_timelines"])
|
||||
rt = self.config["general"]["retweet_mode"]
|
||||
if rt == "ask":
|
||||
self.dialog.set_value("general", "retweet_mode", _(u"Ask"))
|
||||
elif rt == "direct":
|
||||
self.dialog.set_value("general", "retweet_mode", _(u"Retweet without comments"))
|
||||
else:
|
||||
self.dialog.set_value("general", "retweet_mode", _(u"Retweet with comments"))
|
||||
self.dialog.set_value("general", "persist_size", str(self.config["general"]["persist_size"]))
|
||||
self.dialog.set_value("general", "load_cache_in_memory", self.config["general"]["load_cache_in_memory"])
|
||||
self.dialog.create_reporting()
|
||||
self.dialog.set_value("reporting", "speech_reporting", self.config["reporting"]["speech_reporting"])
|
||||
self.dialog.set_value("reporting", "braille_reporting", self.config["reporting"]["braille_reporting"])
|
||||
tweet_template = self.config["templates"]["tweet"]
|
||||
dm_template = self.config["templates"]["dm"]
|
||||
sent_dm_template = self.config["templates"]["dm_sent"]
|
||||
person_template = self.config["templates"]["person"]
|
||||
self.dialog.create_templates(tweet_template=tweet_template, dm_template=dm_template, sent_dm_template=sent_dm_template, person_template=person_template)
|
||||
widgetUtils.connect_event(self.dialog.templates.tweet, widgetUtils.BUTTON_PRESSED, self.edit_tweet_template)
|
||||
widgetUtils.connect_event(self.dialog.templates.dm, widgetUtils.BUTTON_PRESSED, self.edit_dm_template)
|
||||
widgetUtils.connect_event(self.dialog.templates.sent_dm, widgetUtils.BUTTON_PRESSED, self.edit_sent_dm_template)
|
||||
widgetUtils.connect_event(self.dialog.templates.person, widgetUtils.BUTTON_PRESSED, self.edit_person_template)
|
||||
self.dialog.create_other_buffers()
|
||||
buffer_values = self.get_buffers_list()
|
||||
self.dialog.buffers.insert_buffers(buffer_values)
|
||||
self.dialog.buffers.connect_hook_func(self.toggle_buffer_active)
|
||||
widgetUtils.connect_event(self.dialog.buffers.toggle_state, widgetUtils.BUTTON_PRESSED, self.toggle_state)
|
||||
widgetUtils.connect_event(self.dialog.buffers.up, widgetUtils.BUTTON_PRESSED, self.dialog.buffers.move_up)
|
||||
widgetUtils.connect_event(self.dialog.buffers.down, widgetUtils.BUTTON_PRESSED, self.dialog.buffers.move_down)
|
||||
|
||||
self.dialog.create_ignored_clients(self.config["twitter"]["ignored_clients"])
|
||||
widgetUtils.connect_event(self.dialog.ignored_clients.add, widgetUtils.BUTTON_PRESSED, self.add_ignored_client)
|
||||
widgetUtils.connect_event(self.dialog.ignored_clients.remove, widgetUtils.BUTTON_PRESSED, self.remove_ignored_client)
|
||||
self.input_devices = sound_lib.input.Input.get_device_names()
|
||||
self.output_devices = sound_lib.output.Output.get_device_names()
|
||||
self.soundpacks = []
|
||||
[self.soundpacks.append(i) for i in os.listdir(paths.sound_path()) if os.path.isdir(os.path.join(paths.sound_path(), i)) == True ]
|
||||
self.dialog.create_sound(self.input_devices, self.output_devices, self.soundpacks)
|
||||
self.dialog.set_value("sound", "volumeCtrl", int(self.config["sound"]["volume"]*100))
|
||||
self.dialog.set_value("sound", "input", self.config["sound"]["input_device"])
|
||||
self.dialog.set_value("sound", "output", self.config["sound"]["output_device"])
|
||||
self.dialog.set_value("sound", "session_mute", self.config["sound"]["session_mute"])
|
||||
self.dialog.set_value("sound", "soundpack", self.config["sound"]["current_soundpack"])
|
||||
self.dialog.set_value("sound", "indicate_audio", self.config["sound"]["indicate_audio"])
|
||||
self.dialog.set_value("sound", "indicate_geo", self.config["sound"]["indicate_geo"])
|
||||
self.dialog.set_value("sound", "indicate_img", self.config["sound"]["indicate_img"])
|
||||
self.dialog.create_extras(OCRSpace.translatable_langs)
|
||||
self.dialog.set_value("extras", "sndup_apiKey", self.config["sound"]["sndup_api_key"])
|
||||
language_index = OCRSpace.OcrLangs.index(self.config["mysc"]["ocr_language"])
|
||||
self.dialog.extras.ocr_lang.SetSelection(language_index)
|
||||
self.dialog.realize()
|
||||
self.dialog.set_title(_(u"Account settings for %s") % (self.user,))
|
||||
self.response = self.dialog.get_response()
|
||||
|
||||
def edit_tweet_template(self, *args, **kwargs):
|
||||
template = self.config["templates"]["tweet"]
|
||||
control = EditTemplate(template=template, type="tweet")
|
||||
result = control.run_dialog()
|
||||
if result != "": # Template has been saved.
|
||||
self.config["templates"]["tweet"] = result
|
||||
self.config.write()
|
||||
self.dialog.templates.tweet.SetLabel(_("Edit template for tweets. Current template: {}").format(result))
|
||||
|
||||
def edit_dm_template(self, *args, **kwargs):
|
||||
template = self.config["templates"]["dm"]
|
||||
control = EditTemplate(template=template, type="dm")
|
||||
result = control.run_dialog()
|
||||
if result != "": # Template has been saved.
|
||||
self.config["templates"]["dm"] = result
|
||||
self.config.write()
|
||||
self.dialog.templates.dm.SetLabel(_("Edit template for direct messages. Current template: {}").format(result))
|
||||
|
||||
def edit_sent_dm_template(self, *args, **kwargs):
|
||||
template = self.config["templates"]["dm_sent"]
|
||||
control = EditTemplate(template=template, type="dm")
|
||||
result = control.run_dialog()
|
||||
if result != "": # Template has been saved.
|
||||
self.config["templates"]["dm_sent"] = result
|
||||
self.config.write()
|
||||
self.dialog.templates.sent_dm.SetLabel(_("Edit template for sent direct messages. Current template: {}").format(result))
|
||||
|
||||
def edit_person_template(self, *args, **kwargs):
|
||||
template = self.config["templates"]["person"]
|
||||
control = EditTemplate(template=template, type="person")
|
||||
result = control.run_dialog()
|
||||
if result != "": # Template has been saved.
|
||||
self.config["templates"]["person"] = result
|
||||
self.config.write()
|
||||
self.dialog.templates.person.SetLabel(_("Edit template for persons. Current template: {}").format(result))
|
||||
|
||||
def save_configuration(self):
|
||||
if self.config["general"]["relative_times"] != self.dialog.get_value("general", "relative_time"):
|
||||
self.needs_restart = True
|
||||
log.debug("Triggered app restart due to change in relative times.")
|
||||
self.config["general"]["relative_times"] = self.dialog.get_value("general", "relative_time")
|
||||
self.config["general"]["show_screen_names"] = self.dialog.get_value("general", "show_screen_names")
|
||||
self.config["general"]["hide_emojis"] = self.dialog.get_value("general", "hide_emojis")
|
||||
self.config["general"]["max_tweets_per_call"] = self.dialog.get_value("general", "itemsPerApiCall")
|
||||
if self.config["general"]["load_cache_in_memory"] != self.dialog.get_value("general", "load_cache_in_memory"):
|
||||
self.config["general"]["load_cache_in_memory"] = self.dialog.get_value("general", "load_cache_in_memory")
|
||||
self.needs_restart = True
|
||||
log.debug("Triggered app restart due to change in database strategy management.")
|
||||
if self.config["general"]["persist_size"] != self.dialog.get_value("general", "persist_size"):
|
||||
if self.dialog.get_value("general", "persist_size") == '':
|
||||
self.config["general"]["persist_size"] =-1
|
||||
else:
|
||||
try:
|
||||
self.config["general"]["persist_size"] = int(self.dialog.get_value("general", "persist_size"))
|
||||
except ValueError:
|
||||
output.speak("Invalid cache size, setting to default.",True)
|
||||
self.config["general"]["persist_size"] =1764
|
||||
|
||||
if self.config["general"]["reverse_timelines"] != self.dialog.get_value("general", "reverse_timelines"):
|
||||
self.needs_restart = True
|
||||
log.debug("Triggered app restart due to change in timeline order.")
|
||||
self.config["general"]["reverse_timelines"] = self.dialog.get_value("general", "reverse_timelines")
|
||||
rt = self.dialog.get_value("general", "retweet_mode")
|
||||
if rt == _(u"Ask"):
|
||||
self.config["general"]["retweet_mode"] = "ask"
|
||||
elif rt == _(u"Retweet without comments"):
|
||||
self.config["general"]["retweet_mode"] = "direct"
|
||||
else:
|
||||
self.config["general"]["retweet_mode"] = "comment"
|
||||
buffers_list = self.dialog.buffers.get_list()
|
||||
if buffers_list != self.config["general"]["buffer_order"]:
|
||||
self.needs_restart = True
|
||||
log.debug("Triggered app restart due to change in buffer ordering.")
|
||||
self.config["general"]["buffer_order"] = buffers_list
|
||||
self.config["reporting"]["speech_reporting"] = self.dialog.get_value("reporting", "speech_reporting")
|
||||
self.config["reporting"]["braille_reporting"] = self.dialog.get_value("reporting", "braille_reporting")
|
||||
self.config["mysc"]["ocr_language"] = OCRSpace.OcrLangs[self.dialog.extras.ocr_lang.GetSelection()]
|
||||
if self.config["sound"]["input_device"] != self.dialog.sound.get("input"):
|
||||
self.config["sound"]["input_device"] = self.dialog.sound.get("input")
|
||||
try:
|
||||
self.buffer.session.sound.input.set_device(self.buffer.session.sound.input.find_device_by_name(self.config["sound"]["input_device"]))
|
||||
except:
|
||||
self.config["sound"]["input_device"] = "default"
|
||||
if self.config["sound"]["output_device"] != self.dialog.sound.get("output"):
|
||||
self.config["sound"]["output_device"] = self.dialog.sound.get("output")
|
||||
try:
|
||||
self.buffer.session.sound.output.set_device(self.buffer.session.sound.output.find_device_by_name(self.config["sound"]["output_device"]))
|
||||
except:
|
||||
self.config["sound"]["output_device"] = "default"
|
||||
self.config["sound"]["volume"] = self.dialog.get_value("sound", "volumeCtrl")/100.0
|
||||
self.config["sound"]["session_mute"] = self.dialog.get_value("sound", "session_mute")
|
||||
self.config["sound"]["current_soundpack"] = self.dialog.sound.get("soundpack")
|
||||
self.config["sound"]["indicate_audio"] = self.dialog.get_value("sound", "indicate_audio")
|
||||
self.config["sound"]["indicate_geo"] = self.dialog.get_value("sound", "indicate_geo")
|
||||
self.config["sound"]["indicate_img"] = self.dialog.get_value("sound", "indicate_img")
|
||||
self.config["sound"]["sndup_api_key"] = self.dialog.get_value("extras", "sndup_apiKey")
|
||||
self.buffer.session.sound.config = self.config["sound"]
|
||||
self.buffer.session.sound.check_soundpack()
|
||||
self.config.write()
|
||||
|
||||
def toggle_state(self,*args,**kwargs):
|
||||
return self.dialog.buffers.change_selected_item()
|
||||
|
||||
def on_autocompletion_scan(self, *args, **kwargs):
|
||||
configuration = scan.autocompletionScan(self.buffer.session.settings, self.buffer, self.window)
|
||||
to_scan = configuration.show_dialog()
|
||||
if to_scan == True:
|
||||
configuration.prepare_progress_dialog()
|
||||
t = threading.Thread(target=configuration.scan)
|
||||
t.start()
|
||||
|
||||
|
||||
|
||||
def on_autocompletion_manage(self, *args, **kwargs):
|
||||
configuration = manage.autocompletionManage(self.buffer.session)
|
||||
configuration.show_settings()
|
||||
|
||||
def add_ignored_client(self, *args, **kwargs):
|
||||
client = commonMessageDialogs.get_ignored_client()
|
||||
if client == None: return
|
||||
if client not in self.config["twitter"]["ignored_clients"]:
|
||||
self.config["twitter"]["ignored_clients"].append(client)
|
||||
self.dialog.ignored_clients.append(client)
|
||||
|
||||
def remove_ignored_client(self, *args, **kwargs):
|
||||
if self.dialog.ignored_clients.get_clients() == 0: return
|
||||
id = self.dialog.ignored_clients.get_client_id()
|
||||
self.config["twitter"]["ignored_clients"].pop(id)
|
||||
self.dialog.ignored_clients.remove_(id)
|
||||
|
||||
def get_buffers_list(self):
|
||||
all_buffers=OrderedDict()
|
||||
all_buffers['home']=_(u"Home")
|
||||
all_buffers['mentions']=_(u"Mentions")
|
||||
all_buffers['dm']=_(u"Direct Messages")
|
||||
all_buffers['sent_dm']=_(u"Sent direct messages")
|
||||
all_buffers['sent_tweets']=_(u"Sent tweets")
|
||||
all_buffers['favorites']=_(u"Likes")
|
||||
all_buffers['followers']=_(u"Followers")
|
||||
all_buffers['friends']=_(u"Friends")
|
||||
all_buffers['blocks']=_(u"Blocked users")
|
||||
all_buffers['muted']=_(u"Muted users")
|
||||
list_buffers = []
|
||||
hidden_buffers=[]
|
||||
all_buffers_keys = list(all_buffers.keys())
|
||||
# Check buffers shown first.
|
||||
for i in self.config["general"]["buffer_order"]:
|
||||
if i in all_buffers_keys:
|
||||
list_buffers.append((i, all_buffers[i], True))
|
||||
# This second pass will retrieve all hidden buffers.
|
||||
for i in all_buffers_keys:
|
||||
if i not in self.config["general"]["buffer_order"]:
|
||||
hidden_buffers.append((i, all_buffers[i], False))
|
||||
list_buffers.extend(hidden_buffers)
|
||||
return list_buffers
|
||||
|
||||
def toggle_buffer_active(self, ev):
|
||||
change = self.dialog.buffers.get_event(ev)
|
||||
if change == True:
|
||||
self.dialog.buffers.change_selected_item()
|
@@ -1,40 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import wx
|
||||
from typing import List
|
||||
from sessions.twitter.templates import tweet_variables, dm_variables, person_variables
|
||||
from wxUI.dialogs.twitterDialogs import templateDialogs
|
||||
|
||||
class EditTemplate(object):
|
||||
def __init__(self, template: str, type: str) -> None:
|
||||
super(EditTemplate, self).__init__()
|
||||
self.default_template = template
|
||||
if type == "tweet":
|
||||
self.variables = tweet_variables
|
||||
elif type == "dm":
|
||||
self.variables = dm_variables
|
||||
else:
|
||||
self.variables = person_variables
|
||||
self.template: str = template
|
||||
|
||||
def validate_template(self, template: str) -> bool:
|
||||
used_variables: List[str] = re.findall("\$\w+", template)
|
||||
validated: bool = True
|
||||
for var in used_variables:
|
||||
if var[1:] not in self.variables:
|
||||
validated = False
|
||||
return validated
|
||||
|
||||
def run_dialog(self) -> str:
|
||||
dialog = templateDialogs.EditTemplateDialog(template=self.template, variables=self.variables, default_template=self.default_template)
|
||||
response = dialog.ShowModal()
|
||||
if response == wx.ID_SAVE:
|
||||
validated: bool = self.validate_template(dialog.template.GetValue())
|
||||
if validated == False:
|
||||
templateDialogs.invalid_template()
|
||||
self.template = dialog.template.GetValue()
|
||||
return self.run_dialog()
|
||||
else:
|
||||
return dialog.template.GetValue()
|
||||
else:
|
||||
return ""
|
@@ -1,45 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from wxUI.dialogs import trends
|
||||
import widgetUtils
|
||||
|
||||
class trendingTopicsController(object):
|
||||
def __init__(self, session):
|
||||
super(trendingTopicsController, self).__init__()
|
||||
self.countries = {}
|
||||
self.cities = {}
|
||||
self.dialog = trends.trendingTopicsDialog()
|
||||
self.information = session.twitter.available_trends()
|
||||
self.split_information()
|
||||
widgetUtils.connect_event(self.dialog.country, widgetUtils.RADIOBUTTON, self.get_places)
|
||||
widgetUtils.connect_event(self.dialog.city, widgetUtils.RADIOBUTTON, self.get_places)
|
||||
self.get_places()
|
||||
|
||||
def split_information(self):
|
||||
for i in self.information:
|
||||
if i["placeType"]["name"] == "Country":
|
||||
self.countries[i["name"]] = i["woeid"]
|
||||
else:
|
||||
self.cities[i["name"]] = i["woeid"]
|
||||
|
||||
def get_places(self, event=None):
|
||||
values = []
|
||||
if self.dialog.get_active() == "country":
|
||||
for i in self.information:
|
||||
if i["placeType"]["name"] == "Country":
|
||||
values.append(i["name"])
|
||||
elif self.dialog.get_active() == "city":
|
||||
for i in self.information:
|
||||
if i["placeType"]["name"] != "Country":
|
||||
values.append(i["name"])
|
||||
self.dialog.set(values)
|
||||
|
||||
def get_woeid(self):
|
||||
selected = self.dialog.get_item()
|
||||
if self.dialog.get_active() == "country":
|
||||
woeid = self.countries[selected]
|
||||
else:
|
||||
woeid = self.cities[selected]
|
||||
return woeid
|
||||
|
||||
def get_string(self):
|
||||
return self.dialog.get_item()
|
@@ -1,128 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import wx
|
||||
import webbrowser
|
||||
import widgetUtils
|
||||
import output
|
||||
from wxUI.dialogs import update_profile, show_user
|
||||
import logging
|
||||
log = logging.getLogger("controller.user")
|
||||
from tweepy.errors import TweepyException, Forbidden, NotFound
|
||||
from sessions.twitter import utils
|
||||
|
||||
class profileController(object):
|
||||
def __init__(self, session, user=None):
|
||||
super(profileController, self).__init__()
|
||||
self.file = None
|
||||
self.session = session
|
||||
self.user = user
|
||||
if user == None:
|
||||
self.get_data(screen_name=self.session.db["user_name"])
|
||||
self.dialog = update_profile.updateProfileDialog()
|
||||
self.fill_profile_fields()
|
||||
self.uploaded = False
|
||||
widgetUtils.connect_event(self.dialog.upload_image, widgetUtils.BUTTON_PRESSED, self.upload_image)
|
||||
else:
|
||||
try:
|
||||
self.get_data(screen_name=self.user)
|
||||
except TweepyException as err:
|
||||
if type(err) == NotFound:
|
||||
wx.MessageDialog(None, _(u"That user does not exist"), _(u"Error"), wx.ICON_ERROR).ShowModal()
|
||||
if type(err) == Forbidden:
|
||||
wx.MessageDialog(None, _(u"User has been suspended"), _(u"Error"), wx.ICON_ERROR).ShowModal()
|
||||
log.error("error %s" % (str(err)))
|
||||
return
|
||||
self.dialog = show_user.showUserProfile()
|
||||
string = self.get_user_info()
|
||||
self.dialog.set("text", string)
|
||||
self.dialog.set_title(_(u"Information for %s") % (self.data.screen_name))
|
||||
if self.data.url != None:
|
||||
self.dialog.enable_url()
|
||||
widgetUtils.connect_event(self.dialog.url, widgetUtils.BUTTON_PRESSED, self.visit_url)
|
||||
if self.dialog.get_response() == widgetUtils.OK and self.user == None:
|
||||
self.do_update()
|
||||
|
||||
def get_data(self, screen_name):
|
||||
self.data = self.session.twitter.get_user(screen_name=screen_name)
|
||||
if screen_name != self.session.db["user_name"]:
|
||||
self.friendship_status = self.session.twitter.get_friendship(source_screen_name=self.session.db["user_name"], target_screen_name=screen_name)
|
||||
|
||||
def fill_profile_fields(self):
|
||||
self.dialog.set_name(self.data.name)
|
||||
if self.data.url != None:
|
||||
self.dialog.set_url(self.data.url)
|
||||
if len(self.data.location) > 0:
|
||||
self.dialog.set_location(self.data.location)
|
||||
if len(self.data.description) > 0:
|
||||
self.dialog.set_description(self.data.description)
|
||||
|
||||
def get_image(self):
|
||||
file = self.dialog.upload_picture()
|
||||
if file != None:
|
||||
self.file = open(file, "rb")
|
||||
self.uploaded = True
|
||||
self.dialog.change_upload_button(self.uploaded)
|
||||
|
||||
def discard_image(self):
|
||||
self.file = None
|
||||
output.speak(_(u"Discarded"))
|
||||
self.uploaded = False
|
||||
self.dialog.change_upload_button(self.uploaded)
|
||||
|
||||
def upload_image(self, *args, **kwargs):
|
||||
if self.uploaded == False:
|
||||
self.get_image()
|
||||
elif self.uploaded == True:
|
||||
self.discard_image()
|
||||
|
||||
def do_update(self):
|
||||
if self.user != None: return
|
||||
name = self.dialog.get("name")
|
||||
description = self.dialog.get("description")
|
||||
location = self.dialog.get("location")
|
||||
url = self.dialog.get("url")
|
||||
if self.file != None:
|
||||
try:
|
||||
self.session.twitter.update_profile_image(image=self.file)
|
||||
except TweepyException as e:
|
||||
output.speak(u"Error %s" % (str(e)))
|
||||
try:
|
||||
self.session.twitter.update_profile(name=name, description=description, location=location, url=url)
|
||||
except TweepyException as e:
|
||||
output.speak(u"Error %s." % (str(e)))
|
||||
|
||||
def get_user_info(self):
|
||||
string = u""
|
||||
string = string + _(u"Username: @%s\n") % (self.data.screen_name)
|
||||
string = string + _(u"Name: %s\n") % (self.data.name)
|
||||
if self.data.location != "":
|
||||
string = string + _(u"Location: %s\n") % (self.data.location)
|
||||
if self.data.url != None:
|
||||
string = string+ _(u"URL: %s\n") % (self.data.entities["url"]["urls"][0]["expanded_url"])
|
||||
if self.data.description != "":
|
||||
if self.data.entities.get("description") != None and self.data.entities["description"].get("urls"):
|
||||
self.data.description = utils.expand_urls(self.data.description, self.data.entities["description"])
|
||||
string = string+ _(u"Bio: %s\n") % (self.data.description)
|
||||
if self.data.protected == True: protected = _(u"Yes")
|
||||
else: protected = _(u"No")
|
||||
string = string+ _(u"Protected: %s\n") % (protected)
|
||||
if hasattr(self, "friendship_status"):
|
||||
relation = False
|
||||
friendship = _(u"Relationship: ")
|
||||
if self.friendship_status[0].following:
|
||||
friendship += _(u"You follow {0}. ").format(self.data.name,)
|
||||
relation = True
|
||||
if self.friendship_status[1].following:
|
||||
friendship += _(u"{0} is following you.").format(self.data.name,)
|
||||
relation = True
|
||||
if relation == True:
|
||||
string = string+friendship+"\n"
|
||||
string = string+_(u"Followers: %s\n Friends: %s\n") % (self.data.followers_count, self.data.friends_count)
|
||||
if self.data.verified == True: verified = _(u"Yes")
|
||||
else: verified = _(u"No")
|
||||
string = string+ _(u"Verified: %s\n") % (verified)
|
||||
string = string+ _(u"Tweets: %s\n") % (self.data.statuses_count)
|
||||
string = string+ _(u"Likes: %s") % (self.data.favourites_count)
|
||||
return string
|
||||
|
||||
def visit_url(self, *args, **kwargs):
|
||||
webbrowser.open_new_tab(self.data.url)
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user