mirror of
https://github.com/MCV-Software/TWBlue.git
synced 2025-08-25 17:39:23 +00:00
Compare commits
56 Commits
v2023.2.3
...
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 |
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
|
- cd ..\src
|
||||||
- '&$env:PYTHON ..\doc\generator.py'
|
- '&$env:PYTHON ..\doc\generator.py'
|
||||||
- '&$env:PYTHON write_version_data.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'
|
- '&$env:PYTHON setup.py build'
|
||||||
- cd ..
|
- cd ..
|
||||||
- mkdir artifacts
|
- mkdir artifacts
|
||||||
|
11
README.md
11
README.md
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[](https://ci.appveyor.com/project/manuelcortez/twblue)
|
[](https://ci.appveyor.com/project/manuelcortez/twblue)
|
||||||
|
|
||||||
TWBlue is a free and open source application that allows you to interact with the main features of Twitter and mastodon from the comfort of a windows software, with 2 different interfaces specially designed for screen reader users.
|
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.
|
||||||
|
|
||||||
See [TWBlue's webpage](https://twblue.es) for more details.
|
See [TWBlue's webpage](https://twblue.es) for more details.
|
||||||
|
|
||||||
@@ -11,15 +11,6 @@ See [TWBlue's webpage](https://twblue.es) for more details.
|
|||||||
|
|
||||||
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.
|
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.
|
### 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:
|
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:
|
||||||
|
@@ -2,6 +2,34 @@ TWBlue Changelog
|
|||||||
|
|
||||||
## changes in this version
|
## 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 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 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.
|
||||||
|
@@ -10,7 +10,6 @@ from importlib import reload
|
|||||||
# Languages already translated or translating the documentation.
|
# Languages already translated or translating the documentation.
|
||||||
documentation_languages = ["en", "es", "fr", "de", "it", "gl", "ja", "ru", "ro", "eu", "ca", "da", "sr"]
|
documentation_languages = ["en", "es", "fr", "de", "it", "gl", "ja", "ru", "ro", "eu", "ca", "da", "sr"]
|
||||||
|
|
||||||
|
|
||||||
# Changelog translated languages.
|
# Changelog translated languages.
|
||||||
changelog_languages = ["en", "ca", "de", "es", "eu", "fr", "gl", "ja", "ro", "ru", "sr"]
|
changelog_languages = ["en", "ca", "de", "es", "eu", "fr", "gl", "ja", "ro", "ru", "sr"]
|
||||||
|
|
||||||
@@ -29,8 +28,13 @@ def get_translations(name):
|
|||||||
langs = changelog_languages
|
langs = changelog_languages
|
||||||
for l in langs:
|
for l in langs:
|
||||||
if l != "en":
|
if l != "en":
|
||||||
_ = gettext.translation(name, os.path.join(paths.app_path(), "locales"), languages=[l])
|
try:
|
||||||
translations[l] = _
|
_ = gettext.translation(name, os.path.join(paths.app_path(), "locales"), languages=[l])
|
||||||
|
translations[l] = _
|
||||||
|
print(l, name)
|
||||||
|
except FileNotFoundError:
|
||||||
|
_ = gettext.NullTranslations()
|
||||||
|
translations[l] = _
|
||||||
else:
|
else:
|
||||||
_ = gettext.NullTranslations()
|
_ = gettext.NullTranslations()
|
||||||
translations[l] = _
|
translations[l] = _
|
||||||
|
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-oauthlib
|
||||||
requests-toolbelt
|
requests-toolbelt
|
||||||
pypubsub
|
pypubsub
|
||||||
geopy
|
|
||||||
arrow
|
arrow
|
||||||
python-dateutil
|
python-dateutil
|
||||||
winpaths
|
winpaths
|
||||||
@@ -29,7 +28,6 @@ pywin32
|
|||||||
certifi
|
certifi
|
||||||
backports.functools_lru_cache
|
backports.functools_lru_cache
|
||||||
cx_freeze
|
cx_freeze
|
||||||
tweepy
|
|
||||||
twitter-text-parser
|
twitter-text-parser
|
||||||
mastodon.py
|
mastodon.py
|
||||||
pyenchant
|
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]
|
|
@@ -1,22 +1,14 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import datetime
|
|
||||||
|
|
||||||
# Make date check for feb 9.
|
|
||||||
now = datetime.datetime.now()
|
|
||||||
end_of_twitter = datetime.datetime(2023, 2, 9)
|
|
||||||
twitter_support_enabled = True
|
|
||||||
if now >= end_of_twitter:
|
|
||||||
twitter_support_enabled = False
|
|
||||||
name = 'TWBlue'
|
name = 'TWBlue'
|
||||||
short_name='twblue'
|
short_name='twblue'
|
||||||
update_url = 'https://twblue.es/updates/updates.php'
|
update_url = 'https://twblue.es/updates/updates.php'
|
||||||
mirror_update_url = 'https://raw.githubusercontent.com/mcv-software/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"]
|
authors = ["Manuel Cortéz", "José Manuel Delicado"]
|
||||||
authorEmail = "manuel@manuelcortez.net"
|
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."
|
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)"]
|
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"
|
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 = []
|
supported_languages = []
|
||||||
version = "11"
|
version = "11"
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from . import base as base
|
from . import base as base
|
||||||
from . import twitter as twitter
|
|
||||||
from . import mastodon as mastodon
|
from . import mastodon as mastodon
|
@@ -17,9 +17,11 @@ from sessions.mastodon import compose, utils, templates
|
|||||||
from mysc.thread_utils import call_threaded
|
from mysc.thread_utils import call_threaded
|
||||||
from pubsub import pub
|
from pubsub import pub
|
||||||
from extra import ocr
|
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 menus
|
||||||
from wxUI.dialogs.mastodon import dialogs as mastodon_dialogs
|
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")
|
log = logging.getLogger("controller.buffers.mastodon.base")
|
||||||
|
|
||||||
@@ -76,7 +78,7 @@ class BaseBuffer(base.Buffer):
|
|||||||
safe = True
|
safe = True
|
||||||
if self.session.settings["general"]["read_preferences_from_instance"]:
|
if self.session.settings["general"]["read_preferences_from_instance"]:
|
||||||
safe = self.session.expand_spoilers == False
|
safe = self.session.expand_spoilers == False
|
||||||
return self.compose_function(self.get_item(), self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)[1]
|
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):
|
def get_message(self):
|
||||||
post = self.get_item()
|
post = self.get_item()
|
||||||
@@ -89,7 +91,7 @@ class BaseBuffer(base.Buffer):
|
|||||||
template = template.replace("$safe_text", "$text")
|
template = template.replace("$safe_text", "$text")
|
||||||
elif self.session.expand_spoilers == False and "$text" in template:
|
elif self.session.expand_spoilers == False and "$text" in template:
|
||||||
template = template.replace("$text", "$safe_text")
|
template = template.replace("$text", "$safe_text")
|
||||||
t = templates.render_post(post, template, relative_times=self.session.settings["general"]["relative_times"], offset_hours=self.session.db["utc_offset"])
|
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
|
return t
|
||||||
|
|
||||||
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False):
|
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False):
|
||||||
@@ -117,6 +119,7 @@ class BaseBuffer(base.Buffer):
|
|||||||
if hasattr(self, "finished_timeline") and self.finished_timeline == False:
|
if hasattr(self, "finished_timeline") and self.finished_timeline == False:
|
||||||
if "-timeline" in self.name:
|
if "-timeline" in self.name:
|
||||||
self.username = self.session.db[self.name][0]["account"].username
|
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.finished_timeline = True
|
||||||
self.put_items_on_list(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:
|
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:
|
||||||
@@ -136,7 +139,7 @@ class BaseBuffer(base.Buffer):
|
|||||||
safe = True
|
safe = True
|
||||||
if self.session.settings["general"]["read_preferences_from_instance"]:
|
if self.session.settings["general"]["read_preferences_from_instance"]:
|
||||||
safe = self.session.expand_spoilers == False
|
safe = self.session.expand_spoilers == False
|
||||||
output.speak(" ".join(self.compose_function(post, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)))
|
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:
|
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()))
|
output.speak(_("{0} new posts in {1}.").format(number_of_items, self.get_buffer_name()))
|
||||||
|
|
||||||
@@ -167,11 +170,11 @@ class BaseBuffer(base.Buffer):
|
|||||||
safe = self.session.expand_spoilers == False
|
safe = self.session.expand_spoilers == False
|
||||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||||
for i in elements:
|
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"], safe=safe)
|
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)
|
self.buffer.list.insert_item(True, *post)
|
||||||
else:
|
else:
|
||||||
for i in elements:
|
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"], safe=safe)
|
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.insert_item(False, *post)
|
||||||
self.buffer.list.select_item(selection)
|
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)
|
||||||
@@ -205,20 +208,20 @@ class BaseBuffer(base.Buffer):
|
|||||||
safe = self.session.expand_spoilers == False
|
safe = self.session.expand_spoilers == False
|
||||||
if self.buffer.list.get_count() == 0:
|
if self.buffer.list.get_count() == 0:
|
||||||
for i in list_to_use:
|
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"], safe=safe)
|
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.insert_item(False, *post)
|
||||||
self.buffer.set_position(self.session.settings["general"]["reverse_timelines"])
|
self.buffer.set_position(self.session.settings["general"]["reverse_timelines"])
|
||||||
elif self.buffer.list.get_count() > 0 and number_of_items > 0:
|
elif self.buffer.list.get_count() > 0 and number_of_items > 0:
|
||||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||||
items = list_to_use[len(list_to_use)-number_of_items:]
|
items = list_to_use[len(list_to_use)-number_of_items:]
|
||||||
for i in 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"], safe=safe)
|
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.insert_item(False, *post)
|
||||||
else:
|
else:
|
||||||
items = list_to_use[0:number_of_items]
|
items = list_to_use[0:number_of_items]
|
||||||
items.reverse()
|
items.reverse()
|
||||||
for i in 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"], safe=safe)
|
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)
|
self.buffer.list.insert_item(True, *post)
|
||||||
log.debug("Now the list contains %d items " % (self.buffer.list.get_count(),))
|
log.debug("Now the list contains %d items " % (self.buffer.list.get_count(),))
|
||||||
|
|
||||||
@@ -226,7 +229,7 @@ class BaseBuffer(base.Buffer):
|
|||||||
safe = True
|
safe = True
|
||||||
if self.session.settings["general"]["read_preferences_from_instance"]:
|
if self.session.settings["general"]["read_preferences_from_instance"]:
|
||||||
safe = self.session.expand_spoilers == False
|
safe = self.session.expand_spoilers == False
|
||||||
post = self.compose_function(item, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
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:
|
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||||
self.buffer.list.insert_item(False, *post)
|
self.buffer.list.insert_item(False, *post)
|
||||||
else:
|
else:
|
||||||
@@ -238,7 +241,7 @@ class BaseBuffer(base.Buffer):
|
|||||||
safe = True
|
safe = True
|
||||||
if self.session.settings["general"]["read_preferences_from_instance"]:
|
if self.session.settings["general"]["read_preferences_from_instance"]:
|
||||||
safe = self.session.expand_spoilers == False
|
safe = self.session.expand_spoilers == False
|
||||||
post = self.compose_function(item, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
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])
|
self.buffer.list.list.SetItem(position, 1, post[1])
|
||||||
|
|
||||||
def bind_events(self):
|
def bind_events(self):
|
||||||
@@ -414,7 +417,7 @@ class BaseBuffer(base.Buffer):
|
|||||||
if len(urls) == 1:
|
if len(urls) == 1:
|
||||||
url=urls[0]
|
url=urls[0]
|
||||||
elif len(urls) > 1:
|
elif len(urls) > 1:
|
||||||
urls_list = dialogs.urlList.urlList()
|
urls_list = urlList.urlList()
|
||||||
urls_list.populate_list(urls)
|
urls_list.populate_list(urls)
|
||||||
if urls_list.get_response() == widgetUtils.OK:
|
if urls_list.get_response() == widgetUtils.OK:
|
||||||
url=urls_list.get_string()
|
url=urls_list.get_string()
|
||||||
@@ -435,7 +438,7 @@ class BaseBuffer(base.Buffer):
|
|||||||
if len(urls) == 1:
|
if len(urls) == 1:
|
||||||
url=urls[0]
|
url=urls[0]
|
||||||
elif len(urls) > 1:
|
elif len(urls) > 1:
|
||||||
urls_list = dialogs.urlList.urlList()
|
urls_list = urlList.urlList()
|
||||||
urls_list.populate_list(urls)
|
urls_list.populate_list(urls)
|
||||||
if urls_list.get_response() == widgetUtils.OK:
|
if urls_list.get_response() == widgetUtils.OK:
|
||||||
url=urls_list.get_string()
|
url=urls_list.get_string()
|
||||||
@@ -538,4 +541,75 @@ class BaseBuffer(base.Buffer):
|
|||||||
def ocr_image(self):
|
def ocr_image(self):
|
||||||
post = self.get_item()
|
post = self.get_item()
|
||||||
media_list = []
|
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()
|
||||||
|
@@ -28,7 +28,7 @@ class ConversationListBuffer(BaseBuffer):
|
|||||||
return self.session.db[self.name][index]
|
return self.session.db[self.name][index]
|
||||||
|
|
||||||
def get_formatted_message(self):
|
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):
|
def get_message(self):
|
||||||
conversation = self.get_conversation()
|
conversation = self.get_conversation()
|
||||||
@@ -36,7 +36,7 @@ class ConversationListBuffer(BaseBuffer):
|
|||||||
return
|
return
|
||||||
template = self.session.settings["templates"]["conversation"]
|
template = self.session.settings["templates"]["conversation"]
|
||||||
post_template = self.session.settings["templates"]["post"]
|
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
|
return t
|
||||||
|
|
||||||
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False):
|
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False):
|
||||||
@@ -89,11 +89,11 @@ class ConversationListBuffer(BaseBuffer):
|
|||||||
log.debug("Retrieved %d items from cursored search in function %s." % (len(elements), self.function))
|
log.debug("Retrieved %d items from cursored search in function %s." % (len(elements), self.function))
|
||||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||||
for i in elements:
|
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)
|
self.buffer.list.insert_item(True, *conversation)
|
||||||
else:
|
else:
|
||||||
for i in elements:
|
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.insert_item(False, *conversation)
|
||||||
self.buffer.list.select_item(selection)
|
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)
|
||||||
|
@@ -28,6 +28,8 @@ class MentionsBuffer(BaseBuffer):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.exception("Error %s" % (str(e)))
|
log.exception("Error %s" % (str(e)))
|
||||||
return
|
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]
|
||||||
number_of_items = self.session.order_buffer(self.name, items)
|
number_of_items = self.session.order_buffer(self.name, items)
|
||||||
log.debug("Number of items retrieved: %d" % (number_of_items,))
|
log.debug("Number of items retrieved: %d" % (number_of_items,))
|
||||||
self.put_items_on_list(number_of_items)
|
self.put_items_on_list(number_of_items)
|
||||||
@@ -49,7 +51,8 @@ class MentionsBuffer(BaseBuffer):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.exception("Error %s" % (str(e)))
|
log.exception("Error %s" % (str(e)))
|
||||||
return
|
return
|
||||||
print(items)
|
# 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]
|
items_db = self.session.db[self.name]
|
||||||
for i in items:
|
for i in items:
|
||||||
if utils.find_item(i, self.session.db[self.name]) == None:
|
if utils.find_item(i, self.session.db[self.name]) == None:
|
||||||
@@ -66,11 +69,11 @@ class MentionsBuffer(BaseBuffer):
|
|||||||
safe = self.session.expand_spoilers == False
|
safe = self.session.expand_spoilers == False
|
||||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||||
for i in elements:
|
for i in elements:
|
||||||
post = self.compose_function(i.status, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
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)
|
self.buffer.list.insert_item(True, *post)
|
||||||
else:
|
else:
|
||||||
for i in elements:
|
for i in elements:
|
||||||
post = self.compose_function(i.status, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
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.insert_item(False, *post)
|
||||||
self.buffer.list.select_item(selection)
|
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)
|
||||||
@@ -85,20 +88,20 @@ class MentionsBuffer(BaseBuffer):
|
|||||||
safe = self.session.expand_spoilers == False
|
safe = self.session.expand_spoilers == False
|
||||||
if self.buffer.list.get_count() == 0:
|
if self.buffer.list.get_count() == 0:
|
||||||
for i in list_to_use:
|
for i in list_to_use:
|
||||||
post = self.compose_function(i.status, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
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.insert_item(False, *post)
|
||||||
self.buffer.set_position(self.session.settings["general"]["reverse_timelines"])
|
self.buffer.set_position(self.session.settings["general"]["reverse_timelines"])
|
||||||
elif self.buffer.list.get_count() > 0 and number_of_items > 0:
|
elif self.buffer.list.get_count() > 0 and number_of_items > 0:
|
||||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||||
items = list_to_use[len(list_to_use)-number_of_items:]
|
items = list_to_use[len(list_to_use)-number_of_items:]
|
||||||
for i in items:
|
for i in items:
|
||||||
post = self.compose_function(i.status, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
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.insert_item(False, *post)
|
||||||
else:
|
else:
|
||||||
items = list_to_use[0:number_of_items]
|
items = list_to_use[0:number_of_items]
|
||||||
items.reverse()
|
items.reverse()
|
||||||
for i in items:
|
for i in items:
|
||||||
post = self.compose_function(i.status, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
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)
|
self.buffer.list.insert_item(True, *post)
|
||||||
log.debug("Now the list contains %d items " % (self.buffer.list.get_count(),))
|
log.debug("Now the list contains %d items " % (self.buffer.list.get_count(),))
|
||||||
|
|
||||||
@@ -106,7 +109,7 @@ class MentionsBuffer(BaseBuffer):
|
|||||||
safe = True
|
safe = True
|
||||||
if self.session.settings["general"]["read_preferences_from_instance"]:
|
if self.session.settings["general"]["read_preferences_from_instance"]:
|
||||||
safe = self.session.expand_spoilers == False
|
safe = self.session.expand_spoilers == False
|
||||||
post = self.compose_function(item.status, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], safe=safe)
|
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:
|
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||||
self.buffer.list.insert_item(False, *post)
|
self.buffer.list.insert_item(False, *post)
|
||||||
else:
|
else:
|
||||||
|
@@ -18,7 +18,7 @@ class NotificationsBuffer(BaseBuffer):
|
|||||||
return
|
return
|
||||||
template = self.session.settings["templates"]["notification"]
|
template = self.session.settings["templates"]["notification"]
|
||||||
post_template = self.session.settings["templates"]["post"]
|
post_template = self.session.settings["templates"]["post"]
|
||||||
t = templates.render_notification(notification, template, post_template, relative_times=self.session.settings["general"]["relative_times"], offset_hours=self.session.db["utc_offset"])
|
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
|
return t
|
||||||
|
|
||||||
def create_buffer(self, parent, name):
|
def create_buffer(self, parent, name):
|
||||||
@@ -42,6 +42,9 @@ class NotificationsBuffer(BaseBuffer):
|
|||||||
def unfav(self):
|
def unfav(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def vote(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def can_share(self):
|
def can_share(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@@ -4,6 +4,7 @@ import logging
|
|||||||
import wx
|
import wx
|
||||||
import widgetUtils
|
import widgetUtils
|
||||||
import output
|
import output
|
||||||
|
from pubsub import pub
|
||||||
from mysc.thread_utils import call_threaded
|
from mysc.thread_utils import call_threaded
|
||||||
from controller.buffers.mastodon.base import BaseBuffer
|
from controller.buffers.mastodon.base import BaseBuffer
|
||||||
from controller.mastodon import messages
|
from controller.mastodon import messages
|
||||||
@@ -22,7 +23,7 @@ class UserBuffer(BaseBuffer):
|
|||||||
if user == None:
|
if user == None:
|
||||||
return
|
return
|
||||||
template = self.session.settings["templates"]["person"]
|
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
|
return t
|
||||||
|
|
||||||
def bind_events(self):
|
def bind_events(self):
|
||||||
@@ -88,6 +89,11 @@ class UserBuffer(BaseBuffer):
|
|||||||
if hasattr(self, "finished_timeline") and self.finished_timeline == False:
|
if hasattr(self, "finished_timeline") and self.finished_timeline == False:
|
||||||
if "-followers" in self.name or "-following" in self.name:
|
if "-followers" in self.name or "-following" in self.name:
|
||||||
self.username = self.session.api.account(id=self.kwargs.get("id")).username
|
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.finished_timeline = True
|
||||||
self.put_items_on_list(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:
|
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))
|
log.debug("Retrieved %d items from cursored search in function %s." % (len(elements), self.function))
|
||||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||||
for i in elements:
|
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)
|
self.buffer.list.insert_item(True, *post)
|
||||||
else:
|
else:
|
||||||
for i in elements:
|
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.insert_item(False, *post)
|
||||||
self.buffer.list.select_item(selection)
|
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)
|
||||||
|
@@ -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 sound
|
||||||
import output
|
import output
|
||||||
from pubsub import pub
|
from pubsub import pub
|
||||||
from tweepy.errors import TweepyException, Forbidden
|
|
||||||
from geopy.geocoders import Nominatim
|
|
||||||
from extra import SoundsTutorial
|
from extra import SoundsTutorial
|
||||||
from update import updater
|
from update import updater
|
||||||
from wxUI import view, dialogs, commonMessageDialogs, sysTrayIcon
|
from wxUI import view, dialogs, commonMessageDialogs, sysTrayIcon
|
||||||
@@ -25,14 +23,11 @@ from mysc import restart
|
|||||||
from mysc import localization
|
from mysc import localization
|
||||||
from mysc.thread_utils import call_threaded
|
from mysc.thread_utils import call_threaded
|
||||||
from mysc.repeating_timer import RepeatingTimer
|
from mysc.repeating_timer import RepeatingTimer
|
||||||
from controller.twitter import handler as TwitterHandler
|
|
||||||
from controller.mastodon import handler as MastodonHandler
|
from controller.mastodon import handler as MastodonHandler
|
||||||
from . import settings, userAlias
|
from . import settings, userAlias
|
||||||
|
|
||||||
log = logging.getLogger("mainController")
|
log = logging.getLogger("mainController")
|
||||||
|
|
||||||
geocoder = Nominatim(user_agent="TWBlue")
|
|
||||||
|
|
||||||
class Controller(object):
|
class Controller(object):
|
||||||
|
|
||||||
""" Main Controller for TWBlue. It manages the main window and sessions."""
|
""" 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.toggle_share_settings, "toggleShare")
|
||||||
pub.subscribe(self.invisible_shorcuts_changed, "invisible-shorcuts-changed")
|
pub.subscribe(self.invisible_shorcuts_changed, "invisible-shorcuts-changed")
|
||||||
pub.subscribe(self.create_account_buffer, "core.create_account")
|
pub.subscribe(self.create_account_buffer, "core.create_account")
|
||||||
|
pub.subscribe(self.change_buffer_title, "core.change_buffer_title")
|
||||||
# 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")
|
|
||||||
|
|
||||||
# Mastodon specific events.
|
# Mastodon specific events.
|
||||||
pub.subscribe(self.mastodon_new_item, "mastodon.new_item")
|
pub.subscribe(self.mastodon_new_item, "mastodon.new_item")
|
||||||
pub.subscribe(self.mastodon_updated_item, "mastodon.updated_item")
|
pub.subscribe(self.mastodon_updated_item, "mastodon.updated_item")
|
||||||
pub.subscribe(self.mastodon_new_conversation, "mastodon.conversation_received")
|
pub.subscribe(self.mastodon_new_conversation, "mastodon.conversation_received")
|
||||||
|
pub.subscribe(self.mastodon_error_post, "mastodon.error_post")
|
||||||
|
|
||||||
# connect application events to GUI
|
# connect application events to GUI
|
||||||
widgetUtils.connect_event(self.view, widgetUtils.CLOSE_EVENT, self.exit_)
|
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.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.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.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.find, menuitem=self.view.find)
|
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.accountConfiguration, menuitem=self.view.account_settings)
|
||||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.configuration, menuitem=self.view.prefs)
|
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.configuration, menuitem=self.view.prefs)
|
||||||
@@ -156,13 +135,10 @@ class Controller(object):
|
|||||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.add_to_favourites, self.view.fav)
|
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.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_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.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.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.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.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.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.remove_buffer, self.view.deleteTl)
|
||||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.check_for_updates, self.view.check_for_updates)
|
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.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.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.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_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.toggle_buffer_mute, self.view.mute_buffer)
|
||||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.open_timeline, self.view.timeline)
|
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_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.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_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.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.manage_aliases, self.view.manageAliases)
|
||||||
|
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.report_error, self.view.reportError)
|
||||||
|
|
||||||
def set_systray_icon(self):
|
def set_systray_icon(self):
|
||||||
self.systrayIcon = sysTrayIcon.SysTrayIcon()
|
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.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.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.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.check_for_updates, menuitem=self.systrayIcon.check_for_updates)
|
||||||
widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.view_documentation, menuitem=self.systrayIcon.doc)
|
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):
|
def get_handler(self, type):
|
||||||
handler = self.handlers.get(type)
|
handler = self.handlers.get(type)
|
||||||
if handler == None:
|
if handler == None:
|
||||||
if type == "twitter":
|
if type == "mastodon":
|
||||||
handler = TwitterHandler.Handler()
|
|
||||||
elif type == "mastodon":
|
|
||||||
handler = MastodonHandler.Handler()
|
handler = MastodonHandler.Handler()
|
||||||
self.handlers[type]=handler
|
self.handlers[type]=handler
|
||||||
return handler
|
return handler
|
||||||
@@ -261,9 +231,9 @@ class Controller(object):
|
|||||||
if sessions.sessions[i].is_logged == False:
|
if sessions.sessions[i].is_logged == False:
|
||||||
self.create_ignored_session_buffer(sessions.sessions[i])
|
self.create_ignored_session_buffer(sessions.sessions[i])
|
||||||
continue
|
continue
|
||||||
# Valid types currently are twitter and mastodon (Work in progress)
|
# Valid types currently are mastodon (Work in progress)
|
||||||
# More can be added later.
|
# More can be added later.
|
||||||
valid_session_types = ["twitter", "mastodon"]
|
valid_session_types = ["mastodon"]
|
||||||
if sessions.sessions[i].type in valid_session_types:
|
if sessions.sessions[i].type in valid_session_types:
|
||||||
handler = self.get_handler(type=sessions.sessions[i].type)
|
handler = self.get_handler(type=sessions.sessions[i].type)
|
||||||
handler.create_buffers(sessions.sessions[i], controller=self)
|
handler.create_buffers(sessions.sessions[i], controller=self)
|
||||||
@@ -284,8 +254,6 @@ class Controller(object):
|
|||||||
if config.app["app-settings"]["speak_ready_msg"] == True:
|
if config.app["app-settings"]["speak_ready_msg"] == True:
|
||||||
output.speak(_(u"Ready"))
|
output.speak(_(u"Ready"))
|
||||||
self.started = True
|
self.started = True
|
||||||
self.streams_checker_function = RepeatingTimer(60, self.check_streams)
|
|
||||||
self.streams_checker_function.start()
|
|
||||||
if len(self.accounts) > 0:
|
if len(self.accounts) > 0:
|
||||||
b = self.get_first_buffer(self.accounts[0])
|
b = self.get_first_buffer(self.accounts[0])
|
||||||
self.update_menus(handler=self.get_handler(b.session.type))
|
self.update_menus(handler=self.get_handler(b.session.type))
|
||||||
@@ -405,21 +373,6 @@ class Controller(object):
|
|||||||
return output.speak(page.get_message(), True)
|
return output.speak(page.get_message(), True)
|
||||||
output.speak(_(u"{0} not found.").format(string,), 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):
|
def seekLeft(self, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
sound.URLPlayer.seek(-5000)
|
sound.URLPlayer.seek(-5000)
|
||||||
@@ -456,31 +409,6 @@ class Controller(object):
|
|||||||
buffer = self.get_best_buffer()
|
buffer = self.get_best_buffer()
|
||||||
SoundsTutorial.soundsTutorial(buffer.session)
|
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):
|
def configuration(self, *args, **kwargs):
|
||||||
""" Opens the global settings dialogue."""
|
""" Opens the global settings dialogue."""
|
||||||
d = settings.globalSettingsController()
|
d = settings.globalSettingsController()
|
||||||
@@ -526,10 +454,6 @@ class Controller(object):
|
|||||||
for item in sessions.sessions:
|
for item in sessions.sessions:
|
||||||
if sessions.sessions[item].logged == False:
|
if sessions.sessions[item].logged == False:
|
||||||
continue
|
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()
|
sessions.sessions[item].sound.cleaner.cancel()
|
||||||
log.debug("Saving database for " + sessions.sessions[item].session_id)
|
log.debug("Saving database for " + sessions.sessions[item].session_id)
|
||||||
sessions.sessions[item].save_persistent_data()
|
sessions.sessions[item].save_persistent_data()
|
||||||
@@ -537,9 +461,6 @@ class Controller(object):
|
|||||||
pidpath = os.path.join(os.getenv("temp"), "{}.pid".format(application.name))
|
pidpath = os.path.join(os.getenv("temp"), "{}.pid".format(application.name))
|
||||||
if os.path.exists(pidpath):
|
if os.path.exists(pidpath):
|
||||||
os.remove(pidpath)
|
os.remove(pidpath)
|
||||||
if hasattr(self, "streams_checker_function"):
|
|
||||||
log.debug("Stopping stream checker...")
|
|
||||||
self.streams_checker_function.cancel()
|
|
||||||
widgetUtils.exit_application()
|
widgetUtils.exit_application()
|
||||||
|
|
||||||
def follow(self, *args, **kwargs):
|
def follow(self, *args, **kwargs):
|
||||||
@@ -593,6 +514,11 @@ class Controller(object):
|
|||||||
if hasattr(buffer, "toggle_favorite"):
|
if hasattr(buffer, "toggle_favorite"):
|
||||||
return 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):
|
def view_item(self, *args, **kwargs):
|
||||||
buffer = self.get_current_buffer()
|
buffer = self.get_current_buffer()
|
||||||
if hasattr(buffer, "view_item"):
|
if hasattr(buffer, "view_item"):
|
||||||
@@ -636,19 +562,6 @@ class Controller(object):
|
|||||||
self.view.Show()
|
self.view.Show()
|
||||||
self.showing = True
|
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):
|
def get_more_items(self, *args, **kwargs):
|
||||||
buffer = self.get_current_buffer()
|
buffer = self.get_current_buffer()
|
||||||
if hasattr(buffer, "get_more_items"):
|
if hasattr(buffer, "get_more_items"):
|
||||||
@@ -801,7 +714,10 @@ class Controller(object):
|
|||||||
output.speak(msg, True)
|
output.speak(msg, True)
|
||||||
|
|
||||||
def next_account(self, *args, **kwargs):
|
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):
|
if index+1 == len(self.accounts):
|
||||||
index = 0
|
index = 0
|
||||||
else:
|
else:
|
||||||
@@ -826,7 +742,10 @@ class Controller(object):
|
|||||||
output.speak(msg, True)
|
output.speak(msg, True)
|
||||||
|
|
||||||
def previous_account(self, *args, **kwargs):
|
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:
|
if index-1 < 0:
|
||||||
index = len(self.accounts)-1
|
index = len(self.accounts)-1
|
||||||
else:
|
else:
|
||||||
@@ -941,70 +860,6 @@ class Controller(object):
|
|||||||
if message != None:
|
if message != None:
|
||||||
output.speak(message, speech=session.settings["reporting"]["speech_reporting"], braille=session.settings["reporting"]["braille_reporting"])
|
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):
|
def start_buffers(self, session):
|
||||||
log.debug("starting buffers... Session %s" % (session.session_id,))
|
log.debug("starting buffers... Session %s" % (session.session_id,))
|
||||||
handler = self.get_handler(type=session.type)
|
handler = self.get_handler(type=session.type)
|
||||||
@@ -1016,17 +871,6 @@ class Controller(object):
|
|||||||
for i in sessions.sessions:
|
for i in sessions.sessions:
|
||||||
self.set_buffer_positions(i)
|
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):
|
def invisible_shorcuts_changed(self, registered):
|
||||||
if registered == True:
|
if registered == True:
|
||||||
km = self.create_invisible_keyboard_shorcuts()
|
km = self.create_invisible_keyboard_shorcuts()
|
||||||
@@ -1087,17 +931,6 @@ class Controller(object):
|
|||||||
self.accounts.remove(sessions.sessions[i].get_name())
|
self.accounts.remove(sessions.sessions[i].get_name())
|
||||||
sessions.sessions.pop(i)
|
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):
|
def toggle_autoread(self, *args, **kwargs):
|
||||||
buffer = self.get_current_buffer()
|
buffer = self.get_current_buffer()
|
||||||
if hasattr(buffer, "session") and buffer.session == None:
|
if hasattr(buffer, "session") and buffer.session == None:
|
||||||
@@ -1162,16 +995,6 @@ class Controller(object):
|
|||||||
i.start_stream(mandatory=True)
|
i.start_stream(mandatory=True)
|
||||||
except Exception as err:
|
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))
|
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):
|
def update_buffer(self, *args, **kwargs):
|
||||||
bf = self.get_current_buffer()
|
bf = self.get_current_buffer()
|
||||||
@@ -1186,16 +1009,12 @@ class Controller(object):
|
|||||||
def buffer_title_changed(self, buffer):
|
def buffer_title_changed(self, buffer):
|
||||||
if buffer.name.endswith("-timeline"):
|
if buffer.name.endswith("-timeline"):
|
||||||
title = _(u"Timeline for {}").format(buffer.username,)
|
title = _(u"Timeline for {}").format(buffer.username,)
|
||||||
elif buffer.name.endswith("-favorite"):
|
|
||||||
title = _(u"Likes for {}").format(buffer.username,)
|
|
||||||
elif buffer.name.endswith("-followers"):
|
elif buffer.name.endswith("-followers"):
|
||||||
title = _(u"Followers for {}").format(buffer.username,)
|
title = _(u"Followers for {}").format(buffer.username,)
|
||||||
elif buffer.name.endswith("-friends"):
|
elif buffer.name.endswith("-friends"):
|
||||||
title = _(u"Friends for {}").format(buffer.username,)
|
title = _(u"Friends for {}").format(buffer.username,)
|
||||||
elif buffer.name.endswith("-following"):
|
elif buffer.name.endswith("-following"):
|
||||||
title = _(u"Following for {}").format(buffer.username,)
|
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)
|
buffer_index = self.view.search(buffer.name, buffer.account)
|
||||||
self.view.set_page_title(buffer_index, title)
|
self.view.set_page_title(buffer_index, title)
|
||||||
|
|
||||||
@@ -1204,55 +1023,13 @@ class Controller(object):
|
|||||||
if hasattr(buffer, "ocr_image"):
|
if hasattr(buffer, "ocr_image"):
|
||||||
return 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):
|
def save_data_in_db(self):
|
||||||
for i in sessions.sessions:
|
for i in sessions.sessions:
|
||||||
sessions.sessions[i].save_persistent_data()
|
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):
|
def toggle_share_settings(self, shareable=True):
|
||||||
self.view.share.Enable(shareable)
|
self.view.share.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()
|
|
||||||
|
|
||||||
def mastodon_new_item(self, item, session_name, _buffers):
|
def mastodon_new_item(self, item, session_name, _buffers):
|
||||||
sound_to_play = None
|
sound_to_play = None
|
||||||
for buff in _buffers:
|
for buff in _buffers:
|
||||||
@@ -1292,4 +1069,19 @@ class Controller(object):
|
|||||||
# if number_of_items > 0:
|
# if number_of_items > 0:
|
||||||
# sound_to_play = "dm_received.ogg"
|
# sound_to_play = "dm_received.ogg"
|
||||||
# if "direct_messages" not in buffer.session.settings["other_buffers"]["muted_buffers"]:
|
# 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 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import wx
|
import wx
|
||||||
import logging
|
import logging
|
||||||
|
import output
|
||||||
from pubsub import pub
|
from pubsub import pub
|
||||||
from mysc import restart
|
from mysc import restart
|
||||||
from wxUI.dialogs.mastodon import dialogs
|
|
||||||
from wxUI.dialogs.mastodon import search as search_dialogs
|
from wxUI.dialogs.mastodon import search as search_dialogs
|
||||||
from wxUI.dialogs.mastodon import dialogs
|
from wxUI.dialogs.mastodon import dialogs
|
||||||
|
from wxUI.dialogs import userAliasDialogs
|
||||||
from wxUI import commonMessageDialogs
|
from wxUI import commonMessageDialogs
|
||||||
from sessions.twitter import utils
|
|
||||||
from . import userActions, settings
|
from . import userActions, settings
|
||||||
|
|
||||||
log = logging.getLogger("controller.mastodon.handler")
|
log = logging.getLogger("controller.mastodon.handler")
|
||||||
@@ -23,7 +23,7 @@ class Handler(object):
|
|||||||
updateProfile=None,
|
updateProfile=None,
|
||||||
menuitem_search=_("&Search"),
|
menuitem_search=_("&Search"),
|
||||||
lists=None,
|
lists=None,
|
||||||
manageAliases=None,
|
manageAliases=_("Manage user aliases"),
|
||||||
# In item menu.
|
# In item menu.
|
||||||
compose=_("&Post"),
|
compose=_("&Post"),
|
||||||
reply=_("Re&ply"),
|
reply=_("Re&ply"),
|
||||||
@@ -31,18 +31,16 @@ class Handler(object):
|
|||||||
fav=_("&Add to favorites"),
|
fav=_("&Add to favorites"),
|
||||||
unfav=_("Remove from favorites"),
|
unfav=_("Remove from favorites"),
|
||||||
view=_("&Show post"),
|
view=_("&Show post"),
|
||||||
view_coordinates=None,
|
|
||||||
view_conversation=_("View conversa&tion"),
|
view_conversation=_("View conversa&tion"),
|
||||||
ocr=None,
|
ocr=_("Read text in picture"),
|
||||||
delete=_("&Delete"),
|
delete=_("&Delete"),
|
||||||
# In user menu.
|
# In user menu.
|
||||||
follow=_("&Actions..."),
|
follow=_("&Actions..."),
|
||||||
timeline=_("&View timeline..."),
|
timeline=_("&View timeline..."),
|
||||||
dm=_("Direct me&ssage"),
|
dm=_("Direct me&ssage"),
|
||||||
addAlias=None,
|
addAlias=_("Add a&lias"),
|
||||||
addToList=None,
|
addToList=None,
|
||||||
removeFromList=None,
|
removeFromList=None,
|
||||||
viewLists=None,
|
|
||||||
details=None,
|
details=None,
|
||||||
favs=None,
|
favs=None,
|
||||||
# In buffer Menu.
|
# In buffer Menu.
|
||||||
@@ -227,3 +225,33 @@ class Handler(object):
|
|||||||
buffer.session.settings.write()
|
buffer.session.settings.write()
|
||||||
buffer.session.save_persistent_data()
|
buffer.session.save_persistent_data()
|
||||||
restart.restart_program()
|
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 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import wx
|
import wx
|
||||||
import widgetUtils
|
import widgetUtils
|
||||||
import config
|
import config
|
||||||
import output
|
import output
|
||||||
from controller.twitter import messages
|
from twitter_text import parse_tweet, config
|
||||||
|
from controller import messages
|
||||||
from sessions.mastodon import templates
|
from sessions.mastodon import templates
|
||||||
from wxUI.dialogs.mastodon import postDialogs
|
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):
|
def __init__(self, session, title, caption, text="", *args, **kwargs):
|
||||||
# take max character limit from session as this might be different for some instances.
|
# take max character limit from session as this might be different for some instances.
|
||||||
self.max = session.char_limit
|
self.max = session.char_limit
|
||||||
@@ -19,6 +34,7 @@ class post(messages.basicTweet):
|
|||||||
self.message.text.SetInsertionPoint(len(self.message.text.GetValue()))
|
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.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck)
|
||||||
widgetUtils.connect_event(self.message.text, widgetUtils.ENTERED_TEXT, self.text_processor)
|
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.translate, widgetUtils.BUTTON_PRESSED, self.translate)
|
||||||
widgetUtils.connect_event(self.message.add, widgetUtils.BUTTON_PRESSED, self.on_attach)
|
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)
|
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)
|
self.add_post(event=None, update_gui=False)
|
||||||
return self.thread
|
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):
|
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 len(self.thread) > 0:
|
||||||
if hasattr(self.message, "posts"):
|
if hasattr(self.message, "posts"):
|
||||||
self.message.posts.Enable(True)
|
self.message.posts.Enable(True)
|
||||||
@@ -127,9 +167,9 @@ class post(messages.basicTweet):
|
|||||||
break
|
break
|
||||||
if can_attach == False or big_media_present == True:
|
if can_attach == False or big_media_present == True:
|
||||||
return self.message.unable_to_attach_file()
|
return self.message.unable_to_attach_file()
|
||||||
video = self.message.get_video()
|
video, description = self.message.get_video()
|
||||||
if video != None:
|
if video != None:
|
||||||
videoInfo = {"type": "video", "file": video, "description": ""}
|
videoInfo = {"type": "video", "file": video, "description": description}
|
||||||
self.attachments.append(videoInfo)
|
self.attachments.append(videoInfo)
|
||||||
self.message.add_item(item=[os.path.basename(videoInfo["file"]), videoInfo["type"], videoInfo["description"]])
|
self.message.add_item(item=[os.path.basename(videoInfo["file"]), videoInfo["type"], videoInfo["description"]])
|
||||||
self.text_processor()
|
self.text_processor()
|
||||||
@@ -145,9 +185,9 @@ class post(messages.basicTweet):
|
|||||||
break
|
break
|
||||||
if can_attach == False or big_media_present == True:
|
if can_attach == False or big_media_present == True:
|
||||||
return self.message.unable_to_attach_file()
|
return self.message.unable_to_attach_file()
|
||||||
audio = self.message.get_audio()
|
audio, description = self.message.get_audio()
|
||||||
if audio != None:
|
if audio != None:
|
||||||
audioInfo = {"type": "audio", "file": audio, "description": ""}
|
audioInfo = {"type": "audio", "file": audio, "description": description}
|
||||||
self.attachments.append(audioInfo)
|
self.attachments.append(audioInfo)
|
||||||
self.message.add_item(item=[os.path.basename(audioInfo["file"]), audioInfo["type"], audioInfo["description"]])
|
self.message.add_item(item=[os.path.basename(audioInfo["file"]), audioInfo["type"], audioInfo["description"]])
|
||||||
self.text_processor()
|
self.text_processor()
|
||||||
@@ -229,4 +269,12 @@ class viewPost(post):
|
|||||||
def share(self, *args, **kwargs):
|
def share(self, *args, **kwargs):
|
||||||
if hasattr(self, "item_url"):
|
if hasattr(self, "item_url"):
|
||||||
output.copy(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 collections import OrderedDict
|
||||||
from wxUI import commonMessageDialogs
|
from wxUI import commonMessageDialogs
|
||||||
from wxUI.dialogs.mastodon import configuration
|
from wxUI.dialogs.mastodon import configuration
|
||||||
from extra.autocompletionUsers import scan, manage
|
#from extra.autocompletionUsers import scan, manage
|
||||||
from extra.ocr import OCRSpace
|
from extra.ocr import OCRSpace
|
||||||
from controller.settings import globalSettingsController
|
from controller.settings import globalSettingsController
|
||||||
from . templateEditor import EditTemplate
|
from . templateEditor import EditTemplate
|
||||||
@@ -31,6 +31,7 @@ class accountSettingsController(globalSettingsController):
|
|||||||
self.dialog.create_general_account()
|
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.userAutocompletionScan, widgetUtils.BUTTON_PRESSED, self.on_autocompletion_scan)
|
||||||
# widgetUtils.connect_event(self.dialog.general.userAutocompletionManage, widgetUtils.BUTTON_PRESSED, self.on_autocompletion_manage)
|
# 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", "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", "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", "show_screen_names", self.config["general"]["show_screen_names"])
|
||||||
@@ -112,6 +113,10 @@ class accountSettingsController(globalSettingsController):
|
|||||||
self.needs_restart = True
|
self.needs_restart = True
|
||||||
log.debug("Triggered app restart due to change in relative times.")
|
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"]["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"]["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"]["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"]["hide_emojis"] = self.dialog.get_value("general", "hide_emojis")
|
||||||
|
@@ -3,7 +3,7 @@ import re
|
|||||||
import wx
|
import wx
|
||||||
from typing import List
|
from typing import List
|
||||||
from sessions.mastodon.templates import post_variables, conversation_variables, person_variables
|
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):
|
class EditTemplate(object):
|
||||||
def __init__(self, template: str, type: str) -> None:
|
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 wxUI.dialogs.mastodon import userTimeline as userTimelineDialog
|
||||||
from pubsub import pub
|
from pubsub import pub
|
||||||
from mastodon import MastodonError, MastodonNotFoundError
|
from mastodon import MastodonError, MastodonNotFoundError
|
||||||
from extra.autocompletionUsers import completion
|
#from extra.autocompletionUsers import completion
|
||||||
|
|
||||||
log = logging.getLogger("controller.mastodon.userActions")
|
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,377 +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__()
|
|
||||||
# Structure to hold names for menu bar items.
|
|
||||||
# empty names mean the item will be Disabled.
|
|
||||||
self.menus = dict(
|
|
||||||
# In application menu.
|
|
||||||
updateProfile=_("&Update profile"),
|
|
||||||
menuitem_search=_("&Search"),
|
|
||||||
lists=_("&Lists manager"),
|
|
||||||
manageAliases=_("Manage user aliases"),
|
|
||||||
# In Item Menu.
|
|
||||||
compose=_("&Tweet"),
|
|
||||||
reply=_("Re&ply"),
|
|
||||||
share=_("&Retweet"),
|
|
||||||
fav=_("&Like"),
|
|
||||||
unfav=_("&Unlike"),
|
|
||||||
view=_("&Show tweet"),
|
|
||||||
view_coordinates=_("View &address"),
|
|
||||||
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=_("&Add to list"),
|
|
||||||
removeFromList=_("R&emove from list"),
|
|
||||||
viewLists=_("&View lists"),
|
|
||||||
details=_("Show user &profile"),
|
|
||||||
favs=_("View likes"),
|
|
||||||
# In buffer menu.
|
|
||||||
trends=_("New &trending topics buffer..."),
|
|
||||||
filter=_("Create a &filter"),
|
|
||||||
manage_filters=_("&Manage filters"),
|
|
||||||
)
|
|
||||||
# Name for the "tweet" menu in the menu bar.
|
|
||||||
self.item_menu = _("&Tweet")
|
|
||||||
|
|
||||||
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)
|
|
||||||
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)
|
|
@@ -1,85 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import widgetUtils
|
|
||||||
import output
|
|
||||||
from wxUI.dialogs import userActions
|
|
||||||
from pubsub import pub
|
|
||||||
from tweepy.errors import TweepyException
|
|
||||||
from extra.autocompletionUsers import completion
|
|
||||||
|
|
||||||
class userActionsController(object):
|
|
||||||
def __init__(self, buffer, users=[], default="follow"):
|
|
||||||
super(userActionsController, self).__init__()
|
|
||||||
self.buffer = buffer
|
|
||||||
self.session = buffer.session
|
|
||||||
self.dialog = userActions.UserActionsDialog(users, default)
|
|
||||||
widgetUtils.connect_event(self.dialog.autocompletion, widgetUtils.BUTTON_PRESSED, self.autocomplete_users)
|
|
||||||
if self.dialog.get_response() == widgetUtils.OK:
|
|
||||||
self.process_action()
|
|
||||||
|
|
||||||
def autocomplete_users(self, *args, **kwargs):
|
|
||||||
c = completion.autocompletionUsers(self.dialog, self.session.session_id)
|
|
||||||
c.show_menu("dm")
|
|
||||||
|
|
||||||
def process_action(self):
|
|
||||||
action = self.dialog.get_action()
|
|
||||||
user = self.dialog.get_user()
|
|
||||||
if user == "": return
|
|
||||||
getattr(self, action)(user)
|
|
||||||
|
|
||||||
def follow(self, user):
|
|
||||||
try:
|
|
||||||
self.session.twitter.create_friendship(screen_name=user )
|
|
||||||
pub.sendMessage("twitter.restart_streaming", session=self.session.session_id)
|
|
||||||
except TweepyException as err:
|
|
||||||
output.speak("Error %s" % (str(err)), True)
|
|
||||||
|
|
||||||
def unfollow(self, user):
|
|
||||||
try:
|
|
||||||
id = self.session.twitter.destroy_friendship(screen_name=user )
|
|
||||||
pub.sendMessage("twitter.restart_streaming", session=self.session.session_id)
|
|
||||||
except TweepyException as err:
|
|
||||||
output.speak("Error %s" % (str(err)), True)
|
|
||||||
|
|
||||||
def mute(self, user):
|
|
||||||
try:
|
|
||||||
id = self.session.twitter.create_mute(screen_name=user )
|
|
||||||
pub.sendMessage("twitter.restart_streaming", session=self.session.session_id)
|
|
||||||
except TweepyException as err:
|
|
||||||
output.speak("Error %s" % (str(err)), True)
|
|
||||||
|
|
||||||
def unmute(self, user):
|
|
||||||
try:
|
|
||||||
id = self.session.twitter.destroy_mute(screen_name=user )
|
|
||||||
pub.sendMessage("twitter.restart_streaming", session=self.session.session_id)
|
|
||||||
except TweepyException as err:
|
|
||||||
output.speak("Error %s" % (str(err)), True)
|
|
||||||
|
|
||||||
def report(self, user):
|
|
||||||
try:
|
|
||||||
id = self.session.twitter.report_spam(screen_name=user )
|
|
||||||
pub.sendMessage("twitter.restart_streaming", session=self.session.session_id)
|
|
||||||
except TweepyException as err:
|
|
||||||
output.speak("Error %s" % (str(err)), True)
|
|
||||||
|
|
||||||
def block(self, user):
|
|
||||||
try:
|
|
||||||
id = self.session.twitter.create_block(screen_name=user )
|
|
||||||
pub.sendMessage("twitter.restart_streaming", session=self.session.session_id)
|
|
||||||
except TweepyException as err:
|
|
||||||
output.speak("Error %s" % (str(err)), True)
|
|
||||||
|
|
||||||
def unblock(self, user):
|
|
||||||
try:
|
|
||||||
id = self.session.twitter.destroy_block(screen_name=user )
|
|
||||||
except TweepyException as err:
|
|
||||||
output.speak("Error %s" % (str(err)), True)
|
|
||||||
|
|
||||||
def ignore_client(self, user):
|
|
||||||
tweet = self.buffer.get_right_tweet()
|
|
||||||
if hasattr(tweet, "sender"):
|
|
||||||
output.speak(_(u"You can't ignore direct messages"))
|
|
||||||
return
|
|
||||||
client = tweet.source
|
|
||||||
if client not in self.session.settings["twitter"]["ignored_clients"]:
|
|
||||||
self.session.settings["twitter"]["ignored_clients"].append(client)
|
|
||||||
self.session.settings.write()
|
|
@@ -1,39 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
""" Small utility dessigned to select users from the currently focused item or the autocomplete database. """
|
|
||||||
import wx
|
|
||||||
import widgetUtils
|
|
||||||
from wxUI.dialogs import utils
|
|
||||||
from extra.autocompletionUsers import completion
|
|
||||||
|
|
||||||
class userSelector(object):
|
|
||||||
|
|
||||||
def __init__(self, users, session_id, title=_("Select user")):
|
|
||||||
""" Creates a dialog that chooses an user selector, from where users who have the autocomplete database already filled can also use that feature.
|
|
||||||
|
|
||||||
:param users: lists of users extracted from the currently focused item.
|
|
||||||
:type users: list
|
|
||||||
:param session_id: ID of the session to instantiate autocomplete database.
|
|
||||||
:type session_id: str
|
|
||||||
:param title: Title of the user selector dialog.
|
|
||||||
:type title: str
|
|
||||||
"""
|
|
||||||
self.session_id = session_id
|
|
||||||
self.dlg = utils.selectUserDialog(users=users, title=title)
|
|
||||||
widgetUtils.connect_event(self.dlg.autocompletion, widgetUtils.BUTTON_PRESSED, self.on_autocomplete_users)
|
|
||||||
|
|
||||||
def on_autocomplete_users(self, *args, **kwargs):
|
|
||||||
""" performs user autocompletion, if configured properly. """
|
|
||||||
c = completion.autocompletionUsers(self.dlg, self.session_id)
|
|
||||||
c.show_menu("dm")
|
|
||||||
|
|
||||||
def get_user(self):
|
|
||||||
""" Actually shows the dialog and returns an user if the dialog was accepted, None otherwise.
|
|
||||||
|
|
||||||
:rtype: str or None
|
|
||||||
"""
|
|
||||||
if self.dlg.ShowModal() == wx.ID_OK:
|
|
||||||
user = self.dlg.get_user()
|
|
||||||
else:
|
|
||||||
user = None
|
|
||||||
self.dlg.Destroy()
|
|
||||||
return user
|
|
@@ -1,182 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
############################################################
|
|
||||||
# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo <manuel@manuelcortez.net>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
############################################################
|
|
||||||
from __future__ import absolute_import
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
from builtins import str
|
|
||||||
from builtins import object
|
|
||||||
import widgetUtils
|
|
||||||
from . import wx_ui
|
|
||||||
from . import wx_transfer_dialogs
|
|
||||||
from . import transfer
|
|
||||||
import output
|
|
||||||
import tempfile
|
|
||||||
import sound
|
|
||||||
import os
|
|
||||||
import config
|
|
||||||
from pubsub import pub
|
|
||||||
from mysc.thread_utils import call_threaded
|
|
||||||
import sound_lib
|
|
||||||
import logging
|
|
||||||
|
|
||||||
log = logging.getLogger("extra.AudioUploader.audioUploader")
|
|
||||||
|
|
||||||
class audioUploader(object):
|
|
||||||
def __init__(self, configFile, completed_callback):
|
|
||||||
self.config = configFile
|
|
||||||
super(audioUploader, self).__init__()
|
|
||||||
self.dialog = wx_ui.audioDialog(services=self.get_available_services())
|
|
||||||
self.file = None
|
|
||||||
self.recorded = False
|
|
||||||
self.recording = None
|
|
||||||
self.playing = None
|
|
||||||
widgetUtils.connect_event(self.dialog.play, widgetUtils.BUTTON_PRESSED, self.on_play)
|
|
||||||
widgetUtils.connect_event(self.dialog.pause, widgetUtils.BUTTON_PRESSED, self.on_pause)
|
|
||||||
widgetUtils.connect_event(self.dialog.record, widgetUtils.BUTTON_PRESSED, self.on_record)
|
|
||||||
widgetUtils.connect_event(self.dialog.attach_exists, widgetUtils.BUTTON_PRESSED, self.on_attach_exists)
|
|
||||||
widgetUtils.connect_event(self.dialog.discard, widgetUtils.BUTTON_PRESSED, self.on_discard)
|
|
||||||
if self.dialog.get_response() == widgetUtils.OK:
|
|
||||||
self.postprocess()
|
|
||||||
log.debug("Uploading file %s to %s..." % (self.file, self.dialog.get("services")))
|
|
||||||
self.uploaderDialog = wx_transfer_dialogs.UploadDialog(self.file)
|
|
||||||
output.speak(_(u"Attaching..."))
|
|
||||||
if self.dialog.get("services") == "SNDUp":
|
|
||||||
base_url = "https://sndup.net/post.php"
|
|
||||||
if len(self.config["sound"]["sndup_api_key"]) > 0:
|
|
||||||
url = base_url + '?apikey=' + self.config['sound']['sndup_api_key']
|
|
||||||
else:
|
|
||||||
url = base_url
|
|
||||||
self.uploaderFunction = transfer.Upload(obj=self, field='file', url=url, filename=self.file, completed_callback=completed_callback)
|
|
||||||
pub.subscribe(self.uploaderDialog.update, "uploading")
|
|
||||||
self.uploaderDialog.get_response(self.uploaderFunction.perform_threaded)
|
|
||||||
|
|
||||||
def get_available_services(self):
|
|
||||||
services = []
|
|
||||||
services.append("SNDUp")
|
|
||||||
return services
|
|
||||||
|
|
||||||
def on_pause(self, *args, **kwargs):
|
|
||||||
if self.dialog.get("pause") == _(u"Pause"):
|
|
||||||
self.recording.pause()
|
|
||||||
self.dialog.set("pause", _(u"&Resume"))
|
|
||||||
elif self.dialog.get("pause") == _(u"Resume"):
|
|
||||||
self.recording.play()
|
|
||||||
self.dialog.set("pause", _(U"&Pause"))
|
|
||||||
|
|
||||||
def on_record(self, *args, **kwargs):
|
|
||||||
if self.recording != None:
|
|
||||||
self.stop_recording()
|
|
||||||
self.dialog.disable_control("pause")
|
|
||||||
else:
|
|
||||||
self.start_recording()
|
|
||||||
self.dialog.enable_control("pause")
|
|
||||||
|
|
||||||
def start_recording(self):
|
|
||||||
self.dialog.disable_control("attach_exists")
|
|
||||||
self.file = tempfile.mktemp(suffix='.wav')
|
|
||||||
self.recording = sound.recording(self.file)
|
|
||||||
self.recording.play()
|
|
||||||
self.dialog.set("record", _(u"&Stop"))
|
|
||||||
output.speak(_(u"Recording"))
|
|
||||||
|
|
||||||
def stop_recording(self):
|
|
||||||
self.recording.stop()
|
|
||||||
self.recording.free()
|
|
||||||
output.speak(_(u"Stopped"))
|
|
||||||
self.recorded = True
|
|
||||||
self.dialog.set("record", _(u"&Record"))
|
|
||||||
self.file_attached()
|
|
||||||
|
|
||||||
def file_attached(self):
|
|
||||||
self.dialog.set("pause", _(u"&Pause"))
|
|
||||||
self.dialog.disable_control("record")
|
|
||||||
self.dialog.enable_control("play")
|
|
||||||
self.dialog.enable_control("discard")
|
|
||||||
self.dialog.disable_control("attach_exists")
|
|
||||||
self.dialog.enable_control("attach")
|
|
||||||
self.dialog.play.SetFocus()
|
|
||||||
|
|
||||||
def on_discard(self, *args, **kwargs):
|
|
||||||
if self.playing:
|
|
||||||
self._stop()
|
|
||||||
if self.recording != None:
|
|
||||||
self.cleanup()
|
|
||||||
self.dialog.disable_control("attach")
|
|
||||||
self.dialog.disable_control("play")
|
|
||||||
self.file = None
|
|
||||||
self.dialog.enable_control("record")
|
|
||||||
self.dialog.enable_control("attach_exists")
|
|
||||||
self.dialog.record.SetFocus()
|
|
||||||
self.dialog.disable_control("discard")
|
|
||||||
self.recording = None
|
|
||||||
output.speak(_(u"Discarded"))
|
|
||||||
|
|
||||||
def on_play(self, *args, **kwargs):
|
|
||||||
if not self.playing:
|
|
||||||
call_threaded(self._play)
|
|
||||||
else:
|
|
||||||
self._stop()
|
|
||||||
|
|
||||||
def _play(self):
|
|
||||||
output.speak(_(u"Playing..."))
|
|
||||||
# try:
|
|
||||||
self.playing = sound_lib.stream.FileStream(file=str(self.file), flags=sound_lib.stream.BASS_UNICODE)
|
|
||||||
self.playing.play()
|
|
||||||
self.dialog.set("play", _(u"&Stop"))
|
|
||||||
try:
|
|
||||||
while self.playing.is_playing:
|
|
||||||
pass
|
|
||||||
self.dialog.set("play", _(u"&Play"))
|
|
||||||
self.playing.free()
|
|
||||||
self.playing = None
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _stop(self):
|
|
||||||
output.speak(_(u"Stopped"))
|
|
||||||
self.playing.stop()
|
|
||||||
self.playing.free()
|
|
||||||
self.dialog.set("play", _(u"&Play"))
|
|
||||||
self.playing = None
|
|
||||||
|
|
||||||
def postprocess(self):
|
|
||||||
if self.file.lower().endswith('.wav'):
|
|
||||||
output.speak(_(u"Recoding audio..."))
|
|
||||||
sound.recode_audio(self.file)
|
|
||||||
self.wav_file = self.file
|
|
||||||
self.file = '%s.ogg' % self.file[:-4]
|
|
||||||
|
|
||||||
def cleanup(self):
|
|
||||||
if self.playing and self.playing.is_playing:
|
|
||||||
self.playing.stop()
|
|
||||||
if self.recording != None:
|
|
||||||
if self.recording.is_playing:
|
|
||||||
self.recording.stop()
|
|
||||||
try:
|
|
||||||
self.recording.free()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
os.remove(self.file)
|
|
||||||
if hasattr(self, 'wav_file'):
|
|
||||||
os.remove(self.wav_file)
|
|
||||||
|
|
||||||
def on_attach_exists(self, *args, **kwargs):
|
|
||||||
self.file = self.dialog.get_file()
|
|
||||||
if self.file != False:
|
|
||||||
self.file_attached()
|
|
||||||
|
|
@@ -1,88 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import absolute_import
|
|
||||||
from __future__ import division
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
from builtins import object
|
|
||||||
from past.utils import old_div
|
|
||||||
import sys
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
import logging
|
|
||||||
from .utils import convert_bytes
|
|
||||||
from pubsub import pub
|
|
||||||
log = logging.getLogger("extra.AudioUploader.transfer")
|
|
||||||
from requests_toolbelt.multipart.encoder import MultipartEncoder, MultipartEncoderMonitor
|
|
||||||
import requests
|
|
||||||
import os
|
|
||||||
class Upload(object):
|
|
||||||
def __init__(self, field=None, obj=None, url=None, filename=None, follow_location=True, completed_callback=None, verbose=False, *args, **kwargs):
|
|
||||||
super(Upload, self).__init__(*args, **kwargs)
|
|
||||||
self.url=url
|
|
||||||
self.filename=filename
|
|
||||||
log.debug("Uploading audio to %s, filename %s" % (url, filename))
|
|
||||||
self.start_time = None
|
|
||||||
self.completed_callback = completed_callback
|
|
||||||
self.background_thread = None
|
|
||||||
self.transfer_rate = 0
|
|
||||||
self.local_filename=os.path.basename(self.filename)
|
|
||||||
if isinstance(self.local_filename, str):
|
|
||||||
self.local_filename=self.local_filename.encode(sys.getfilesystemencoding())
|
|
||||||
self.fin=open(self.filename, 'rb')
|
|
||||||
self.m = MultipartEncoder(fields={field:(self.local_filename, self.fin, "application/octet-stream")})
|
|
||||||
self.monitor = MultipartEncoderMonitor(self.m, self.progress_callback)
|
|
||||||
self.response=None
|
|
||||||
self.obj=obj
|
|
||||||
self.follow_location=follow_location
|
|
||||||
#the verbose parameter is deprecated and will be removed soon
|
|
||||||
|
|
||||||
def elapsed_time(self):
|
|
||||||
if not self.start_time:
|
|
||||||
return 0
|
|
||||||
return time.time() - self.start_time
|
|
||||||
|
|
||||||
def progress_callback(self, monitor):
|
|
||||||
progress = {}
|
|
||||||
progress["total"] = monitor.len
|
|
||||||
progress["current"] = monitor.bytes_read
|
|
||||||
if progress["current"] == 0:
|
|
||||||
progress["percent"] = 0
|
|
||||||
self.transfer_rate = 0
|
|
||||||
else:
|
|
||||||
progress["percent"] = int((float(progress["current"]) / progress["total"]) * 100)
|
|
||||||
self.transfer_rate = old_div(progress["current"], self.elapsed_time())
|
|
||||||
progress["speed"] = '%s/s' % convert_bytes(self.transfer_rate)
|
|
||||||
if self.transfer_rate:
|
|
||||||
progress["eta"] = old_div((progress["total"] - progress["current"]), self.transfer_rate)
|
|
||||||
else:
|
|
||||||
progress["eta"] = 0
|
|
||||||
pub.sendMessage("uploading", data=progress)
|
|
||||||
|
|
||||||
def perform_transfer(self):
|
|
||||||
log.debug("starting upload...")
|
|
||||||
self.start_time = time.time()
|
|
||||||
self.response=requests.post(url=self.url, data=self.monitor, headers={"Content-Type":self.m.content_type}, allow_redirects=self.follow_location, stream=True)
|
|
||||||
log.debug("Upload finished.")
|
|
||||||
self.complete_transfer()
|
|
||||||
|
|
||||||
def perform_threaded(self, *args, **kwargs):
|
|
||||||
self.background_thread = threading.Thread(target=self.perform_transfer)
|
|
||||||
self.background_thread.daemon = True
|
|
||||||
self.background_thread.start()
|
|
||||||
|
|
||||||
def complete_transfer(self):
|
|
||||||
if callable(self.completed_callback):
|
|
||||||
self.completed_callback(self.obj)
|
|
||||||
if hasattr(self,'fin') and callable(self.fin.close):
|
|
||||||
self.fin.close()
|
|
||||||
|
|
||||||
def get_url(self):
|
|
||||||
try:
|
|
||||||
data = self.response.json()
|
|
||||||
except:
|
|
||||||
return _("Error in file upload: {0}").format(self.data.content,)
|
|
||||||
if "url" in data and data["url"] != "0":
|
|
||||||
return data["url"]
|
|
||||||
elif "error" in data and data["error"] != "0":
|
|
||||||
return data["error"]
|
|
||||||
else:
|
|
||||||
return _("Error in file upload: {0}").format(self.data.content,)
|
|
@@ -1,44 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
from builtins import str
|
|
||||||
def convert_bytes(n):
|
|
||||||
K, M, G, T, P = 1 << 10, 1 << 20, 1 << 30, 1 << 40, 1 << 50
|
|
||||||
if n >= P:
|
|
||||||
return '%.2fPb' % (float(n) / T)
|
|
||||||
elif n >= T:
|
|
||||||
return '%.2fTb' % (float(n) / T)
|
|
||||||
elif n >= G:
|
|
||||||
return '%.2fGb' % (float(n) / G)
|
|
||||||
elif n >= M:
|
|
||||||
return '%.2fMb' % (float(n) / M)
|
|
||||||
elif n >= K:
|
|
||||||
return '%.2fKb' % (float(n) / K)
|
|
||||||
else:
|
|
||||||
return '%d' % n
|
|
||||||
|
|
||||||
def seconds_to_string(seconds, precision=0):
|
|
||||||
day = seconds // 86400
|
|
||||||
hour = seconds // 3600
|
|
||||||
min = (seconds // 60) % 60
|
|
||||||
sec = seconds - (hour * 3600) - (min * 60)
|
|
||||||
sec_spec = "." + str(precision) + "f"
|
|
||||||
sec_string = sec.__format__(sec_spec)
|
|
||||||
string = ""
|
|
||||||
if day == 1:
|
|
||||||
string += _(u"%d day, ") % day
|
|
||||||
elif day >= 2:
|
|
||||||
string += _(u"%d days, ") % day
|
|
||||||
if (hour == 1):
|
|
||||||
string += _(u"%d hour, ") % hour
|
|
||||||
elif (hour >= 2):
|
|
||||||
string += _("%d hours, ") % hour
|
|
||||||
if (min == 1):
|
|
||||||
string += _(u"%d minute, ") % min
|
|
||||||
elif (min >= 2):
|
|
||||||
string += _(u"%d minutes, ") % min
|
|
||||||
if sec >= 0 and sec <= 2:
|
|
||||||
string += _(u"%s second") % sec_string
|
|
||||||
else:
|
|
||||||
string += _(u"%s seconds") % sec_string
|
|
||||||
return string
|
|
@@ -1,63 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import absolute_import
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import wx
|
|
||||||
from .utils import *
|
|
||||||
import widgetUtils
|
|
||||||
|
|
||||||
class UploadDialog(widgetUtils.BaseDialog):
|
|
||||||
|
|
||||||
def __init__(self, filename, *args, **kwargs):
|
|
||||||
super(UploadDialog, self).__init__(parent=None, id=wx.ID_ANY, *args, **kwargs)
|
|
||||||
self.pane = wx.Panel(self)
|
|
||||||
self.progress_bar = wx.Gauge(parent=self.pane)
|
|
||||||
fileBox = wx.BoxSizer(wx.HORIZONTAL)
|
|
||||||
fileLabel = wx.StaticText(self.pane, -1, _(u"File"))
|
|
||||||
self.file = wx.TextCtrl(self.pane, -1, value=filename, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(200, 100))
|
|
||||||
self.file.SetFocus()
|
|
||||||
fileBox.Add(fileLabel)
|
|
||||||
fileBox.Add(self.file)
|
|
||||||
currentAmountBox = wx.BoxSizer(wx.HORIZONTAL)
|
|
||||||
current_amount_label = wx.StaticText(self.pane, -1, _(u"Transferred"))
|
|
||||||
self.current_amount = wx.TextCtrl(self.pane, -1, value='0', style=wx.TE_READONLY|wx.TE_MULTILINE)
|
|
||||||
currentAmountBox.Add(current_amount_label)
|
|
||||||
currentAmountBox.Add(self.current_amount)
|
|
||||||
totalSizeBox = wx.BoxSizer(wx.HORIZONTAL)
|
|
||||||
total_size_label = wx.StaticText(self.pane, -1, _(u"Total file size"))
|
|
||||||
self.total_size = wx.TextCtrl(self.pane, -1, value='0', style=wx.TE_READONLY|wx.TE_MULTILINE)
|
|
||||||
totalSizeBox.Add(total_size_label)
|
|
||||||
totalSizeBox.Add(self.total_size)
|
|
||||||
speedBox = wx.BoxSizer(wx.HORIZONTAL)
|
|
||||||
speedLabel = wx.StaticText(self.pane, -1, _(u"Transfer rate"))
|
|
||||||
self.speed = wx.TextCtrl(self.pane, -1, style=wx.TE_READONLY|wx.TE_MULTILINE, value="0 Kb/s")
|
|
||||||
speedBox.Add(speedLabel)
|
|
||||||
speedBox.Add(self.speed)
|
|
||||||
etaBox = wx.BoxSizer(wx.HORIZONTAL)
|
|
||||||
etaLabel = wx.StaticText(self.pane, -1, _(u"Time left"))
|
|
||||||
self.eta = wx.TextCtrl(self.pane, -1, style=wx.TE_READONLY|wx.TE_MULTILINE, value="Unknown", size=(200, 100))
|
|
||||||
etaBox.Add(etaLabel)
|
|
||||||
etaBox.Add(self.eta)
|
|
||||||
self.create_buttons()
|
|
||||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
|
||||||
sizer.Add(fileBox)
|
|
||||||
sizer.Add(currentAmountBox)
|
|
||||||
sizer.Add(totalSizeBox)
|
|
||||||
sizer.Add(speedBox)
|
|
||||||
sizer.Add(etaBox)
|
|
||||||
sizer.Add(self.progress_bar)
|
|
||||||
self.pane.SetSizerAndFit(sizer)
|
|
||||||
|
|
||||||
def update(self, data):
|
|
||||||
wx.CallAfter(self.progress_bar.SetValue, data["percent"])
|
|
||||||
wx.CallAfter(self.current_amount.SetValue, '%s (%d%%)' % (convert_bytes(data["current"]), data["percent"]))
|
|
||||||
wx.CallAfter(self.total_size.SetValue, convert_bytes(data["total"]))
|
|
||||||
wx.CallAfter(self.speed.SetValue, data["speed"])
|
|
||||||
if data["eta"]:
|
|
||||||
wx.CallAfter(self.eta.SetValue, seconds_to_string(data["eta"]))
|
|
||||||
|
|
||||||
def create_buttons(self):
|
|
||||||
self.cancel_button = wx.Button(parent=self.pane, id=wx.ID_CANCEL)
|
|
||||||
|
|
||||||
def get_response(self, fn):
|
|
||||||
wx.CallAfter(fn, 0.01)
|
|
||||||
self.ShowModal()
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user