mirror of
https://github.com/MCV-Software/TWBlue.git
synced 2025-08-26 18:09:21 +00:00
Compare commits
33 Commits
Author | SHA1 | Date | |
---|---|---|---|
f9864a887d | |||
3d8519313e | |||
f4ecf10885 | |||
c67b415934 | |||
10511d3022 | |||
9ea36a26d2 | |||
97286496fc | |||
![]() |
6436af76f5 | ||
![]() |
576b5064c0 | ||
![]() |
342265b3c0 | ||
![]() |
54938ecb6c | ||
![]() |
7aff8252d2 | ||
![]() |
9c680130f7 | ||
24d1ad093d | |||
b2b9cd810f | |||
582be54dea | |||
ff0fbeafa3 | |||
e314cf0599 | |||
![]() |
e7b72112cf | ||
![]() |
70c095febe | ||
6119b029f8 | |||
b74cd9a73d | |||
8ff6809f08 | |||
39af9d8623 | |||
3688d7548c | |||
07f9afb14e | |||
de12dadac2 | |||
877c909482 | |||
![]() |
1206aba83b | ||
![]() |
fcd631b2de | ||
![]() |
86130954d7 | ||
![]() |
23a56c637d | ||
![]() |
d5ac0db67b |
@@ -2,6 +2,14 @@
|
|||||||
|
|
||||||
## changes in this version
|
## changes in this version
|
||||||
|
|
||||||
|
* When reading a tweet, if the tweet contains more than 2 consecutive mentions, TWBlue will announce how many more users the tweet includes, as opposed to read every user in the conversation. You still can display the tweet to read all users.
|
||||||
|
* In the tweet displayer, It is possible to copy a link to the current tweet or person by pressing a button called "copy link to clipboard".
|
||||||
|
* Added a keymap capable to work under Windows 11. ([#391](https://github.com/manuelcortez/TWBlue/pull/391))
|
||||||
|
* Added user aliases to TWBlue. This feature allows you to rename user's display names on Twitter, so the next time you'll read an user it will be announced as you configured. For adding an alias to an user, select the "add alias" option in the user menu, located in the menu bar. This feature works only if you have set display screen names unchecked. Users are displayed with their display name in people buffers only. This action is supported in all keymaps, although it is undefined by default. ([#389](https://github.com/manuelcortez/TWBlue/pull/389))
|
||||||
|
* There are some changes to the autocomplete users feature:
|
||||||
|
* Now users can search for twitter screen names or display names in the database.
|
||||||
|
* It is possible to undefine keystrokes in the current keymap in TWBlue. This allows you, for example, to redefine keystrokes completely.
|
||||||
|
* We have changed our Geocoding service to the Nominatim API from OpenStreetMap. Addresses present in tweets are going to be determined by this service, as the Google Maps API now requires an API key. ([#390](https://github.com/manuelcortez/TWBlue/issues/390))
|
||||||
* Added a limited version of the Twitter's Streaming API: The Streaming API will work only for tweets, and will receive tweets only by people you follow. Protected users are not possible to be streamed. It is possible that during high tweet traffic, the Stream might get disconnected at times, but TWBlue should be capable of detecting this problem and reconnecting the stream again. ([#385](https://github.com/manuelcortez/TWBlue/pull/385))
|
* Added a limited version of the Twitter's Streaming API: The Streaming API will work only for tweets, and will receive tweets only by people you follow. Protected users are not possible to be streamed. It is possible that during high tweet traffic, the Stream might get disconnected at times, but TWBlue should be capable of detecting this problem and reconnecting the stream again. ([#385](https://github.com/manuelcortez/TWBlue/pull/385))
|
||||||
* Fixed an issue that made TWBlue to not show a dialog when attempting to show a profile for a suspended user. ([#387](https://github.com/manuelcortez/TWBlue/issues/387))
|
* Fixed an issue that made TWBlue to not show a dialog when attempting to show a profile for a suspended user. ([#387](https://github.com/manuelcortez/TWBlue/issues/387))
|
||||||
* Added support for Twitter audio and videos: Tweets which contains audio or videos will be detected as audio items, and you can playback those with the regular command to play audios. ([#384,](https://github.com/manuelcortez/TWBlue/pull/384))
|
* Added support for Twitter audio and videos: Tweets which contains audio or videos will be detected as audio items, and you can playback those with the regular command to play audios. ([#384,](https://github.com/manuelcortez/TWBlue/pull/384))
|
||||||
|
@@ -9,7 +9,7 @@ oauthlib
|
|||||||
requests-oauthlib
|
requests-oauthlib
|
||||||
requests-toolbelt
|
requests-toolbelt
|
||||||
pypubsub
|
pypubsub
|
||||||
pygeocoder
|
geopy
|
||||||
arrow
|
arrow
|
||||||
python-dateutil
|
python-dateutil
|
||||||
futures
|
futures
|
||||||
@@ -25,6 +25,7 @@ urllib3
|
|||||||
youtube-dl
|
youtube-dl
|
||||||
python-vlc
|
python-vlc
|
||||||
pypiwin32
|
pypiwin32
|
||||||
|
pywin32
|
||||||
certifi
|
certifi
|
||||||
backports.functools_lru_cache
|
backports.functools_lru_cache
|
||||||
cx_freeze
|
cx_freeze
|
||||||
@@ -32,6 +33,20 @@ tweepy
|
|||||||
twitter-text-parser
|
twitter-text-parser
|
||||||
pyenchant
|
pyenchant
|
||||||
sqlitedict
|
sqlitedict
|
||||||
|
cx-Logging
|
||||||
|
h11
|
||||||
|
h2
|
||||||
|
hpack
|
||||||
|
hstspreload
|
||||||
|
httpcore
|
||||||
|
httpx
|
||||||
|
hyperframe
|
||||||
|
rfc3986
|
||||||
|
sniffio
|
||||||
|
attrs
|
||||||
|
importlib-metadata
|
||||||
|
numpy
|
||||||
|
pillow
|
||||||
git+https://github.com/accessibleapps/libloader
|
git+https://github.com/accessibleapps/libloader
|
||||||
git+https://github.com/accessibleapps/platform_utils
|
git+https://github.com/accessibleapps/platform_utils
|
||||||
git+https://github.com/accessibleapps/accessible_output2
|
git+https://github.com/accessibleapps/accessible_output2
|
||||||
|
@@ -49,3 +49,5 @@ braille_reporting = boolean(default=True)
|
|||||||
speech_reporting = boolean(default=True)
|
speech_reporting = boolean(default=True)
|
||||||
|
|
||||||
[filters]
|
[filters]
|
||||||
|
|
||||||
|
[user-aliases]
|
@@ -237,7 +237,7 @@ class BaseBuffer(base.Buffer):
|
|||||||
items_db = self.session.db[self.name]
|
items_db = self.session.db[self.name]
|
||||||
self.session.add_users_from_results(items)
|
self.session.add_users_from_results(items)
|
||||||
for i in items:
|
for i in items:
|
||||||
if utils.is_allowed(i, self.session.settings, self.name) == True and utils.find_item(i.id, self.session.db[self.name]) == None:
|
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 = reduce.reduce_tweet(i)
|
||||||
i = self.session.check_quoted_status(i)
|
i = self.session.check_quoted_status(i)
|
||||||
i = self.session.check_long_tweet(i)
|
i = self.session.check_long_tweet(i)
|
||||||
@@ -644,8 +644,12 @@ class BaseBuffer(base.Buffer):
|
|||||||
original_tweet.text = utils.find_urls_in_text(original_tweet.text, original_tweet.entities)
|
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"])
|
return compose.compose_quoted_tweet(quoted_tweet, original_tweet, self.session.db, self.session.settings["general"]["relative_times"])
|
||||||
|
|
||||||
def open_in_browser(self, *args, **kwargs):
|
def get_item_url(self):
|
||||||
tweet = self.get_tweet()
|
tweet = self.get_tweet()
|
||||||
output.speak(_(u"Opening item in web browser..."))
|
|
||||||
url = "https://twitter.com/{screen_name}/status/{tweet_id}".format(screen_name=self.session.get_user(tweet.user).screen_name, tweet_id=tweet.id)
|
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)
|
webbrowser.open(url)
|
@@ -252,8 +252,7 @@ class PeopleBuffer(base.BaseBuffer):
|
|||||||
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(_(u"{0} new followers.").format(number_of_items))
|
output.speak(_(u"{0} new followers.").format(number_of_items))
|
||||||
|
|
||||||
def open_in_browser(self, *args, **kwargs):
|
def get_item_url(self, *args, **kwargs):
|
||||||
tweet = self.get_tweet()
|
tweet = self.get_tweet()
|
||||||
output.speak(_(u"Opening item in web browser..."))
|
|
||||||
url = "https://twitter.com/{screen_name}".format(screen_name=tweet.screen_name)
|
url = "https://twitter.com/{screen_name}".format(screen_name=tweet.screen_name)
|
||||||
webbrowser.open(url)
|
return url
|
@@ -35,17 +35,16 @@ from mysc.repeating_timer import RepeatingTimer
|
|||||||
from mysc import restart
|
from mysc import restart
|
||||||
import config
|
import config
|
||||||
import widgetUtils
|
import widgetUtils
|
||||||
import pygeocoder
|
|
||||||
from pygeolib import GeocoderError
|
|
||||||
import logging
|
import logging
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
from geopy.geocoders import Nominatim
|
||||||
from mysc import localization
|
from mysc import localization
|
||||||
import os
|
import os
|
||||||
import languageHandler
|
import languageHandler
|
||||||
|
|
||||||
log = logging.getLogger("mainController")
|
log = logging.getLogger("mainController")
|
||||||
|
|
||||||
geocoder = pygeocoder.Geocoder()
|
geocoder = Nominatim(user_agent="TWBlue")
|
||||||
|
|
||||||
class Controller(object):
|
class Controller(object):
|
||||||
|
|
||||||
@@ -185,6 +184,7 @@ class Controller(object):
|
|||||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.report_error, self.view.reportError)
|
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.report_error, self.view.reportError)
|
||||||
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_to_list, self.view.addToList)
|
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.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)
|
||||||
@@ -754,6 +754,26 @@ class Controller(object):
|
|||||||
users = utils.get_all_users(tweet, buff.session)
|
users = utils.get_all_users(tweet, buff.session)
|
||||||
u = userActionsController.userActionsController(buff, users, "report")
|
u = userActionsController.userActionsController(buff, users, "report")
|
||||||
|
|
||||||
|
def add_alias(self, *args, **kwargs):
|
||||||
|
buff = self.get_best_buffer()
|
||||||
|
if not hasattr(buff, "get_right_tweet"): return
|
||||||
|
tweet = buff.get_right_tweet()
|
||||||
|
if buff.type == "people":
|
||||||
|
users = [tweet.screen_name]
|
||||||
|
elif buff.type == "dm":
|
||||||
|
users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name]
|
||||||
|
else:
|
||||||
|
users = utils.get_all_users(tweet, buff.session)
|
||||||
|
dlg = dialogs.utils.addAliasDialog(_("Add an user alias"), users)
|
||||||
|
if dlg.get_response() == widgetUtils.OK:
|
||||||
|
user, alias = dlg.get_user()
|
||||||
|
if user == "" or alias == "":
|
||||||
|
return
|
||||||
|
user_id = buff.session.get_user_by_screen_name(user)
|
||||||
|
buff.session.settings["user-aliases"][str(user_id)] = alias
|
||||||
|
buff.session.settings.write()
|
||||||
|
output.speak(_("Alias has been set correctly for {}.").format(user))
|
||||||
|
|
||||||
def post_tweet(self, event=None):
|
def post_tweet(self, event=None):
|
||||||
buffer = self.get_best_buffer()
|
buffer = self.get_best_buffer()
|
||||||
buffer.post_status()
|
buffer.post_status()
|
||||||
@@ -810,7 +830,7 @@ class Controller(object):
|
|||||||
return
|
return
|
||||||
elif buffer.type == "baseBuffer" or buffer.type == "favourites_timeline" or buffer.type == "list" or buffer.type == "search":
|
elif buffer.type == "baseBuffer" or buffer.type == "favourites_timeline" or buffer.type == "list" or buffer.type == "search":
|
||||||
tweet, tweetsList = buffer.get_full_tweet()
|
tweet, tweetsList = buffer.get_full_tweet()
|
||||||
msg = messages.viewTweet(tweet, tweetsList, utc_offset=buffer.session.db["utc_offset"])
|
msg = messages.viewTweet(tweet, tweetsList, utc_offset=buffer.session.db["utc_offset"], item_url=buffer.get_item_url())
|
||||||
elif buffer.type == "dm":
|
elif buffer.type == "dm":
|
||||||
non_tweet = buffer.get_formatted_message()
|
non_tweet = buffer.get_formatted_message()
|
||||||
item = buffer.get_right_tweet()
|
item = buffer.get_right_tweet()
|
||||||
@@ -818,8 +838,11 @@ class Controller(object):
|
|||||||
date = original_date.shift(seconds=buffer.session.db["utc_offset"]).format(_(u"MMM D, YYYY. H:m"), locale=languageHandler.getLanguage())
|
date = original_date.shift(seconds=buffer.session.db["utc_offset"]).format(_(u"MMM D, YYYY. H:m"), locale=languageHandler.getLanguage())
|
||||||
msg = messages.viewTweet(non_tweet, [], False, date=date)
|
msg = messages.viewTweet(non_tweet, [], False, date=date)
|
||||||
else:
|
else:
|
||||||
|
item_url = ""
|
||||||
|
if hasattr(buffer, "get_item_url"):
|
||||||
|
item_url = buffer.get_item_url()
|
||||||
non_tweet = buffer.get_formatted_message()
|
non_tweet = buffer.get_formatted_message()
|
||||||
msg = messages.viewTweet(non_tweet, [], False)
|
msg = messages.viewTweet(non_tweet, [], False, item_url=item_url)
|
||||||
|
|
||||||
def open_in_browser(self, *args, **kwargs):
|
def open_in_browser(self, *args, **kwargs):
|
||||||
buffer = self.get_current_buffer()
|
buffer = self.get_current_buffer()
|
||||||
@@ -977,19 +1000,17 @@ class Controller(object):
|
|||||||
if tweet.coordinates != None:
|
if tweet.coordinates != None:
|
||||||
x = tweet.coordinates["coordinates"][0]
|
x = tweet.coordinates["coordinates"][0]
|
||||||
y = tweet.coordinates["coordinates"][1]
|
y = tweet.coordinates["coordinates"][1]
|
||||||
address = geocoder.reverse_geocode(y, x, language = languageHandler.curLang)
|
address = geocoder.reverse("{}, {}".format(y, x), language = languageHandler.curLang)
|
||||||
if event == None: output.speak(address[0].__str__())
|
if event == None: output.speak(address.address)
|
||||||
else: self.view.show_address(address[0].__str__())
|
else: self.view.show_address(address.address)
|
||||||
else:
|
else:
|
||||||
output.speak(_(u"There are no coordinates in this tweet"))
|
output.speak(_(u"There are no coordinates in this tweet"))
|
||||||
except GeocoderError:
|
|
||||||
output.speak(_(u"There are no results for the coordinates in this tweet"))
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
output.speak(_(u"Error decoding coordinates. Try again later."))
|
output.speak(_(u"Error decoding coordinates. Try again later."))
|
||||||
except KeyError:
|
# except KeyError:
|
||||||
pass
|
# pass
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
output.speak(_("Unable to find address in OpenStreetMap."))
|
||||||
|
|
||||||
def view_reverse_geocode(self, event=None):
|
def view_reverse_geocode(self, event=None):
|
||||||
try:
|
try:
|
||||||
@@ -1244,14 +1265,17 @@ class Controller(object):
|
|||||||
keymap = {}
|
keymap = {}
|
||||||
for i in config.keymap["keymap"]:
|
for i in config.keymap["keymap"]:
|
||||||
if hasattr(self, i):
|
if hasattr(self, i):
|
||||||
keymap[config.keymap["keymap"][i]] = getattr(self, i)
|
if config.keymap["keymap"][i] != "":
|
||||||
|
keymap[config.keymap["keymap"][i]] = getattr(self, i)
|
||||||
return keymap
|
return keymap
|
||||||
|
|
||||||
def register_invisible_keyboard_shorcuts(self, keymap):
|
def register_invisible_keyboard_shorcuts(self, keymap):
|
||||||
if config.changed_keymap:
|
if config.changed_keymap:
|
||||||
commonMessageDialogs.changed_keymap()
|
commonMessageDialogs.changed_keymap()
|
||||||
|
# Make sure we pass a keymap without undefined keystrokes.
|
||||||
|
new_keymap = {key: keymap[key] for key in keymap.keys() if keymap[key] != ""}
|
||||||
self.keyboard_handler = WXKeyboardHandler(self.view)
|
self.keyboard_handler = WXKeyboardHandler(self.view)
|
||||||
self.keyboard_handler.register_keys(keymap)
|
self.keyboard_handler.register_keys(new_keymap)
|
||||||
|
|
||||||
def unregister_invisible_keyboard_shorcuts(self, keymap):
|
def unregister_invisible_keyboard_shorcuts(self, keymap):
|
||||||
try:
|
try:
|
||||||
|
@@ -102,7 +102,7 @@ class basicTweet(object):
|
|||||||
else:
|
else:
|
||||||
self.message.disable_button("shortenButton")
|
self.message.disable_button("shortenButton")
|
||||||
self.message.disable_button("unshortenButton")
|
self.message.disable_button("unshortenButton")
|
||||||
if self.message.get("long_tweet") == False:
|
if self.message.get("long_tweet") == False and hasattr(self, "max"):
|
||||||
text = self.message.get_text()
|
text = self.message.get_text()
|
||||||
results = parse_tweet(text)
|
results = parse_tweet(text)
|
||||||
self.message.set_title(_(u"%s - %s of %d characters") % (self.title, results.weightedLength, self.max))
|
self.message.set_title(_(u"%s - %s of %d characters") % (self.title, results.weightedLength, self.max))
|
||||||
@@ -205,7 +205,7 @@ class dm(basicTweet):
|
|||||||
c.show_menu("dm")
|
c.show_menu("dm")
|
||||||
|
|
||||||
class viewTweet(basicTweet):
|
class viewTweet(basicTweet):
|
||||||
def __init__(self, tweet, tweetList, is_tweet=True, utc_offset=0, date=""):
|
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.
|
""" 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 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 tweetList: If is_tweet is set to True, this could be a list of quoted tweets.
|
||||||
@@ -273,6 +273,10 @@ class viewTweet(basicTweet):
|
|||||||
text = tweet
|
text = tweet
|
||||||
self.message = message.viewNonTweet(text, date)
|
self.message = message.viewNonTweet(text, date)
|
||||||
widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck)
|
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)
|
widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate)
|
||||||
if self.contain_urls() == True:
|
if self.contain_urls() == True:
|
||||||
self.message.enable_button("unshortenButton")
|
self.message.enable_button("unshortenButton")
|
||||||
@@ -290,3 +294,8 @@ class viewTweet(basicTweet):
|
|||||||
if "https://twitter.com/" in i:
|
if "https://twitter.com/" in i:
|
||||||
text = text.replace(i, "\n")
|
text = text.replace(i, "\n")
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
def share(self, *args, **kwargs):
|
||||||
|
if hasattr(self, "item_url"):
|
||||||
|
output.copy(self.item_url)
|
||||||
|
output.speak(_("Link copied to clipboard."))
|
@@ -21,7 +21,7 @@ class storage(object):
|
|||||||
return self.cursor.fetchall()
|
return self.cursor.fetchall()
|
||||||
|
|
||||||
def get_users(self, term):
|
def get_users(self, term):
|
||||||
self.cursor.execute("""SELECT * FROM users WHERE user LIKE ?""", ('{}%'.format(term),))
|
self.cursor.execute("""SELECT * FROM users WHERE UPPER(user) LIKE :term OR UPPER(name) LIKE :term""", {"term": "%{}%".format(term.upper())})
|
||||||
return self.cursor.fetchall()
|
return self.cursor.fetchall()
|
||||||
|
|
||||||
def set_user(self, screen_name, user_name, from_a_buffer):
|
def set_user(self, screen_name, user_name, from_a_buffer):
|
||||||
|
@@ -34,4 +34,5 @@ configuration = string(default="control+win+o")
|
|||||||
accountConfiguration = string(default="control+win+shift+o")
|
accountConfiguration = string(default="control+win+shift+o")
|
||||||
update_buffer = string(default="control+win+shift+u")
|
update_buffer = string(default="control+win+shift+u")
|
||||||
ocr_image = string(default="win+alt+o")
|
ocr_image = string(default="win+alt+o")
|
||||||
open_in_browser = string(default="alt+control+win+return")
|
open_in_browser = string(default="alt+control+win+return")
|
||||||
|
add_alias=string(default="")
|
@@ -53,4 +53,5 @@ configuration = string(default="control+win+o")
|
|||||||
accountConfiguration = string(default="control+win+shift+o")
|
accountConfiguration = string(default="control+win+shift+o")
|
||||||
update_buffer = string(default="control+win+shift+u")
|
update_buffer = string(default="control+win+shift+u")
|
||||||
ocr_image = string(default="win+alt+o")
|
ocr_image = string(default="win+alt+o")
|
||||||
open_in_browser = string(default="alt+control+win+return")
|
open_in_browser = string(default="alt+control+win+return")
|
||||||
|
add_alias=string(default="")
|
@@ -54,4 +54,5 @@ configuration = string(default="control+win+alt+o")
|
|||||||
accountConfiguration = string(default="control+win+shift+o")
|
accountConfiguration = string(default="control+win+shift+o")
|
||||||
update_buffer = string(default="control+alt+shift+u")
|
update_buffer = string(default="control+alt+shift+u")
|
||||||
ocr_image = string(default="win+alt+o")
|
ocr_image = string(default="win+alt+o")
|
||||||
open_in_browser = string(default="alt+control+win+return")
|
open_in_browser = string(default="alt+control+win+return")
|
||||||
|
add_alias=string(default="")
|
58
src/keymaps/Windows11.keymap
Normal file
58
src/keymaps/Windows11.keymap
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
[info]
|
||||||
|
name = string(default="Windows 11")
|
||||||
|
desc = string(default="A keymap with remapped modifiers for Windows 11 compatibility.")
|
||||||
|
author = string(default="Bill Jesús <galorasd@gmail.com>")
|
||||||
|
|
||||||
|
[keymap]
|
||||||
|
up = string(default="control+alt+win+up")
|
||||||
|
down = string(default="control+alt+win+down")
|
||||||
|
left = string(default="control+alt+win+left")
|
||||||
|
right = string(default="control+alt+win+right")
|
||||||
|
next_account = string(default="control+alt+win+shift+right")
|
||||||
|
previous_account = string(default="control+alt+win+shift+left")
|
||||||
|
open_conversation = string(default="control+alt+win+c")
|
||||||
|
show_hide = string(default="control+win+w")
|
||||||
|
post_tweet = string(default="alt+win+n")
|
||||||
|
post_reply = string(default="control+win+r")
|
||||||
|
post_retweet = string(default="alt+win+shift+r")
|
||||||
|
send_dm = string(default="alt+win+shift+d")
|
||||||
|
toggle_like = string(default="control+alt+win+f")
|
||||||
|
follow = string(default="alt+win+shift+s")
|
||||||
|
user_details = string(default="alt+win+shift+n")
|
||||||
|
view_item = string(default="alt+win+v")
|
||||||
|
exit = string(default="alt+win+f4")
|
||||||
|
open_timeline = string(default="alt+win+i")
|
||||||
|
remove_buffer = string(default="alt+win+shift+i")
|
||||||
|
url = string(default="alt+win+return")
|
||||||
|
audio = string(default="alt+shift+win+return")
|
||||||
|
volume_up = string(default="control+alt+win+shift+up")
|
||||||
|
go_home = string(default="control+alt+win+home")
|
||||||
|
volume_down = string(default="control+alt+win+shift+down")
|
||||||
|
go_end = string(default="control+alt+win+end")
|
||||||
|
go_page_up = string(default="control+win+pageup")
|
||||||
|
go_page_down = string(default="control+win+pagedown")
|
||||||
|
update_profile = string(default="alt+win+p")
|
||||||
|
delete = string(default="alt+win+delete")
|
||||||
|
clear_buffer = string(default="alt+win+shift+delete")
|
||||||
|
repeat_item = string(default="control+alt+win+space")
|
||||||
|
copy_to_clipboard = string(default="alt+win+shift+c")
|
||||||
|
add_to_list = string(default="alt+win+a")
|
||||||
|
remove_from_list = string(default="alt+win+shift+a")
|
||||||
|
toggle_buffer_mute = string(default="alt+win+shift+m")
|
||||||
|
toggle_session_mute = string(default="control+alt+win+m")
|
||||||
|
toggle_autoread = string(default="alt+win+e")
|
||||||
|
search = string(default="alt+win+-")
|
||||||
|
edit_keystrokes = string(default="alt+win+k")
|
||||||
|
view_user_lists = string(default="alt+win+l")
|
||||||
|
get_more_items = string(default="alt+win+pageup")
|
||||||
|
reverse_geocode = string(default="control+win+g")
|
||||||
|
view_reverse_geocode = string(default="alt+win+shift+g")
|
||||||
|
get_trending_topics = string(default="control+win+t")
|
||||||
|
check_for_updates = string(default="alt+win+u")
|
||||||
|
list_manager = string(default="alt+win+shift+l")
|
||||||
|
configuration = string(default="control+win+alt+o")
|
||||||
|
accountConfiguration = string(default="control+win+shift+o")
|
||||||
|
update_buffer = string(default="control+alt+shift+u")
|
||||||
|
ocr_image = string(default="win+alt+o")
|
||||||
|
open_in_browser = string(default="alt+control+win+return")
|
||||||
|
add_alias=string(default="")
|
@@ -55,4 +55,5 @@ list_manager = string(default="control+win+shift+l")
|
|||||||
configuration = string(default="control+win+o")
|
configuration = string(default="control+win+o")
|
||||||
accountConfiguration = string(default="control+win+shift+o")
|
accountConfiguration = string(default="control+win+shift+o")
|
||||||
update_buffer = string(default="control+win+shift+u")
|
update_buffer = string(default="control+win+shift+u")
|
||||||
open_in_browser = string(default="alt+control+win+return")
|
open_in_browser = string(default="alt+control+win+return")
|
||||||
|
add_alias=string(default="")
|
@@ -56,4 +56,5 @@ configuration = string(default="control+win+o")
|
|||||||
accountConfiguration = string(default="control+win+shift+o")
|
accountConfiguration = string(default="control+win+shift+o")
|
||||||
update_buffer = string(default="control+win+shift+u")
|
update_buffer = string(default="control+win+shift+u")
|
||||||
ocr_image = string(default="win+alt+o")
|
ocr_image = string(default="win+alt+o")
|
||||||
open_in_browser = string(default="alt+control+win+return")
|
open_in_browser = string(default="alt+control+win+return")
|
||||||
|
add_alias=string(default="")
|
@@ -1,5 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
|
||||||
actions = {
|
actions = {
|
||||||
"up": _(u"Go up in the current buffer"),
|
"up": _(u"Go up in the current buffer"),
|
||||||
"down": _(u"Go down in the current buffer"),
|
"down": _(u"Go down in the current buffer"),
|
||||||
@@ -57,4 +56,6 @@ actions = {
|
|||||||
"audio": _(u"Try to play an audio file"),
|
"audio": _(u"Try to play an audio file"),
|
||||||
"update_buffer": _(u"Updates the buffer and retrieves possible lost items there."),
|
"update_buffer": _(u"Updates the buffer and retrieves possible lost items there."),
|
||||||
"ocr_image": _(u"Extracts the text from a picture and displays the result in a dialog."),
|
"ocr_image": _(u"Extracts the text from a picture and displays the result in a dialog."),
|
||||||
|
"add_alias": _("Adds an alias to an user"),
|
||||||
}
|
}
|
||||||
|
|
@@ -1,7 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import absolute_import
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
from builtins import object
|
|
||||||
import widgetUtils
|
import widgetUtils
|
||||||
import config
|
import config
|
||||||
from . import wx_ui
|
from . import wx_ui
|
||||||
@@ -18,6 +15,7 @@ class KeystrokeEditor(object):
|
|||||||
self.hold_map = self.map.copy()
|
self.hold_map = self.map.copy()
|
||||||
self.dialog.put_keystrokes(constants.actions, self.map)
|
self.dialog.put_keystrokes(constants.actions, self.map)
|
||||||
widgetUtils.connect_event(self.dialog.edit, widgetUtils.BUTTON_PRESSED, self.edit_keystroke)
|
widgetUtils.connect_event(self.dialog.edit, widgetUtils.BUTTON_PRESSED, self.edit_keystroke)
|
||||||
|
widgetUtils.connect_event(self.dialog.undefine, widgetUtils.BUTTON_PRESSED, self.undefine_keystroke)
|
||||||
widgetUtils.connect_event(self.dialog.execute, widgetUtils.BUTTON_PRESSED, self.execute_action)
|
widgetUtils.connect_event(self.dialog.execute, widgetUtils.BUTTON_PRESSED, self.execute_action)
|
||||||
self.dialog.get_response()
|
self.dialog.get_response()
|
||||||
|
|
||||||
@@ -33,6 +31,17 @@ class KeystrokeEditor(object):
|
|||||||
self.map[action] = new_keystroke
|
self.map[action] = new_keystroke
|
||||||
self.dialog.put_keystrokes(constants.actions, self.map)
|
self.dialog.put_keystrokes(constants.actions, self.map)
|
||||||
|
|
||||||
|
def undefine_keystroke(self, *args, **kwargs):
|
||||||
|
action = self.dialog.actions[self.dialog.get_action()]
|
||||||
|
keystroke = self.map.get(action)
|
||||||
|
if keystroke == None:
|
||||||
|
return
|
||||||
|
answer = self.dialog.undefine_keystroke_confirmation()
|
||||||
|
if answer == widgetUtils.YES:
|
||||||
|
self.map[action] = ""
|
||||||
|
self.changed = True
|
||||||
|
self.dialog.put_keystrokes(constants.actions, self.map)
|
||||||
|
|
||||||
def set_keystroke(self, keystroke, dialog):
|
def set_keystroke(self, keystroke, dialog):
|
||||||
for i in keystroke.split("+"):
|
for i in keystroke.split("+"):
|
||||||
if hasattr(dialog, i):
|
if hasattr(dialog, i):
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
|
||||||
import wx
|
import wx
|
||||||
from multiplatform_widgets import widgets
|
from multiplatform_widgets import widgets
|
||||||
from wxUI.dialogs import baseDialog
|
from wxUI.dialogs import baseDialog
|
||||||
@@ -18,6 +17,7 @@ class keystrokeEditorDialog(baseDialog.BaseWXDialog):
|
|||||||
firstSizer.Add(self.keys.list, 0, wx.ALL, 5)
|
firstSizer.Add(self.keys.list, 0, wx.ALL, 5)
|
||||||
self.edit = wx.Button(panel, -1, _(u"Edit"))
|
self.edit = wx.Button(panel, -1, _(u"Edit"))
|
||||||
self.edit.SetDefault()
|
self.edit.SetDefault()
|
||||||
|
self.undefine = wx.Button(panel, -1, _("Undefine keystroke"))
|
||||||
self.execute = wx.Button(panel, -1, _(u"Execute action"))
|
self.execute = wx.Button(panel, -1, _(u"Execute action"))
|
||||||
close = wx.Button(panel, wx.ID_CANCEL, _(u"Close"))
|
close = wx.Button(panel, wx.ID_CANCEL, _(u"Close"))
|
||||||
secondSizer = wx.BoxSizer(wx.HORIZONTAL)
|
secondSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
@@ -37,13 +37,18 @@ class keystrokeEditorDialog(baseDialog.BaseWXDialog):
|
|||||||
continue
|
continue
|
||||||
action = actions[i]
|
action = actions[i]
|
||||||
self.actions.append(i)
|
self.actions.append(i)
|
||||||
keystroke = keystrokes[i]
|
keystroke = keystrokes.get(i)
|
||||||
|
if keystroke == "":
|
||||||
|
keystroke = _("Undefined")
|
||||||
self.keys.insert_item(False, *[action, keystroke])
|
self.keys.insert_item(False, *[action, keystroke])
|
||||||
self.keys.select_item(selection)
|
self.keys.select_item(selection)
|
||||||
|
|
||||||
def get_action(self):
|
def get_action(self):
|
||||||
return self.keys.get_selected()
|
return self.keys.get_selected()
|
||||||
|
|
||||||
|
def undefine_keystroke_confirmation(self):
|
||||||
|
return wx.MessageDialog(self, _("Are you sure you want to undefine this keystroke?"), _("Undefine keystroke"), wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION).ShowModal()
|
||||||
|
|
||||||
class editKeystrokeDialog(baseDialog.BaseWXDialog):
|
class editKeystrokeDialog(baseDialog.BaseWXDialog):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(editKeystrokeDialog, self).__init__(parent=None, id=-1, title=_(u"Editing keystroke"))
|
super(editKeystrokeDialog, self).__init__(parent=None, id=-1, title=_(u"Editing keystroke"))
|
||||||
|
Binary file not shown.
@@ -6,7 +6,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: TW Blue 0.85\n"
|
"Project-Id-Version: TW Blue 0.85\n"
|
||||||
"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n"
|
"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n"
|
||||||
"PO-Revision-Date: 2020-10-23 14:30+0300\n"
|
"PO-Revision-Date: 2021-07-05 16:03+0200\n"
|
||||||
"Last-Translator: Artem Plaksin <admin@maniyax.ru>\n"
|
"Last-Translator: Artem Plaksin <admin@maniyax.ru>\n"
|
||||||
"Language-Team: Alexander Jaszyn <a.jaszyn@ya.ru>\n"
|
"Language-Team: Alexander Jaszyn <a.jaszyn@ya.ru>\n"
|
||||||
"Language: ru\n"
|
"Language: ru\n"
|
||||||
@@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Generated-By: pygettext.py 1.5\n"
|
"Generated-By: pygettext.py 1.5\n"
|
||||||
"X-Generator: Poedit 1.8.8\n"
|
"X-Generator: Poedit 3.0\n"
|
||||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
|
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
|
||||||
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||||
"X-Poedit-SourceCharset: UTF-8\n"
|
"X-Poedit-SourceCharset: UTF-8\n"
|
||||||
@@ -208,14 +208,12 @@ msgstr ""
|
|||||||
"личных сообщений вместо этого."
|
"личных сообщений вместо этого."
|
||||||
|
|
||||||
#: ../src\controller\buffers\twitterBuffers.py:983
|
#: ../src\controller\buffers\twitterBuffers.py:983
|
||||||
#, fuzzy
|
|
||||||
msgid "{0} new followers."
|
msgid "{0} new followers."
|
||||||
msgstr "Новый читатель."
|
msgstr "{0} новых читателей."
|
||||||
|
|
||||||
#: ../src\controller\buffers\twitterBuffers.py:1266
|
#: ../src\controller\buffers\twitterBuffers.py:1266
|
||||||
#, fuzzy
|
|
||||||
msgid "This action is not supported in the buffer, yet."
|
msgid "This action is not supported in the buffer, yet."
|
||||||
msgstr "Это действие не поддерживается в данном буфере"
|
msgstr "Это действие пока не поддерживается в буфере."
|
||||||
|
|
||||||
#: ../src\controller\mainController.py:273
|
#: ../src\controller\mainController.py:273
|
||||||
msgid "Ready"
|
msgid "Ready"
|
||||||
@@ -314,9 +312,8 @@ msgid "Select the user"
|
|||||||
msgstr "Выберите пользователя"
|
msgstr "Выберите пользователя"
|
||||||
|
|
||||||
#: ../src\controller\mainController.py:809 ../src\controller\messages.py:236
|
#: ../src\controller\mainController.py:809 ../src\controller\messages.py:236
|
||||||
#, fuzzy
|
|
||||||
msgid "MMM D, YYYY. H:m"
|
msgid "MMM D, YYYY. H:m"
|
||||||
msgstr "dddd, MMMM D, YYYY H:m:s"
|
msgstr "MMM D, YYYY. H:m"
|
||||||
|
|
||||||
#: ../src\controller\mainController.py:934
|
#: ../src\controller\mainController.py:934
|
||||||
msgid "Conversation with {0}"
|
msgid "Conversation with {0}"
|
||||||
@@ -1702,9 +1699,8 @@ msgid "Opens the global settings dialogue"
|
|||||||
msgstr "Открыть основные настройки"
|
msgstr "Открыть основные настройки"
|
||||||
|
|
||||||
#: ../src\keystrokeEditor\constants.py:54
|
#: ../src\keystrokeEditor\constants.py:54
|
||||||
#, fuzzy
|
|
||||||
msgid "Opens the list manager"
|
msgid "Opens the list manager"
|
||||||
msgstr "Менеджер Списков"
|
msgstr "Открывает менеджер списков"
|
||||||
|
|
||||||
#: ../src\keystrokeEditor\constants.py:55
|
#: ../src\keystrokeEditor\constants.py:55
|
||||||
msgid "Opens the account settings dialogue"
|
msgid "Opens the account settings dialogue"
|
||||||
|
@@ -45,9 +45,9 @@ def compose_tweet(tweet, db, relative_times, show_screen_names=False, session=No
|
|||||||
else:
|
else:
|
||||||
value = "text"
|
value = "text"
|
||||||
if hasattr(tweet, "retweeted_status") and value != "message":
|
if hasattr(tweet, "retweeted_status") and value != "message":
|
||||||
text = StripChars(getattr(tweet.retweeted_status, value))
|
text = utils.clean_mentions(StripChars(getattr(tweet.retweeted_status, value)))
|
||||||
else:
|
else:
|
||||||
text = StripChars(getattr(tweet, value))
|
text = utils.clean_mentions(StripChars(getattr(tweet, value)))
|
||||||
if show_screen_names:
|
if show_screen_names:
|
||||||
user = session.get_user(tweet.user).screen_name
|
user = session.get_user(tweet.user).screen_name
|
||||||
else:
|
else:
|
||||||
@@ -111,7 +111,7 @@ def compose_quoted_tweet(quoted_tweet, original_tweet, show_screen_names=False,
|
|||||||
value = "full_text"
|
value = "full_text"
|
||||||
else:
|
else:
|
||||||
value = "text"
|
value = "text"
|
||||||
text = StripChars(getattr(quoted_tweet, value))
|
text = utils.clean_mentions(StripChars(getattr(quoted_tweet, value)))
|
||||||
if show_screen_names:
|
if show_screen_names:
|
||||||
quoting_user = session.get_user(quoted_tweet.user).screen_name
|
quoting_user = session.get_user(quoted_tweet.user).screen_name
|
||||||
else:
|
else:
|
||||||
@@ -124,9 +124,9 @@ def compose_quoted_tweet(quoted_tweet, original_tweet, show_screen_names=False,
|
|||||||
if hasattr(original_tweet, "message"):
|
if hasattr(original_tweet, "message"):
|
||||||
original_text = original_tweet.message
|
original_text = original_tweet.message
|
||||||
elif hasattr(original_tweet, "full_text"):
|
elif hasattr(original_tweet, "full_text"):
|
||||||
original_text = StripChars(original_tweet.full_text)
|
original_text = utils.clean_mentions(StripChars(original_tweet.full_text))
|
||||||
else:
|
else:
|
||||||
original_text = StripChars(original_tweet.text)
|
original_text = utils.clean_mentions(StripChars(original_tweet.text))
|
||||||
quoted_tweet.message = _(u"{0}. Quoted tweet from @{1}: {2}").format( text, original_user, original_text)
|
quoted_tweet.message = _(u"{0}. Quoted tweet from @{1}: {2}").format( text, original_user, original_text)
|
||||||
quoted_tweet = tweets.clear_url(quoted_tweet)
|
quoted_tweet = tweets.clear_url(quoted_tweet)
|
||||||
if hasattr(original_tweet, "entities") and original_tweet.entities.get("urls"):
|
if hasattr(original_tweet, "entities") and original_tweet.entities.get("urls"):
|
||||||
|
@@ -51,7 +51,7 @@ class Session(base.baseSession):
|
|||||||
if i.id < last_id:
|
if i.id < last_id:
|
||||||
log.error("Ignoring an older tweet... Last id: {0}, tweet id: {1}".format(last_id, i.id))
|
log.error("Ignoring an older tweet... Last id: {0}, tweet id: {1}".format(last_id, i.id))
|
||||||
continue
|
continue
|
||||||
if utils.find_item(i.id, self.db[name]) == None and utils.is_allowed(i, self.settings, name) == True:
|
if utils.find_item(i, self.db[name]) == None and utils.is_allowed(i, self.settings, name) == True:
|
||||||
if i == False: continue
|
if i == False: continue
|
||||||
reduced_object = reduce.reduce_tweet(i)
|
reduced_object = reduce.reduce_tweet(i)
|
||||||
reduced_object = self.check_quoted_status(reduced_object)
|
reduced_object = self.check_quoted_status(reduced_object)
|
||||||
@@ -72,7 +72,7 @@ class Session(base.baseSession):
|
|||||||
self.db[name] = []
|
self.db[name] = []
|
||||||
objects = self.db[name]
|
objects = self.db[name]
|
||||||
for i in data:
|
for i in data:
|
||||||
if utils.find_item(i.id, self.db[name]) == None:
|
if utils.find_item(i, self.db[name]) == None:
|
||||||
if self.settings["general"]["reverse_timelines"] == False: objects.append(i)
|
if self.settings["general"]["reverse_timelines"] == False: objects.append(i)
|
||||||
else: objects.insert(0, i)
|
else: objects.insert(0, i)
|
||||||
num = num+1
|
num = num+1
|
||||||
@@ -94,12 +94,12 @@ class Session(base.baseSession):
|
|||||||
for i in data:
|
for i in data:
|
||||||
# Twitter returns sender_id as str, which must be converted to int in order to match to our user_id object.
|
# Twitter returns sender_id as str, which must be converted to int in order to match to our user_id object.
|
||||||
if int(i.message_create["sender_id"]) == self.db["user_id"]:
|
if int(i.message_create["sender_id"]) == self.db["user_id"]:
|
||||||
if "sent_direct_messages" in self.db and utils.find_item(i.id, self.db["sent_direct_messages"]) == None:
|
if "sent_direct_messages" in self.db and utils.find_item(i, self.db["sent_direct_messages"]) == None:
|
||||||
if self.settings["general"]["reverse_timelines"] == False: sent_objects.append(i)
|
if self.settings["general"]["reverse_timelines"] == False: sent_objects.append(i)
|
||||||
else: sent_objects.insert(0, i)
|
else: sent_objects.insert(0, i)
|
||||||
sent = sent+1
|
sent = sent+1
|
||||||
else:
|
else:
|
||||||
if utils.find_item(i.id, self.db["direct_messages"]) == None:
|
if utils.find_item(i, self.db["direct_messages"]) == None:
|
||||||
if self.settings["general"]["reverse_timelines"] == False: objects.append(i)
|
if self.settings["general"]["reverse_timelines"] == False: objects.append(i)
|
||||||
else: objects.insert(0, i)
|
else: objects.insert(0, i)
|
||||||
incoming = incoming+1
|
incoming = incoming+1
|
||||||
@@ -430,9 +430,25 @@ class Session(base.baseSession):
|
|||||||
users = self.db["users"]
|
users = self.db["users"]
|
||||||
users[user.id_str] = user
|
users[user.id_str] = user
|
||||||
self.db["users"] = users
|
self.db["users"] = users
|
||||||
|
user.name = self.get_user_alias(user)
|
||||||
return user
|
return user
|
||||||
else:
|
else:
|
||||||
return self.db["users"][str(id)]
|
user = self.db["users"][str(id)]
|
||||||
|
user.name = self.get_user_alias(user)
|
||||||
|
return user
|
||||||
|
|
||||||
|
def get_user_alias(self, user):
|
||||||
|
""" Retrieves an alias for the passed user model, if exists.
|
||||||
|
@ user Tweepy.models.user: An user object.
|
||||||
|
"""
|
||||||
|
aliases = self.settings.get("user-aliases")
|
||||||
|
if aliases == None:
|
||||||
|
log.error("Aliases are not defined for this config spec.")
|
||||||
|
return user.name
|
||||||
|
user_alias = aliases.get(user.id_str)
|
||||||
|
if user_alias != None:
|
||||||
|
return user_alias
|
||||||
|
return user.name
|
||||||
|
|
||||||
def get_user_by_screen_name(self, screen_name):
|
def get_user_by_screen_name(self, screen_name):
|
||||||
""" Returns an user identifier associated with a screen_name.
|
""" Returns an user identifier associated with a screen_name.
|
||||||
|
@@ -60,9 +60,13 @@ def find_urls (tweet, twitter_media=False):
|
|||||||
urls.append(i)
|
urls.append(i)
|
||||||
return urls
|
return urls
|
||||||
|
|
||||||
def find_item(id, listItem):
|
def find_item(item, listItems):
|
||||||
for i in range(0, len(listItem)):
|
for i in range(0, len(listItems)):
|
||||||
if listItem[i].id == id: return i
|
if listItems[i].id == item.id:
|
||||||
|
return i
|
||||||
|
# Check also retweets.
|
||||||
|
if hasattr(item, "retweeted_status") and item.retweeted_status.id == listItems[i].id:
|
||||||
|
return i
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def find_list(name, lists):
|
def find_list(name, lists):
|
||||||
@@ -240,3 +244,20 @@ def expand_urls(text, entities):
|
|||||||
if url["url"] in text:
|
if url["url"] in text:
|
||||||
text = text.replace(url["url"], url["expanded_url"])
|
text = text.replace(url["url"], url["expanded_url"])
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
def clean_mentions(text):
|
||||||
|
new_text = text
|
||||||
|
mentionned_people = [u for u in re.finditer("(?<=^|(?<=[^a-zA-Z0-9-\.]))@([A-Za-z0-9_]+)", text)]
|
||||||
|
if len(mentionned_people) <= 2:
|
||||||
|
return text
|
||||||
|
end = -2
|
||||||
|
total_users = 0
|
||||||
|
for user in mentionned_people:
|
||||||
|
if abs(user.start()-end) < 3:
|
||||||
|
new_text = new_text.replace(user.group(0), "")
|
||||||
|
total_users = total_users+1
|
||||||
|
end = user.end()
|
||||||
|
if total_users < 1:
|
||||||
|
return text
|
||||||
|
new_text = _("{user_1}, {user_2} and {all_users} more: {text}").format(user_1=mentionned_people[0].group(0), user_2=mentionned_people[1].group(0), all_users=total_users-2, text=new_text)
|
||||||
|
return new_text
|
@@ -3,7 +3,7 @@ import sys
|
|||||||
import application
|
import application
|
||||||
import platform
|
import platform
|
||||||
import os
|
import os
|
||||||
from cx_Freeze import setup, Executable
|
from cx_Freeze import setup, Executable, winmsvcr
|
||||||
from requests import certs
|
from requests import certs
|
||||||
|
|
||||||
def get_architecture_files():
|
def get_architecture_files():
|
||||||
@@ -40,7 +40,7 @@ build_exe_options = dict(
|
|||||||
build_exe="dist",
|
build_exe="dist",
|
||||||
optimize=1,
|
optimize=1,
|
||||||
includes=["enchant.tokenize.en"], # This is not handled automatically by cx_freeze.
|
includes=["enchant.tokenize.en"], # This is not handled automatically by cx_freeze.
|
||||||
include_msvcr=True,
|
include_msvcr=False,
|
||||||
replace_paths = [("*", "")],
|
replace_paths = [("*", "")],
|
||||||
include_files=["icon.ico", "conf.defaults", "app-configuration.defaults", "keymaps", "locales", "sounds", "documentation", ("keys/lib", "keys/lib"), find_sound_lib_datafiles(), find_accessible_output2_datafiles()]+get_architecture_files(),
|
include_files=["icon.ico", "conf.defaults", "app-configuration.defaults", "keymaps", "locales", "sounds", "documentation", ("keys/lib", "keys/lib"), find_sound_lib_datafiles(), find_accessible_output2_datafiles()]+get_architecture_files(),
|
||||||
packages=["wxUI"],
|
packages=["wxUI"],
|
||||||
@@ -50,6 +50,8 @@ executables = [
|
|||||||
Executable('main.py', base=base, targetName="twblue")
|
Executable('main.py', base=base, targetName="twblue")
|
||||||
]
|
]
|
||||||
|
|
||||||
|
winmsvcr.FILES = ()
|
||||||
|
winmsvcr.FILES_TO_DUPLICATE = ()
|
||||||
setup(name=application.name,
|
setup(name=application.name,
|
||||||
version=application.version,
|
version=application.version,
|
||||||
description=application.description,
|
description=application.description,
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
|
||||||
from builtins import str
|
|
||||||
import wx
|
import wx
|
||||||
import widgetUtils
|
import widgetUtils
|
||||||
|
|
||||||
@@ -356,6 +354,8 @@ class viewTweet(widgetUtils.BaseDialog):
|
|||||||
infoBox.Add(sourceBox, 0, wx.ALL, 5)
|
infoBox.Add(sourceBox, 0, wx.ALL, 5)
|
||||||
mainBox.Add(infoBox, 0, wx.ALL, 5)
|
mainBox.Add(infoBox, 0, wx.ALL, 5)
|
||||||
mainBox.Add(dateBox, 0, wx.ALL, 5)
|
mainBox.Add(dateBox, 0, wx.ALL, 5)
|
||||||
|
self.share = wx.Button(panel, wx.ID_ANY, _("Copy link to clipboard"))
|
||||||
|
self.share.Enable(False)
|
||||||
self.spellcheck = wx.Button(panel, -1, _("Check &spelling..."), size=wx.DefaultSize)
|
self.spellcheck = wx.Button(panel, -1, _("Check &spelling..."), size=wx.DefaultSize)
|
||||||
self.unshortenButton = wx.Button(panel, -1, _(u"&Expand URL"), size=wx.DefaultSize)
|
self.unshortenButton = wx.Button(panel, -1, _(u"&Expand URL"), size=wx.DefaultSize)
|
||||||
self.unshortenButton.Disable()
|
self.unshortenButton.Disable()
|
||||||
@@ -363,6 +363,7 @@ class viewTweet(widgetUtils.BaseDialog):
|
|||||||
cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize)
|
cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize)
|
||||||
cancelButton.SetDefault()
|
cancelButton.SetDefault()
|
||||||
buttonsBox = wx.BoxSizer(wx.HORIZONTAL)
|
buttonsBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
buttonsBox.Add(self.share, 0, wx.ALL, 5)
|
||||||
buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5)
|
buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5)
|
||||||
buttonsBox.Add(self.unshortenButton, 0, wx.ALL, 5)
|
buttonsBox.Add(self.unshortenButton, 0, wx.ALL, 5)
|
||||||
buttonsBox.Add(self.translateButton, 0, wx.ALL, 5)
|
buttonsBox.Add(self.translateButton, 0, wx.ALL, 5)
|
||||||
@@ -429,6 +430,8 @@ class viewNonTweet(widgetUtils.BaseDialog):
|
|||||||
dateBox.Add(dateLabel, 0, wx.ALL, 5)
|
dateBox.Add(dateLabel, 0, wx.ALL, 5)
|
||||||
dateBox.Add(date, 0, wx.ALL, 5)
|
dateBox.Add(date, 0, wx.ALL, 5)
|
||||||
mainBox.Add(dateBox, 0, wx.ALL, 5)
|
mainBox.Add(dateBox, 0, wx.ALL, 5)
|
||||||
|
self.share = wx.Button(panel, wx.ID_ANY, _("Copy link to clipboard"))
|
||||||
|
self.share.Enable(False)
|
||||||
self.spellcheck = wx.Button(panel, -1, _("Check &spelling..."), size=wx.DefaultSize)
|
self.spellcheck = wx.Button(panel, -1, _("Check &spelling..."), size=wx.DefaultSize)
|
||||||
self.unshortenButton = wx.Button(panel, -1, _(u"&Expand URL"), size=wx.DefaultSize)
|
self.unshortenButton = wx.Button(panel, -1, _(u"&Expand URL"), size=wx.DefaultSize)
|
||||||
self.unshortenButton.Disable()
|
self.unshortenButton.Disable()
|
||||||
@@ -436,6 +439,7 @@ class viewNonTweet(widgetUtils.BaseDialog):
|
|||||||
cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize)
|
cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize)
|
||||||
cancelButton.SetDefault()
|
cancelButton.SetDefault()
|
||||||
buttonsBox = wx.BoxSizer(wx.HORIZONTAL)
|
buttonsBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
buttonsBox.Add(self.share, 0, wx.ALL, 5)
|
||||||
buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5)
|
buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5)
|
||||||
buttonsBox.Add(self.unshortenButton, 0, wx.ALL, 5)
|
buttonsBox.Add(self.unshortenButton, 0, wx.ALL, 5)
|
||||||
buttonsBox.Add(self.translateButton, 0, wx.ALL, 5)
|
buttonsBox.Add(self.translateButton, 0, wx.ALL, 5)
|
||||||
@@ -463,5 +467,5 @@ class viewNonTweet(widgetUtils.BaseDialog):
|
|||||||
self.text.SetFocus()
|
self.text.SetFocus()
|
||||||
|
|
||||||
def enable_button(self, buttonName):
|
def enable_button(self, buttonName):
|
||||||
if getattr(self, buttonName):
|
if hasattr(self, buttonName):
|
||||||
return getattr(self, buttonName).Enable()
|
return getattr(self, buttonName).Enable()
|
||||||
|
@@ -48,3 +48,36 @@ class selectUserDialog(baseDialog.BaseWXDialog):
|
|||||||
def get_user(self):
|
def get_user(self):
|
||||||
return self.cb.GetValue()
|
return self.cb.GetValue()
|
||||||
|
|
||||||
|
class addAliasDialog(baseDialog.BaseWXDialog):
|
||||||
|
def __init__(self, title, users):
|
||||||
|
super(addAliasDialog, self).__init__(parent=None, id=wx.ID_ANY, title=title)
|
||||||
|
panel = wx.Panel(self)
|
||||||
|
userSizer = wx.BoxSizer()
|
||||||
|
self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0], size=wx.DefaultSize)
|
||||||
|
self.cb.SetFocus()
|
||||||
|
self.autocompletion = wx.Button(panel, -1, _(u"&Autocomplete users"))
|
||||||
|
userSizer.Add(wx.StaticText(panel, -1, _(u"User")), 0, wx.ALL, 5)
|
||||||
|
userSizer.Add(self.cb, 0, wx.ALL, 5)
|
||||||
|
userSizer.Add(self.autocompletion, 0, wx.ALL, 5)
|
||||||
|
aliasSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
aliasLabel = wx.StaticText(panel, wx.ID_ANY, _("Alias"))
|
||||||
|
self.alias = wx.TextCtrl(panel, wx.ID_ANY)
|
||||||
|
aliasSizer.Add(aliasLabel, 0, wx.ALL, 5)
|
||||||
|
aliasSizer.Add(self.alias, 0, wx.ALL, 5)
|
||||||
|
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||||
|
ok = wx.Button(panel, wx.ID_OK, _(u"OK"))
|
||||||
|
ok.SetDefault()
|
||||||
|
# ok.Bind(wx.EVT_BUTTON, self.onok)
|
||||||
|
cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Close"))
|
||||||
|
btnsizer = wx.BoxSizer()
|
||||||
|
btnsizer.Add(ok, 0, wx.ALL, 5)
|
||||||
|
btnsizer.Add(cancel, 0, wx.ALL, 5)
|
||||||
|
sizer.Add(userSizer, 0, wx.ALL, 5)
|
||||||
|
sizer.Add(aliasSizer, 0, wx.ALL, 5)
|
||||||
|
sizer.Add(btnsizer, 0, wx.ALL, 5)
|
||||||
|
panel.SetSizer(sizer)
|
||||||
|
self.SetClientSize(sizer.CalcMin())
|
||||||
|
|
||||||
|
def get_user(self):
|
||||||
|
return (self.cb.GetValue(), self.alias.GetValue())
|
||||||
|
|
||||||
|
@@ -43,6 +43,7 @@ class mainFrame(wx.Frame):
|
|||||||
self.follow = user.Append(wx.ID_ANY, _(u"&Actions..."))
|
self.follow = user.Append(wx.ID_ANY, _(u"&Actions..."))
|
||||||
self.timeline = user.Append(wx.ID_ANY, _(u"&View timeline..."))
|
self.timeline = user.Append(wx.ID_ANY, _(u"&View timeline..."))
|
||||||
self.dm = user.Append(wx.ID_ANY, _(u"Direct me&ssage"))
|
self.dm = user.Append(wx.ID_ANY, _(u"Direct me&ssage"))
|
||||||
|
self.addAlias = user.Append(wx.ID_ANY, _("Add a&lias"))
|
||||||
self.addToList = user.Append(wx.ID_ANY, _(u"&Add to list"))
|
self.addToList = user.Append(wx.ID_ANY, _(u"&Add to list"))
|
||||||
self.removeFromList = user.Append(wx.ID_ANY, _(u"R&emove from list"))
|
self.removeFromList = user.Append(wx.ID_ANY, _(u"R&emove from list"))
|
||||||
self.viewLists = user.Append(wx.ID_ANY, _(u"&View lists"))
|
self.viewLists = user.Append(wx.ID_ANY, _(u"&View lists"))
|
||||||
|
Submodule windows-dependencies updated: 3244b9e3fb...27a7c41983
Reference in New Issue
Block a user