Made code indentation to comply with PEP8

This commit is contained in:
Manuel Cortez 2021-06-16 16:18:41 -05:00
parent 2aaa4eced3
commit 39e1fb017c
145 changed files with 9577 additions and 9584 deletions

View File

@ -5,13 +5,13 @@ name = 'TWBlue'
short_name='twblue' short_name='twblue'
snapshot = True snapshot = True
if snapshot == False: if snapshot == False:
version = "0.95" version = "0.95"
update_url = 'https://twblue.es/updates/stable.php' update_url = 'https://twblue.es/updates/stable.php'
mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json'
else: else:
version = "5" version = "5"
update_url = 'https://twblue.es/updates/snapshot.php' update_url = 'https://twblue.es/updates/snapshot.php'
mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.json' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.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-2021, Manuel cortéz." copyright = "Copyright (C) 2013-2021, Manuel cortéz."
@ -19,4 +19,4 @@ description = name+" is an app designed to use Twitter simply and efficiently wh
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)", "Oreonan (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)", "Oreonan (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 = u"https://twblue.es" url = u"https://twblue.es"
report_bugs_url = "https://github.com/manuelcortez/twblue/issues" report_bugs_url = "https://github.com/manuelcortez/twblue/issues"
supported_languages = [] supported_languages = []

View File

@ -2,22 +2,22 @@ from __future__ import unicode_literals
from functools import wraps from functools import wraps
def matches_url(url): def matches_url(url):
def url_setter(func): def url_setter(func):
@wraps(func) @wraps(func)
def internal_url_setter(*args, **kwargs): def internal_url_setter(*args, **kwargs):
return func(*args, **kwargs) return func(*args, **kwargs)
internal_url_setter.url = url internal_url_setter.url = url
return internal_url_setter return internal_url_setter
return url_setter return url_setter
def find_url_transformer(url): def find_url_transformer(url):
from audio_services import services from audio_services import services
funcs = [] funcs = []
for i in dir(services): for i in dir(services):
possible = getattr(services, i) possible = getattr(services, i)
if callable(possible) and hasattr(possible, 'url'): if callable(possible) and hasattr(possible, 'url'):
funcs.append(possible) funcs.append(possible)
for f in funcs: for f in funcs:
if url.lower().startswith(f.url.lower()): if url.lower().startswith(f.url.lower()):
return f return f
return services.convert_generic_audio return services.convert_generic_audio

View File

@ -5,37 +5,37 @@ from . import youtube_utils
@matches_url('https://audioboom.com') @matches_url('https://audioboom.com')
def convert_audioboom(url): def convert_audioboom(url):
if "audioboom.com" not in url.lower(): if "audioboom.com" not in url.lower():
raise TypeError('%r is not a valid URL' % url) raise TypeError('%r is not a valid URL' % url)
audio_id = url.split('.com/')[-1] audio_id = url.split('.com/')[-1]
return 'https://audioboom.com/%s.mp3' % audio_id return 'https://audioboom.com/%s.mp3' % audio_id
@matches_url ('https://soundcloud.com/') @matches_url ('https://soundcloud.com/')
def convert_soundcloud (url): def convert_soundcloud (url):
client_id = "df8113ca95c157b6c9731f54b105b473" client_id = "df8113ca95c157b6c9731f54b105b473"
with requests.get('http://api.soundcloud.com/resolve.json', client_id=client_id, url=url) as permalink: with requests.get('http://api.soundcloud.com/resolve.json', client_id=client_id, url=url) as permalink:
if permalink.status_code==404: if permalink.status_code==404:
raise TypeError('%r is not a valid URL' % permalink.url) raise TypeError('%r is not a valid URL' % permalink.url)
else: else:
resolved_url = permalink.url resolved_url = permalink.url
with requests.get(resolved_url) as track_url: with requests.get(resolved_url) as track_url:
track_data = track_url.json() track_data = track_url.json()
if track_data ['streamable']: if track_data ['streamable']:
return track_data ['stream_url'] + "?client_id=%s" %client_id return track_data ['stream_url'] + "?client_id=%s" %client_id
else: else:
raise TypeError('%r is not streamable' % url) raise TypeError('%r is not streamable' % url)
@matches_url ('https://www.youtube.com/watch') @matches_url ('https://www.youtube.com/watch')
def convert_youtube_long (url): def convert_youtube_long (url):
return youtube_utils.get_video_url(url) return youtube_utils.get_video_url(url)
@matches_url ('http://anyaudio.net/listen') @matches_url ('http://anyaudio.net/listen')
def convert_anyaudio(url): def convert_anyaudio(url):
values = url.split("audio=") values = url.split("audio=")
if len(values) != 2: if len(values) != 2:
raise TypeError('%r is not streamable' % url) raise TypeError('%r is not streamable' % url)
return "http://anyaudio.net/audiodownload?audio=%s" % (values[1],) return "http://anyaudio.net/audiodownload?audio=%s" % (values[1],)
def convert_generic_audio(url): def convert_generic_audio(url):
return url return url

View File

@ -3,11 +3,11 @@ from __future__ import unicode_literals
import youtube_dl import youtube_dl
def get_video_url(url): def get_video_url(url):
ydl = youtube_dl.YoutubeDL({'quiet': True, 'format': 'bestaudio/best', 'outtmpl': u'%(id)s%(ext)s'}) ydl = youtube_dl.YoutubeDL({'quiet': True, 'format': 'bestaudio/best', 'outtmpl': u'%(id)s%(ext)s'})
with ydl: with ydl:
result = ydl.extract_info(url, download=False) result = ydl.extract_info(url, download=False)
if 'entries' in result: if 'entries' in result:
video = result['entries'][0] video = result['entries'][0]
else: else:
video = result video = result
return video["formats"][0]["url"] return video["formats"][0]["url"]

View File

@ -15,14 +15,14 @@ keymap=None
changed_keymap = False changed_keymap = False
def setup (): def setup ():
global app global app
log.debug("Loading global app settings...") log.debug("Loading global app settings...")
app = config_utils.load_config(os.path.join(paths.config_path(), MAINFILE), os.path.join(paths.app_path(), MAINSPEC)) app = config_utils.load_config(os.path.join(paths.config_path(), MAINFILE), os.path.join(paths.app_path(), MAINSPEC))
log.debug("Loading keymap...") log.debug("Loading keymap...")
global keymap global keymap
if float(platform.version()[:2]) >= 10 and app["app-settings"]["load_keymap"] == "default.keymap": if float(platform.version()[:2]) >= 10 and app["app-settings"]["load_keymap"] == "default.keymap":
app["app-settings"]["load_keymap"] = "Windows 10.keymap" app["app-settings"]["load_keymap"] = "Windows 10.keymap"
app.write() app.write()
global changed_keymap global changed_keymap
changed_keymap = True changed_keymap = True
keymap = config_utils.load_config(os.path.join(paths.config_path(), "keymap.keymap"), os.path.join(paths.app_path(), "keymaps/"+app['app-settings']['load_keymap']), copy=False) keymap = config_utils.load_config(os.path.join(paths.config_path(), "keymap.keymap"), os.path.join(paths.app_path(), "keymaps/"+app['app-settings']['load_keymap']), copy=False)

View File

@ -9,69 +9,69 @@ log = getLogger("config_utils")
class ConfigLoadError(Exception): pass class ConfigLoadError(Exception): pass
def load_config(config_path, configspec_path=None, copy=True, *args, **kwargs): def load_config(config_path, configspec_path=None, copy=True, *args, **kwargs):
spec = ConfigObj(configspec_path, encoding='UTF8', list_values=False, _inspec=True) spec = ConfigObj(configspec_path, encoding='UTF8', list_values=False, _inspec=True)
try: try:
config = ConfigObj(infile=config_path, configspec=spec, create_empty=True, encoding='UTF8', *args, **kwargs) config = ConfigObj(infile=config_path, configspec=spec, create_empty=True, encoding='UTF8', *args, **kwargs)
except ParseError: except ParseError:
raise ConfigLoadError("Unable to load %r" % config_path) raise ConfigLoadError("Unable to load %r" % config_path)
validator = Validator() validator = Validator()
validated = config.validate(validator, preserve_errors=False, copy=copy) validated = config.validate(validator, preserve_errors=False, copy=copy)
if validated == True: if validated == True:
config.write() config.write()
return config return config
else: else:
log.exception("Error in config file: {0}".format(validated,)) log.exception("Error in config file: {0}".format(validated,))
def is_blank(arg): def is_blank(arg):
"Check if a line is blank." "Check if a line is blank."
for c in arg: for c in arg:
if c not in string.whitespace: if c not in string.whitespace:
return False return False
return True return True
def get_keys(path): def get_keys(path):
"Gets the keys of a configobj config file." "Gets the keys of a configobj config file."
res=[] res=[]
fin=open(path) fin=open(path)
for line in fin: for line in fin:
if not is_blank(line): if not is_blank(line):
res.append(line[0:line.find('=')].strip()) res.append(line[0:line.find('=')].strip())
fin.close() fin.close()
return res return res
def hist(keys): def hist(keys):
"Generates a histogram of an iterable." "Generates a histogram of an iterable."
res={} res={}
for k in keys: for k in keys:
res[k]=res.setdefault(k,0)+1 res[k]=res.setdefault(k,0)+1
return res return res
def find_problems(hist): def find_problems(hist):
"Takes a histogram and returns a list of items occurring more than once." "Takes a histogram and returns a list of items occurring more than once."
res=[] res=[]
for k,v in hist.items(): for k,v in hist.items():
if v>1: if v>1:
res.append(k) res.append(k)
return res return res
def clean_config(path): def clean_config(path):
"Cleans a config file. If duplicate values are found, delete all of them and just use the default." "Cleans a config file. If duplicate values are found, delete all of them and just use the default."
orig=[] orig=[]
cleaned=[] cleaned=[]
fin=open(path) fin=open(path)
for line in fin: for line in fin:
orig.append(line) orig.append(line)
fin.close() fin.close()
for p in find_problems(hist(get_keys(path))): for p in find_problems(hist(get_keys(path))):
for o in orig: for o in orig:
o.strip() o.strip()
if p not in o: if p not in o:
cleaned.append(o) cleaned.append(o)
if len(cleaned) != 0: if len(cleaned) != 0:
cam=open(path,'w') cam=open(path,'w')
for c in cleaned: for c in cleaned:
cam.write(c) cam.write(c)
cam.close() cam.close()
return True return True
else: else:
return False return False

View File

@ -8,33 +8,33 @@ from wxUI.dialogs import attach as gui
log = logging.getLogger("controller.attach") log = logging.getLogger("controller.attach")
class attach(object): class attach(object):
def __init__(self): def __init__(self):
self.attachments = list() self.attachments = list()
self.dialog = gui.attachDialog() self.dialog = gui.attachDialog()
widgetUtils.connect_event(self.dialog.photo, widgetUtils.BUTTON_PRESSED, self.upload_image) widgetUtils.connect_event(self.dialog.photo, widgetUtils.BUTTON_PRESSED, self.upload_image)
widgetUtils.connect_event(self.dialog.remove, widgetUtils.BUTTON_PRESSED, self.remove_attachment) widgetUtils.connect_event(self.dialog.remove, widgetUtils.BUTTON_PRESSED, self.remove_attachment)
self.dialog.get_response() self.dialog.get_response()
log.debug("Attachments controller started.") log.debug("Attachments controller started.")
def upload_image(self, *args, **kwargs): def upload_image(self, *args, **kwargs):
image, description = self.dialog.get_image() image, description = self.dialog.get_image()
if image != None: if image != None:
imageInfo = {"type": "photo", "file": image, "description": description} imageInfo = {"type": "photo", "file": image, "description": description}
log.debug("Image data to upload: %r" % (imageInfo,)) log.debug("Image data to upload: %r" % (imageInfo,))
self.attachments.append(imageInfo) self.attachments.append(imageInfo)
info = [_(u"Photo"), description] info = [_(u"Photo"), description]
self.dialog.attachments.insert_item(False, *info) self.dialog.attachments.insert_item(False, *info)
self.dialog.remove.Enable(True) self.dialog.remove.Enable(True)
def remove_attachment(self, *args, **kwargs): def remove_attachment(self, *args, **kwargs):
current_item = self.dialog.attachments.get_selected() current_item = self.dialog.attachments.get_selected()
log.debug("Removing item %d" % (current_item,)) log.debug("Removing item %d" % (current_item,))
if current_item == -1: current_item = 0 if current_item == -1: current_item = 0
self.attachments.pop(current_item) self.attachments.pop(current_item)
self.dialog.attachments.remove_item(current_item) self.dialog.attachments.remove_item(current_item)
self.check_remove_status() self.check_remove_status()
log.debug("Removed") log.debug("Removed")
def check_remove_status(self): def check_remove_status(self):
if len(self.attachments) == 0 and self.dialog.attachments.get_count() == 0: if len(self.attachments) == 0 and self.dialog.attachments.get_count() == 0:
self.dialog.remove.Enable(False) self.dialog.remove.Enable(False)

View File

@ -5,4 +5,4 @@
* baseBuffers: Define a set of functions and structure to be expected in all buffers. New buffers should inherit its classes from one of the classes present here. * baseBuffers: Define a set of functions and structure to be expected in all buffers. New buffers should inherit its classes from one of the classes present here.
* twitterBuffers: All other code, specific to Twitter. * twitterBuffers: All other code, specific to Twitter.
""" """
from __future__ import unicode_literals from __future__ import unicode_literals

View File

@ -14,196 +14,196 @@ from wxUI import buffers
log = logging.getLogger("controller.buffers.baseBuffers") log = logging.getLogger("controller.buffers.baseBuffers")
def _items_exist(function): def _items_exist(function):
""" A decorator to execute a function only if the selected buffer contains at least one item.""" """ A decorator to execute a function only if the selected buffer contains at least one item."""
def function_(self, *args, **kwargs): def function_(self, *args, **kwargs):
if self.buffer.list.get_count() > 0: if self.buffer.list.get_count() > 0:
function(self, *args, **kwargs) function(self, *args, **kwargs)
return function_ return function_
class buffer(object): class buffer(object):
""" A basic buffer object. This should be the base class for all other derived buffers.""" """ A basic buffer object. This should be the base class for all other derived buffers."""
def __init__(self, parent=None, function=None, session=None, *args, **kwargs): def __init__(self, parent=None, function=None, session=None, *args, **kwargs):
"""Inits the main controller for this buffer: """Inits the main controller for this buffer:
@ parent wx.Treebook object: Container where we will put this buffer. @ parent wx.Treebook object: Container where we will put this buffer.
@ function str or None: function to be called periodically and update items on this buffer. @ function str or None: function to be called periodically and update items on this buffer.
@ session sessionmanager.session object or None: Session handler for settings, database and data access. @ session sessionmanager.session object or None: Session handler for settings, database and data access.
""" """
super(buffer, self).__init__() super(buffer, self).__init__()
self.function = function self.function = function
# Compose_function will be used to render an object on this buffer. Normally, signature is as follows: # Compose_function will be used to render an object on this buffer. Normally, signature is as follows:
# compose_function(item, db, relative_times, show_screen_names=False, session=None) # compose_function(item, db, relative_times, show_screen_names=False, session=None)
# Read more about compose functions in twitter/compose.py. # Read more about compose functions in twitter/compose.py.
self.compose_function = None self.compose_function = None
self.args = args self.args = args
self.kwargs = kwargs self.kwargs = kwargs
# This will be used as a reference to the wx.Panel object wich stores the buffer GUI. # This will be used as a reference to the wx.Panel object wich stores the buffer GUI.
self.buffer = None self.buffer = None
# This should countains the account associated to this buffer. # This should countains the account associated to this buffer.
self.account = "" self.account = ""
# This controls whether the start_stream function should be called when starting the program. # This controls whether the start_stream function should be called when starting the program.
self.needs_init = True self.needs_init = True
# if this is set to False, the buffer will be ignored on the invisible interface. # if this is set to False, the buffer will be ignored on the invisible interface.
self.invisible = False self.invisible = False
# Control variable, used to track time of execution for calls to start_stream. # Control variable, used to track time of execution for calls to start_stream.
self.execution_time = 0 self.execution_time = 0
def clear_list(self): def clear_list(self):
pass pass
def get_event(self, ev): def get_event(self, ev):
""" Catch key presses in the WX interface and generate the corresponding event names.""" """ Catch key presses in the WX interface and generate the corresponding event names."""
if ev.GetKeyCode() == wx.WXK_RETURN and ev.ControlDown(): event = "audio" if ev.GetKeyCode() == wx.WXK_RETURN and ev.ControlDown(): event = "audio"
elif ev.GetKeyCode() == wx.WXK_RETURN: event = "url" elif ev.GetKeyCode() == wx.WXK_RETURN: event = "url"
elif ev.GetKeyCode() == wx.WXK_F5: event = "volume_down" elif ev.GetKeyCode() == wx.WXK_F5: event = "volume_down"
elif ev.GetKeyCode() == wx.WXK_F6: event = "volume_up" elif ev.GetKeyCode() == wx.WXK_F6: event = "volume_up"
elif ev.GetKeyCode() == wx.WXK_DELETE and ev.ShiftDown(): event = "clear_list" elif ev.GetKeyCode() == wx.WXK_DELETE and ev.ShiftDown(): event = "clear_list"
elif ev.GetKeyCode() == wx.WXK_DELETE: event = "destroy_status" elif ev.GetKeyCode() == wx.WXK_DELETE: event = "destroy_status"
# Raise a Special event when pressed Shift+F10 because Wx==4.1.x does not seems to trigger this by itself. # Raise a Special event when pressed Shift+F10 because Wx==4.1.x does not seems to trigger this by itself.
# See https://github.com/manuelcortez/TWBlue/issues/353 # See https://github.com/manuelcortez/TWBlue/issues/353
elif ev.GetKeyCode() == wx.WXK_F10 and ev.ShiftDown(): event = "show_menu" elif ev.GetKeyCode() == wx.WXK_F10 and ev.ShiftDown(): event = "show_menu"
else: else:
event = None event = None
ev.Skip() ev.Skip()
if event != None: if event != None:
try: try:
### ToDo: Remove after WX fixes issue #353 in the widgets. ### ToDo: Remove after WX fixes issue #353 in the widgets.
if event == "show_menu": if event == "show_menu":
return self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition()) return self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition())
getattr(self, event)() getattr(self, event)()
except AttributeError: except AttributeError:
pass pass
def volume_down(self): def volume_down(self):
""" Decreases volume by 5%""" """ Decreases volume by 5%"""
if self.session.settings["sound"]["volume"] > 0.0: if self.session.settings["sound"]["volume"] > 0.0:
if self.session.settings["sound"]["volume"] <= 0.05: if self.session.settings["sound"]["volume"] <= 0.05:
self.session.settings["sound"]["volume"] = 0.0 self.session.settings["sound"]["volume"] = 0.0
else: else:
self.session.settings["sound"]["volume"] -=0.05 self.session.settings["sound"]["volume"] -=0.05
sound.URLPlayer.player.audio_set_volume(int(self.session.settings["sound"]["volume"]*100.0)) sound.URLPlayer.player.audio_set_volume(int(self.session.settings["sound"]["volume"]*100.0))
self.session.sound.play("volume_changed.ogg") self.session.sound.play("volume_changed.ogg")
self.session.settings.write() self.session.settings.write()
def volume_up(self): def volume_up(self):
""" Increases volume by 5%.""" """ Increases volume by 5%."""
if self.session.settings["sound"]["volume"] < 1.0: if self.session.settings["sound"]["volume"] < 1.0:
if self.session.settings["sound"]["volume"] >= 0.95: if self.session.settings["sound"]["volume"] >= 0.95:
self.session.settings["sound"]["volume"] = 1.0 self.session.settings["sound"]["volume"] = 1.0
else: else:
self.session.settings["sound"]["volume"] +=0.05 self.session.settings["sound"]["volume"] +=0.05
sound.URLPlayer.player.audio_set_volume(int(self.session.settings["sound"]["volume"]*100)) sound.URLPlayer.player.audio_set_volume(int(self.session.settings["sound"]["volume"]*100))
self.session.sound.play("volume_changed.ogg") self.session.sound.play("volume_changed.ogg")
self.session.settings.write() self.session.settings.write()
def start_stream(self, mandatory=False, play_sound=True): def start_stream(self, mandatory=False, play_sound=True):
pass pass
def get_more_items(self): def get_more_items(self):
output.speak(_(u"This action is not supported for this buffer"), True) output.speak(_(u"This action is not supported for this buffer"), True)
def put_items_on_list(self, items): def put_items_on_list(self, items):
pass pass
def remove_buffer(self): def remove_buffer(self):
return False return False
def remove_item(self, item): def remove_item(self, item):
f = self.buffer.list.get_selected() f = self.buffer.list.get_selected()
self.buffer.list.remove_item(item) self.buffer.list.remove_item(item)
self.buffer.list.select_item(f) self.buffer.list.select_item(f)
def bind_events(self): def bind_events(self):
pass pass
def get_object(self): def get_object(self):
return self.buffer return self.buffer
def get_message(self): def get_message(self):
pass pass
def set_list_position(self, reversed=False): def set_list_position(self, reversed=False):
if reversed == False: if reversed == False:
self.buffer.list.select_item(-1) self.buffer.list.select_item(-1)
else: else:
self.buffer.list.select_item(0) self.buffer.list.select_item(0)
def reply(self): def reply(self):
pass pass
def send_message(self): def send_message(self):
pass pass
def share_item(self): def share_item(self):
pass pass
def destroy_status(self): def destroy_status(self):
pass pass
def post_status(self, *args, **kwargs): def post_status(self, *args, **kwargs):
pass pass
def save_positions(self): def save_positions(self):
try: try:
self.session.db[self.name+"_pos"]=self.buffer.list.get_selected() self.session.db[self.name+"_pos"]=self.buffer.list.get_selected()
except AttributeError: except AttributeError:
pass pass
class accountPanel(buffer): class accountPanel(buffer):
def __init__(self, parent, name, account, account_id): def __init__(self, parent, name, account, account_id):
super(accountPanel, self).__init__(parent, None, name) super(accountPanel, self).__init__(parent, None, name)
log.debug("Initializing buffer %s, account %s" % (name, account,)) log.debug("Initializing buffer %s, account %s" % (name, account,))
self.buffer = buffers.accountPanel(parent, name) self.buffer = buffers.accountPanel(parent, name)
self.type = self.buffer.type self.type = self.buffer.type
self.compose_function = None self.compose_function = None
self.session = None self.session = None
self.needs_init = False self.needs_init = False
self.account = account self.account = account
self.buffer.account = account self.buffer.account = account
self.name = name self.name = name
self.account_id = account_id self.account_id = account_id
def setup_account(self): def setup_account(self):
widgetUtils.connect_event(self.buffer, widgetUtils.CHECKBOX, self.autostart, menuitem=self.buffer.autostart_account) widgetUtils.connect_event(self.buffer, widgetUtils.CHECKBOX, self.autostart, menuitem=self.buffer.autostart_account)
if self.account_id in config.app["sessions"]["ignored_sessions"]: if self.account_id in config.app["sessions"]["ignored_sessions"]:
self.buffer.change_autostart(False) self.buffer.change_autostart(False)
else: else:
self.buffer.change_autostart(True) self.buffer.change_autostart(True)
if not hasattr(self, "logged"): if not hasattr(self, "logged"):
self.buffer.change_login(login=False) self.buffer.change_login(login=False)
widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.logout) widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.logout)
else: else:
self.buffer.change_login(login=True) self.buffer.change_login(login=True)
widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.login) widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.login)
def login(self, *args, **kwargs): def login(self, *args, **kwargs):
del self.logged del self.logged
self.setup_account() self.setup_account()
pub.sendMessage("login", session_id=self.account_id) pub.sendMessage("login", session_id=self.account_id)
def logout(self, *args, **kwargs): def logout(self, *args, **kwargs):
self.logged = False self.logged = False
self.setup_account() self.setup_account()
pub.sendMessage("logout", session_id=self.account_id) pub.sendMessage("logout", session_id=self.account_id)
def autostart(self, *args, **kwargs): def autostart(self, *args, **kwargs):
if self.account_id in config.app["sessions"]["ignored_sessions"]: if self.account_id in config.app["sessions"]["ignored_sessions"]:
self.buffer.change_autostart(True) self.buffer.change_autostart(True)
config.app["sessions"]["ignored_sessions"].remove(self.account_id) config.app["sessions"]["ignored_sessions"].remove(self.account_id)
else: else:
self.buffer.change_autostart(False) self.buffer.change_autostart(False)
config.app["sessions"]["ignored_sessions"].append(self.account_id) config.app["sessions"]["ignored_sessions"].append(self.account_id)
config.app.write() config.app.write()
class emptyPanel(buffer): class emptyPanel(buffer):
def __init__(self, parent, name, account): def __init__(self, parent, name, account):
super(emptyPanel, self).__init__(parent=parent) super(emptyPanel, self).__init__(parent=parent)
log.debug("Initializing buffer %s, account %s" % (name, account,)) log.debug("Initializing buffer %s, account %s" % (name, account,))
self.buffer = buffers.emptyPanel(parent, name) self.buffer = buffers.emptyPanel(parent, name)
self.type = self.buffer.type self.type = self.buffer.type
self.compose_function = None self.compose_function = None
self.account = account self.account = account
self.buffer.account = account self.buffer.account = account
self.name = name self.name = name
self.session = None self.session = None
self.needs_init = True self.needs_init = True

File diff suppressed because it is too large Load Diff

View File

@ -8,71 +8,71 @@ from wxUI.dialogs import filterDialogs
from wxUI import commonMessageDialogs from wxUI import commonMessageDialogs
class filter(object): class filter(object):
def __init__(self, buffer, filter_title=None, if_word_exists=None, in_lang=None, regexp=None, word=None, in_buffer=None): 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.buffer = buffer
self.dialog = filterDialogs.filterDialog(languages=[i["name"] for i in application.supported_languages]) self.dialog = filterDialogs.filterDialog(languages=[i["name"] for i in application.supported_languages])
if self.dialog.get_response() == widgetUtils.OK: if self.dialog.get_response() == widgetUtils.OK:
title = self.dialog.get("title") title = self.dialog.get("title")
contains = self.dialog.get("contains") contains = self.dialog.get("contains")
term = self.dialog.get("term") term = self.dialog.get("term")
regexp = self.dialog.get("regexp") regexp = self.dialog.get("regexp")
allow_rts = self.dialog.get("allow_rts") allow_rts = self.dialog.get("allow_rts")
allow_quotes = self.dialog.get("allow_quotes") allow_quotes = self.dialog.get("allow_quotes")
allow_replies = self.dialog.get("allow_replies") allow_replies = self.dialog.get("allow_replies")
load_language = self.dialog.get("load_language") load_language = self.dialog.get("load_language")
ignore_language = self.dialog.get("ignore_language") ignore_language = self.dialog.get("ignore_language")
lang_option = None lang_option = None
if ignore_language: if ignore_language:
lang_option = False lang_option = False
elif load_language: elif load_language:
lang_option = True lang_option = True
langs = self.dialog.get_selected_langs() langs = self.dialog.get_selected_langs()
langcodes = [] langcodes = []
for i in application.supported_languages: for i in application.supported_languages:
if i["name"] in langs: if i["name"] in langs:
langcodes.append(i["code"]) 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) 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"]: if title in self.buffer.session.settings["filters"]:
return commonMessageDialogs.existing_filter() return commonMessageDialogs.existing_filter()
self.buffer.session.settings["filters"][title] = d self.buffer.session.settings["filters"][title] = d
self.buffer.session.settings.write() self.buffer.session.settings.write()
class filterManager(object): class filterManager(object):
def __init__(self, session): def __init__(self, session):
self.session = session self.session = session
self.dialog = filterDialogs.filterManagerDialog() self.dialog = filterDialogs.filterManagerDialog()
self.insert_filters(self.session.settings["filters"]) self.insert_filters(self.session.settings["filters"])
if self.dialog.filters.get_count() == 0: if self.dialog.filters.get_count() == 0:
self.dialog.edit.Enable(False) self.dialog.edit.Enable(False)
self.dialog.delete.Enable(False) self.dialog.delete.Enable(False)
else: else:
widgetUtils.connect_event(self.dialog.edit, widgetUtils.BUTTON_PRESSED, self.edit_filter) widgetUtils.connect_event(self.dialog.edit, widgetUtils.BUTTON_PRESSED, self.edit_filter)
widgetUtils.connect_event(self.dialog.delete, widgetUtils.BUTTON_PRESSED, self.delete_filter) widgetUtils.connect_event(self.dialog.delete, widgetUtils.BUTTON_PRESSED, self.delete_filter)
response = self.dialog.get_response() response = self.dialog.get_response()
def insert_filters(self, filters): def insert_filters(self, filters):
self.dialog.filters.clear() self.dialog.filters.clear()
for f in list(filters.keys()): for f in list(filters.keys()):
filterName = f filterName = f
buffer = filters[f]["in_buffer"] buffer = filters[f]["in_buffer"]
if filters[f]["if_word_exists"] == "True" and filters[f]["word"] != "": if filters[f]["if_word_exists"] == "True" and filters[f]["word"] != "":
filter_by_word = "True" filter_by_word = "True"
else: else:
filter_by_word = "False" filter_by_word = "False"
filter_by_lang = "" filter_by_lang = ""
if filters[f]["in_lang"] != "None": if filters[f]["in_lang"] != "None":
filter_by_lang = "True" filter_by_lang = "True"
b = [f, buffer, filter_by_word, filter_by_lang] b = [f, buffer, filter_by_word, filter_by_lang]
self.dialog.filters.insert_item(False, *b) self.dialog.filters.insert_item(False, *b)
def edit_filter(self, *args, **kwargs): def edit_filter(self, *args, **kwargs):
pass pass
def delete_filter(self, *args, **kwargs): def delete_filter(self, *args, **kwargs):
filter_title = self.dialog.filters.get_text_column(self.dialog.filters.get_selected(), 0) filter_title = self.dialog.filters.get_text_column(self.dialog.filters.get_selected(), 0)
response = commonMessageDialogs.delete_filter() response = commonMessageDialogs.delete_filter()
if response == widgetUtils.YES: if response == widgetUtils.YES:
self.session.settings["filters"].pop(filter_title) self.session.settings["filters"].pop(filter_title)
self.session.settings.write() self.session.settings.write()
self.insert_filters(self.session.settings["filters"]) self.insert_filters(self.session.settings["filters"])

View File

@ -10,101 +10,101 @@ from pubsub import pub
log = logging.getLogger("controller.listsController") log = logging.getLogger("controller.listsController")
class listsController(object): class listsController(object):
def __init__(self, session, user=None): def __init__(self, session, user=None):
super(listsController, self).__init__() super(listsController, self).__init__()
self.session = session self.session = session
if user == None: if user == None:
self.dialog = lists.listViewer() self.dialog = lists.listViewer()
self.dialog.populate_list(self.get_all_lists()) 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.createBtn, widgetUtils.BUTTON_PRESSED, self.create_list)
widgetUtils.connect_event(self.dialog.editBtn, widgetUtils.BUTTON_PRESSED, self.edit_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.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.view, widgetUtils.BUTTON_PRESSED, self.open_list_as_buffer)
widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.remove_list) widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.remove_list)
else: else:
self.dialog = lists.userListViewer(user) self.dialog = lists.userListViewer(user)
self.dialog.populate_list(self.get_user_lists(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.createBtn, widgetUtils.BUTTON_PRESSED, self.subscribe)
widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.unsubscribe) widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.unsubscribe)
self.dialog.get_response() self.dialog.get_response()
def get_all_lists(self): def get_all_lists(self):
return [compose.compose_list(item) for item in self.session.db["lists"]] return [compose.compose_list(item) for item in self.session.db["lists"]]
def get_user_lists(self, user): def get_user_lists(self, user):
self.lists = self.session.twitter.lists_all(reverse=True, screen_name=user) self.lists = self.session.twitter.lists_all(reverse=True, screen_name=user)
return [compose.compose_list(item) for item in self.lists] return [compose.compose_list(item) for item in self.lists]
def create_list(self, *args, **kwargs): def create_list(self, *args, **kwargs):
dialog = lists.createListDialog() dialog = lists.createListDialog()
if dialog.get_response() == widgetUtils.OK: if dialog.get_response() == widgetUtils.OK:
name = dialog.get("name") name = dialog.get("name")
description = dialog.get("description") description = dialog.get("description")
p = dialog.get("public") p = dialog.get("public")
if p == True: if p == True:
mode = "public" mode = "public"
else: else:
mode = "private" mode = "private"
try: try:
new_list = self.session.twitter.create_list(name=name, description=description, mode=mode) new_list = self.session.twitter.create_list(name=name, description=description, mode=mode)
self.session.db["lists"].append(new_list) self.session.db["lists"].append(new_list)
self.dialog.lista.insert_item(False, *compose.compose_list(new_list)) self.dialog.lista.insert_item(False, *compose.compose_list(new_list))
except TweepError as e: except TweepError as e:
output.speak("error %s: %s" % (e.api_code, e.reason)) output.speak("error %s: %s" % (e.api_code, e.reason))
log.exception("error %s: %s" % (e.api_code, e.reason)) log.exception("error %s: %s" % (e.api_code, e.reason))
dialog.destroy() dialog.destroy()
def edit_list(self, *args, **kwargs): def edit_list(self, *args, **kwargs):
if self.dialog.lista.get_count() == 0: return if self.dialog.lista.get_count() == 0: return
list = self.session.db["lists"][self.dialog.get_item()] list = self.session.db["lists"][self.dialog.get_item()]
dialog = lists.editListDialog(list) dialog = lists.editListDialog(list)
if dialog.get_response() == widgetUtils.OK: if dialog.get_response() == widgetUtils.OK:
name = dialog.get("name") name = dialog.get("name")
description = dialog.get("description") description = dialog.get("description")
p = dialog.get("public") p = dialog.get("public")
if p == True: if p == True:
mode = "public" mode = "public"
else: else:
mode = "private" mode = "private"
try: try:
self.session.twitter.update_list(list_id=list.id, name=name, description=description, mode=mode) self.session.twitter.update_list(list_id=list.id, name=name, description=description, mode=mode)
self.session.get_lists() self.session.get_lists()
self.dialog.populate_list(self.get_all_lists(), True) self.dialog.populate_list(self.get_all_lists(), True)
except TweepError as e: except TweepError as e:
output.speak("error %s: %s" % (e.api_code, e.reason)) output.speak("error %s: %s" % (e.api_code, e.reason))
dialog.destroy() dialog.destroy()
def remove_list(self, *args, **kwargs): def remove_list(self, *args, **kwargs):
if self.dialog.lista.get_count() == 0: return if self.dialog.lista.get_count() == 0: return
list = self.session.db["lists"][self.dialog.get_item()].id list = self.session.db["lists"][self.dialog.get_item()].id
if lists.remove_list() == widgetUtils.YES: if lists.remove_list() == widgetUtils.YES:
try: try:
self.session.twitter.destroy_list(list_id=list) self.session.twitter.destroy_list(list_id=list)
self.session.db["lists"].pop(self.dialog.get_item()) self.session.db["lists"].pop(self.dialog.get_item())
self.dialog.lista.remove_item(self.dialog.get_item()) self.dialog.lista.remove_item(self.dialog.get_item())
except TweepError as e: except TweepError as e:
output.speak("error %s: %s" % (e.api_code, e.reason)) output.speak("error %s: %s" % (e.api_code, e.reason))
def open_list_as_buffer(self, *args, **kwargs): def open_list_as_buffer(self, *args, **kwargs):
if self.dialog.lista.get_count() == 0: return if self.dialog.lista.get_count() == 0: return
list = self.session.db["lists"][self.dialog.get_item()] list = self.session.db["lists"][self.dialog.get_item()]
pub.sendMessage("create-new-buffer", buffer="list", account=self.session.db["user_name"], create=list.name) pub.sendMessage("create-new-buffer", buffer="list", account=self.session.db["user_name"], create=list.name)
def subscribe(self, *args, **kwargs): def subscribe(self, *args, **kwargs):
if self.dialog.lista.get_count() == 0: return if self.dialog.lista.get_count() == 0: return
list_id = self.lists[self.dialog.get_item()].id list_id = self.lists[self.dialog.get_item()].id
try: try:
list = self.session.twitter.subscribe_list(list_id=list_id) list = self.session.twitter.subscribe_list(list_id=list_id)
item = utils.find_item(list.id, self.session.db["lists"]) item = utils.find_item(list.id, self.session.db["lists"])
self.session.db["lists"].append(list) self.session.db["lists"].append(list)
except TweepError as e: except TweepError as e:
output.speak("error %s: %s" % (e.api_code, e.reason)) output.speak("error %s: %s" % (e.api_code, e.reason))
def unsubscribe(self, *args, **kwargs): def unsubscribe(self, *args, **kwargs):
if self.dialog.lista.get_count() == 0: return if self.dialog.lista.get_count() == 0: return
list_id = self.lists[self.dialog.get_item()].id list_id = self.lists[self.dialog.get_item()].id
try: try:
list = self.session.twitter.unsubscribe_list(list_id=list_id) list = self.session.twitter.unsubscribe_list(list_id=list_id)
self.session.db["lists"].remove(list) self.session.db["lists"].remove(list)
except TweepError as e: except TweepError as e:
output.speak("error %s: %s" % (e.api_code, e.reason)) output.speak("error %s: %s" % (e.api_code, e.reason))

File diff suppressed because it is too large Load Diff

View File

@ -12,281 +12,281 @@ import config
from pubsub import pub from pubsub import pub
from twitter_text import parse_tweet from twitter_text import parse_tweet
if system == "Windows": if system == "Windows":
from wxUI.dialogs import message, urlList from wxUI.dialogs import message, urlList
from wxUI import commonMessageDialogs from wxUI import commonMessageDialogs
from extra import translator, SpellChecker, autocompletionUsers from extra import translator, SpellChecker, autocompletionUsers
from extra.AudioUploader import audioUploader from extra.AudioUploader import audioUploader
elif system == "Linux": elif system == "Linux":
from gtkUI.dialogs import message from gtkUI.dialogs import message
from sessions.twitter import utils from sessions.twitter import utils
from . import attach from . import attach
class basicTweet(object): class basicTweet(object):
""" This class handles the tweet main features. Other classes should derive from this class.""" """ 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): def __init__(self, session, title, caption, text, messageType="tweet", max=280, *args, **kwargs):
super(basicTweet, self).__init__() super(basicTweet, self).__init__()
self.max = max self.max = max
self.title = title self.title = title
self.session = session self.session = session
self.message = getattr(message, messageType)(title, caption, text, *args, **kwargs) self.message = getattr(message, messageType)(title, caption, text, *args, **kwargs)
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.attach, widgetUtils.BUTTON_PRESSED, self.attach) widgetUtils.connect_event(self.message.attach, widgetUtils.BUTTON_PRESSED, self.attach)
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.shortenButton, widgetUtils.BUTTON_PRESSED, self.shorten) widgetUtils.connect_event(self.message.shortenButton, widgetUtils.BUTTON_PRESSED, self.shorten)
widgetUtils.connect_event(self.message.unshortenButton, widgetUtils.BUTTON_PRESSED, self.unshorten) widgetUtils.connect_event(self.message.unshortenButton, widgetUtils.BUTTON_PRESSED, self.unshorten)
widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate) widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate)
if hasattr(self.message, "long_tweet"): if hasattr(self.message, "long_tweet"):
widgetUtils.connect_event(self.message.long_tweet, widgetUtils.CHECKBOX, self.text_processor) widgetUtils.connect_event(self.message.long_tweet, widgetUtils.CHECKBOX, self.text_processor)
if config.app["app-settings"]["remember_mention_and_longtweet"]: if config.app["app-settings"]["remember_mention_and_longtweet"]:
self.message.long_tweet.SetValue(config.app["app-settings"]["longtweet"]) self.message.long_tweet.SetValue(config.app["app-settings"]["longtweet"])
self.attachments = [] self.attachments = []
def translate(self, event=None): def translate(self, event=None):
dlg = translator.gui.translateDialog() dlg = translator.gui.translateDialog()
if dlg.get_response() == widgetUtils.OK: if dlg.get_response() == widgetUtils.OK:
text_to_translate = self.message.get_text() text_to_translate = self.message.get_text()
language_dict = translator.translator.available_languages() language_dict = translator.translator.available_languages()
for k in language_dict: for k in language_dict:
if language_dict[k] == dlg.dest_lang.GetStringSelection(): if language_dict[k] == dlg.dest_lang.GetStringSelection():
dst = k dst = k
msg = translator.translator.translate(text=text_to_translate, target=dst) msg = translator.translator.translate(text=text_to_translate, target=dst)
self.message.set_text(msg) self.message.set_text(msg)
self.text_processor() self.text_processor()
self.message.text_focus() self.message.text_focus()
output.speak(_(u"Translated")) output.speak(_(u"Translated"))
else: else:
return return
def shorten(self, event=None): def shorten(self, event=None):
urls = utils.find_urls_in_text(self.message.get_text()) urls = utils.find_urls_in_text(self.message.get_text())
if len(urls) == 0: if len(urls) == 0:
output.speak(_(u"There's no URL to be shortened")) output.speak(_(u"There's no URL to be shortened"))
self.message.text_focus() self.message.text_focus()
elif len(urls) == 1: elif len(urls) == 1:
self.message.set_text(self.message.get_text().replace(urls[0], url_shortener.shorten(urls[0]))) self.message.set_text(self.message.get_text().replace(urls[0], url_shortener.shorten(urls[0])))
output.speak(_(u"URL shortened")) output.speak(_(u"URL shortened"))
self.text_processor() self.text_processor()
self.message.text_focus() self.message.text_focus()
elif len(urls) > 1: elif len(urls) > 1:
list_urls = urlList.urlList() list_urls = urlList.urlList()
list_urls.populate_list(urls) list_urls.populate_list(urls)
if list_urls.get_response() == widgetUtils.OK: if list_urls.get_response() == widgetUtils.OK:
self.message.set_text(self.message.get_text().replace(urls[list_urls.get_item()], url_shortener.shorten(list_urls.get_string()))) self.message.set_text(self.message.get_text().replace(urls[list_urls.get_item()], url_shortener.shorten(list_urls.get_string())))
output.speak(_(u"URL shortened")) output.speak(_(u"URL shortened"))
self.text_processor() self.text_processor()
self.message.text_focus() self.message.text_focus()
def unshorten(self, event=None): def unshorten(self, event=None):
urls = utils.find_urls_in_text(self.message.get_text()) urls = utils.find_urls_in_text(self.message.get_text())
if len(urls) == 0: if len(urls) == 0:
output.speak(_(u"There's no URL to be expanded")) output.speak(_(u"There's no URL to be expanded"))
self.message.text_focus() self.message.text_focus()
elif len(urls) == 1: elif len(urls) == 1:
self.message.set_text(self.message.get_text().replace(urls[0], url_shortener.unshorten(urls[0]))) self.message.set_text(self.message.get_text().replace(urls[0], url_shortener.unshorten(urls[0])))
output.speak(_(u"URL expanded")) output.speak(_(u"URL expanded"))
self.text_processor() self.text_processor()
self.message.text_focus() self.message.text_focus()
elif len(urls) > 1: elif len(urls) > 1:
list_urls = urlList.urlList() list_urls = urlList.urlList()
list_urls.populate_list(urls) list_urls.populate_list(urls)
if list_urls.get_response() == widgetUtils.OK: if list_urls.get_response() == widgetUtils.OK:
self.message.set_text(self.message.get_text().replace(urls[list_urls.get_item()], url_shortener.unshorten(list_urls.get_string()))) self.message.set_text(self.message.get_text().replace(urls[list_urls.get_item()], url_shortener.unshorten(list_urls.get_string())))
output.speak(_(u"URL expanded")) output.speak(_(u"URL expanded"))
self.text_processor() self.text_processor()
self.message.text_focus() self.message.text_focus()
def text_processor(self, *args, **kwargs): def text_processor(self, *args, **kwargs):
if len(self.message.get_text()) > 1: if len(self.message.get_text()) > 1:
self.message.enable_button("shortenButton") self.message.enable_button("shortenButton")
self.message.enable_button("unshortenButton") self.message.enable_button("unshortenButton")
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:
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))
if results.weightedLength > self.max: if results.weightedLength > self.max:
self.session.sound.play("max_length.ogg") self.session.sound.play("max_length.ogg")
else: else:
self.message.set_title(_(u"%s - %s characters") % (self.title, len(self.message.get_text()))) self.message.set_title(_(u"%s - %s characters") % (self.title, len(self.message.get_text())))
def spellcheck(self, event=None): def spellcheck(self, event=None):
text = self.message.get_text() text = self.message.get_text()
checker = SpellChecker.spellchecker.spellChecker(text, "") checker = SpellChecker.spellchecker.spellChecker(text, "")
if hasattr(checker, "fixed_text"): if hasattr(checker, "fixed_text"):
self.message.set_text(checker.fixed_text) self.message.set_text(checker.fixed_text)
self.text_processor() self.text_processor()
self.message.text_focus() self.message.text_focus()
def attach(self, *args, **kwargs): def attach(self, *args, **kwargs):
def completed_callback(dlg): def completed_callback(dlg):
url = dlg.uploaderFunction.get_url() url = dlg.uploaderFunction.get_url()
pub.unsubscribe(dlg.uploaderDialog.update, "uploading") pub.unsubscribe(dlg.uploaderDialog.update, "uploading")
dlg.uploaderDialog.destroy() dlg.uploaderDialog.destroy()
if "sndup.net/" in url: if "sndup.net/" in url:
self.message.set_text(self.message.get_text()+url+" #audio") self.message.set_text(self.message.get_text()+url+" #audio")
self.text_processor() self.text_processor()
else: else:
commonMessageDialogs.common_error(url) commonMessageDialogs.common_error(url)
dlg.cleanup() dlg.cleanup()
dlg = audioUploader.audioUploader(self.session.settings, completed_callback) dlg = audioUploader.audioUploader(self.session.settings, completed_callback)
self.message.text_focus() self.message.text_focus()
class tweet(basicTweet): class tweet(basicTweet):
def __init__(self, session, title, caption, text, max=280, messageType="tweet", *args, **kwargs): def __init__(self, session, title, caption, text, max=280, messageType="tweet", *args, **kwargs):
super(tweet, self).__init__(session, title, caption, text, messageType, max, *args, **kwargs) super(tweet, self).__init__(session, title, caption, text, messageType, max, *args, **kwargs)
self.image = None self.image = None
widgetUtils.connect_event(self.message.upload_image, widgetUtils.BUTTON_PRESSED, self.upload_image) widgetUtils.connect_event(self.message.upload_image, widgetUtils.BUTTON_PRESSED, self.upload_image)
widgetUtils.connect_event(self.message.autocompletionButton, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) widgetUtils.connect_event(self.message.autocompletionButton, widgetUtils.BUTTON_PRESSED, self.autocomplete_users)
self.text_processor() self.text_processor()
def upload_image(self, *args, **kwargs): def upload_image(self, *args, **kwargs):
a = attach.attach() a = attach.attach()
if len(a.attachments) != 0: if len(a.attachments) != 0:
self.attachments = a.attachments self.attachments = a.attachments
def autocomplete_users(self, *args, **kwargs): def autocomplete_users(self, *args, **kwargs):
c = autocompletionUsers.completion.autocompletionUsers(self.message, self.session.session_id) c = autocompletionUsers.completion.autocompletionUsers(self.message, self.session.session_id)
c.show_menu() c.show_menu()
class reply(tweet): class reply(tweet):
def __init__(self, session, title, caption, text, users=[], ids=[]): def __init__(self, session, title, caption, text, users=[], ids=[]):
super(reply, self).__init__(session, title, caption, text, messageType="reply", users=users) super(reply, self).__init__(session, title, caption, text, messageType="reply", users=users)
self.ids = ids self.ids = ids
self.users = users self.users = users
if len(users) > 0: if len(users) > 0:
widgetUtils.connect_event(self.message.mentionAll, widgetUtils.CHECKBOX, self.mention_all) widgetUtils.connect_event(self.message.mentionAll, widgetUtils.CHECKBOX, self.mention_all)
self.message.enable_button("mentionAll") self.message.enable_button("mentionAll")
if config.app["app-settings"]["remember_mention_and_longtweet"]: if config.app["app-settings"]["remember_mention_and_longtweet"]:
self.message.mentionAll.SetValue(config.app["app-settings"]["mention_all"]) self.message.mentionAll.SetValue(config.app["app-settings"]["mention_all"])
self.mention_all() self.mention_all()
self.message.set_cursor_at_end() self.message.set_cursor_at_end()
self.text_processor() self.text_processor()
def mention_all(self, *args, **kwargs): def mention_all(self, *args, **kwargs):
if self.message.mentionAll.GetValue() == True: if self.message.mentionAll.GetValue() == True:
for i in self.message.checkboxes: for i in self.message.checkboxes:
i.SetValue(True) i.SetValue(True)
i.Hide() i.Hide()
else: else:
for i in self.message.checkboxes: for i in self.message.checkboxes:
i.SetValue(False) i.SetValue(False)
i.Show() i.Show()
def get_ids(self): def get_ids(self):
excluded_ids = "" excluded_ids = ""
for i in range(0, len(self.message.checkboxes)): for i in range(0, len(self.message.checkboxes)):
if self.message.checkboxes[i].GetValue() == False: if self.message.checkboxes[i].GetValue() == False:
excluded_ids = excluded_ids + "{0},".format(self.ids[i],) excluded_ids = excluded_ids + "{0},".format(self.ids[i],)
return excluded_ids return excluded_ids
def get_people(self): def get_people(self):
people = "" people = ""
for i in range(0, len(self.message.checkboxes)): for i in range(0, len(self.message.checkboxes)):
if self.message.checkboxes[i].GetValue() == True: if self.message.checkboxes[i].GetValue() == True:
people = people + "{0} ".format(self.message.checkboxes[i].GetLabel(),) people = people + "{0} ".format(self.message.checkboxes[i].GetLabel(),)
return people return people
class dm(basicTweet): class dm(basicTweet):
def __init__(self, session, title, caption, text): def __init__(self, session, title, caption, text):
super(dm, self).__init__(session, title, caption, text, messageType="dm", max=10000) super(dm, self).__init__(session, title, caption, text, messageType="dm", max=10000)
widgetUtils.connect_event(self.message.autocompletionButton, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) widgetUtils.connect_event(self.message.autocompletionButton, widgetUtils.BUTTON_PRESSED, self.autocomplete_users)
self.text_processor() self.text_processor()
widgetUtils.connect_event(self.message.cb, widgetUtils.ENTERED_TEXT, self.user_changed) widgetUtils.connect_event(self.message.cb, widgetUtils.ENTERED_TEXT, self.user_changed)
def user_changed(self, *args, **kwargs): def user_changed(self, *args, **kwargs):
self.title = _("Direct message to %s") % (self.message.get_user()) self.title = _("Direct message to %s") % (self.message.get_user())
self.text_processor() self.text_processor()
def autocomplete_users(self, *args, **kwargs): def autocomplete_users(self, *args, **kwargs):
c = autocompletionUsers.completion.autocompletionUsers(self.message, self.session.session_id) c = autocompletionUsers.completion.autocompletionUsers(self.message, self.session.session_id)
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=""):
""" 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.
param is_tweet: True or false, depending wether the passed object is a tweet or not.""" param is_tweet: True or false, depending wether the passed object is a tweet or not."""
if is_tweet == True: if is_tweet == True:
self.title = _(u"Tweet") self.title = _(u"Tweet")
image_description = [] image_description = []
text = "" text = ""
for i in range(0, len(tweetList)): for i in range(0, len(tweetList)):
# tweets with message keys are longer tweets, the message value is the full messaje taken from twishort. # 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: if hasattr(tweetList[i], "message") and tweetList[i].is_quote_status == False:
value = "message" value = "message"
else: else:
value = "full_text" value = "full_text"
if hasattr(tweetList[i], "retweeted_status") and tweetList[i].is_quote_status == False: if hasattr(tweetList[i], "retweeted_status") and tweetList[i].is_quote_status == False:
if not hasattr(tweetList[i], "message"): 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) text = text + "rt @%s: %s\n" % (tweetList[i].retweeted_status.user.screen_name, tweetList[i].retweeted_status.full_text)
else: else:
text = text + "rt @%s: %s\n" % (tweetList[i].retweeted_status.user.screen_name, getattr(tweetList[i], value)) text = text + "rt @%s: %s\n" % (tweetList[i].retweeted_status.user.screen_name, getattr(tweetList[i], value))
else: else:
text = text + " @%s: %s\n" % (tweetList[i].user.screen_name, getattr(tweetList[i], value)) text = text + " @%s: %s\n" % (tweetList[i].user.screen_name, getattr(tweetList[i], value))
# tweets with extended_entities could include image descriptions. # tweets with extended_entities could include image descriptions.
if hasattr(tweetList[i], "extended_entities") and "media" in tweetList[i].extended_entities: if hasattr(tweetList[i], "extended_entities") and "media" in tweetList[i].extended_entities:
for z in tweetList[i].extended_entities["media"]: for z in tweetList[i].extended_entities["media"]:
if "ext_alt_text" in z and z["ext_alt_text"] != None: if "ext_alt_text" in z and z["ext_alt_text"] != None:
image_description.append(z["ext_alt_text"]) 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"]: 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"]: for z in tweetList[i].retweeted_status.extended_entities["media"]:
if "ext_alt_text" in z and z["ext_alt_text"] != None: if "ext_alt_text" in z and z["ext_alt_text"] != None:
image_description.append(z["ext_alt_text"]) image_description.append(z["ext_alt_text"])
# set rt and likes counters. # set rt and likes counters.
rt_count = str(tweet.retweet_count) rt_count = str(tweet.retweet_count)
favs_count = str(tweet.favorite_count) favs_count = str(tweet.favorite_count)
# Gets the client from where this tweet was made. # Gets the client from where this tweet was made.
source = tweet.source source = tweet.source
original_date = arrow.get(tweet.created_at, locale="en") 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()) date = original_date.shift(seconds=utc_offset).format(_(u"MMM D, YYYY. H:m"), locale=languageHandler.getLanguage())
if text == "": if text == "":
if hasattr(tweet, "message"): if hasattr(tweet, "message"):
value = "message" value = "message"
else: else:
value = "full_text" value = "full_text"
if hasattr(tweet, "retweeted_status"): if hasattr(tweet, "retweeted_status"):
if not hasattr(tweet, "message"): if not hasattr(tweet, "message"):
text = "rt @%s: %s" % (tweet.retweeted_status.user.screen_name, tweet.retweeted_status.full_text) text = "rt @%s: %s" % (tweet.retweeted_status.user.screen_name, tweet.retweeted_status.full_text)
else: else:
text = "rt @%s: %s" % (tweet.retweeted_status.user.screen_name, getattr(tweet, value)) text = "rt @%s: %s" % (tweet.retweeted_status.user.screen_name, getattr(tweet, value))
else: else:
text = getattr(tweet, value) text = getattr(tweet, value)
text = self.clear_text(text) text = self.clear_text(text)
if hasattr(tweet, "extended_entities") and "media" in tweet.extended_entities: if hasattr(tweet, "extended_entities") and "media" in tweet.extended_entities:
for z in tweet.extended_entities["media"]: for z in tweet.extended_entities["media"]:
if "ext_alt_text" in z and z["ext_alt_text"] != None: if "ext_alt_text" in z and z["ext_alt_text"] != None:
image_description.append(z["ext_alt_text"]) 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: 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"]: for z in tweet.retweeted_status.extended_entities["media"]:
if "ext_alt_text" in z and z["ext_alt_text"] != None: if "ext_alt_text" in z and z["ext_alt_text"] != None:
image_description.append(z["ext_alt_text"]) image_description.append(z["ext_alt_text"])
self.message = message.viewTweet(text, rt_count, favs_count, source, date) self.message = message.viewTweet(text, rt_count, favs_count, source, date)
results = parse_tweet(text) results = parse_tweet(text)
self.message.set_title(results.weightedLength) self.message.set_title(results.weightedLength)
[self.message.set_image_description(i) for i in image_description] [self.message.set_image_description(i) for i in image_description]
else: else:
self.title = _(u"View item") self.title = _(u"View item")
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)
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")
widgetUtils.connect_event(self.message.unshortenButton, widgetUtils.BUTTON_PRESSED, self.unshorten) widgetUtils.connect_event(self.message.unshortenButton, widgetUtils.BUTTON_PRESSED, self.unshorten)
self.message.get_response() self.message.get_response()
def contain_urls(self): def contain_urls(self):
if len(utils.find_urls_in_text(self.message.get_text())) > 0: if len(utils.find_urls_in_text(self.message.get_text())) > 0:
return True return True
return False return False
def clear_text(self, text): def clear_text(self, text):
urls = utils.find_urls_in_text(text) urls = utils.find_urls_in_text(text)
for i in urls: for i in urls:
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

View File

@ -24,202 +24,202 @@ from collections import OrderedDict
from mysc import autostart as autostart_windows from mysc import autostart as autostart_windows
class globalSettingsController(object): class globalSettingsController(object):
def __init__(self): def __init__(self):
super(globalSettingsController, self).__init__() super(globalSettingsController, self).__init__()
self.dialog = configuration.configurationDialog() self.dialog = configuration.configurationDialog()
self.create_config() self.create_config()
self.needs_restart = False self.needs_restart = False
self.is_started = True self.is_started = True
def make_kmmap(self): def make_kmmap(self):
res={} res={}
for i in os.listdir(os.path.join(paths.app_path(), 'keymaps')): for i in os.listdir(os.path.join(paths.app_path(), 'keymaps')):
if ".keymap" not in i: if ".keymap" not in i:
continue continue
try: try:
res[i[:-7]] =i res[i[:-7]] =i
except: except:
log.exception("Exception while loading keymap " + i) log.exception("Exception while loading keymap " + i)
return res return res
def create_config(self): def create_config(self):
self.kmmap=self.make_kmmap() self.kmmap=self.make_kmmap()
self.langs = languageHandler.getAvailableLanguages() self.langs = languageHandler.getAvailableLanguages()
langs = [] langs = []
[langs.append(i[1]) for i in self.langs] [langs.append(i[1]) for i in self.langs]
self.codes = [] self.codes = []
[self.codes.append(i[0]) for i in self.langs] [self.codes.append(i[0]) for i in self.langs]
id = self.codes.index(config.app["app-settings"]["language"]) id = self.codes.index(config.app["app-settings"]["language"])
self.kmfriendlies=[] self.kmfriendlies=[]
self.kmnames=[] self.kmnames=[]
for k,v in list(self.kmmap.items()): for k,v in list(self.kmmap.items()):
self.kmfriendlies.append(k) self.kmfriendlies.append(k)
self.kmnames.append(v) self.kmnames.append(v)
self.kmid=self.kmnames.index(config.app['app-settings']['load_keymap']) self.kmid=self.kmnames.index(config.app['app-settings']['load_keymap'])
self.dialog.create_general(langs,self.kmfriendlies) self.dialog.create_general(langs,self.kmfriendlies)
self.dialog.general.language.SetSelection(id) self.dialog.general.language.SetSelection(id)
self.dialog.general.km.SetSelection(self.kmid) self.dialog.general.km.SetSelection(self.kmid)
if paths.mode == "installed": if paths.mode == "installed":
self.dialog.set_value("general", "autostart", config.app["app-settings"]["autostart"]) self.dialog.set_value("general", "autostart", config.app["app-settings"]["autostart"])
else: else:
self.dialog.general.autostart.Enable(False) self.dialog.general.autostart.Enable(False)
self.dialog.set_value("general", "ask_at_exit", config.app["app-settings"]["ask_at_exit"]) self.dialog.set_value("general", "ask_at_exit", config.app["app-settings"]["ask_at_exit"])
self.dialog.set_value("general", "no_streaming", config.app["app-settings"]["no_streaming"]) self.dialog.set_value("general", "no_streaming", config.app["app-settings"]["no_streaming"])
self.dialog.set_value("general", "play_ready_sound", config.app["app-settings"]["play_ready_sound"]) self.dialog.set_value("general", "play_ready_sound", config.app["app-settings"]["play_ready_sound"])
self.dialog.set_value("general", "speak_ready_msg", config.app["app-settings"]["speak_ready_msg"]) self.dialog.set_value("general", "speak_ready_msg", config.app["app-settings"]["speak_ready_msg"])
self.dialog.set_value("general", "handle_longtweets", config.app["app-settings"]["handle_longtweets"]) self.dialog.set_value("general", "handle_longtweets", config.app["app-settings"]["handle_longtweets"])
self.dialog.set_value("general", "use_invisible_shorcuts", config.app["app-settings"]["use_invisible_keyboard_shorcuts"]) self.dialog.set_value("general", "use_invisible_shorcuts", config.app["app-settings"]["use_invisible_keyboard_shorcuts"])
self.dialog.set_value("general", "disable_sapi5", config.app["app-settings"]["voice_enabled"]) self.dialog.set_value("general", "disable_sapi5", config.app["app-settings"]["voice_enabled"])
self.dialog.set_value("general", "hide_gui", config.app["app-settings"]["hide_gui"]) self.dialog.set_value("general", "hide_gui", config.app["app-settings"]["hide_gui"])
self.dialog.set_value("general", "update_period", config.app["app-settings"]["update_period"]) self.dialog.set_value("general", "update_period", config.app["app-settings"]["update_period"])
self.dialog.set_value("general", "check_for_updates", config.app["app-settings"]["check_for_updates"]) self.dialog.set_value("general", "check_for_updates", config.app["app-settings"]["check_for_updates"])
self.dialog.set_value("general", "remember_mention_and_longtweet", config.app["app-settings"]["remember_mention_and_longtweet"]) self.dialog.set_value("general", "remember_mention_and_longtweet", config.app["app-settings"]["remember_mention_and_longtweet"])
proxyTypes = [_("System default"), _("HTTP"), _("SOCKS v4"), _("SOCKS v4 with DNS support"), _("SOCKS v5"), _("SOCKS v5 with DNS support")] proxyTypes = [_("System default"), _("HTTP"), _("SOCKS v4"), _("SOCKS v4 with DNS support"), _("SOCKS v5"), _("SOCKS v5 with DNS support")]
self.dialog.create_proxy(proxyTypes) self.dialog.create_proxy(proxyTypes)
try: try:
self.dialog.proxy.type.SetSelection(config.app["proxy"]["type"]) self.dialog.proxy.type.SetSelection(config.app["proxy"]["type"])
except: except:
self.dialog.proxy.type.SetSelection(0) self.dialog.proxy.type.SetSelection(0)
self.dialog.set_value("proxy", "server", config.app["proxy"]["server"]) self.dialog.set_value("proxy", "server", config.app["proxy"]["server"])
self.dialog.set_value("proxy", "port", config.app["proxy"]["port"]) self.dialog.set_value("proxy", "port", config.app["proxy"]["port"])
self.dialog.set_value("proxy", "user", config.app["proxy"]["user"]) self.dialog.set_value("proxy", "user", config.app["proxy"]["user"])
self.dialog.set_value("proxy", "password", config.app["proxy"]["password"]) self.dialog.set_value("proxy", "password", config.app["proxy"]["password"])
self.dialog.realize() self.dialog.realize()
self.response = self.dialog.get_response() self.response = self.dialog.get_response()
def save_configuration(self): def save_configuration(self):
if self.codes[self.dialog.general.language.GetSelection()] != config.app["app-settings"]["language"]: if self.codes[self.dialog.general.language.GetSelection()] != config.app["app-settings"]["language"]:
config.app["app-settings"]["language"] = self.codes[self.dialog.general.language.GetSelection()] config.app["app-settings"]["language"] = self.codes[self.dialog.general.language.GetSelection()]
languageHandler.setLanguage(config.app["app-settings"]["language"]) languageHandler.setLanguage(config.app["app-settings"]["language"])
self.needs_restart = True self.needs_restart = True
if self.kmnames[self.dialog.general.km.GetSelection()] != config.app["app-settings"]["load_keymap"]: if self.kmnames[self.dialog.general.km.GetSelection()] != config.app["app-settings"]["load_keymap"]:
config.app["app-settings"]["load_keymap"] =self.kmnames[self.dialog.general.km.GetSelection()] config.app["app-settings"]["load_keymap"] =self.kmnames[self.dialog.general.km.GetSelection()]
kmFile = open(os.path.join(paths.config_path(), "keymap.keymap"), "w") kmFile = open(os.path.join(paths.config_path(), "keymap.keymap"), "w")
kmFile.close() kmFile.close()
self.needs_restart = True self.needs_restart = True
if config.app["app-settings"]["autostart"] != self.dialog.get_value("general", "autostart") and paths.mode == "installed": if config.app["app-settings"]["autostart"] != self.dialog.get_value("general", "autostart") and paths.mode == "installed":
config.app["app-settings"]["autostart"] = self.dialog.get_value("general", "autostart") config.app["app-settings"]["autostart"] = self.dialog.get_value("general", "autostart")
autostart_windows.setAutoStart(application.name, enable=self.dialog.get_value("general", "autostart")) autostart_windows.setAutoStart(application.name, enable=self.dialog.get_value("general", "autostart"))
if config.app["app-settings"]["use_invisible_keyboard_shorcuts"] != self.dialog.get_value("general", "use_invisible_shorcuts"): if config.app["app-settings"]["use_invisible_keyboard_shorcuts"] != self.dialog.get_value("general", "use_invisible_shorcuts"):
config.app["app-settings"]["use_invisible_keyboard_shorcuts"] = self.dialog.get_value("general", "use_invisible_shorcuts") config.app["app-settings"]["use_invisible_keyboard_shorcuts"] = self.dialog.get_value("general", "use_invisible_shorcuts")
pub.sendMessage("invisible-shorcuts-changed", registered=self.dialog.get_value("general", "use_invisible_shorcuts")) pub.sendMessage("invisible-shorcuts-changed", registered=self.dialog.get_value("general", "use_invisible_shorcuts"))
if config.app["app-settings"]["no_streaming"] != self.dialog.get_value("general", "no_streaming"): if config.app["app-settings"]["no_streaming"] != self.dialog.get_value("general", "no_streaming"):
config.app["app-settings"]["no_streaming"] = self.dialog.get_value("general", "no_streaming") config.app["app-settings"]["no_streaming"] = self.dialog.get_value("general", "no_streaming")
self.needs_restart = True self.needs_restart = True
if config.app["app-settings"]["update_period"] != self.dialog.get_value("general", "update_period"): if config.app["app-settings"]["update_period"] != self.dialog.get_value("general", "update_period"):
config.app["app-settings"]["update_period"] = self.dialog.get_value("general", "update_period") config.app["app-settings"]["update_period"] = self.dialog.get_value("general", "update_period")
self.needs_restart = True self.needs_restart = True
config.app["app-settings"]["voice_enabled"] = self.dialog.get_value("general", "disable_sapi5") config.app["app-settings"]["voice_enabled"] = self.dialog.get_value("general", "disable_sapi5")
config.app["app-settings"]["hide_gui"] = self.dialog.get_value("general", "hide_gui") config.app["app-settings"]["hide_gui"] = self.dialog.get_value("general", "hide_gui")
config.app["app-settings"]["ask_at_exit"] = self.dialog.get_value("general", "ask_at_exit") config.app["app-settings"]["ask_at_exit"] = self.dialog.get_value("general", "ask_at_exit")
config.app["app-settings"]["handle_longtweets"] = self.dialog.get_value("general", "handle_longtweets") config.app["app-settings"]["handle_longtweets"] = self.dialog.get_value("general", "handle_longtweets")
config.app["app-settings"]["play_ready_sound"] = self.dialog.get_value("general", "play_ready_sound") config.app["app-settings"]["play_ready_sound"] = self.dialog.get_value("general", "play_ready_sound")
config.app["app-settings"]["speak_ready_msg"] = self.dialog.get_value("general", "speak_ready_msg") config.app["app-settings"]["speak_ready_msg"] = self.dialog.get_value("general", "speak_ready_msg")
config.app["app-settings"]["check_for_updates"] = self.dialog.get_value("general", "check_for_updates") config.app["app-settings"]["check_for_updates"] = self.dialog.get_value("general", "check_for_updates")
config.app["app-settings"]["remember_mention_and_longtweet"] = self.dialog.get_value("general", "remember_mention_and_longtweet") config.app["app-settings"]["remember_mention_and_longtweet"] = self.dialog.get_value("general", "remember_mention_and_longtweet")
if config.app["proxy"]["type"]!=self.dialog.get_value("proxy", "type") or config.app["proxy"]["server"] != self.dialog.get_value("proxy", "server") or config.app["proxy"]["port"] != self.dialog.get_value("proxy", "port") or config.app["proxy"]["user"] != self.dialog.get_value("proxy", "user") or config.app["proxy"]["password"] != self.dialog.get_value("proxy", "password"): if config.app["proxy"]["type"]!=self.dialog.get_value("proxy", "type") or config.app["proxy"]["server"] != self.dialog.get_value("proxy", "server") or config.app["proxy"]["port"] != self.dialog.get_value("proxy", "port") or config.app["proxy"]["user"] != self.dialog.get_value("proxy", "user") or config.app["proxy"]["password"] != self.dialog.get_value("proxy", "password"):
if self.is_started == True: if self.is_started == True:
self.needs_restart = True self.needs_restart = True
config.app["proxy"]["type"] = self.dialog.proxy.type.Selection config.app["proxy"]["type"] = self.dialog.proxy.type.Selection
config.app["proxy"]["server"] = self.dialog.get_value("proxy", "server") config.app["proxy"]["server"] = self.dialog.get_value("proxy", "server")
config.app["proxy"]["port"] = self.dialog.get_value("proxy", "port") config.app["proxy"]["port"] = self.dialog.get_value("proxy", "port")
config.app["proxy"]["user"] = self.dialog.get_value("proxy", "user") config.app["proxy"]["user"] = self.dialog.get_value("proxy", "user")
config.app["proxy"]["password"] = self.dialog.get_value("proxy", "password") config.app["proxy"]["password"] = self.dialog.get_value("proxy", "password")
config.app.write() config.app.write()
class accountSettingsController(globalSettingsController): class accountSettingsController(globalSettingsController):
def __init__(self, buffer, window): def __init__(self, buffer, window):
self.user = buffer.session.db["user_name"] self.user = buffer.session.db["user_name"]
self.buffer = buffer self.buffer = buffer
self.window = window self.window = window
self.config = buffer.session.settings self.config = buffer.session.settings
super(accountSettingsController, self).__init__() super(accountSettingsController, self).__init__()
def create_config(self): def create_config(self):
self.dialog.create_general_account() self.dialog.create_general_account()
widgetUtils.connect_event(self.dialog.general.au, widgetUtils.BUTTON_PRESSED, self.manage_autocomplete) widgetUtils.connect_event(self.dialog.general.au, widgetUtils.BUTTON_PRESSED, self.manage_autocomplete)
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", "show_screen_names", self.config["general"]["show_screen_names"]) self.dialog.set_value("general", "show_screen_names", self.config["general"]["show_screen_names"])
self.dialog.set_value("general", "itemsPerApiCall", self.config["general"]["max_tweets_per_call"]) 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"]) self.dialog.set_value("general", "reverse_timelines", self.config["general"]["reverse_timelines"])
rt = self.config["general"]["retweet_mode"] rt = self.config["general"]["retweet_mode"]
if rt == "ask": if rt == "ask":
self.dialog.set_value("general", "retweet_mode", _(u"Ask")) self.dialog.set_value("general", "retweet_mode", _(u"Ask"))
elif rt == "direct": elif rt == "direct":
self.dialog.set_value("general", "retweet_mode", _(u"Retweet without comments")) self.dialog.set_value("general", "retweet_mode", _(u"Retweet without comments"))
else: else:
self.dialog.set_value("general", "retweet_mode", _(u"Retweet with comments")) 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", "persist_size", str(self.config["general"]["persist_size"]))
self.dialog.create_reporting() self.dialog.create_reporting()
self.dialog.set_value("reporting", "speech_reporting", self.config["reporting"]["speech_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"]) self.dialog.set_value("reporting", "braille_reporting", self.config["reporting"]["braille_reporting"])
self.dialog.create_other_buffers() self.dialog.create_other_buffers()
buffer_values = self.get_buffers_list() buffer_values = self.get_buffers_list()
self.dialog.buffers.insert_buffers(buffer_values) self.dialog.buffers.insert_buffers(buffer_values)
self.dialog.buffers.connect_hook_func(self.toggle_buffer_active) 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.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.up, widgetUtils.BUTTON_PRESSED, self.dialog.buffers.move_up)
widgetUtils.connect_event(self.dialog.buffers.down, widgetUtils.BUTTON_PRESSED, self.dialog.buffers.move_down) 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"]) 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.add, widgetUtils.BUTTON_PRESSED, self.add_ignored_client)
widgetUtils.connect_event(self.dialog.ignored_clients.remove, widgetUtils.BUTTON_PRESSED, self.remove_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.input_devices = sound_lib.input.Input.get_device_names()
self.output_devices = sound_lib.output.Output.get_device_names() self.output_devices = sound_lib.output.Output.get_device_names()
self.soundpacks = [] 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.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.create_sound(self.input_devices, self.output_devices, self.soundpacks)
self.dialog.set_value("sound", "volumeCtrl", self.config["sound"]["volume"]*100) self.dialog.set_value("sound", "volumeCtrl", self.config["sound"]["volume"]*100)
self.dialog.set_value("sound", "input", self.config["sound"]["input_device"]) 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", "output", self.config["sound"]["output_device"])
self.dialog.set_value("sound", "session_mute", self.config["sound"]["session_mute"]) 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", "soundpack", self.config["sound"]["current_soundpack"])
self.dialog.set_value("sound", "indicate_audio", self.config["sound"]["indicate_audio"]) 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_geo", self.config["sound"]["indicate_geo"])
self.dialog.set_value("sound", "indicate_img", self.config["sound"]["indicate_img"]) self.dialog.set_value("sound", "indicate_img", self.config["sound"]["indicate_img"])
self.dialog.create_extras(OCRSpace.translatable_langs) self.dialog.create_extras(OCRSpace.translatable_langs)
self.dialog.set_value("extras", "sndup_apiKey", self.config["sound"]["sndup_api_key"]) self.dialog.set_value("extras", "sndup_apiKey", self.config["sound"]["sndup_api_key"])
language_index = OCRSpace.OcrLangs.index(self.config["mysc"]["ocr_language"]) language_index = OCRSpace.OcrLangs.index(self.config["mysc"]["ocr_language"])
self.dialog.extras.ocr_lang.SetSelection(language_index) self.dialog.extras.ocr_lang.SetSelection(language_index)
self.dialog.realize() self.dialog.realize()
self.dialog.set_title(_(u"Account settings for %s") % (self.user,)) self.dialog.set_title(_(u"Account settings for %s") % (self.user,))
self.response = self.dialog.get_response() self.response = self.dialog.get_response()
def save_configuration(self): def save_configuration(self):
if self.config["general"]["relative_times"] != self.dialog.get_value("general", "relative_time"): if self.config["general"]["relative_times"] != self.dialog.get_value("general", "relative_time"):
self.needs_restart = True self.needs_restart = True
self.config["general"]["relative_times"] = self.dialog.get_value("general", "relative_time") 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"]["show_screen_names"] = self.dialog.get_value("general", "show_screen_names")
self.config["general"]["max_tweets_per_call"] = self.dialog.get_value("general", "itemsPerApiCall") self.config["general"]["max_tweets_per_call"] = self.dialog.get_value("general", "itemsPerApiCall")
if self.config["general"]["persist_size"] != self.dialog.get_value("general", "persist_size"): if self.config["general"]["persist_size"] != self.dialog.get_value("general", "persist_size"):
if self.dialog.get_value("general", "persist_size") == '': if self.dialog.get_value("general", "persist_size") == '':
self.config["general"]["persist_size"] =-1 self.config["general"]["persist_size"] =-1
else: else:
try: try:
self.config["general"]["persist_size"] = int(self.dialog.get_value("general", "persist_size")) self.config["general"]["persist_size"] = int(self.dialog.get_value("general", "persist_size"))
except ValueError: except ValueError:
output.speak("Invalid cache size, setting to default.",True) output.speak("Invalid cache size, setting to default.",True)
self.config["general"]["persist_size"] =1764 self.config["general"]["persist_size"] =1764
if self.config["general"]["reverse_timelines"] != self.dialog.get_value("general", "reverse_timelines"): if self.config["general"]["reverse_timelines"] != self.dialog.get_value("general", "reverse_timelines"):
self.needs_restart = True self.needs_restart = True
self.config["general"]["reverse_timelines"] = self.dialog.get_value("general", "reverse_timelines") self.config["general"]["reverse_timelines"] = self.dialog.get_value("general", "reverse_timelines")
rt = self.dialog.get_value("general", "retweet_mode") rt = self.dialog.get_value("general", "retweet_mode")
if rt == _(u"Ask"): if rt == _(u"Ask"):
self.config["general"]["retweet_mode"] = "ask" self.config["general"]["retweet_mode"] = "ask"
elif rt == _(u"Retweet without comments"): elif rt == _(u"Retweet without comments"):
self.config["general"]["retweet_mode"] = "direct" self.config["general"]["retweet_mode"] = "direct"
else: else:
self.config["general"]["retweet_mode"] = "comment" self.config["general"]["retweet_mode"] = "comment"
buffers_list = self.dialog.buffers.get_list() buffers_list = self.dialog.buffers.get_list()
if buffers_list != self.config["general"]["buffer_order"]: if buffers_list != self.config["general"]["buffer_order"]:
self.needs_restart = True self.needs_restart = True
self.config["general"]["buffer_order"] = buffers_list self.config["general"]["buffer_order"] = buffers_list
self.config["reporting"]["speech_reporting"] = self.dialog.get_value("reporting", "speech_reporting") 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["reporting"]["braille_reporting"] = self.dialog.get_value("reporting", "braille_reporting")
self.config["mysc"]["ocr_language"] = OCRSpace.OcrLangs[self.dialog.extras.ocr_lang.GetSelection()] self.config["mysc"]["ocr_language"] = OCRSpace.OcrLangs[self.dialog.extras.ocr_lang.GetSelection()]
# if self.config["other_buffers"]["show_followers"] != self.dialog.get_value("buffers", "followers"): # if self.config["other_buffers"]["show_followers"] != self.dialog.get_value("buffers", "followers"):
# self.config["other_buffers"]["show_followers"] = self.dialog.get_value("buffers", "followers") # self.config["other_buffers"]["show_followers"] = self.dialog.get_value("buffers", "followers")
# pub.sendMessage("create-new-buffer", buffer="followers", account=self.user, create=self.config["other_buffers"]["show_followers"]) # pub.sendMessage("create-new-buffer", buffer="followers", account=self.user, create=self.config["other_buffers"]["show_followers"])
@ -238,75 +238,75 @@ class accountSettingsController(globalSettingsController):
# if self.config["other_buffers"]["show_events"] != self.dialog.get_value("buffers", "events"): # if self.config["other_buffers"]["show_events"] != self.dialog.get_value("buffers", "events"):
# self.config["other_buffers"]["show_events"] = self.dialog.get_value("buffers", "events") # self.config["other_buffers"]["show_events"] = self.dialog.get_value("buffers", "events")
# pub.sendMessage("create-new-buffer", buffer="events", account=self.user, create=self.config["other_buffers"]["show_events"]) # pub.sendMessage("create-new-buffer", buffer="events", account=self.user, create=self.config["other_buffers"]["show_events"])
if self.config["sound"]["input_device"] != self.dialog.sound.get("input"): if self.config["sound"]["input_device"] != self.dialog.sound.get("input"):
self.config["sound"]["input_device"] = self.dialog.sound.get("input") self.config["sound"]["input_device"] = self.dialog.sound.get("input")
try: try:
self.buffer.session.sound.input.set_device(self.buffer.session.sound.input.find_device_by_name(self.config["sound"]["input_device"])) self.buffer.session.sound.input.set_device(self.buffer.session.sound.input.find_device_by_name(self.config["sound"]["input_device"]))
except: except:
self.config["sound"]["input_device"] = "default" self.config["sound"]["input_device"] = "default"
if self.config["sound"]["output_device"] != self.dialog.sound.get("output"): if self.config["sound"]["output_device"] != self.dialog.sound.get("output"):
self.config["sound"]["output_device"] = self.dialog.sound.get("output") self.config["sound"]["output_device"] = self.dialog.sound.get("output")
try: try:
self.buffer.session.sound.output.set_device(self.buffer.session.sound.output.find_device_by_name(self.config["sound"]["output_device"])) self.buffer.session.sound.output.set_device(self.buffer.session.sound.output.find_device_by_name(self.config["sound"]["output_device"]))
except: except:
self.config["sound"]["output_device"] = "default" self.config["sound"]["output_device"] = "default"
self.config["sound"]["volume"] = self.dialog.get_value("sound", "volumeCtrl")/100.0 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"]["session_mute"] = self.dialog.get_value("sound", "session_mute")
self.config["sound"]["current_soundpack"] = self.dialog.sound.get("soundpack") 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_audio"] = self.dialog.get_value("sound", "indicate_audio")
self.config["sound"]["indicate_geo"] = self.dialog.get_value("sound", "indicate_geo") 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"]["indicate_img"] = self.dialog.get_value("sound", "indicate_img")
self.config["sound"]["sndup_api_key"] = self.dialog.get_value("extras", "sndup_apiKey") 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.config = self.config["sound"]
self.buffer.session.sound.check_soundpack() self.buffer.session.sound.check_soundpack()
self.config.write() self.config.write()
def toggle_state(self,*args,**kwargs): def toggle_state(self,*args,**kwargs):
return self.dialog.buffers.change_selected_item() return self.dialog.buffers.change_selected_item()
def manage_autocomplete(self, *args, **kwargs): def manage_autocomplete(self, *args, **kwargs):
configuration = settings.autocompletionSettings(self.buffer.session.settings, self.buffer, self.window) configuration = settings.autocompletionSettings(self.buffer.session.settings, self.buffer, self.window)
def add_ignored_client(self, *args, **kwargs): def add_ignored_client(self, *args, **kwargs):
client = commonMessageDialogs.get_ignored_client() client = commonMessageDialogs.get_ignored_client()
if client == None: return if client == None: return
if client not in self.config["twitter"]["ignored_clients"]: if client not in self.config["twitter"]["ignored_clients"]:
self.config["twitter"]["ignored_clients"].append(client) self.config["twitter"]["ignored_clients"].append(client)
self.dialog.ignored_clients.append(client) self.dialog.ignored_clients.append(client)
def remove_ignored_client(self, *args, **kwargs): def remove_ignored_client(self, *args, **kwargs):
if self.dialog.ignored_clients.get_clients() == 0: return if self.dialog.ignored_clients.get_clients() == 0: return
id = self.dialog.ignored_clients.get_client_id() id = self.dialog.ignored_clients.get_client_id()
self.config["twitter"]["ignored_clients"].pop(id) self.config["twitter"]["ignored_clients"].pop(id)
self.dialog.ignored_clients.remove_(id) self.dialog.ignored_clients.remove_(id)
def get_buffers_list(self): def get_buffers_list(self):
all_buffers=OrderedDict() all_buffers=OrderedDict()
all_buffers['home']=_(u"Home") all_buffers['home']=_(u"Home")
all_buffers['mentions']=_(u"Mentions") all_buffers['mentions']=_(u"Mentions")
all_buffers['dm']=_(u"Direct Messages") all_buffers['dm']=_(u"Direct Messages")
all_buffers['sent_dm']=_(u"Sent direct messages") all_buffers['sent_dm']=_(u"Sent direct messages")
all_buffers['sent_tweets']=_(u"Sent tweets") all_buffers['sent_tweets']=_(u"Sent tweets")
all_buffers['favorites']=_(u"Likes") all_buffers['favorites']=_(u"Likes")
all_buffers['followers']=_(u"Followers") all_buffers['followers']=_(u"Followers")
all_buffers['friends']=_(u"Friends") all_buffers['friends']=_(u"Friends")
all_buffers['blocks']=_(u"Blocked users") all_buffers['blocks']=_(u"Blocked users")
all_buffers['muted']=_(u"Muted users") all_buffers['muted']=_(u"Muted users")
list_buffers = [] list_buffers = []
hidden_buffers=[] hidden_buffers=[]
all_buffers_keys = list(all_buffers.keys()) all_buffers_keys = list(all_buffers.keys())
# Check buffers shown first. # Check buffers shown first.
for i in self.config["general"]["buffer_order"]: for i in self.config["general"]["buffer_order"]:
if i in all_buffers_keys: if i in all_buffers_keys:
list_buffers.append((i, all_buffers[i], True)) list_buffers.append((i, all_buffers[i], True))
# This second pass will retrieve all hidden buffers. # This second pass will retrieve all hidden buffers.
for i in all_buffers_keys: for i in all_buffers_keys:
if i not in self.config["general"]["buffer_order"]: if i not in self.config["general"]["buffer_order"]:
hidden_buffers.append((i, all_buffers[i], False)) hidden_buffers.append((i, all_buffers[i], False))
list_buffers.extend(hidden_buffers) list_buffers.extend(hidden_buffers)
return list_buffers return list_buffers
def toggle_buffer_active(self, ev): def toggle_buffer_active(self, ev):
change = self.dialog.buffers.get_event(ev) change = self.dialog.buffers.get_event(ev)
if change == True: if change == True:
self.dialog.buffers.change_selected_item() self.dialog.buffers.change_selected_item()

View File

@ -3,43 +3,43 @@ from wxUI.dialogs import trends
import widgetUtils import widgetUtils
class trendingTopicsController(object): class trendingTopicsController(object):
def __init__(self, session): def __init__(self, session):
super(trendingTopicsController, self).__init__() super(trendingTopicsController, self).__init__()
self.countries = {} self.countries = {}
self.cities = {} self.cities = {}
self.dialog = trends.trendingTopicsDialog() self.dialog = trends.trendingTopicsDialog()
self.information = session.twitter.trends_available() self.information = session.twitter.trends_available()
self.split_information() self.split_information()
widgetUtils.connect_event(self.dialog.country, widgetUtils.RADIOBUTTON, self.get_places) widgetUtils.connect_event(self.dialog.country, widgetUtils.RADIOBUTTON, self.get_places)
widgetUtils.connect_event(self.dialog.city, widgetUtils.RADIOBUTTON, self.get_places) widgetUtils.connect_event(self.dialog.city, widgetUtils.RADIOBUTTON, self.get_places)
self.get_places() self.get_places()
def split_information(self): def split_information(self):
for i in self.information: for i in self.information:
if i["placeType"]["name"] == "Country": if i["placeType"]["name"] == "Country":
self.countries[i["name"]] = i["woeid"] self.countries[i["name"]] = i["woeid"]
else: else:
self.cities[i["name"]] = i["woeid"] self.cities[i["name"]] = i["woeid"]
def get_places(self, event=None): def get_places(self, event=None):
values = [] values = []
if self.dialog.get_active() == "country": if self.dialog.get_active() == "country":
for i in self.information: for i in self.information:
if i["placeType"]["name"] == "Country": if i["placeType"]["name"] == "Country":
values.append(i["name"]) values.append(i["name"])
elif self.dialog.get_active() == "city": elif self.dialog.get_active() == "city":
for i in self.information: for i in self.information:
if i["placeType"]["name"] != "Country": if i["placeType"]["name"] != "Country":
values.append(i["name"]) values.append(i["name"])
self.dialog.set(values) self.dialog.set(values)
def get_woeid(self): def get_woeid(self):
selected = self.dialog.get_item() selected = self.dialog.get_item()
if self.dialog.get_active() == "country": if self.dialog.get_active() == "country":
woeid = self.countries[selected] woeid = self.countries[selected]
else: else:
woeid = self.cities[selected] woeid = self.cities[selected]
return woeid return woeid
def get_string(self): def get_string(self):
return self.dialog.get_item() return self.dialog.get_item()

View File

@ -10,119 +10,119 @@ from tweepy.error import TweepError
from sessions.twitter import utils from sessions.twitter import utils
class profileController(object): class profileController(object):
def __init__(self, session, user=None): def __init__(self, session, user=None):
super(profileController, self).__init__() super(profileController, self).__init__()
self.file = None self.file = None
self.session = session self.session = session
self.user = user self.user = user
if user == None: if user == None:
self.get_data(screen_name=self.session.db["user_name"]) self.get_data(screen_name=self.session.db["user_name"])
self.dialog = update_profile.updateProfileDialog() self.dialog = update_profile.updateProfileDialog()
self.fill_profile_fields() self.fill_profile_fields()
self.uploaded = False self.uploaded = False
widgetUtils.connect_event(self.dialog.upload_image, widgetUtils.BUTTON_PRESSED, self.upload_image) widgetUtils.connect_event(self.dialog.upload_image, widgetUtils.BUTTON_PRESSED, self.upload_image)
else: else:
try: try:
self.get_data(screen_name=self.user) self.get_data(screen_name=self.user)
except TweepError as err: except TweepError as err:
if err.api_code == 50: if err.api_code == 50:
wx.MessageDialog(None, _(u"That user does not exist"), _(u"Error"), wx.ICON_ERROR).ShowModal() wx.MessageDialog(None, _(u"That user does not exist"), _(u"Error"), wx.ICON_ERROR).ShowModal()
if err.api_code == 403: if err.api_code == 403:
wx.MessageDialog(None, _(u"User has been suspended"), _(u"Error"), wx.ICON_ERROR).ShowModal() wx.MessageDialog(None, _(u"User has been suspended"), _(u"Error"), wx.ICON_ERROR).ShowModal()
log.error("error %d: %s" % (err.api_code, err.reason)) log.error("error %d: %s" % (err.api_code, err.reason))
return return
self.dialog = show_user.showUserProfile() self.dialog = show_user.showUserProfile()
string = self.get_user_info() string = self.get_user_info()
self.dialog.set("text", string) self.dialog.set("text", string)
self.dialog.set_title(_(u"Information for %s") % (self.data.screen_name)) self.dialog.set_title(_(u"Information for %s") % (self.data.screen_name))
if self.data.url != None: if self.data.url != None:
self.dialog.enable_url() self.dialog.enable_url()
widgetUtils.connect_event(self.dialog.url, widgetUtils.BUTTON_PRESSED, self.visit_url) widgetUtils.connect_event(self.dialog.url, widgetUtils.BUTTON_PRESSED, self.visit_url)
if self.dialog.get_response() == widgetUtils.OK and self.user == None: if self.dialog.get_response() == widgetUtils.OK and self.user == None:
self.do_update() self.do_update()
def get_data(self, screen_name): def get_data(self, screen_name):
self.data = self.session.twitter.get_user(screen_name=screen_name) self.data = self.session.twitter.get_user(screen_name=screen_name)
if screen_name != self.session.db["user_name"]: if screen_name != self.session.db["user_name"]:
self.friendship_status = self.session.twitter.show_friendship(source_screen_name=self.session.db["user_name"], target_screen_name=screen_name) self.friendship_status = self.session.twitter.show_friendship(source_screen_name=self.session.db["user_name"], target_screen_name=screen_name)
def fill_profile_fields(self): def fill_profile_fields(self):
self.dialog.set_name(self.data.name) self.dialog.set_name(self.data.name)
if self.data.url != None: if self.data.url != None:
self.dialog.set_url(self.data.url) self.dialog.set_url(self.data.url)
if len(self.data.location) > 0: if len(self.data.location) > 0:
self.dialog.set_location(self.data.location) self.dialog.set_location(self.data.location)
if len(self.data.description) > 0: if len(self.data.description) > 0:
self.dialog.set_description(self.data.description) self.dialog.set_description(self.data.description)
def get_image(self): def get_image(self):
file = self.dialog.upload_picture() file = self.dialog.upload_picture()
if file != None: if file != None:
self.file = open(file, "rb") self.file = open(file, "rb")
self.uploaded = True self.uploaded = True
self.dialog.change_upload_button(self.uploaded) self.dialog.change_upload_button(self.uploaded)
def discard_image(self): def discard_image(self):
self.file = None self.file = None
output.speak(_(u"Discarded")) output.speak(_(u"Discarded"))
self.uploaded = False self.uploaded = False
self.dialog.change_upload_button(self.uploaded) self.dialog.change_upload_button(self.uploaded)
def upload_image(self, *args, **kwargs): def upload_image(self, *args, **kwargs):
if self.uploaded == False: if self.uploaded == False:
self.get_image() self.get_image()
elif self.uploaded == True: elif self.uploaded == True:
self.discard_image() self.discard_image()
def do_update(self): def do_update(self):
if self.user != None: return if self.user != None: return
name = self.dialog.get("name") name = self.dialog.get("name")
description = self.dialog.get("description") description = self.dialog.get("description")
location = self.dialog.get("location") location = self.dialog.get("location")
url = self.dialog.get("url") url = self.dialog.get("url")
if self.file != None: if self.file != None:
try: try:
self.session.twitter.update_profile_image(image=self.file) self.session.twitter.update_profile_image(image=self.file)
except TweepError as e: except TweepError as e:
output.speak(u"Error %s. %s" % (e.api_code, e.reason)) output.speak(u"Error %s. %s" % (e.api_code, e.reason))
try: try:
self.session.twitter.update_profile(name=name, description=description, location=location, url=url) self.session.twitter.update_profile(name=name, description=description, location=location, url=url)
except TweepError as e: except TweepError as e:
output.speak(u"Error %s. %s" % (e.api_code, e.reason)) output.speak(u"Error %s. %s" % (e.api_code, e.reason))
def get_user_info(self): def get_user_info(self):
string = u"" string = u""
string = string + _(u"Username: @%s\n") % (self.data.screen_name) string = string + _(u"Username: @%s\n") % (self.data.screen_name)
string = string + _(u"Name: %s\n") % (self.data.name) string = string + _(u"Name: %s\n") % (self.data.name)
if self.data.location != "": if self.data.location != "":
string = string + _(u"Location: %s\n") % (self.data.location) string = string + _(u"Location: %s\n") % (self.data.location)
if self.data.url != None: if self.data.url != None:
string = string+ _(u"URL: %s\n") % (self.data.entities["url"]["urls"][0]["expanded_url"]) string = string+ _(u"URL: %s\n") % (self.data.entities["url"]["urls"][0]["expanded_url"])
if self.data.description != "": if self.data.description != "":
if self.data.entities.get("description") != None and self.data.entities["description"].get("urls"): 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"]) self.data.description = utils.expand_urls(self.data.description, self.data.entities["description"])
string = string+ _(u"Bio: %s\n") % (self.data.description) string = string+ _(u"Bio: %s\n") % (self.data.description)
if self.data.protected == True: protected = _(u"Yes") if self.data.protected == True: protected = _(u"Yes")
else: protected = _(u"No") else: protected = _(u"No")
string = string+ _(u"Protected: %s\n") % (protected) string = string+ _(u"Protected: %s\n") % (protected)
if hasattr(self, "friendship_status"): if hasattr(self, "friendship_status"):
relation = False relation = False
friendship = "Relationship: " friendship = "Relationship: "
if self.friendship_status[0].following: if self.friendship_status[0].following:
friendship += _(u"You follow {0}. ").format(self.data.name,) friendship += _(u"You follow {0}. ").format(self.data.name,)
relation = True relation = True
if self.friendship_status[1].following: if self.friendship_status[1].following:
friendship += _(u"{0} is following you.").format(self.data.name,) friendship += _(u"{0} is following you.").format(self.data.name,)
relation = True relation = True
if relation == True: if relation == True:
string = string+friendship+"\n" string = string+friendship+"\n"
string = string+_(u"Followers: %s\n Friends: %s\n") % (self.data.followers_count, self.data.friends_count) 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") if self.data.verified == True: verified = _(u"Yes")
else: verified = _(u"No") else: verified = _(u"No")
string = string+ _(u"Verified: %s\n") % (verified) string = string+ _(u"Verified: %s\n") % (verified)
string = string+ _(u"Tweets: %s\n") % (self.data.statuses_count) string = string+ _(u"Tweets: %s\n") % (self.data.statuses_count)
string = string+ _(u"Likes: %s") % (self.data.favourites_count) string = string+ _(u"Likes: %s") % (self.data.favourites_count)
return string return string
def visit_url(self, *args, **kwargs): def visit_url(self, *args, **kwargs):
webbrowser.open_new_tab(self.data.url) webbrowser.open_new_tab(self.data.url)

View File

@ -7,73 +7,73 @@ from tweepy.error import TweepError
from extra import autocompletionUsers from extra import autocompletionUsers
class userActionsController(object): class userActionsController(object):
def __init__(self, buffer, users=[], default="follow"): def __init__(self, buffer, users=[], default="follow"):
super(userActionsController, self).__init__() super(userActionsController, self).__init__()
self.buffer = buffer self.buffer = buffer
self.session = buffer.session self.session = buffer.session
self.dialog = userActions.UserActionsDialog(users, default) self.dialog = userActions.UserActionsDialog(users, default)
widgetUtils.connect_event(self.dialog.autocompletion, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) widgetUtils.connect_event(self.dialog.autocompletion, widgetUtils.BUTTON_PRESSED, self.autocomplete_users)
if self.dialog.get_response() == widgetUtils.OK: if self.dialog.get_response() == widgetUtils.OK:
self.process_action() self.process_action()
def autocomplete_users(self, *args, **kwargs): def autocomplete_users(self, *args, **kwargs):
c = autocompletionUsers.completion.autocompletionUsers(self.dialog, self.session.session_id) c = autocompletionUsers.completion.autocompletionUsers(self.dialog, self.session.session_id)
c.show_menu("dm") c.show_menu("dm")
def process_action(self): def process_action(self):
action = self.dialog.get_action() action = self.dialog.get_action()
user = self.dialog.get_user() user = self.dialog.get_user()
if user == "": return if user == "": return
getattr(self, action)(user) getattr(self, action)(user)
def follow(self, user): def follow(self, user):
try: try:
self.session.twitter.create_friendship(screen_name=user ) self.session.twitter.create_friendship(screen_name=user )
except TweepError as err: except TweepError as err:
output.speak("Error %s: %s" % (err.api_code, err.reason), True) output.speak("Error %s: %s" % (err.api_code, err.reason), True)
def unfollow(self, user): def unfollow(self, user):
try: try:
id = self.session.twitter.destroy_friendship(screen_name=user ) id = self.session.twitter.destroy_friendship(screen_name=user )
except TweepError as err: except TweepError as err:
output.speak("Error %s: %s" % (err.api_code, err.reason), True) output.speak("Error %s: %s" % (err.api_code, err.reason), True)
def mute(self, user): def mute(self, user):
try: try:
id = self.session.twitter.create_mute(screen_name=user ) id = self.session.twitter.create_mute(screen_name=user )
except TweepError as err: except TweepError as err:
output.speak("Error %s: %s" % (err.api_code, err.reason), True) output.speak("Error %s: %s" % (err.api_code, err.reason), True)
def unmute(self, user): def unmute(self, user):
try: try:
id = self.session.twitter.destroy_mute(screen_name=user ) id = self.session.twitter.destroy_mute(screen_name=user )
except TweepError as err: except TweepError as err:
output.speak("Error %s: %s" % (err.api_code, err.reason), True) output.speak("Error %s: %s" % (err.api_code, err.reason), True)
def report(self, user): def report(self, user):
try: try:
id = self.session.twitter.report_spam(screen_name=user ) id = self.session.twitter.report_spam(screen_name=user )
except TweepError as err: except TweepError as err:
output.speak("Error %s: %s" % (err.api_code, err.reason), True) output.speak("Error %s: %s" % (err.api_code, err.reason), True)
def block(self, user): def block(self, user):
try: try:
id = self.session.twitter.create_block(screen_name=user ) id = self.session.twitter.create_block(screen_name=user )
except TweepError as err: except TweepError as err:
output.speak("Error %s: %s" % (err.api_code, err.reason), True) output.speak("Error %s: %s" % (err.api_code, err.reason), True)
def unblock(self, user): def unblock(self, user):
try: try:
id = self.session.twitter.destroy_block(screen_name=user ) id = self.session.twitter.destroy_block(screen_name=user )
except TweepError as err: except TweepError as err:
output.speak("Error %s: %s" % (err.api_code, err.reason), True) output.speak("Error %s: %s" % (err.api_code, err.reason), True)
def ignore_client(self, user): def ignore_client(self, user):
tweet = self.buffer.get_right_tweet() tweet = self.buffer.get_right_tweet()
if hasattr(tweet, "sender"): if hasattr(tweet, "sender"):
output.speak(_(u"You can't ignore direct messages")) output.speak(_(u"You can't ignore direct messages"))
return return
client = tweet.source client = tweet.source
if client not in self.session.settings["twitter"]["ignored_clients"]: if client not in self.session.settings["twitter"]["ignored_clients"]:
self.session.settings["twitter"]["ignored_clients"].append(client) self.session.settings["twitter"]["ignored_clients"].append(client)
self.session.settings.write() self.session.settings.write()

View File

@ -37,146 +37,146 @@ import logging
log = logging.getLogger("extra.AudioUploader.audioUploader") log = logging.getLogger("extra.AudioUploader.audioUploader")
class audioUploader(object): class audioUploader(object):
def __init__(self, configFile, completed_callback): def __init__(self, configFile, completed_callback):
self.config = configFile self.config = configFile
super(audioUploader, self).__init__() super(audioUploader, self).__init__()
self.dialog = wx_ui.audioDialog(services=self.get_available_services()) self.dialog = wx_ui.audioDialog(services=self.get_available_services())
self.file = None self.file = None
self.recorded = False self.recorded = False
self.recording = None self.recording = None
self.playing = None self.playing = None
widgetUtils.connect_event(self.dialog.play, widgetUtils.BUTTON_PRESSED, self.on_play) 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.pause, widgetUtils.BUTTON_PRESSED, self.on_pause)
widgetUtils.connect_event(self.dialog.record, widgetUtils.BUTTON_PRESSED, self.on_record) 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.attach_exists, widgetUtils.BUTTON_PRESSED, self.on_attach_exists)
widgetUtils.connect_event(self.dialog.discard, widgetUtils.BUTTON_PRESSED, self.on_discard) widgetUtils.connect_event(self.dialog.discard, widgetUtils.BUTTON_PRESSED, self.on_discard)
if self.dialog.get_response() == widgetUtils.OK: if self.dialog.get_response() == widgetUtils.OK:
self.postprocess() self.postprocess()
log.debug("Uploading file %s to %s..." % (self.file, self.dialog.get("services"))) log.debug("Uploading file %s to %s..." % (self.file, self.dialog.get("services")))
self.uploaderDialog = wx_transfer_dialogs.UploadDialog(self.file) self.uploaderDialog = wx_transfer_dialogs.UploadDialog(self.file)
output.speak(_(u"Attaching...")) output.speak(_(u"Attaching..."))
if self.dialog.get("services") == "SNDUp": if self.dialog.get("services") == "SNDUp":
base_url = "https://sndup.net/post.php" base_url = "https://sndup.net/post.php"
if len(self.config["sound"]["sndup_api_key"]) > 0: if len(self.config["sound"]["sndup_api_key"]) > 0:
url = base_url + '?apikey=' + self.config['sound']['sndup_api_key'] url = base_url + '?apikey=' + self.config['sound']['sndup_api_key']
else: else:
url = base_url url = base_url
self.uploaderFunction = transfer.Upload(obj=self, field='file', url=url, filename=self.file, completed_callback=completed_callback) self.uploaderFunction = transfer.Upload(obj=self, field='file', url=url, filename=self.file, completed_callback=completed_callback)
pub.subscribe(self.uploaderDialog.update, "uploading") pub.subscribe(self.uploaderDialog.update, "uploading")
self.uploaderDialog.get_response(self.uploaderFunction.perform_threaded) self.uploaderDialog.get_response(self.uploaderFunction.perform_threaded)
def get_available_services(self): def get_available_services(self):
services = [] services = []
services.append("SNDUp") services.append("SNDUp")
return services return services
def on_pause(self, *args, **kwargs): def on_pause(self, *args, **kwargs):
if self.dialog.get("pause") == _(u"Pause"): if self.dialog.get("pause") == _(u"Pause"):
self.recording.pause() self.recording.pause()
self.dialog.set("pause", _(u"&Resume")) self.dialog.set("pause", _(u"&Resume"))
elif self.dialog.get("pause") == _(u"Resume"): elif self.dialog.get("pause") == _(u"Resume"):
self.recording.play() self.recording.play()
self.dialog.set("pause", _(U"&Pause")) self.dialog.set("pause", _(U"&Pause"))
def on_record(self, *args, **kwargs): def on_record(self, *args, **kwargs):
if self.recording != None: if self.recording != None:
self.stop_recording() self.stop_recording()
self.dialog.disable_control("pause") self.dialog.disable_control("pause")
else: else:
self.start_recording() self.start_recording()
self.dialog.enable_control("pause") self.dialog.enable_control("pause")
def start_recording(self): def start_recording(self):
self.dialog.disable_control("attach_exists") self.dialog.disable_control("attach_exists")
self.file = tempfile.mktemp(suffix='.wav') self.file = tempfile.mktemp(suffix='.wav')
self.recording = sound.recording(self.file) self.recording = sound.recording(self.file)
self.recording.play() self.recording.play()
self.dialog.set("record", _(u"&Stop")) self.dialog.set("record", _(u"&Stop"))
output.speak(_(u"Recording")) output.speak(_(u"Recording"))
def stop_recording(self): def stop_recording(self):
self.recording.stop() self.recording.stop()
self.recording.free() self.recording.free()
output.speak(_(u"Stopped")) output.speak(_(u"Stopped"))
self.recorded = True self.recorded = True
self.dialog.set("record", _(u"&Record")) self.dialog.set("record", _(u"&Record"))
self.file_attached() self.file_attached()
def file_attached(self): def file_attached(self):
self.dialog.set("pause", _(u"&Pause")) self.dialog.set("pause", _(u"&Pause"))
self.dialog.disable_control("record") self.dialog.disable_control("record")
self.dialog.enable_control("play") self.dialog.enable_control("play")
self.dialog.enable_control("discard") self.dialog.enable_control("discard")
self.dialog.disable_control("attach_exists") self.dialog.disable_control("attach_exists")
self.dialog.enable_control("attach") self.dialog.enable_control("attach")
self.dialog.play.SetFocus() self.dialog.play.SetFocus()
def on_discard(self, *args, **kwargs): def on_discard(self, *args, **kwargs):
if self.playing: if self.playing:
self._stop() self._stop()
if self.recording != None: if self.recording != None:
self.cleanup() self.cleanup()
self.dialog.disable_control("attach") self.dialog.disable_control("attach")
self.dialog.disable_control("play") self.dialog.disable_control("play")
self.file = None self.file = None
self.dialog.enable_control("record") self.dialog.enable_control("record")
self.dialog.enable_control("attach_exists") self.dialog.enable_control("attach_exists")
self.dialog.record.SetFocus() self.dialog.record.SetFocus()
self.dialog.disable_control("discard") self.dialog.disable_control("discard")
self.recording = None self.recording = None
output.speak(_(u"Discarded")) output.speak(_(u"Discarded"))
def on_play(self, *args, **kwargs): def on_play(self, *args, **kwargs):
if not self.playing: if not self.playing:
call_threaded(self._play) call_threaded(self._play)
else: else:
self._stop() self._stop()
def _play(self): def _play(self):
output.speak(_(u"Playing...")) output.speak(_(u"Playing..."))
# try: # try:
self.playing = sound_lib.stream.FileStream(file=str(self.file), flags=sound_lib.stream.BASS_UNICODE) self.playing = sound_lib.stream.FileStream(file=str(self.file), flags=sound_lib.stream.BASS_UNICODE)
self.playing.play() self.playing.play()
self.dialog.set("play", _(u"&Stop")) self.dialog.set("play", _(u"&Stop"))
try: try:
while self.playing.is_playing: while self.playing.is_playing:
pass pass
self.dialog.set("play", _(u"&Play")) self.dialog.set("play", _(u"&Play"))
self.playing.free() self.playing.free()
self.playing = None self.playing = None
except: except:
pass pass
def _stop(self): def _stop(self):
output.speak(_(u"Stopped")) output.speak(_(u"Stopped"))
self.playing.stop() self.playing.stop()
self.playing.free() self.playing.free()
self.dialog.set("play", _(u"&Play")) self.dialog.set("play", _(u"&Play"))
self.playing = None self.playing = None
def postprocess(self): def postprocess(self):
if self.file.lower().endswith('.wav'): if self.file.lower().endswith('.wav'):
output.speak(_(u"Recoding audio...")) output.speak(_(u"Recoding audio..."))
sound.recode_audio(self.file) sound.recode_audio(self.file)
self.wav_file = self.file self.wav_file = self.file
self.file = '%s.ogg' % self.file[:-4] self.file = '%s.ogg' % self.file[:-4]
def cleanup(self): def cleanup(self):
if self.playing and self.playing.is_playing: if self.playing and self.playing.is_playing:
self.playing.stop() self.playing.stop()
if self.recording != None: if self.recording != None:
if self.recording.is_playing: if self.recording.is_playing:
self.recording.stop() self.recording.stop()
try: try:
self.recording.free() self.recording.free()
except: except:
pass pass
os.remove(self.file) os.remove(self.file)
if hasattr(self, 'wav_file'): if hasattr(self, 'wav_file'):
os.remove(self.wav_file) os.remove(self.wav_file)
def on_attach_exists(self, *args, **kwargs): def on_attach_exists(self, *args, **kwargs):
self.file = self.dialog.get_file() self.file = self.dialog.get_file()
if self.file != False: if self.file != False:
self.file_attached() self.file_attached()

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import absolute_import from __future__ import absolute_import
from __future__ import division from __future__ import division
from __future__ import unicode_literals from __future__ import unicode_literals
from builtins import object from builtins import object
from past.utils import old_div from past.utils import old_div
import sys import sys
import threading import threading
import time import time
@ -15,74 +15,74 @@ from requests_toolbelt.multipart.encoder import MultipartEncoder, MultipartEncod
import requests import requests
import os import os
class Upload(object): class Upload(object):
def __init__(self, field=None, obj=None, url=None, filename=None, follow_location=True, completed_callback=None, verbose=False, *args, **kwargs): 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) super(Upload, self).__init__(*args, **kwargs)
self.url=url self.url=url
self.filename=filename self.filename=filename
log.debug("Uploading audio to %s, filename %s" % (url, filename)) log.debug("Uploading audio to %s, filename %s" % (url, filename))
self.start_time = None self.start_time = None
self.completed_callback = completed_callback self.completed_callback = completed_callback
self.background_thread = None self.background_thread = None
self.transfer_rate = 0 self.transfer_rate = 0
self.local_filename=os.path.basename(self.filename) self.local_filename=os.path.basename(self.filename)
if isinstance(self.local_filename, str): if isinstance(self.local_filename, str):
self.local_filename=self.local_filename.encode(sys.getfilesystemencoding()) self.local_filename=self.local_filename.encode(sys.getfilesystemencoding())
self.fin=open(self.filename, 'rb') self.fin=open(self.filename, 'rb')
self.m = MultipartEncoder(fields={field:(self.local_filename, self.fin, "application/octet-stream")}) self.m = MultipartEncoder(fields={field:(self.local_filename, self.fin, "application/octet-stream")})
self.monitor = MultipartEncoderMonitor(self.m, self.progress_callback) self.monitor = MultipartEncoderMonitor(self.m, self.progress_callback)
self.response=None self.response=None
self.obj=obj self.obj=obj
self.follow_location=follow_location self.follow_location=follow_location
#the verbose parameter is deprecated and will be removed soon #the verbose parameter is deprecated and will be removed soon
def elapsed_time(self): def elapsed_time(self):
if not self.start_time: if not self.start_time:
return 0 return 0
return time.time() - self.start_time return time.time() - self.start_time
def progress_callback(self, monitor): def progress_callback(self, monitor):
progress = {} progress = {}
progress["total"] = monitor.len progress["total"] = monitor.len
progress["current"] = monitor.bytes_read progress["current"] = monitor.bytes_read
if progress["current"] == 0: if progress["current"] == 0:
progress["percent"] = 0 progress["percent"] = 0
self.transfer_rate = 0 self.transfer_rate = 0
else: else:
progress["percent"] = int((float(progress["current"]) / progress["total"]) * 100) progress["percent"] = int((float(progress["current"]) / progress["total"]) * 100)
self.transfer_rate = old_div(progress["current"], self.elapsed_time()) self.transfer_rate = old_div(progress["current"], self.elapsed_time())
progress["speed"] = '%s/s' % convert_bytes(self.transfer_rate) progress["speed"] = '%s/s' % convert_bytes(self.transfer_rate)
if self.transfer_rate: if self.transfer_rate:
progress["eta"] = old_div((progress["total"] - progress["current"]), self.transfer_rate) progress["eta"] = old_div((progress["total"] - progress["current"]), self.transfer_rate)
else: else:
progress["eta"] = 0 progress["eta"] = 0
pub.sendMessage("uploading", data=progress) pub.sendMessage("uploading", data=progress)
def perform_transfer(self): def perform_transfer(self):
log.debug("starting upload...") log.debug("starting upload...")
self.start_time = time.time() 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) 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.") log.debug("Upload finished.")
self.complete_transfer() self.complete_transfer()
def perform_threaded(self, *args, **kwargs): def perform_threaded(self, *args, **kwargs):
self.background_thread = threading.Thread(target=self.perform_transfer) self.background_thread = threading.Thread(target=self.perform_transfer)
self.background_thread.daemon = True self.background_thread.daemon = True
self.background_thread.start() self.background_thread.start()
def complete_transfer(self): def complete_transfer(self):
if callable(self.completed_callback): if callable(self.completed_callback):
self.completed_callback(self.obj) self.completed_callback(self.obj)
if hasattr(self,'fin') and callable(self.fin.close): if hasattr(self,'fin') and callable(self.fin.close):
self.fin.close() self.fin.close()
def get_url(self): def get_url(self):
try: try:
data = self.response.json() data = self.response.json()
except: except:
return _("Error in file upload: {0}").format(self.data.content,) return _("Error in file upload: {0}").format(self.data.content,)
if "url" in data and data["url"] != "0": if "url" in data and data["url"] != "0":
return data["url"] return data["url"]
elif "error" in data and data["error"] != "0": elif "error" in data and data["error"] != "0":
return data["error"] return data["error"]
else: else:
return _("Error in file upload: {0}").format(self.data.content,) return _("Error in file upload: {0}").format(self.data.content,)

View File

@ -3,42 +3,42 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from builtins import str from builtins import str
def convert_bytes(n): def convert_bytes(n):
K, M, G, T, P = 1 << 10, 1 << 20, 1 << 30, 1 << 40, 1 << 50 K, M, G, T, P = 1 << 10, 1 << 20, 1 << 30, 1 << 40, 1 << 50
if n >= P: if n >= P:
return '%.2fPb' % (float(n) / T) return '%.2fPb' % (float(n) / T)
elif n >= T: elif n >= T:
return '%.2fTb' % (float(n) / T) return '%.2fTb' % (float(n) / T)
elif n >= G: elif n >= G:
return '%.2fGb' % (float(n) / G) return '%.2fGb' % (float(n) / G)
elif n >= M: elif n >= M:
return '%.2fMb' % (float(n) / M) return '%.2fMb' % (float(n) / M)
elif n >= K: elif n >= K:
return '%.2fKb' % (float(n) / K) return '%.2fKb' % (float(n) / K)
else: else:
return '%d' % n return '%d' % n
def seconds_to_string(seconds, precision=0): def seconds_to_string(seconds, precision=0):
day = seconds // 86400 day = seconds // 86400
hour = seconds // 3600 hour = seconds // 3600
min = (seconds // 60) % 60 min = (seconds // 60) % 60
sec = seconds - (hour * 3600) - (min * 60) sec = seconds - (hour * 3600) - (min * 60)
sec_spec = "." + str(precision) + "f" sec_spec = "." + str(precision) + "f"
sec_string = sec.__format__(sec_spec) sec_string = sec.__format__(sec_spec)
string = "" string = ""
if day == 1: if day == 1:
string += _(u"%d day, ") % day string += _(u"%d day, ") % day
elif day >= 2: elif day >= 2:
string += _(u"%d days, ") % day string += _(u"%d days, ") % day
if (hour == 1): if (hour == 1):
string += _(u"%d hour, ") % hour string += _(u"%d hour, ") % hour
elif (hour >= 2): elif (hour >= 2):
string += _("%d hours, ") % hour string += _("%d hours, ") % hour
if (min == 1): if (min == 1):
string += _(u"%d minute, ") % min string += _(u"%d minute, ") % min
elif (min >= 2): elif (min >= 2):
string += _(u"%d minutes, ") % min string += _(u"%d minutes, ") % min
if sec >= 0 and sec <= 2: if sec >= 0 and sec <= 2:
string += _(u"%s second") % sec_string string += _(u"%s second") % sec_string
else: else:
string += _(u"%s seconds") % sec_string string += _(u"%s seconds") % sec_string
return string return string

View File

@ -7,57 +7,57 @@ import widgetUtils
class UploadDialog(widgetUtils.BaseDialog): class UploadDialog(widgetUtils.BaseDialog):
def __init__(self, filename, *args, **kwargs): def __init__(self, filename, *args, **kwargs):
super(UploadDialog, self).__init__(parent=None, id=wx.ID_ANY, *args, **kwargs) super(UploadDialog, self).__init__(parent=None, id=wx.ID_ANY, *args, **kwargs)
self.pane = wx.Panel(self) self.pane = wx.Panel(self)
self.progress_bar = wx.Gauge(parent=self.pane) self.progress_bar = wx.Gauge(parent=self.pane)
fileBox = wx.BoxSizer(wx.HORIZONTAL) fileBox = wx.BoxSizer(wx.HORIZONTAL)
fileLabel = wx.StaticText(self.pane, -1, _(u"File")) 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 = wx.TextCtrl(self.pane, -1, value=filename, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(200, 100))
self.file.SetFocus() self.file.SetFocus()
fileBox.Add(fileLabel) fileBox.Add(fileLabel)
fileBox.Add(self.file) fileBox.Add(self.file)
currentAmountBox = wx.BoxSizer(wx.HORIZONTAL) currentAmountBox = wx.BoxSizer(wx.HORIZONTAL)
current_amount_label = wx.StaticText(self.pane, -1, _(u"Transferred")) 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) self.current_amount = wx.TextCtrl(self.pane, -1, value='0', style=wx.TE_READONLY|wx.TE_MULTILINE)
currentAmountBox.Add(current_amount_label) currentAmountBox.Add(current_amount_label)
currentAmountBox.Add(self.current_amount) currentAmountBox.Add(self.current_amount)
totalSizeBox = wx.BoxSizer(wx.HORIZONTAL) totalSizeBox = wx.BoxSizer(wx.HORIZONTAL)
total_size_label = wx.StaticText(self.pane, -1, _(u"Total file size")) 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) self.total_size = wx.TextCtrl(self.pane, -1, value='0', style=wx.TE_READONLY|wx.TE_MULTILINE)
totalSizeBox.Add(total_size_label) totalSizeBox.Add(total_size_label)
totalSizeBox.Add(self.total_size) totalSizeBox.Add(self.total_size)
speedBox = wx.BoxSizer(wx.HORIZONTAL) speedBox = wx.BoxSizer(wx.HORIZONTAL)
speedLabel = wx.StaticText(self.pane, -1, _(u"Transfer rate")) 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") self.speed = wx.TextCtrl(self.pane, -1, style=wx.TE_READONLY|wx.TE_MULTILINE, value="0 Kb/s")
speedBox.Add(speedLabel) speedBox.Add(speedLabel)
speedBox.Add(self.speed) speedBox.Add(self.speed)
etaBox = wx.BoxSizer(wx.HORIZONTAL) etaBox = wx.BoxSizer(wx.HORIZONTAL)
etaLabel = wx.StaticText(self.pane, -1, _(u"Time left")) 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)) self.eta = wx.TextCtrl(self.pane, -1, style=wx.TE_READONLY|wx.TE_MULTILINE, value="Unknown", size=(200, 100))
etaBox.Add(etaLabel) etaBox.Add(etaLabel)
etaBox.Add(self.eta) etaBox.Add(self.eta)
self.create_buttons() self.create_buttons()
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(fileBox) sizer.Add(fileBox)
sizer.Add(currentAmountBox) sizer.Add(currentAmountBox)
sizer.Add(totalSizeBox) sizer.Add(totalSizeBox)
sizer.Add(speedBox) sizer.Add(speedBox)
sizer.Add(etaBox) sizer.Add(etaBox)
sizer.Add(self.progress_bar) sizer.Add(self.progress_bar)
self.pane.SetSizerAndFit(sizer) self.pane.SetSizerAndFit(sizer)
def update(self, data): def update(self, data):
wx.CallAfter(self.progress_bar.SetValue, data["percent"]) 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.current_amount.SetValue, '%s (%d%%)' % (convert_bytes(data["current"]), data["percent"]))
wx.CallAfter(self.total_size.SetValue, convert_bytes(data["total"])) wx.CallAfter(self.total_size.SetValue, convert_bytes(data["total"]))
wx.CallAfter(self.speed.SetValue, data["speed"]) wx.CallAfter(self.speed.SetValue, data["speed"])
if data["eta"]: if data["eta"]:
wx.CallAfter(self.eta.SetValue, seconds_to_string(data["eta"])) wx.CallAfter(self.eta.SetValue, seconds_to_string(data["eta"]))
def create_buttons(self): def create_buttons(self):
self.cancel_button = wx.Button(parent=self.pane, id=wx.ID_CANCEL) self.cancel_button = wx.Button(parent=self.pane, id=wx.ID_CANCEL)
def get_response(self, fn): def get_response(self, fn):
wx.CallAfter(fn, 0.01) wx.CallAfter(fn, 0.01)
self.ShowModal() self.ShowModal()

View File

@ -24,56 +24,56 @@ import logging
log = logging.getLogger("extra.AudioUploader.wx_UI") log = logging.getLogger("extra.AudioUploader.wx_UI")
class audioDialog(widgetUtils.BaseDialog): class audioDialog(widgetUtils.BaseDialog):
def __init__(self, services): def __init__(self, services):
log.debug("creating audio dialog.") log.debug("creating audio dialog.")
super(audioDialog, self).__init__(None, -1, _(u"Attach audio")) super(audioDialog, self).__init__(None, -1, _(u"Attach audio"))
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
btnSizer = wx.BoxSizer(wx.HORIZONTAL) btnSizer = wx.BoxSizer(wx.HORIZONTAL)
btnSizer2 = wx.BoxSizer(wx.HORIZONTAL) btnSizer2 = wx.BoxSizer(wx.HORIZONTAL)
self.play = wx.Button(panel, -1, _(u"&Play")) self.play = wx.Button(panel, -1, _(u"&Play"))
self.play.Disable() self.play.Disable()
self.pause = wx.Button(panel, -1, _(u"&Pause")) self.pause = wx.Button(panel, -1, _(u"&Pause"))
self.pause.Disable() self.pause.Disable()
self.record = wx.Button(panel, -1, _(u"&Record")) self.record = wx.Button(panel, -1, _(u"&Record"))
self.record.SetFocus() self.record.SetFocus()
self.attach_exists = wx.Button(panel, -1, _(u"&Add an existing file")) self.attach_exists = wx.Button(panel, -1, _(u"&Add an existing file"))
self.discard = wx.Button(panel, -1, _(u"&Discard")) self.discard = wx.Button(panel, -1, _(u"&Discard"))
self.discard.Disable() self.discard.Disable()
label = wx.StaticText(panel, -1, _(u"Upload to")) label = wx.StaticText(panel, -1, _(u"Upload to"))
self.services = wx.ComboBox(panel, -1, choices=services, value=services[0], style=wx.CB_READONLY) self.services = wx.ComboBox(panel, -1, choices=services, value=services[0], style=wx.CB_READONLY)
servicesBox = wx.BoxSizer(wx.HORIZONTAL) servicesBox = wx.BoxSizer(wx.HORIZONTAL)
servicesBox.Add(label, 0, wx.ALL, 5) servicesBox.Add(label, 0, wx.ALL, 5)
servicesBox.Add(self.services, 0, wx.ALL, 5) servicesBox.Add(self.services, 0, wx.ALL, 5)
self.attach = wx.Button(panel, wx.ID_OK, _(u"Attach")) self.attach = wx.Button(panel, wx.ID_OK, _(u"Attach"))
self.attach.Disable() self.attach.Disable()
cancel = wx.Button(panel, wx.ID_CANCEL, _(u"&Cancel")) cancel = wx.Button(panel, wx.ID_CANCEL, _(u"&Cancel"))
btnSizer.Add(self.play, 0, wx.ALL, 5) btnSizer.Add(self.play, 0, wx.ALL, 5)
btnSizer.Add(self.pause, 0, wx.ALL, 5) btnSizer.Add(self.pause, 0, wx.ALL, 5)
btnSizer.Add(self.record, 0, wx.ALL, 5) btnSizer.Add(self.record, 0, wx.ALL, 5)
btnSizer2.Add(self.attach_exists, 0, wx.ALL, 5) btnSizer2.Add(self.attach_exists, 0, wx.ALL, 5)
btnSizer2.Add(self.discard, 0, wx.ALL, 5) btnSizer2.Add(self.discard, 0, wx.ALL, 5)
btnSizer2.Add(self.attach, 0, wx.ALL, 5) btnSizer2.Add(self.attach, 0, wx.ALL, 5)
btnSizer2.Add(cancel, 0, wx.ALL, 5) btnSizer2.Add(cancel, 0, wx.ALL, 5)
sizer.Add(servicesBox, 0, wx.ALL, 5) sizer.Add(servicesBox, 0, wx.ALL, 5)
sizer.Add(btnSizer, 0, wx.ALL, 5) sizer.Add(btnSizer, 0, wx.ALL, 5)
sizer.Add(btnSizer2, 0, wx.ALL, 5) sizer.Add(btnSizer2, 0, wx.ALL, 5)
panel.SetSizer(sizer) panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin()) self.SetClientSize(sizer.CalcMin())
def enable_control(self, control): def enable_control(self, control):
log.debug("Enabling control %s" % (control,)) log.debug("Enabling control %s" % (control,))
if hasattr(self, control): if hasattr(self, control):
getattr(self, control).Enable() getattr(self, control).Enable()
def disable_control(self, control): def disable_control(self, control):
log.debug("Disabling control %s" % (control,)) log.debug("Disabling control %s" % (control,))
if hasattr(self, control): if hasattr(self, control):
getattr(self, control).Disable() getattr(self, control).Disable()
def get_file(self): def get_file(self):
openFileDialog = wx.FileDialog(self, _(u"Select the audio file to be uploaded"), "", "", _("Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) openFileDialog = wx.FileDialog(self, _(u"Select the audio file to be uploaded"), "", "", _("Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
if openFileDialog.ShowModal() == wx.ID_CANCEL: if openFileDialog.ShowModal() == wx.ID_CANCEL:
return False return False
return openFileDialog.GetPath() return openFileDialog.GetPath()

View File

@ -4,23 +4,23 @@ from gi.repository import Gtk
import widgetUtils import widgetUtils
class soundsTutorialDialog(Gtk.Dialog): class soundsTutorialDialog(Gtk.Dialog):
def __init__(self, actions): def __init__(self, actions):
super(soundsTutorialDialog, self).__init__("Sounds tutorial", None, 0, (Gtk.STOCK_CANCEL, widgetUtils.CANCEL)) super(soundsTutorialDialog, self).__init__("Sounds tutorial", None, 0, (Gtk.STOCK_CANCEL, widgetUtils.CANCEL))
box = self.get_content_area() box = self.get_content_area()
label = Gtk.Label("Press enter for listen the sound") label = Gtk.Label("Press enter for listen the sound")
self.list = widgetUtils.list("Action") self.list = widgetUtils.list("Action")
self.populate_actions(actions) self.populate_actions(actions)
lBox = Gtk.Box(spacing=6) lBox = Gtk.Box(spacing=6)
lBox.add(label) lBox.add(label)
lBox.add(self.list.list) lBox.add(self.list.list)
box.add(lBox) box.add(lBox)
self.play = Gtk.Button("Play") self.play = Gtk.Button("Play")
box.add(self.play) box.add(self.play)
self.show_all() self.show_all()
def populate_actions(self, actions): def populate_actions(self, actions):
for i in actions: for i in actions:
self.list.insert_item(i) self.list.insert_item(i)
def get_selected(self): def get_selected(self):
return self.list.get_selected() return self.list.get_selected()

View File

@ -1,4 +1,4 @@
from __future__ import unicode_literals from __future__ import unicode_literals
#Reverse sort, by Bill Dengler <codeofdusk@gmail.com> for use in TWBlue http://twblue.es #Reverse sort, by Bill Dengler <codeofdusk@gmail.com> for use in TWBlue http://twblue.es
def invert_tuples(t): def invert_tuples(t):
"Invert a list of tuples, so that the 0th element becomes the -1th, and the -1th becomes the 0th." "Invert a list of tuples, so that the 0th element becomes the -1th, and the -1th becomes the 0th."
@ -9,4 +9,4 @@ def invert_tuples(t):
def reverse_sort(t): def reverse_sort(t):
"Sorts a list of tuples/lists by their last elements, not their first." "Sorts a list of tuples/lists by their last elements, not their first."
return invert_tuples(sorted(invert_tuples(t))) return invert_tuples(sorted(invert_tuples(t)))

View File

@ -10,28 +10,28 @@ import logging
log = logging.getLogger("extra.SoundsTutorial.soundsTutorial") log = logging.getLogger("extra.SoundsTutorial.soundsTutorial")
from . import soundsTutorial_constants from . import soundsTutorial_constants
if platform.system() == "Windows": if platform.system() == "Windows":
from . import wx_ui as UI from . import wx_ui as UI
elif platform.system() == "Linux": elif platform.system() == "Linux":
from . import gtk_ui as UI from . import gtk_ui as UI
class soundsTutorial(object): class soundsTutorial(object):
def __init__(self, sessionObject): def __init__(self, sessionObject):
log.debug("Creating sounds tutorial object...") log.debug("Creating sounds tutorial object...")
super(soundsTutorial, self).__init__() super(soundsTutorial, self).__init__()
self.session = sessionObject self.session = sessionObject
self.actions = [] self.actions = []
log.debug("Loading actions for sounds tutorial...") log.debug("Loading actions for sounds tutorial...")
[self.actions.append(i[1]) for i in soundsTutorial_constants.actions] [self.actions.append(i[1]) for i in soundsTutorial_constants.actions]
self.files = [] self.files = []
log.debug("Searching sound files...") log.debug("Searching sound files...")
[self.files.append(i[0]) for i in soundsTutorial_constants.actions] [self.files.append(i[0]) for i in soundsTutorial_constants.actions]
log.debug("Creating dialog...") log.debug("Creating dialog...")
self.dialog = UI.soundsTutorialDialog(self.actions) self.dialog = UI.soundsTutorialDialog(self.actions)
widgetUtils.connect_event(self.dialog.play, widgetUtils.BUTTON_PRESSED, self.on_play) widgetUtils.connect_event(self.dialog.play, widgetUtils.BUTTON_PRESSED, self.on_play)
self.dialog.get_response() self.dialog.get_response()
def on_play(self, *args, **kwargs): def on_play(self, *args, **kwargs):
try: try:
self.session.sound.play(self.files[self.dialog.get_selection()]+".ogg") self.session.sound.play(self.files[self.dialog.get_selection()]+".ogg")
except: except:
log.exception("Error playing the %s sound" % (self.files[self.dialog.items.GetSelection()],)) log.exception("Error playing the %s sound" % (self.files[self.dialog.items.GetSelection()],))

View File

@ -5,27 +5,27 @@ from __future__ import unicode_literals
from . import reverse_sort from . import reverse_sort
import application import application
actions = reverse_sort.reverse_sort([ ("audio", _(u"Audio tweet.")), actions = reverse_sort.reverse_sort([ ("audio", _(u"Audio tweet.")),
("create_timeline", _(u"User timeline buffer created.")), ("create_timeline", _(u"User timeline buffer created.")),
("delete_timeline", _(u"Buffer destroied.")), ("delete_timeline", _(u"Buffer destroied.")),
("dm_received", _(u"Direct message received.")), ("dm_received", _(u"Direct message received.")),
("dm_sent", _(u"Direct message sent.")), ("dm_sent", _(u"Direct message sent.")),
("error", _(u"Error.")), ("error", _(u"Error.")),
("favourite", _(u"Tweet liked.")), ("favourite", _(u"Tweet liked.")),
("favourites_timeline_updated", _(u"Likes buffer updated.")), ("favourites_timeline_updated", _(u"Likes buffer updated.")),
("geo", _(u"Geotweet.")), ("geo", _(u"Geotweet.")),
("image", _("Tweet contains one or more images")), ("image", _("Tweet contains one or more images")),
("limit", _(u"Boundary reached.")), ("limit", _(u"Boundary reached.")),
("list_tweet", _(u"List updated.")), ("list_tweet", _(u"List updated.")),
("max_length", _(u"Too many characters.")), ("max_length", _(u"Too many characters.")),
("mention_received", _(u"Mention received.")), ("mention_received", _(u"Mention received.")),
("new_event", _(u"New event.")), ("new_event", _(u"New event.")),
("ready", _(u"{0} is ready.").format(application.name,)), ("ready", _(u"{0} is ready.").format(application.name,)),
("reply_send", _(u"Mention sent.")), ("reply_send", _(u"Mention sent.")),
("retweet_send", _(u"Tweet retweeted.")), ("retweet_send", _(u"Tweet retweeted.")),
("search_updated", _(u"Search buffer updated.")), ("search_updated", _(u"Search buffer updated.")),
("tweet_received", _(u"Tweet received.")), ("tweet_received", _(u"Tweet received.")),
("tweet_send", _(u"Tweet sent.")), ("tweet_send", _(u"Tweet sent.")),
("trends_updated", _(u"Trending topics buffer updated.")), ("trends_updated", _(u"Trending topics buffer updated.")),
("tweet_timeline", _(u"New tweet in user timeline buffer.")), ("tweet_timeline", _(u"New tweet in user timeline buffer.")),
("update_followers", _(u"New follower.")), ("update_followers", _(u"New follower.")),
("volume_changed", _(u"Volume changed."))]) ("volume_changed", _(u"Volume changed."))])

View File

@ -4,27 +4,27 @@ import wx
import widgetUtils import widgetUtils
class soundsTutorialDialog(widgetUtils.BaseDialog): class soundsTutorialDialog(widgetUtils.BaseDialog):
def __init__(self, actions): def __init__(self, actions):
super(soundsTutorialDialog, self).__init__(None, -1) super(soundsTutorialDialog, self).__init__(None, -1)
self.SetTitle(_(u"Sounds tutorial")) self.SetTitle(_(u"Sounds tutorial"))
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
label = wx.StaticText(panel, -1, _(u"Press enter to listen to the sound for the selected event")) label = wx.StaticText(panel, -1, _(u"Press enter to listen to the sound for the selected event"))
self.items = wx.ListBox(panel, 1, choices=actions, style=wx.LB_SINGLE) self.items = wx.ListBox(panel, 1, choices=actions, style=wx.LB_SINGLE)
self.items.SetSelection(0) self.items.SetSelection(0)
listBox = wx.BoxSizer(wx.HORIZONTAL) listBox = wx.BoxSizer(wx.HORIZONTAL)
listBox.Add(label) listBox.Add(label)
listBox.Add(self.items) listBox.Add(self.items)
self.play = wx.Button(panel, 1, (u"Play")) self.play = wx.Button(panel, 1, (u"Play"))
self.play.SetDefault() self.play.SetDefault()
close = wx.Button(panel, wx.ID_CANCEL) close = wx.Button(panel, wx.ID_CANCEL)
btnBox = wx.BoxSizer(wx.HORIZONTAL) btnBox = wx.BoxSizer(wx.HORIZONTAL)
btnBox.Add(self.play) btnBox.Add(self.play)
btnBox.Add(close) btnBox.Add(close)
sizer.Add(listBox) sizer.Add(listBox)
sizer.Add(btnBox) sizer.Add(btnBox)
panel.SetSizer(sizer) panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin()) self.SetClientSize(sizer.CalcMin())
def get_selection(self): def get_selection(self):
return self.items.GetSelection() return self.items.GetSelection()

View File

@ -3,4 +3,4 @@ from __future__ import unicode_literals
from . import spellchecker from . import spellchecker
import platform import platform
if platform.system() == "Windows": if platform.system() == "Windows":
from .wx_ui import * from .wx_ui import *

View File

@ -19,69 +19,69 @@ from enchant import tokenize
log = logging.getLogger("extra.SpellChecker.spellChecker") log = logging.getLogger("extra.SpellChecker.spellChecker")
class spellChecker(object): class spellChecker(object):
def __init__(self, text, dictionary): def __init__(self, text, dictionary):
super(spellChecker, self).__init__() super(spellChecker, self).__init__()
# Set Dictionary path if not set in a previous call to this method. # Set Dictionary path if not set in a previous call to this method.
# Dictionary path will be located in user config, see https://github.com/manuelcortez/twblue/issues/208 # Dictionary path will be located in user config, see https://github.com/manuelcortez/twblue/issues/208
# dict_path = enchant.get_param("enchant.myspell.dictionary.path") # dict_path = enchant.get_param("enchant.myspell.dictionary.path")
# if dict_path == None: # if dict_path == None:
# enchant.set_param("enchant.myspell.dictionary.path", os.path.join(paths.config_path(), "dicts")) # enchant.set_param("enchant.myspell.dictionary.path", os.path.join(paths.config_path(), "dicts"))
# log.debug("Dictionary path set to %s" % (os.path.join(paths.config_path(), "dicts"),)) # log.debug("Dictionary path set to %s" % (os.path.join(paths.config_path(), "dicts"),))
log.debug("Creating the SpellChecker object. Dictionary: %s" % (dictionary,)) log.debug("Creating the SpellChecker object. Dictionary: %s" % (dictionary,))
self.active = True self.active = True
try: try:
if config.app["app-settings"]["language"] == "system": if config.app["app-settings"]["language"] == "system":
log.debug("Using the system language") log.debug("Using the system language")
self.dict = enchant.DictWithPWL(languageHandler.curLang[:2], os.path.join(paths.config_path(), "wordlist.dict")) self.dict = enchant.DictWithPWL(languageHandler.curLang[:2], os.path.join(paths.config_path(), "wordlist.dict"))
else: else:
log.debug("Using language: %s" % (languageHandler.getLanguage(),)) log.debug("Using language: %s" % (languageHandler.getLanguage(),))
self.dict = enchant.DictWithPWL(languageHandler.getLanguage()[:2], os.path.join(paths.config_path(), "wordlist.dict")) self.dict = enchant.DictWithPWL(languageHandler.getLanguage()[:2], os.path.join(paths.config_path(), "wordlist.dict"))
except DictNotFoundError: except DictNotFoundError:
log.exception("Dictionary for language %s not found." % (dictionary,)) log.exception("Dictionary for language %s not found." % (dictionary,))
wx_ui.dict_not_found_error() wx_ui.dict_not_found_error()
self.active = False self.active = False
self.checker = SpellChecker(self.dict, filters=[twitterFilter.TwitterFilter, tokenize.EmailFilter, tokenize.URLFilter]) self.checker = SpellChecker(self.dict, filters=[twitterFilter.TwitterFilter, tokenize.EmailFilter, tokenize.URLFilter])
self.checker.set_text(text) self.checker.set_text(text)
if self.active == True: if self.active == True:
log.debug("Creating dialog...") log.debug("Creating dialog...")
self.dialog = wx_ui.spellCheckerDialog() self.dialog = wx_ui.spellCheckerDialog()
widgetUtils.connect_event(self.dialog.ignore, widgetUtils.BUTTON_PRESSED, self.ignore) widgetUtils.connect_event(self.dialog.ignore, widgetUtils.BUTTON_PRESSED, self.ignore)
widgetUtils.connect_event(self.dialog.ignoreAll, widgetUtils.BUTTON_PRESSED, self.ignoreAll) widgetUtils.connect_event(self.dialog.ignoreAll, widgetUtils.BUTTON_PRESSED, self.ignoreAll)
widgetUtils.connect_event(self.dialog.replace, widgetUtils.BUTTON_PRESSED, self.replace) widgetUtils.connect_event(self.dialog.replace, widgetUtils.BUTTON_PRESSED, self.replace)
widgetUtils.connect_event(self.dialog.replaceAll, widgetUtils.BUTTON_PRESSED, self.replaceAll) widgetUtils.connect_event(self.dialog.replaceAll, widgetUtils.BUTTON_PRESSED, self.replaceAll)
widgetUtils.connect_event(self.dialog.add, widgetUtils.BUTTON_PRESSED, self.add) widgetUtils.connect_event(self.dialog.add, widgetUtils.BUTTON_PRESSED, self.add)
self.check() self.check()
self.dialog.get_response() self.dialog.get_response()
self.fixed_text = self.checker.get_text() self.fixed_text = self.checker.get_text()
def check(self): def check(self):
try: try:
next(self.checker) next(self.checker)
textToSay = _(u"Misspelled word: %s") % (self.checker.word,) textToSay = _(u"Misspelled word: %s") % (self.checker.word,)
context = u"... %s %s %s" % (self.checker.leading_context(10), self.checker.word, self.checker.trailing_context(10)) context = u"... %s %s %s" % (self.checker.leading_context(10), self.checker.word, self.checker.trailing_context(10))
self.dialog.set_title(textToSay) self.dialog.set_title(textToSay)
output.speak(textToSay) output.speak(textToSay)
self.dialog.set_word_and_suggestions(word=self.checker.word, context=context, suggestions=self.checker.suggest()) self.dialog.set_word_and_suggestions(word=self.checker.word, context=context, suggestions=self.checker.suggest())
except StopIteration: except StopIteration:
log.debug("Process finished.") log.debug("Process finished.")
wx_ui.finished() wx_ui.finished()
self.dialog.Destroy() self.dialog.Destroy()
def ignore(self, ev): def ignore(self, ev):
self.check() self.check()
def ignoreAll(self, ev): def ignoreAll(self, ev):
self.checker.ignore_always(word=self.checker.word) self.checker.ignore_always(word=self.checker.word)
self.check() self.check()
def replace(self, ev): def replace(self, ev):
self.checker.replace(self.dialog.get_selected_suggestion()) self.checker.replace(self.dialog.get_selected_suggestion())
self.check() self.check()
def replaceAll(self, ev): def replaceAll(self, ev):
self.checker.replace_always(self.dialog.get_selected_suggestion()) self.checker.replace_always(self.dialog.get_selected_suggestion())
self.check() self.check()
def add(self, ev): def add(self, ev):
self.checker.add() self.checker.add()
self.check() self.check()

View File

@ -21,63 +21,63 @@ import wx
import application import application
class spellCheckerDialog(wx.Dialog): class spellCheckerDialog(wx.Dialog):
def __init__(self): def __init__(self):
super(spellCheckerDialog, self).__init__(None, 1) super(spellCheckerDialog, self).__init__(None, 1)
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
word = wx.StaticText(panel, -1, _(u"Misspelled word")) word = wx.StaticText(panel, -1, _(u"Misspelled word"))
self.word = wx.TextCtrl(panel, -1) self.word = wx.TextCtrl(panel, -1)
wordBox = wx.BoxSizer(wx.HORIZONTAL) wordBox = wx.BoxSizer(wx.HORIZONTAL)
wordBox.Add(word, 0, wx.ALL, 5) wordBox.Add(word, 0, wx.ALL, 5)
wordBox.Add(self.word, 0, wx.ALL, 5) wordBox.Add(self.word, 0, wx.ALL, 5)
context = wx.StaticText(panel, -1, _(u"Context")) context = wx.StaticText(panel, -1, _(u"Context"))
self.context = wx.TextCtrl(panel, -1) self.context = wx.TextCtrl(panel, -1)
contextBox = wx.BoxSizer(wx.HORIZONTAL) contextBox = wx.BoxSizer(wx.HORIZONTAL)
contextBox.Add(context, 0, wx.ALL, 5) contextBox.Add(context, 0, wx.ALL, 5)
contextBox.Add(self.context, 0, wx.ALL, 5) contextBox.Add(self.context, 0, wx.ALL, 5)
suggest = wx.StaticText(panel, -1, _(u"Suggestions")) suggest = wx.StaticText(panel, -1, _(u"Suggestions"))
self.suggestions = wx.ListBox(panel, -1, choices=[], style=wx.LB_SINGLE) self.suggestions = wx.ListBox(panel, -1, choices=[], style=wx.LB_SINGLE)
suggestionsBox = wx.BoxSizer(wx.HORIZONTAL) suggestionsBox = wx.BoxSizer(wx.HORIZONTAL)
suggestionsBox.Add(suggest, 0, wx.ALL, 5) suggestionsBox.Add(suggest, 0, wx.ALL, 5)
suggestionsBox.Add(self.suggestions, 0, wx.ALL, 5) suggestionsBox.Add(self.suggestions, 0, wx.ALL, 5)
self.ignore = wx.Button(panel, -1, _(u"&Ignore")) self.ignore = wx.Button(panel, -1, _(u"&Ignore"))
self.ignoreAll = wx.Button(panel, -1, _(u"I&gnore all")) self.ignoreAll = wx.Button(panel, -1, _(u"I&gnore all"))
self.replace = wx.Button(panel, -1, _(u"&Replace")) self.replace = wx.Button(panel, -1, _(u"&Replace"))
self.replaceAll = wx.Button(panel, -1, _(u"R&eplace all")) self.replaceAll = wx.Button(panel, -1, _(u"R&eplace all"))
self.add = wx.Button(panel, -1, _(u"&Add to personal dictionary")) self.add = wx.Button(panel, -1, _(u"&Add to personal dictionary"))
close = wx.Button(panel, wx.ID_CANCEL) close = wx.Button(panel, wx.ID_CANCEL)
btnBox = wx.BoxSizer(wx.HORIZONTAL) btnBox = wx.BoxSizer(wx.HORIZONTAL)
btnBox.Add(self.ignore, 0, wx.ALL, 5) btnBox.Add(self.ignore, 0, wx.ALL, 5)
btnBox.Add(self.ignoreAll, 0, wx.ALL, 5) btnBox.Add(self.ignoreAll, 0, wx.ALL, 5)
btnBox.Add(self.replace, 0, wx.ALL, 5) btnBox.Add(self.replace, 0, wx.ALL, 5)
btnBox.Add(self.replaceAll, 0, wx.ALL, 5) btnBox.Add(self.replaceAll, 0, wx.ALL, 5)
btnBox.Add(self.add, 0, wx.ALL, 5) btnBox.Add(self.add, 0, wx.ALL, 5)
btnBox.Add(close, 0, wx.ALL, 5) btnBox.Add(close, 0, wx.ALL, 5)
sizer.Add(wordBox, 0, wx.ALL, 5) sizer.Add(wordBox, 0, wx.ALL, 5)
sizer.Add(contextBox, 0, wx.ALL, 5) sizer.Add(contextBox, 0, wx.ALL, 5)
sizer.Add(suggestionsBox, 0, wx.ALL, 5) sizer.Add(suggestionsBox, 0, wx.ALL, 5)
sizer.Add(btnBox, 0, wx.ALL, 5) sizer.Add(btnBox, 0, wx.ALL, 5)
panel.SetSizer(sizer) panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin()) self.SetClientSize(sizer.CalcMin())
def get_response(self): def get_response(self):
return self.ShowModal() return self.ShowModal()
def set_title(self, title): def set_title(self, title):
return self.SetTitle(title) return self.SetTitle(title)
def set_word_and_suggestions(self, word, context, suggestions): def set_word_and_suggestions(self, word, context, suggestions):
self.word.SetValue(word) self.word.SetValue(word)
self.context.ChangeValue(context) self.context.ChangeValue(context)
self.suggestions.Set(suggestions) self.suggestions.Set(suggestions)
self.suggestions.SetFocus() self.suggestions.SetFocus()
def get_selected_suggestion(self): def get_selected_suggestion(self):
return self.suggestions.GetStringSelection() return self.suggestions.GetStringSelection()
def dict_not_found_error(): def dict_not_found_error():
wx.MessageDialog(None, _(u"An error has occurred. There are no dictionaries available for the selected language in {0}").format(application.name,), _(u"Error"), wx.ICON_ERROR).ShowModal() wx.MessageDialog(None, _(u"An error has occurred. There are no dictionaries available for the selected language in {0}").format(application.name,), _(u"Error"), wx.ICON_ERROR).ShowModal()
def finished(): def finished():
wx.MessageDialog(None, _(u"Spell check complete."), application.name, style=wx.OK).ShowModal() wx.MessageDialog(None, _(u"Spell check complete."), application.name, style=wx.OK).ShowModal()

View File

@ -2,4 +2,4 @@
from __future__ import absolute_import from __future__ import absolute_import
from __future__ import unicode_literals from __future__ import unicode_literals
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from . import completion, settings from . import completion, settings

View File

@ -4,44 +4,44 @@ from . import storage
from . import wx_menu from . import wx_menu
class autocompletionUsers(object): class autocompletionUsers(object):
def __init__(self, window, session_id): def __init__(self, window, session_id):
super(autocompletionUsers, self).__init__() super(autocompletionUsers, self).__init__()
self.window = window self.window = window
self.db = storage.storage(session_id) self.db = storage.storage(session_id)
def show_menu(self, mode="tweet"): def show_menu(self, mode="tweet"):
position = self.window.get_position() position = self.window.get_position()
if mode == "tweet": if mode == "tweet":
text = self.window.get_text() text = self.window.get_text()
text = text[:position] text = text[:position]
try: try:
pattern = text.split()[-1] pattern = text.split()[-1]
except IndexError: except IndexError:
output.speak(_(u"You have to start writing")) output.speak(_(u"You have to start writing"))
return return
if pattern.startswith("@") == True: if pattern.startswith("@") == True:
menu = wx_menu.menu(self.window.text, pattern[1:], mode=mode) menu = wx_menu.menu(self.window.text, pattern[1:], mode=mode)
users = self.db.get_users(pattern[1:]) users = self.db.get_users(pattern[1:])
if len(users) > 0: if len(users) > 0:
menu.append_options(users) menu.append_options(users)
self.window.popup_menu(menu) self.window.popup_menu(menu)
menu.destroy() menu.destroy()
else: else:
output.speak(_(u"There are no results in your users database")) output.speak(_(u"There are no results in your users database"))
else: else:
output.speak(_(u"Autocompletion only works for users.")) output.speak(_(u"Autocompletion only works for users."))
elif mode == "dm": elif mode == "dm":
text = self.window.get_user() text = self.window.get_user()
try: try:
pattern = text.split()[-1] pattern = text.split()[-1]
except IndexError: except IndexError:
output.speak(_(u"You have to start writing")) output.speak(_(u"You have to start writing"))
return return
menu = wx_menu.menu(self.window.cb, pattern, mode=mode) menu = wx_menu.menu(self.window.cb, pattern, mode=mode)
users = self.db.get_users(pattern) users = self.db.get_users(pattern)
if len(users) > 0: if len(users) > 0:
menu.append_options(users) menu.append_options(users)
self.window.popup_menu(menu) self.window.popup_menu(menu)
menu.destroy() menu.destroy()
else: else:
output.speak(_(u"There are no results in your users database")) output.speak(_(u"There are no results in your users database"))

View File

@ -4,39 +4,39 @@ from . import storage, wx_manage
from wxUI import commonMessageDialogs from wxUI import commonMessageDialogs
class autocompletionManage(object): class autocompletionManage(object):
def __init__(self, session): def __init__(self, session):
super(autocompletionManage, self).__init__() super(autocompletionManage, self).__init__()
self.session = session self.session = session
self.dialog = wx_manage.autocompletionManageDialog() self.dialog = wx_manage.autocompletionManageDialog()
self.database = storage.storage(self.session.session_id) self.database = storage.storage(self.session.session_id)
self.users = self.database.get_all_users() self.users = self.database.get_all_users()
self.dialog.put_users(self.users) self.dialog.put_users(self.users)
widgetUtils.connect_event(self.dialog.add, widgetUtils.BUTTON_PRESSED, self.add_user) widgetUtils.connect_event(self.dialog.add, widgetUtils.BUTTON_PRESSED, self.add_user)
widgetUtils.connect_event(self.dialog.remove, widgetUtils.BUTTON_PRESSED, self.remove_user) widgetUtils.connect_event(self.dialog.remove, widgetUtils.BUTTON_PRESSED, self.remove_user)
self.dialog.get_response() self.dialog.get_response()
def update_list(self): def update_list(self):
item = self.dialog.users.get_selected() item = self.dialog.users.get_selected()
self.dialog.users.clear() self.dialog.users.clear()
self.users = self.database.get_all_users() self.users = self.database.get_all_users()
self.dialog.put_users(self.users) self.dialog.put_users(self.users)
self.dialog.users.select_item(item) self.dialog.users.select_item(item)
def add_user(self, *args, **kwargs): def add_user(self, *args, **kwargs):
usr = self.dialog.get_user() usr = self.dialog.get_user()
if usr == False: if usr == False:
return return
try: try:
data = self.session.twitter.twitter.get_user(screen_name=usr) data = self.session.twitter.twitter.get_user(screen_name=usr)
except: except:
self.dialog.show_invalid_user_error() self.dialog.show_invalid_user_error()
return return
self.database.set_user(data.screen_name, data.name, 0) self.database.set_user(data.screen_name, data.name, 0)
self.update_list() self.update_list()
def remove_user(self, ev): def remove_user(self, ev):
if commonMessageDialogs.delete_user_from_db() == widgetUtils.YES: if commonMessageDialogs.delete_user_from_db() == widgetUtils.YES:
item = self.dialog.users.get_selected() item = self.dialog.users.get_selected()
user = self.users[item] user = self.users[item]
self.database.remove_user(user[0]) self.database.remove_user(user[0])
self.update_list() self.update_list()

View File

@ -7,53 +7,53 @@ from . import storage
from mysc.thread_utils import call_threaded from mysc.thread_utils import call_threaded
class autocompletionSettings(object): class autocompletionSettings(object):
def __init__(self, config, buffer, window): def __init__(self, config, buffer, window):
super(autocompletionSettings, self).__init__() super(autocompletionSettings, self).__init__()
self.config = config self.config = config
self.buffer = buffer self.buffer = buffer
self.window = window self.window = window
self.dialog = wx_settings.autocompletionSettingsDialog() self.dialog = wx_settings.autocompletionSettingsDialog()
self.dialog.set("friends_buffer", self.config["mysc"]["save_friends_in_autocompletion_db"]) self.dialog.set("friends_buffer", self.config["mysc"]["save_friends_in_autocompletion_db"])
self.dialog.set("followers_buffer", self.config["mysc"]["save_followers_in_autocompletion_db"]) self.dialog.set("followers_buffer", self.config["mysc"]["save_followers_in_autocompletion_db"])
widgetUtils.connect_event(self.dialog.viewList, widgetUtils.BUTTON_PRESSED, self.view_list) widgetUtils.connect_event(self.dialog.viewList, widgetUtils.BUTTON_PRESSED, self.view_list)
if self.dialog.get_response() == widgetUtils.OK: if self.dialog.get_response() == widgetUtils.OK:
call_threaded(self.add_users_to_database) call_threaded(self.add_users_to_database)
def add_users_to_database(self): def add_users_to_database(self):
self.config["mysc"]["save_friends_in_autocompletion_db"] = self.dialog.get("friends_buffer") self.config["mysc"]["save_friends_in_autocompletion_db"] = self.dialog.get("friends_buffer")
self.config["mysc"]["save_followers_in_autocompletion_db"] = self.dialog.get("followers_buffer") self.config["mysc"]["save_followers_in_autocompletion_db"] = self.dialog.get("followers_buffer")
output.speak(_(u"Updating database... You can close this window now. A message will tell you when the process finishes.")) output.speak(_(u"Updating database... You can close this window now. A message will tell you when the process finishes."))
database = storage.storage(self.buffer.session.session_id) database = storage.storage(self.buffer.session.session_id)
if self.dialog.get("followers_buffer") == True: if self.dialog.get("followers_buffer") == True:
buffer = self.window.search_buffer("followers", self.config["twitter"]["user_name"]) buffer = self.window.search_buffer("followers", self.config["twitter"]["user_name"])
for i in buffer.session.db[buffer.name]: for i in buffer.session.db[buffer.name]:
database.set_user(i.screen_name, i.name, 1) database.set_user(i.screen_name, i.name, 1)
else: else:
database.remove_by_buffer(1) database.remove_by_buffer(1)
if self.dialog.get("friends_buffer") == True: if self.dialog.get("friends_buffer") == True:
buffer = self.window.search_buffer("friends", self.config["twitter"]["user_name"]) buffer = self.window.search_buffer("friends", self.config["twitter"]["user_name"])
for i in buffer.session.db[buffer.name]: for i in buffer.session.db[buffer.name]:
database.set_user(i.screen_name, i.name, 2) database.set_user(i.screen_name, i.name, 2)
else: else:
database.remove_by_buffer(2) database.remove_by_buffer(2)
wx_settings.show_success_dialog() wx_settings.show_success_dialog()
self.dialog.destroy() self.dialog.destroy()
def view_list(self, ev): def view_list(self, ev):
q = manage.autocompletionManage(self.buffer.session) q = manage.autocompletionManage(self.buffer.session)
def execute_at_startup(window, buffer, config): def execute_at_startup(window, buffer, config):
database = storage.storage(buffer.session.session_id) database = storage.storage(buffer.session.session_id)
if config["mysc"]["save_followers_in_autocompletion_db"] == True and config["other_buffers"]["show_followers"] == True: if config["mysc"]["save_followers_in_autocompletion_db"] == True and config["other_buffers"]["show_followers"] == True:
buffer = window.search_buffer("followers", config["twitter"]["user_name"]) buffer = window.search_buffer("followers", config["twitter"]["user_name"])
for i in buffer.session.db[buffer.name]: for i in buffer.session.db[buffer.name]:
database.set_user(i.screen_name, i.name, 1) database.set_user(i.screen_name, i.name, 1)
else: else:
database.remove_by_buffer(1) database.remove_by_buffer(1)
if config["mysc"]["save_friends_in_autocompletion_db"] == True and config["other_buffers"]["show_friends"] == True: if config["mysc"]["save_friends_in_autocompletion_db"] == True and config["other_buffers"]["show_friends"] == True:
buffer = window.search_buffer("friends", config["twitter"]["user_name"]) buffer = window.search_buffer("friends", config["twitter"]["user_name"])
for i in buffer.session.db[buffer.name]: for i in buffer.session.db[buffer.name]:
database.set_user(i.screen_name, i.name, 2) database.set_user(i.screen_name, i.name, 2)
else: else:
database.remove_by_buffer(2) database.remove_by_buffer(2)

View File

@ -2,51 +2,51 @@
import os, sqlite3, paths import os, sqlite3, paths
class storage(object): class storage(object):
def __init__(self, session_id): def __init__(self, session_id):
self.connection = sqlite3.connect(os.path.join(paths.config_path(), "%s/autocompletionUsers.dat" % (session_id))) self.connection = sqlite3.connect(os.path.join(paths.config_path(), "%s/autocompletionUsers.dat" % (session_id)))
self.cursor = self.connection.cursor() self.cursor = self.connection.cursor()
if self.table_exist("users") == False: if self.table_exist("users") == False:
self.create_table() self.create_table()
def table_exist(self, table): def table_exist(self, table):
ask = self.cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='%s'" % (table)) ask = self.cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='%s'" % (table))
answer = ask.fetchone() answer = ask.fetchone()
if answer == None: if answer == None:
return False return False
else: else:
return True return True
def get_all_users(self): def get_all_users(self):
self.cursor.execute("""select * from users""") self.cursor.execute("""select * from users""")
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 user LIKE ?""", ('{}%'.format(term),))
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):
self.cursor.execute("""insert or ignore into users values(?, ?, ?)""", (screen_name, user_name, from_a_buffer)) self.cursor.execute("""insert or ignore into users values(?, ?, ?)""", (screen_name, user_name, from_a_buffer))
self.connection.commit() self.connection.commit()
def remove_user(self, user): def remove_user(self, user):
self.cursor.execute("""DELETE FROM users WHERE user = ?""", (user,)) self.cursor.execute("""DELETE FROM users WHERE user = ?""", (user,))
self.connection.commit() self.connection.commit()
return self.cursor.fetchone() return self.cursor.fetchone()
def remove_by_buffer(self, bufferType): def remove_by_buffer(self, bufferType):
""" Removes all users saved on a buffer. BufferType is 0 for no buffer, 1 for friends and 2 for followers""" """ Removes all users saved on a buffer. BufferType is 0 for no buffer, 1 for friends and 2 for followers"""
self.cursor.execute("""DELETE FROM users WHERE from_a_buffer = ?""", (bufferType,)) self.cursor.execute("""DELETE FROM users WHERE from_a_buffer = ?""", (bufferType,))
self.connection.commit() self.connection.commit()
return self.cursor.fetchone() return self.cursor.fetchone()
def create_table(self): def create_table(self):
self.cursor.execute(""" self.cursor.execute("""
create table users( create table users(
user TEXT UNIQUE, user TEXT UNIQUE,
name TEXT, name TEXT,
from_a_buffer INTEGER from_a_buffer INTEGER
)""") )""")
def __del__(self): def __del__(self):
self.cursor.close() self.cursor.close()
self.connection.close() self.connection.close()

View File

@ -5,40 +5,40 @@ from multiplatform_widgets import widgets
import application import application
class autocompletionManageDialog(widgetUtils.BaseDialog): class autocompletionManageDialog(widgetUtils.BaseDialog):
def __init__(self): def __init__(self):
super(autocompletionManageDialog, self).__init__(parent=None, id=-1, title=_(u"Manage Autocompletion database")) super(autocompletionManageDialog, self).__init__(parent=None, id=-1, title=_(u"Manage Autocompletion database"))
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
label = wx.StaticText(panel, -1, _(u"Editing {0} users database").format(application.name,)) label = wx.StaticText(panel, -1, _(u"Editing {0} users database").format(application.name,))
self.users = widgets.list(panel, _(u"Username"), _(u"Name"), style=wx.LC_REPORT) self.users = widgets.list(panel, _(u"Username"), _(u"Name"), style=wx.LC_REPORT)
sizer.Add(label, 0, wx.ALL, 5) sizer.Add(label, 0, wx.ALL, 5)
sizer.Add(self.users.list, 0, wx.ALL, 5) sizer.Add(self.users.list, 0, wx.ALL, 5)
self.add = wx.Button(panel, -1, _(u"Add user")) self.add = wx.Button(panel, -1, _(u"Add user"))
self.remove = wx.Button(panel, -1, _(u"Remove user")) self.remove = wx.Button(panel, -1, _(u"Remove user"))
optionsBox = wx.BoxSizer(wx.HORIZONTAL) optionsBox = wx.BoxSizer(wx.HORIZONTAL)
optionsBox.Add(self.add, 0, wx.ALL, 5) optionsBox.Add(self.add, 0, wx.ALL, 5)
optionsBox.Add(self.remove, 0, wx.ALL, 5) optionsBox.Add(self.remove, 0, wx.ALL, 5)
sizer.Add(optionsBox, 0, wx.ALL, 5) sizer.Add(optionsBox, 0, wx.ALL, 5)
ok = wx.Button(panel, wx.ID_OK) ok = wx.Button(panel, wx.ID_OK)
cancel = wx.Button(panel, wx.ID_CANCEL) cancel = wx.Button(panel, wx.ID_CANCEL)
sizerBtn = wx.BoxSizer(wx.HORIZONTAL) sizerBtn = wx.BoxSizer(wx.HORIZONTAL)
sizerBtn.Add(ok, 0, wx.ALL, 5) sizerBtn.Add(ok, 0, wx.ALL, 5)
sizer.Add(cancel, 0, wx.ALL, 5) sizer.Add(cancel, 0, wx.ALL, 5)
sizer.Add(sizerBtn, 0, wx.ALL, 5) sizer.Add(sizerBtn, 0, wx.ALL, 5)
panel.SetSizer(sizer) panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin()) self.SetClientSize(sizer.CalcMin())
def put_users(self, users): def put_users(self, users):
for i in users: for i in users:
j = [i[0], i[1]] j = [i[0], i[1]]
self.users.insert_item(False, *j) self.users.insert_item(False, *j)
def get_user(self): def get_user(self):
usr = False usr = False
userDlg = wx.TextEntryDialog(None, _(u"Twitter username"), _(u"Add user to database")) userDlg = wx.TextEntryDialog(None, _(u"Twitter username"), _(u"Add user to database"))
if userDlg.ShowModal() == wx.ID_OK: if userDlg.ShowModal() == wx.ID_OK:
usr = userDlg.GetValue() usr = userDlg.GetValue()
return usr return usr
def show_invalid_user_error(self): def show_invalid_user_error(self):
wx.MessageDialog(None, _(u"The user does not exist"), _(u"Error!"), wx.ICON_ERROR).ShowModal() wx.MessageDialog(None, _(u"The user does not exist"), _(u"Error!"), wx.ICON_ERROR).ShowModal()

View File

@ -2,24 +2,24 @@
import wx import wx
class menu(wx.Menu): class menu(wx.Menu):
def __init__(self, window, pattern, mode): def __init__(self, window, pattern, mode):
super(menu, self).__init__() super(menu, self).__init__()
self.window = window self.window = window
self.pattern = pattern self.pattern = pattern
self.mode = mode self.mode = mode
def append_options(self, options): def append_options(self, options):
for i in options: for i in options:
item = wx.MenuItem(self, wx.ID_ANY, "%s (@%s)" % (i[1], i[0])) item = wx.MenuItem(self, wx.ID_ANY, "%s (@%s)" % (i[1], i[0]))
self.AppendItem(item) self.AppendItem(item)
self.Bind(wx.EVT_MENU, lambda evt, temp=i[0]: self.select_text(evt, temp), item) self.Bind(wx.EVT_MENU, lambda evt, temp=i[0]: self.select_text(evt, temp), item)
def select_text(self, ev, text): def select_text(self, ev, text):
if self.mode == "tweet": if self.mode == "tweet":
self.window.ChangeValue(self.window.GetValue().replace("@"+self.pattern, "@"+text+" ")) self.window.ChangeValue(self.window.GetValue().replace("@"+self.pattern, "@"+text+" "))
elif self.mode == "dm": elif self.mode == "dm":
self.window.SetValue(self.window.GetValue().replace(self.pattern, text)) self.window.SetValue(self.window.GetValue().replace(self.pattern, text))
self.window.SetInsertionPointEnd() self.window.SetInsertionPointEnd()
def destroy(self): def destroy(self):
self.Destroy() self.Destroy()

View File

@ -4,24 +4,24 @@ import widgetUtils
import application import application
class autocompletionSettingsDialog(widgetUtils.BaseDialog): class autocompletionSettingsDialog(widgetUtils.BaseDialog):
def __init__(self): def __init__(self):
super(autocompletionSettingsDialog, self).__init__(parent=None, id=-1, title=_(u"Autocomplete users' settings")) super(autocompletionSettingsDialog, self).__init__(parent=None, id=-1, title=_(u"Autocomplete users' settings"))
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
self.followers_buffer = wx.CheckBox(panel, -1, _(u"Add users from followers buffer")) self.followers_buffer = wx.CheckBox(panel, -1, _(u"Add users from followers buffer"))
self.friends_buffer = wx.CheckBox(panel, -1, _(u"Add users from friends buffer")) self.friends_buffer = wx.CheckBox(panel, -1, _(u"Add users from friends buffer"))
sizer.Add(self.followers_buffer, 0, wx.ALL, 5) sizer.Add(self.followers_buffer, 0, wx.ALL, 5)
sizer.Add(self.friends_buffer, 0, wx.ALL, 5) sizer.Add(self.friends_buffer, 0, wx.ALL, 5)
self.viewList = wx.Button(panel, -1, _(u"Manage database...")) self.viewList = wx.Button(panel, -1, _(u"Manage database..."))
sizer.Add(self.viewList, 0, wx.ALL, 5) sizer.Add(self.viewList, 0, wx.ALL, 5)
ok = wx.Button(panel, wx.ID_OK) ok = wx.Button(panel, wx.ID_OK)
cancel = wx.Button(panel, wx.ID_CANCEL) cancel = wx.Button(panel, wx.ID_CANCEL)
sizerBtn = wx.BoxSizer(wx.HORIZONTAL) sizerBtn = wx.BoxSizer(wx.HORIZONTAL)
sizerBtn.Add(ok, 0, wx.ALL, 5) sizerBtn.Add(ok, 0, wx.ALL, 5)
sizer.Add(cancel, 0, wx.ALL, 5) sizer.Add(cancel, 0, wx.ALL, 5)
sizer.Add(sizerBtn, 0, wx.ALL, 5) sizer.Add(sizerBtn, 0, wx.ALL, 5)
panel.SetSizer(sizer) panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin()) self.SetClientSize(sizer.CalcMin())
def show_success_dialog(): def show_success_dialog():
wx.MessageDialog(None, _(u"{0}'s database of users has been updated.").format(application.name,), _(u"Done"), wx.OK).ShowModal() wx.MessageDialog(None, _(u"{0}'s database of users has been updated.").format(application.name,), _(u"Done"), wx.OK).ShowModal()

View File

@ -9,37 +9,37 @@ short_langs = ["", "da", "du", "en", "fi", "fr", "de", "hu", "ko", "it", "ja", "
OcrLangs = ["", "dan", "dut", "eng", "fin", "fre", "ger", "hun", "kor", "ita", "jpn", "pol", "por", "rus", "spa", "tur"] OcrLangs = ["", "dan", "dut", "eng", "fin", "fre", "ger", "hun", "kor", "ita", "jpn", "pol", "por", "rus", "spa", "tur"]
class APIError(Exception): class APIError(Exception):
pass pass
class OCRSpaceAPI(object): class OCRSpaceAPI(object):
def __init__(self, key="4e72ae996f88957", url='https://api.ocr.space/parse/image'): def __init__(self, key="4e72ae996f88957", url='https://api.ocr.space/parse/image'):
self.key = key self.key = key
self.url = url self.url = url
def OCR_URL(self, url, overlay=False, lang=None): def OCR_URL(self, url, overlay=False, lang=None):
payload = { payload = {
'url': url, 'url': url,
'isOverlayRequired': overlay, 'isOverlayRequired': overlay,
'apikey': self.key, 'apikey': self.key,
} }
if lang != None: if lang != None:
payload.update(language=lang) payload.update(language=lang)
r = requests.post(self.url, data=payload) r = requests.post(self.url, data=payload)
result = r.json()['ParsedResults'][0] result = r.json()['ParsedResults'][0]
if result['ErrorMessage']: if result['ErrorMessage']:
raise APIError(result['ErrorMessage']) raise APIError(result['ErrorMessage'])
return result return result
def OCR_file(self, fileobj, overlay=False): def OCR_file(self, fileobj, overlay=False):
payload = { payload = {
'isOverlayRequired': overlay, 'isOverlayRequired': overlay,
'apikey': self.key, 'apikey': self.key,
'lang': 'es', 'lang': 'es',
} }
r = requests.post(self.url, data=payload, files={'file': fileobj}) r = requests.post(self.url, data=payload, files={'file': fileobj})
results = r.json()['ParsedResults'] results = r.json()['ParsedResults']
if results[0]['ErrorMessage']: if results[0]['ErrorMessage']:
raise APIError(results[0]['ErrorMessage']) raise APIError(results[0]['ErrorMessage'])
return results return results

View File

@ -2,4 +2,4 @@
from __future__ import absolute_import from __future__ import absolute_import
from __future__ import unicode_literals from __future__ import unicode_literals
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from . import OCRSpace from . import OCRSpace

View File

@ -4,5 +4,5 @@ from __future__ import unicode_literals
from . import translator from . import translator
import platform import platform
if platform.system() == "Windows": if platform.system() == "Windows":
from . import wx_ui as gui from . import wx_ui as gui

View File

@ -9,108 +9,108 @@ log = logging.getLogger("extras.translator")
t = None t = None
def translate(text="", target="en"): def translate(text="", target="en"):
global t global t
log.debug("Received translation request for language %s, text=%s" % (target, text)) log.debug("Received translation request for language %s, text=%s" % (target, text))
if t == None: if t == None:
t = Translator() t = Translator()
vars = dict(text=text, dest=target) vars = dict(text=text, dest=target)
return t.translate(**vars).text return t.translate(**vars).text
supported_langs = None supported_langs = None
languages = { languages = {
"af": _(u"Afrikaans"), "af": _(u"Afrikaans"),
"sq": _(u"Albanian"), "sq": _(u"Albanian"),
"am": _(u"Amharic"), "am": _(u"Amharic"),
"ar": _(u"Arabic"), "ar": _(u"Arabic"),
"hy": _(u"Armenian"), "hy": _(u"Armenian"),
"az": _(u"Azerbaijani"), "az": _(u"Azerbaijani"),
"eu": _(u"Basque"), "eu": _(u"Basque"),
"be": _(u"Belarusian"), "be": _(u"Belarusian"),
"bn": _(u"Bengali"), "bn": _(u"Bengali"),
"bh": _(u"Bihari"), "bh": _(u"Bihari"),
"bg": _(u"Bulgarian"), "bg": _(u"Bulgarian"),
"my": _(u"Burmese"), "my": _(u"Burmese"),
"ca": _(u"Catalan"), "ca": _(u"Catalan"),
"chr": _(u"Cherokee"), "chr": _(u"Cherokee"),
"zh": _(u"Chinese"), "zh": _(u"Chinese"),
"zh-CN": _(u"Chinese_simplified"), "zh-CN": _(u"Chinese_simplified"),
"zh-TW": _(u"Chinese_traditional"), "zh-TW": _(u"Chinese_traditional"),
"hr": _(u"Croatian"), "hr": _(u"Croatian"),
"cs": _(u"Czech"), "cs": _(u"Czech"),
"da": _(u"Danish"), "da": _(u"Danish"),
"dv": _(u"Dhivehi"), "dv": _(u"Dhivehi"),
"nl": _(u"Dutch"), "nl": _(u"Dutch"),
"en": _(u"English"), "en": _(u"English"),
"eo": _(u"Esperanto"), "eo": _(u"Esperanto"),
"et": _(u"Estonian"), "et": _(u"Estonian"),
"tl": _(u"Filipino"), "tl": _(u"Filipino"),
"fi": _(u"Finnish"), "fi": _(u"Finnish"),
"fr": _(u"French"), "fr": _(u"French"),
"gl": _(u"Galician"), "gl": _(u"Galician"),
"ka": _(u"Georgian"), "ka": _(u"Georgian"),
"de": _(u"German"), "de": _(u"German"),
"el": _(u"Greek"), "el": _(u"Greek"),
"gn": _(u"Guarani"), "gn": _(u"Guarani"),
"gu": _(u"Gujarati"), "gu": _(u"Gujarati"),
"iw": _(u"Hebrew"), "iw": _(u"Hebrew"),
"hi": _(u"Hindi"), "hi": _(u"Hindi"),
"hu": _(u"Hungarian"), "hu": _(u"Hungarian"),
"is": _(u"Icelandic"), "is": _(u"Icelandic"),
"id": _(u"Indonesian"), "id": _(u"Indonesian"),
"iu": _(u"Inuktitut"), "iu": _(u"Inuktitut"),
"ga": _(u"Irish"), "ga": _(u"Irish"),
"it": _(u"Italian"), "it": _(u"Italian"),
"ja": _(u"Japanese"), "ja": _(u"Japanese"),
"kn": _(u"Kannada"), "kn": _(u"Kannada"),
"kk": _(u"Kazakh"), "kk": _(u"Kazakh"),
"km": _(u"Khmer"), "km": _(u"Khmer"),
"ko": _(u"Korean"), "ko": _(u"Korean"),
"ku": _(u"Kurdish"), "ku": _(u"Kurdish"),
"ky": _(u"Kyrgyz"), "ky": _(u"Kyrgyz"),
"lo": _(u"Laothian"), "lo": _(u"Laothian"),
"lv": _(u"Latvian"), "lv": _(u"Latvian"),
"lt": _(u"Lithuanian"), "lt": _(u"Lithuanian"),
"mk": _(u"Macedonian"), "mk": _(u"Macedonian"),
"ms": _(u"Malay"), "ms": _(u"Malay"),
"ml": _(u"Malayalam"), "ml": _(u"Malayalam"),
"mt": _(u"Maltese"), "mt": _(u"Maltese"),
"mr": _(u"Marathi"), "mr": _(u"Marathi"),
"mn": _(u"Mongolian"), "mn": _(u"Mongolian"),
"ne": _(u"Nepali"), "ne": _(u"Nepali"),
"no": _(u"Norwegian"), "no": _(u"Norwegian"),
"or": _(u"Oriya"), "or": _(u"Oriya"),
"ps": _(u"Pashto"), "ps": _(u"Pashto"),
"fa": _(u"Persian"), "fa": _(u"Persian"),
"pl": _(u"Polish"), "pl": _(u"Polish"),
"pt": _(u"Portuguese"), "pt": _(u"Portuguese"),
"pa": _(u"Punjabi"), "pa": _(u"Punjabi"),
"ro": _(u"Romanian"), "ro": _(u"Romanian"),
"ru": _(u"Russian"), "ru": _(u"Russian"),
"sa": _(u"Sanskrit"), "sa": _(u"Sanskrit"),
"sr": _(u"Serbian"), "sr": _(u"Serbian"),
"sd": _(u"Sindhi"), "sd": _(u"Sindhi"),
"si": _(u"Sinhalese"), "si": _(u"Sinhalese"),
"sk": _(u"Slovak"), "sk": _(u"Slovak"),
"sl": _(u"Slovenian"), "sl": _(u"Slovenian"),
"es": _(u"Spanish"), "es": _(u"Spanish"),
"sw": _(u"Swahili"), "sw": _(u"Swahili"),
"sv": _(u"Swedish"), "sv": _(u"Swedish"),
"tg": _(u"Tajik"), "tg": _(u"Tajik"),
"ta": _(u"Tamil"), "ta": _(u"Tamil"),
"tl": _(u"Tagalog"), "tl": _(u"Tagalog"),
"te": _(u"Telugu"), "te": _(u"Telugu"),
"th": _(u"Thai"), "th": _(u"Thai"),
"bo": _(u"Tibetan"), "bo": _(u"Tibetan"),
"tr": _(u"Turkish"), "tr": _(u"Turkish"),
"uk": _(u"Ukrainian"), "uk": _(u"Ukrainian"),
"ur": _(u"Urdu"), "ur": _(u"Urdu"),
"uz": _(u"Uzbek"), "uz": _(u"Uzbek"),
"ug": _(u"Uighur"), "ug": _(u"Uighur"),
"vi": _(u"Vietnamese"), "vi": _(u"Vietnamese"),
"cy": _(u"Welsh"), "cy": _(u"Welsh"),
"yi": _(u"Yiddish") "yi": _(u"Yiddish")
} }
def available_languages(): def available_languages():
return dict(sorted(languages.items(), key=lambda x: x[1])) return dict(sorted(languages.items(), key=lambda x: x[1]))

View File

@ -21,25 +21,25 @@ import wx
from wxUI.dialogs import baseDialog from wxUI.dialogs import baseDialog
class translateDialog(baseDialog.BaseWXDialog): class translateDialog(baseDialog.BaseWXDialog):
def __init__(self): def __init__(self):
languages = [] languages = []
language_dict = translator.available_languages() language_dict = translator.available_languages()
for k in language_dict: for k in language_dict:
languages.append(language_dict[k]) languages.append(language_dict[k])
super(translateDialog, self).__init__(None, -1, title=_(u"Translate message")) super(translateDialog, self).__init__(None, -1, title=_(u"Translate message"))
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
staticDest = wx.StaticText(panel, -1, _(u"Target language")) staticDest = wx.StaticText(panel, -1, _(u"Target language"))
self.dest_lang = wx.ComboBox(panel, -1, choices=languages, style = wx.CB_READONLY) self.dest_lang = wx.ComboBox(panel, -1, choices=languages, style = wx.CB_READONLY)
self.dest_lang.SetFocus() self.dest_lang.SetFocus()
self.dest_lang.SetSelection(0) self.dest_lang.SetSelection(0)
listSizer = wx.BoxSizer(wx.HORIZONTAL) listSizer = wx.BoxSizer(wx.HORIZONTAL)
listSizer.Add(staticDest) listSizer.Add(staticDest)
listSizer.Add(self.dest_lang) listSizer.Add(self.dest_lang)
ok = wx.Button(panel, wx.ID_OK) ok = wx.Button(panel, wx.ID_OK)
ok.SetDefault() ok.SetDefault()
cancel = wx.Button(panel, wx.ID_CANCEL) cancel = wx.Button(panel, wx.ID_CANCEL)
self.SetEscapeId(wx.ID_CANCEL) self.SetEscapeId(wx.ID_CANCEL)
def get(self, control): def get(self, control):
return getattr(self, control).GetSelection() return getattr(self, control).GetSelection()

View File

@ -9,11 +9,11 @@ from . import fix_urllib3_warnings # Avoiding some SSL warnings related to Twyth
from . import fix_win32com from . import fix_win32com
#from . import fix_requests #fix cacert.pem location for TWBlue binary copies #from . import fix_requests #fix cacert.pem location for TWBlue binary copies
def setup(): def setup():
fix_arrow.fix() fix_arrow.fix()
if hasattr(sys, "frozen"): if hasattr(sys, "frozen"):
fix_libloader.fix() fix_libloader.fix()
fix_win32com.fix() fix_win32com.fix()
# fix_requests.fix() # fix_requests.fix()
# else: # else:
# fix_requests.fix(False) # fix_requests.fix(False)
fix_urllib3_warnings.fix() fix_urllib3_warnings.fix()

View File

@ -16,27 +16,27 @@ log = logging.getLogger("fixes.fix_libloader")
fixed=False fixed=False
def patched_getmodule(modname): def patched_getmodule(modname):
mod=__import__(modname) mod=__import__(modname)
return sys.modules[modname] return sys.modules[modname]
def load_com(*names): def load_com(*names):
global fixed global fixed
if fixed==False: if fixed==False:
gencache._GetModule=patched_getmodule gencache._GetModule=patched_getmodule
com.prepare_gencache() com.prepare_gencache()
fixed=True fixed=True
result = None result = None
for name in names: for name in names:
try: try:
result = gencache.EnsureDispatch(name) result = gencache.EnsureDispatch(name)
break break
except com_error: except com_error:
continue continue
if result is None: if result is None:
raise com_error("Unable to load any of the provided com objects.") raise com_error("Unable to load any of the provided com objects.")
return result return result
def fix(): def fix():
log.debug("Applying fix for Libloader...") log.debug("Applying fix for Libloader...")
com.load_com = load_com com.load_com = load_com
log.debug("Load_com has been mapped correctly.") log.debug("Load_com has been mapped correctly.")

View File

@ -7,6 +7,6 @@ import logging
log = logging.getLogger("fixes.fix_requests") log = logging.getLogger("fixes.fix_requests")
def fix(): def fix():
log.debug("Applying fix for requests...") log.debug("Applying fix for requests...")
os.environ["REQUESTS_CA_BUNDLE"] = os.path.join(paths.app_path(), "certifi", "cacert.pem")#.encode(paths.fsencoding) os.environ["REQUESTS_CA_BUNDLE"] = os.path.join(paths.app_path(), "certifi", "cacert.pem")#.encode(paths.fsencoding)
# log.debug("Changed CA path to %s" % (os.environ["REQUESTS_CA_BUNDLE"]))#.decode(paths.fsencoding))) # log.debug("Changed CA path to %s" % (os.environ["REQUESTS_CA_BUNDLE"]))#.decode(paths.fsencoding)))

View File

@ -8,8 +8,8 @@ import six
import urllib.request, urllib.parse, urllib.error import urllib.request, urllib.parse, urllib.error
def fix(): def fix():
urllib3.disable_warnings() urllib3.disable_warnings()
fields.format_header_param=patched_format_header_param fields.format_header_param=patched_format_header_param
def patched_format_header_param(name, value): def patched_format_header_param(name, value):
if not any(ch in value for ch in '"\\\r\n'): if not any(ch in value for ch in '"\\\r\n'):

View File

@ -1,6 +1,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import win32com.client import win32com.client
def fix(): def fix():
if win32com.client.gencache.is_readonly == True: if win32com.client.gencache.is_readonly == True:
win32com.client.gencache.is_readonly = False win32com.client.gencache.is_readonly = False
win32com.client.gencache.Rebuild() win32com.client.gencache.Rebuild()

View File

@ -27,40 +27,40 @@ from suds.client import Client
import constants import constants
class reportBug(object): class reportBug(object):
def __init__(self, user_name): def __init__(self, user_name):
self.user_name = user_name self.user_name = user_name
self.categories = [_(u"General")] self.categories = [_(u"General")]
self.reproducibilities = [_(u"always"), _(u"sometimes"), _(u"random"), _(u"have not tried"), _(u"unable to duplicate")] self.reproducibilities = [_(u"always"), _(u"sometimes"), _(u"random"), _(u"have not tried"), _(u"unable to duplicate")]
self.severities = [_(u"block"), _(u"crash"), _(u"major"), _(u"minor"), _(u"tweak"), _(u"text"), _(u"trivial"), _(u"feature")] self.severities = [_(u"block"), _(u"crash"), _(u"major"), _(u"minor"), _(u"tweak"), _(u"text"), _(u"trivial"), _(u"feature")]
self.dialog = wx_ui.reportBugDialog(self.categories, self.reproducibilities, self.severities) self.dialog = wx_ui.reportBugDialog(self.categories, self.reproducibilities, self.severities)
widgetUtils.connect_event(self.dialog.ok, widgetUtils.BUTTON_PRESSED, self.send) widgetUtils.connect_event(self.dialog.ok, widgetUtils.BUTTON_PRESSED, self.send)
self.dialog.get_response() self.dialog.get_response()
def send(self, *args, **kwargs): def send(self, *args, **kwargs):
if self.dialog.get("summary") == "" or self.dialog.get("description") == "": if self.dialog.get("summary") == "" or self.dialog.get("description") == "":
self.dialog.no_filled() self.dialog.no_filled()
return return
if self.dialog.get("agree") == False: if self.dialog.get("agree") == False:
self.dialog.no_checkbox() self.dialog.no_checkbox()
return return
try: try:
client = Client(application.report_bugs_url) client = Client(application.report_bugs_url)
issue = client.factory.create('IssueData') issue = client.factory.create('IssueData')
issue.project.name = application.name issue.project.name = application.name
issue.project.id = 0 issue.project.id = 0
issue.summary = self.dialog.get("summary"), issue.summary = self.dialog.get("summary"),
issue.description = "Reported by @%s on version %s (snapshot = %s)\n\n" % (self.user_name, application.version, application.snapshot) + self.dialog.get("description") issue.description = "Reported by @%s on version %s (snapshot = %s)\n\n" % (self.user_name, application.version, application.snapshot) + self.dialog.get("description")
# to do: Create getters for category, severity and reproducibility in wx_UI. # to do: Create getters for category, severity and reproducibility in wx_UI.
issue.category = constants.categories[self.dialog.category.GetSelection()] issue.category = constants.categories[self.dialog.category.GetSelection()]
issue.reproducibility.name = constants.reproducibilities[self.dialog.reproducibility.GetSelection()] issue.reproducibility.name = constants.reproducibilities[self.dialog.reproducibility.GetSelection()]
issue.severity.name = constants.severities[self.dialog.severity.GetSelection()] issue.severity.name = constants.severities[self.dialog.severity.GetSelection()]
issue.priority.name = "normal" issue.priority.name = "normal"
issue.view_state.name = "public" issue.view_state.name = "public"
issue.resolution.name = "open" issue.resolution.name = "open"
issue.projection.name = "none" issue.projection.name = "none"
issue.eta.name = "eta" issue.eta.name = "eta"
issue.status.name = "new" issue.status.name = "new"
id = client.service.mc_issue_add(keys.keyring.get("bts_user"), keys.keyring.get("bts_password"), issue) id = client.service.mc_issue_add(keys.keyring.get("bts_user"), keys.keyring.get("bts_password"), issue)
self.dialog.success(id) self.dialog.success(id)
except: except:
self.dialog.error() self.dialog.error()

View File

@ -21,75 +21,75 @@ import wx
import widgetUtils import widgetUtils
import application import application
class reportBugDialog(widgetUtils.BaseDialog): class reportBugDialog(widgetUtils.BaseDialog):
def __init__(self, categories, reproducibilities, severities): def __init__(self, categories, reproducibilities, severities):
super(reportBugDialog, self).__init__(parent=None, id=wx.NewId()) super(reportBugDialog, self).__init__(parent=None, id=wx.NewId())
self.SetTitle(_(u"Report an error")) self.SetTitle(_(u"Report an error"))
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
categoryLabel = wx.StaticText(panel, -1, _(u"Select a category"), size=wx.DefaultSize) categoryLabel = wx.StaticText(panel, -1, _(u"Select a category"), size=wx.DefaultSize)
self.category = wx.ComboBox(panel, -1, choices=categories, style=wx.CB_READONLY) self.category = wx.ComboBox(panel, -1, choices=categories, style=wx.CB_READONLY)
self.category.SetSelection(0) self.category.SetSelection(0)
categoryB = wx.BoxSizer(wx.HORIZONTAL) categoryB = wx.BoxSizer(wx.HORIZONTAL)
categoryB.Add(categoryLabel, 0, wx.ALL, 5) categoryB.Add(categoryLabel, 0, wx.ALL, 5)
categoryB.Add(self.category, 0, wx.ALL, 5) categoryB.Add(self.category, 0, wx.ALL, 5)
self.category.SetFocus() self.category.SetFocus()
sizer.Add(categoryB, 0, wx.ALL, 5) sizer.Add(categoryB, 0, wx.ALL, 5)
summaryLabel = wx.StaticText(panel, -1, _(u"Briefly describe what happened. You will be able to thoroughly explain it later"), size=wx.DefaultSize) summaryLabel = wx.StaticText(panel, -1, _(u"Briefly describe what happened. You will be able to thoroughly explain it later"), size=wx.DefaultSize)
self.summary = wx.TextCtrl(panel, -1) self.summary = wx.TextCtrl(panel, -1)
dc = wx.WindowDC(self.summary) dc = wx.WindowDC(self.summary)
dc.SetFont(self.summary.GetFont()) dc.SetFont(self.summary.GetFont())
self.summary.SetSize(dc.GetTextExtent("a"*80)) self.summary.SetSize(dc.GetTextExtent("a"*80))
summaryB = wx.BoxSizer(wx.HORIZONTAL) summaryB = wx.BoxSizer(wx.HORIZONTAL)
summaryB.Add(summaryLabel, 0, wx.ALL, 5) summaryB.Add(summaryLabel, 0, wx.ALL, 5)
summaryB.Add(self.summary, 0, wx.ALL, 5) summaryB.Add(self.summary, 0, wx.ALL, 5)
sizer.Add(summaryB, 0, wx.ALL, 5) sizer.Add(summaryB, 0, wx.ALL, 5)
descriptionLabel = wx.StaticText(panel, -1, _(u"Here, you can describe the bug in detail"), size=wx.DefaultSize) descriptionLabel = wx.StaticText(panel, -1, _(u"Here, you can describe the bug in detail"), size=wx.DefaultSize)
self.description = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE) self.description = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE)
dc = wx.WindowDC(self.description) dc = wx.WindowDC(self.description)
dc.SetFont(self.description.GetFont()) dc.SetFont(self.description.GetFont())
(x, y, z) = dc.GetMultiLineTextExtent("0"*2000) (x, y, z) = dc.GetMultiLineTextExtent("0"*2000)
self.description.SetSize((x, y)) self.description.SetSize((x, y))
descBox = wx.BoxSizer(wx.HORIZONTAL) descBox = wx.BoxSizer(wx.HORIZONTAL)
descBox.Add(descriptionLabel, 0, wx.ALL, 5) descBox.Add(descriptionLabel, 0, wx.ALL, 5)
descBox.Add(self.description, 0, wx.ALL, 5) descBox.Add(self.description, 0, wx.ALL, 5)
sizer.Add(descBox, 0, wx.ALL, 5) sizer.Add(descBox, 0, wx.ALL, 5)
reproducibilityLabel = wx.StaticText(panel, -1, _(u"how often does this bug happen?"), size=wx.DefaultSize) reproducibilityLabel = wx.StaticText(panel, -1, _(u"how often does this bug happen?"), size=wx.DefaultSize)
self.reproducibility = wx.ComboBox(panel, -1, choices=reproducibilities, style=wx.CB_READONLY) self.reproducibility = wx.ComboBox(panel, -1, choices=reproducibilities, style=wx.CB_READONLY)
self.reproducibility.SetSelection(3) self.reproducibility.SetSelection(3)
reprB = wx.BoxSizer(wx.HORIZONTAL) reprB = wx.BoxSizer(wx.HORIZONTAL)
reprB.Add(reproducibilityLabel, 0, wx.ALL, 5) reprB.Add(reproducibilityLabel, 0, wx.ALL, 5)
reprB.Add(self.reproducibility, 0, wx.ALL, 5) reprB.Add(self.reproducibility, 0, wx.ALL, 5)
sizer.Add(reprB, 0, wx.ALL, 5) sizer.Add(reprB, 0, wx.ALL, 5)
severityLabel = wx.StaticText(panel, -1, _(u"Select the importance that you think this bug has")) severityLabel = wx.StaticText(panel, -1, _(u"Select the importance that you think this bug has"))
self.severity = wx.ComboBox(panel, -1, choices=severities, style=wx.CB_READONLY) self.severity = wx.ComboBox(panel, -1, choices=severities, style=wx.CB_READONLY)
self.severity.SetSelection(3) self.severity.SetSelection(3)
severityB = wx.BoxSizer(wx.HORIZONTAL) severityB = wx.BoxSizer(wx.HORIZONTAL)
severityB.Add(severityLabel, 0, wx.ALL, 5) severityB.Add(severityLabel, 0, wx.ALL, 5)
severityB.Add(self.severity, 0, wx.ALL, 5) severityB.Add(self.severity, 0, wx.ALL, 5)
sizer.Add(severityB, 0, wx.ALL, 5) sizer.Add(severityB, 0, wx.ALL, 5)
self.agree = wx.CheckBox(panel, -1, _(u"I know that the {0} bug system will get my Twitter username to contact me and fix the bug quickly").format(application.name,)) self.agree = wx.CheckBox(panel, -1, _(u"I know that the {0} bug system will get my Twitter username to contact me and fix the bug quickly").format(application.name,))
self.agree.SetValue(False) self.agree.SetValue(False)
sizer.Add(self.agree, 0, wx.ALL, 5) sizer.Add(self.agree, 0, wx.ALL, 5)
self.ok = wx.Button(panel, wx.ID_OK, _(u"Send report")) self.ok = wx.Button(panel, wx.ID_OK, _(u"Send report"))
self.ok.SetDefault() self.ok.SetDefault()
cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Cancel")) cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Cancel"))
btnBox = wx.BoxSizer(wx.HORIZONTAL) btnBox = wx.BoxSizer(wx.HORIZONTAL)
btnBox.Add(self.ok, 0, wx.ALL, 5) btnBox.Add(self.ok, 0, wx.ALL, 5)
btnBox.Add(cancel, 0, wx.ALL, 5) btnBox.Add(cancel, 0, wx.ALL, 5)
sizer.Add(btnBox, 0, wx.ALL, 5) sizer.Add(btnBox, 0, wx.ALL, 5)
panel.SetSizer(sizer) panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin()) self.SetClientSize(sizer.CalcMin())
def no_filled(self): def no_filled(self):
wx.MessageDialog(self, _(u"You must fill out both fields"), _(u"Error"), wx.OK|wx.ICON_ERROR).ShowModal() wx.MessageDialog(self, _(u"You must fill out both fields"), _(u"Error"), wx.OK|wx.ICON_ERROR).ShowModal()
def no_checkbox(self): def no_checkbox(self):
wx.MessageDialog(self, _(u"You need to mark the checkbox to provide us your twitter username to contact you if it is necessary."), _(u"Error"), wx.ICON_ERROR).ShowModal() wx.MessageDialog(self, _(u"You need to mark the checkbox to provide us your twitter username to contact you if it is necessary."), _(u"Error"), wx.ICON_ERROR).ShowModal()
def success(self, id): def success(self, id):
wx.MessageDialog(self, _(u"Thanks for reporting this bug! In future versions, you may be able to find it in the changes list. You've reported the bug number %i") % (id), _(u"reported"), wx.OK).ShowModal() wx.MessageDialog(self, _(u"Thanks for reporting this bug! In future versions, you may be able to find it in the changes list. You've reported the bug number %i") % (id), _(u"reported"), wx.OK).ShowModal()
self.EndModal(wx.ID_OK) self.EndModal(wx.ID_OK)
def error(self): def error(self):
wx.MessageDialog(self, _(u"Something unexpected occurred while trying to report the bug. Please, try again later"), _(u"Error while reporting"), wx.ICON_ERROR|wx.OK).ShowModal() wx.MessageDialog(self, _(u"Something unexpected occurred while trying to report the bug. Please, try again later"), _(u"Error while reporting"), wx.ICON_ERROR|wx.OK).ShowModal()
self.EndModal(wx.ID_CANCEL) self.EndModal(wx.ID_CANCEL)

View File

@ -1,8 +1,8 @@
from __future__ import absolute_import from __future__ import absolute_import
import platform import platform
if platform.system() == 'Linux': if platform.system() == 'Linux':
from .linux import LinuxKeyboardHandler as GlobalKeyboardHandler from .linux import LinuxKeyboardHandler as GlobalKeyboardHandler
else: else:
from .wx_handler import WXKeyboardHandler as GlobalKeyboardHandler from .wx_handler import WXKeyboardHandler as GlobalKeyboardHandler
#elif platform.system() == 'Darwin': #elif platform.system() == 'Darwin':
#from osx import OSXKeyboardHandler as GlobalKeyboardHandler #from osx import OSXKeyboardHandler as GlobalKeyboardHandler

View File

@ -1,127 +1,127 @@
keys = { keys = {
'accept': 30, 'accept': 30,
'add': 107, 'add': 107,
'apps': 93, 'apps': 93,
'attn': 246, 'attn': 246,
'back': 8, 'back': 8,
'browser_back': 166, 'browser_back': 166,
'browser_forward': 167, 'browser_forward': 167,
'cancel': 3, 'cancel': 3,
'capital': 20, 'capital': 20,
'clear': 12, 'clear': 12,
'control': 17, 'control': 17,
'convert': 28, 'convert': 28,
'crsel': 247, 'crsel': 247,
'decimal': 110, 'decimal': 110,
'delete': 46, 'delete': 46,
'divide': 111, 'divide': 111,
'down': 40, 'down': 40,
'end': 35, 'end': 35,
'ereof': 249, 'ereof': 249,
'escape': 27, 'escape': 27,
'execute': 43, 'execute': 43,
'exsel': 248, 'exsel': 248,
'f1': 112, 'f1': 112,
'f10': 121, 'f10': 121,
'f11': 122, 'f11': 122,
'f12': 123, 'f12': 123,
'f13': 124, 'f13': 124,
'f14': 125, 'f14': 125,
'f15': 126, 'f15': 126,
'f16': 127, 'f16': 127,
'f17': 128, 'f17': 128,
'f18': 129, 'f18': 129,
'f19': 130, 'f19': 130,
'f2': 113, 'f2': 113,
'f20': 131, 'f20': 131,
'f21': 132, 'f21': 132,
'f22': 133, 'f22': 133,
'f23': 134, 'f23': 134,
'f24': 135, 'f24': 135,
'f3': 114, 'f3': 114,
'f4': 115, 'f4': 115,
'f5': 116, 'f5': 116,
'f6': 117, 'f6': 117,
'f7': 118, 'f7': 118,
'f8': 119, 'f8': 119,
'f9': 120, 'f9': 120,
'final': 24, 'final': 24,
'hangeul': 21, 'hangeul': 21,
'hangul': 21, 'hangul': 21,
'hanja': 25, 'hanja': 25,
'help': 47, 'help': 47,
'home': 36, 'home': 36,
'insert': 45, 'insert': 45,
'junja': 23, 'junja': 23,
'kana': 21, 'kana': 21,
'kanji': 25, 'kanji': 25,
'lbutton': 1, 'lbutton': 1,
'lcontrol': 162, 'lcontrol': 162,
'left': 37, 'left': 37,
'lmenu': 164, 'lmenu': 164,
'lshift': 160, 'lshift': 160,
'lwin': 91, 'lwin': 91,
'mbutton': 4, 'mbutton': 4,
'media_next_track': 176, 'media_next_track': 176,
'media_play_pause': 179, 'media_play_pause': 179,
'media_prev_track': 177, 'media_prev_track': 177,
'menu': 18, 'menu': 18,
'modechange': 31, 'modechange': 31,
'multiply': 106, 'multiply': 106,
'next': 34, 'next': 34,
'noname': 252, 'noname': 252,
'nonconvert': 29, 'nonconvert': 29,
'numlock': 144, 'numlock': 144,
'numpad0': 96, 'numpad0': 96,
'numpad1': 97, 'numpad1': 97,
'numpad2': 98, 'numpad2': 98,
'numpad3': 99, 'numpad3': 99,
'numpad4': 100, 'numpad4': 100,
'numpad5': 101, 'numpad5': 101,
'numpad6': 102, 'numpad6': 102,
'numpad7': 103, 'numpad7': 103,
'numpad8': 104, 'numpad8': 104,
'numpad9': 105, 'numpad9': 105,
'oem_clear': 254, 'oem_clear': 254,
'pa1': 253, 'pa1': 253,
'pagedown': 34, 'pagedown': 34,
'pageup': 33, 'pageup': 33,
'pause': 19, 'pause': 19,
'play': 250, 'play': 250,
'print': 42, 'print': 42,
'prior': 33, 'prior': 33,
'processkey': 229, 'processkey': 229,
'rbutton': 2, 'rbutton': 2,
'rcontrol': 163, 'rcontrol': 163,
'return': 13, 'return': 13,
'right': 39, 'right': 39,
'rmenu': 165, 'rmenu': 165,
'rshift': 161, 'rshift': 161,
'rwin': 92, 'rwin': 92,
'scroll': 145, 'scroll': 145,
'select': 41, 'select': 41,
'separator': 108, 'separator': 108,
'shift': 16, 'shift': 16,
'snapshot': 44, 'snapshot': 44,
'space': 32, 'space': 32,
'subtract': 109, 'subtract': 109,
'tab': 9, 'tab': 9,
'up': 38, 'up': 38,
'volume_down': 174, 'volume_down': 174,
'volume_mute': 173, 'volume_mute': 173,
'volume_up': 175, 'volume_up': 175,
'xbutton1': 5, 'xbutton1': 5,
'xbutton2': 6, 'xbutton2': 6,
'zoom': 251, 'zoom': 251,
'/': 191, '/': 191,
';': 218, ';': 218,
'[': 219, '[': 219,
'\\': 220, '\\': 220,
']': 221, ']': 221,
'\'': 222, '\'': 222,
'=': 187, '=': 187,
'-': 189, '-': 189,
';': 186, ';': 186,
} }
modifiers = {'alt': 1, 'control': 2, 'shift': 4, 'win': 8} modifiers = {'alt': 1, 'control': 2, 'shift': 4, 'win': 8}

View File

@ -3,56 +3,56 @@ import threading
import thread import thread
import pyatspi import pyatspi
def parse(s): def parse(s):
"""parse a string like control+f into (modifier, key). """parse a string like control+f into (modifier, key).
Unknown modifiers will return ValueError.""" Unknown modifiers will return ValueError."""
m = 0 m = 0
lst = s.split('+') lst = s.split('+')
if not len(lst): return (0, s) if not len(lst): return (0, s)
#Are these right? #Are these right?
d = { d = {
"shift": 1<<pyatspi.MODIFIER_SHIFT, "shift": 1<<pyatspi.MODIFIER_SHIFT,
"control": 1<<pyatspi.MODIFIER_CONTROL, "control": 1<<pyatspi.MODIFIER_CONTROL,
"alt": 1<<pyatspi.MODIFIER_ALT, "alt": 1<<pyatspi.MODIFIER_ALT,
"win":1<<pyatspi.MODIFIER_META3, "win":1<<pyatspi.MODIFIER_META3,
} }
for item in lst: for item in lst:
if item in d: if item in d:
m|=d[item] m|=d[item]
lst.remove(item) lst.remove(item)
#end if #end if
if len(lst) > 1: #more than one key, parse error if len(lst) > 1: #more than one key, parse error
raise ValueError, 'unknown modifier %s' % lst[0] raise ValueError, 'unknown modifier %s' % lst[0]
return (m, lst[0].lower()) return (m, lst[0].lower())
class AtspiThread(threading.Thread): class AtspiThread(threading.Thread):
def run(self): def run(self):
pyatspi.Registry.registerKeystrokeListener(handler, kind=(pyatspi.KEY_PRESSED_EVENT,), pyatspi.Registry.registerKeystrokeListener(handler, kind=(pyatspi.KEY_PRESSED_EVENT,),
mask=pyatspi.allModifiers()) mask=pyatspi.allModifiers())
pyatspi.Registry.start() pyatspi.Registry.start()
#the keys we registered #the keys we registered
keys = {} keys = {}
def handler(e): def handler(e):
m,k = e.modifiers,e.event_string.lower() m,k = e.modifiers,e.event_string.lower()
#not sure why we can't catch control+f. Try to fix it. #not sure why we can't catch control+f. Try to fix it.
if (not e.is_text) and e.id >= 97 <= 126: if (not e.is_text) and e.id >= 97 <= 126:
k = chr(e.id) k = chr(e.id)
if (m,k) not in keys: return False if (m,k) not in keys: return False
thread.start_new(keys[(m,k)], ()) thread.start_new(keys[(m,k)], ())
return True #don't pass it on return True #don't pass it on
class LinuxKeyboardHandler(KeyboardHandler): class LinuxKeyboardHandler(KeyboardHandler):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
KeyboardHandler.__init__(self, *args, **kwargs) KeyboardHandler.__init__(self, *args, **kwargs)
t = AtspiThread() t = AtspiThread()
t.start() t.start()
def register_key(self, key, function): def register_key(self, key, function):
"""key will be a string, such as control+shift+f. """key will be a string, such as control+shift+f.
We need to convert that, using parse_key, We need to convert that, using parse_key,
into modifier and key to put into our dictionary.""" into modifier and key to put into our dictionary."""
#register key so we know if we have it on event receive. #register key so we know if we have it on event receive.
t = parse(key) t = parse(key)
keys[t] = function keys[t] = function
#if we got this far, the key is valid. #if we got this far, the key is valid.
KeyboardHandler.register_key(self, key, function) KeyboardHandler.register_key(self, key, function)
def unregister_key (self, key, function): def unregister_key (self, key, function):
KeyboardHandler.unregister_key(self, key, function) KeyboardHandler.unregister_key(self, key, function)
del keys[parse(key)] del keys[parse(key)]

View File

@ -5,84 +5,84 @@ class KeyboardHandlerError (Exception): pass
class KeyboardHandler(object): class KeyboardHandler(object):
def __init__(self, repeat_rate=0.0, *args, **kwargs): def __init__(self, repeat_rate=0.0, *args, **kwargs):
self.repeat_rate = repeat_rate #How long between accepting the same keystroke? self.repeat_rate = repeat_rate #How long between accepting the same keystroke?
self._last_key = None self._last_key = None
self._last_keypress_time = 0 self._last_keypress_time = 0
super(KeyboardHandler, self).__init__(*args, **kwargs) super(KeyboardHandler, self).__init__(*args, **kwargs)
self.active_keys = {} self.active_keys = {}
if not hasattr(self, 'replacement_mods'): if not hasattr(self, 'replacement_mods'):
self.replacement_mods = {} self.replacement_mods = {}
if not hasattr(self, 'replacement_keys'): if not hasattr(self, 'replacement_keys'):
self.replacement_keys = {} self.replacement_keys = {}
def register_key (self, key, function): def register_key (self, key, function):
if key in self.active_keys: if key in self.active_keys:
raise KeyboardHandlerError("Key %s is already registered to a function" % key) raise KeyboardHandlerError("Key %s is already registered to a function" % key)
if not callable(function): if not callable(function):
raise TypeError("Must provide a callable to be invoked upon keypress") raise TypeError("Must provide a callable to be invoked upon keypress")
self.active_keys[key] = function self.active_keys[key] = function
def unregister_key (self, key, function): def unregister_key (self, key, function):
try: try:
if self.active_keys[key] != function: if self.active_keys[key] != function:
raise KeyboardHandlerError("key %s is not registered to that function" % key) raise KeyboardHandlerError("key %s is not registered to that function" % key)
except KeyError: except KeyError:
raise KeyboardHandlerError("Key %s not currently registered" % key) raise KeyboardHandlerError("Key %s not currently registered" % key)
del(self.active_keys[key]) del(self.active_keys[key])
def unregister_all_keys(self): def unregister_all_keys(self):
for key in list(self.active_keys): for key in list(self.active_keys):
self.unregister_key(key, self.active_keys[key]) self.unregister_key(key, self.active_keys[key])
def handle_key (self, key): def handle_key (self, key):
if self.repeat_rate and key == self._last_key and time.time() - self._last_keypress_time < self.repeat_rate: if self.repeat_rate and key == self._last_key and time.time() - self._last_keypress_time < self.repeat_rate:
return return
try: try:
function = self.active_keys[key] function = self.active_keys[key]
except KeyError: except KeyError:
return return
self._last_key = key self._last_key = key
self._last_keypress_time = time.time() self._last_keypress_time = time.time()
return function() return function()
def register_keys(self, keys): def register_keys(self, keys):
"""Given a mapping of keystrokes to functions, registers all keystrokes""" """Given a mapping of keystrokes to functions, registers all keystrokes"""
for k in keys: for k in keys:
self.register_key(k, keys[k]) self.register_key(k, keys[k])
def unregister_keys(self, keys): def unregister_keys(self, keys):
"""Given a mapping of keys to their functions, unregisters all provided keys.""" """Given a mapping of keys to their functions, unregisters all provided keys."""
for k in keys: for k in keys:
self.unregister_key(k, keys[k]) self.unregister_key(k, keys[k])
def standardize_key(self, key): def standardize_key(self, key):
"""Takes a keystroke and places it in a standard case and order in a list.""" """Takes a keystroke and places it in a standard case and order in a list."""
working = key.split('+') working = key.split('+')
working = [i.lower() for i in working] working = [i.lower() for i in working]
answer = [] answer = []
if "control" in working: if "control" in working:
answer.append("control") answer.append("control")
if "win" in working: if "win" in working:
answer.append("win") answer.append("win")
if "alt" in working: if "alt" in working:
answer.append("alt") answer.append("alt")
if "shift" in working: if "shift" in working:
answer.append("shift") answer.append("shift")
if working[-1] not in answer: if working[-1] not in answer:
answer.append(working[-1]) answer.append(working[-1])
return answer return answer
def standardize_keymap(self, keymap): def standardize_keymap(self, keymap):
"""Given a keymap, returns the keymap standardized.""" """Given a keymap, returns the keymap standardized."""
full = {} full = {}
for i in keymap: for i in keymap:
answer = "" answer = ""
new = self.standardize_key(keymap[i]) new = self.standardize_key(keymap[i])
for (c, j) in enumerate(new): for (c, j) in enumerate(new):
if c < len(new)-1: if c < len(new)-1:
answer = "%s%s+" % (answer, j) answer = "%s%s+" % (answer, j)
else: else:
answer = "%s%s" % (answer, j) answer = "%s%s" % (answer, j)
full[i] = answer full[i] = answer
return full return full

View File

@ -12,45 +12,45 @@ kEventHotKeyReleasedSubtype = 9
class OSXKeyboardHandler(KeyboardHandler): class OSXKeyboardHandler(KeyboardHandler):
def __init__(self): def __init__(self):
super(OSXKeyboardHandler, self).__init__() super(OSXKeyboardHandler, self).__init__()
self.replacement_keys = dict() self.replacement_keys = dict()
self.app = KeyboardCapturingNSApplication.alloc().init() self.app = KeyboardCapturingNSApplication.alloc().init()
self._event_thread = Thread(target=AppHelper.runEventLoop) self._event_thread = Thread(target=AppHelper.runEventLoop)
self._event_thread.start() self._event_thread.start()
def register_key (self, key, function): def register_key (self, key, function):
super(OSXKeyboardHandler, self).register_key(key, function) super(OSXKeyboardHandler, self).register_key(key, function)
k, m = self.parse_key(key) k, m = self.parse_key(key)
key_id = RegisterEventHotKey(k, m, (0, 0), GetApplicationEventTarget(), 0) key_id = RegisterEventHotKey(k, m, (0, 0), GetApplicationEventTarget(), 0)
self.key_ids[key] = key_id self.key_ids[key] = key_id
def unregister_key (self, key, function): def unregister_key (self, key, function):
super(OSXKeyboardHandler, self).unregister_key(key, function) super(OSXKeyboardHandler, self).unregister_key(key, function)
key_id = self.key_ids[key] key_id = self.key_ids[key]
raise NotImplementedError raise NotImplementedError
def parse_key (self, key): def parse_key (self, key):
key=key.split("+") key=key.split("+")
#replacements #replacements
#Modifier keys: #Modifier keys:
for index, item in enumerate(key[0:-1]): for index, item in enumerate(key[0:-1]):
if self.replacement_mods.has_key(item): if self.replacement_mods.has_key(item):
key[index] = self.replacement_mods[item] key[index] = self.replacement_mods[item]
if self.replacement_keys.has_key(key[-1]): if self.replacement_keys.has_key(key[-1]):
key[-1] = self.replacement_keys[key[-1]] key[-1] = self.replacement_keys[key[-1]]
elif len(key[-1])==1: elif len(key[-1])==1:
key[-1] = ord(str(key[-1]))-36 key[-1] = ord(str(key[-1]))-36
mods = 0 mods = 0
for i in key[:-1]: for i in key[:-1]:
mods = mods|i mods = mods|i
return [key[-1], mods] return [key[-1], mods]
class KeyboardCapturingNSApplication(NSApplication): class KeyboardCapturingNSApplication(NSApplication):
def sendEvent_(self, theEvent): def sendEvent_(self, theEvent):
if theEvent.type() == NSSystemDefined and theEvent.subtype() == kEventHotKeyPressedSubtype: if theEvent.type() == NSSystemDefined and theEvent.subtype() == kEventHotKeyPressedSubtype:
self.activateIgnoringOtherApps_(True) self.activateIgnoringOtherApps_(True)
NSRunAlertPanel(u'Hot Key Pressed', u'Hot Key Pressed', None, None, None) NSRunAlertPanel(u'Hot Key Pressed', u'Hot Key Pressed', None, None, None)
super(NSApplication, self).sendEvent_(theEvent) super(NSApplication, self).sendEvent_(theEvent)

View File

@ -5,36 +5,36 @@ from main import KeyboardHandler
class WindowsKeyboardHandler(KeyboardHandler): class WindowsKeyboardHandler(KeyboardHandler):
def __init__ (self, *args, **kwargs): def __init__ (self, *args, **kwargs):
super(WindowsKeyboardHandler, self).__init__(*args, **kwargs) super(WindowsKeyboardHandler, self).__init__(*args, **kwargs)
#Setup the replacement dictionaries. #Setup the replacement dictionaries.
for i in dir(win32con): for i in dir(win32con):
if i.startswith("VK_"): if i.startswith("VK_"):
key = i[3:].lower() key = i[3:].lower()
self.replacement_keys[key] = getattr(win32con, i) self.replacement_keys[key] = getattr(win32con, i)
elif i.startswith("MOD_"): elif i.startswith("MOD_"):
key = i[4:].lower() key = i[4:].lower()
self.replacement_mods[key] = getattr(win32con, i) self.replacement_mods[key] = getattr(win32con, i)
self.replacement_keys .update(dict(pageup=win32con.VK_PRIOR, pagedown=win32con.VK_NEXT)) self.replacement_keys .update(dict(pageup=win32con.VK_PRIOR, pagedown=win32con.VK_NEXT))
def parse_key (self, keystroke, separator="+"): def parse_key (self, keystroke, separator="+"):
keystroke = str(keystroke) #We don't want unicode keystroke = str(keystroke) #We don't want unicode
keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)] keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)]
mods = 0 mods = 0
for i in keystroke[:-1]: for i in keystroke[:-1]:
mods = mods | i #or everything together mods = mods | i #or everything together
return (mods, keystroke[-1]) return (mods, keystroke[-1])
def keycode_from_key(self, key): def keycode_from_key(self, key):
if key in self.replacement_mods: if key in self.replacement_mods:
return self.replacement_mods[key] return self.replacement_mods[key]
if key in self.replacement_keys: if key in self.replacement_keys:
return self.replacement_keys[key] return self.replacement_keys[key]
if len(key) == 1: if len(key) == 1:
return win32api.VkKeyScanEx(key, win32api.GetKeyboardLayout()) return win32api.VkKeyScanEx(key, win32api.GetKeyboardLayout())
def is_key_pressed(self, key): def is_key_pressed(self, key):
"""Returns if the given key was pressed. Requires an active message loop or will simply give if the key was pressed recently.""" """Returns if the given key was pressed. Requires an active message loop or will simply give if the key was pressed recently."""
key = self.keycode_from_key(key) key = self.keycode_from_key(key)
return win32api.GetAsyncKeyState(key) return win32api.GetAsyncKeyState(key)

View File

@ -10,121 +10,121 @@ from . import key_constants
__all__ = ['WXKeyboardHandler', 'WXControlKeyboardHandler'] __all__ = ['WXKeyboardHandler', 'WXControlKeyboardHandler']
def call_after(func): def call_after(func):
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
wx.CallAfter(func, *args, **kwargs) wx.CallAfter(func, *args, **kwargs)
functools.update_wrapper(wrapper, func) functools.update_wrapper(wrapper, func)
return wrapper return wrapper
class BaseWXKeyboardHandler(KeyboardHandler): class BaseWXKeyboardHandler(KeyboardHandler):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(BaseWXKeyboardHandler, self).__init__(*args, **kwargs) super(BaseWXKeyboardHandler, self).__init__(*args, **kwargs)
#Setup the replacement dictionaries. #Setup the replacement dictionaries.
for i in dir(wx): for i in dir(wx):
if i.startswith('WXK_'): if i.startswith('WXK_'):
key = i[4:].lower() key = i[4:].lower()
self.replacement_keys[key] = getattr(wx, i) self.replacement_keys[key] = getattr(wx, i)
elif i.startswith('MOD_'): elif i.startswith('MOD_'):
key = i[4:].lower() key = i[4:].lower()
self.replacement_mods[key] = getattr(wx, i) self.replacement_mods[key] = getattr(wx, i)
def parse_key (self, keystroke, separator="+"): def parse_key (self, keystroke, separator="+"):
keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)] keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)]
mods = 0 mods = 0
for i in keystroke[:-1]: for i in keystroke[:-1]:
mods = mods | i #or everything together mods = mods | i #or everything together
return (mods, keystroke[-1]) return (mods, keystroke[-1])
def keycode_from_key(self, key):
result = None
if key in self.replacement_mods:
result = self.replacement_mods[key]
elif key in self.replacement_keys:
result = self.replacement_keys[key]
if result >= 277:
result -= 277
elif len(key) == 1:
result = ord(key.upper())
if result is None:
raise KeyboardHandlerError("Could not translate key %r into a valid keycode." % key)
return result
def keycode_from_key(self, key):
result = None
if key in self.replacement_mods:
result = self.replacement_mods[key]
elif key in self.replacement_keys:
result = self.replacement_keys[key]
if result >= 277:
result -= 277
elif len(key) == 1:
result = ord(key.upper())
if result is None:
raise KeyboardHandlerError("Could not translate key %r into a valid keycode." % key)
return result
class WXKeyboardHandler(BaseWXKeyboardHandler): class WXKeyboardHandler(BaseWXKeyboardHandler):
def __init__ (self, parent, *args, **kwargs): def __init__ (self, parent, *args, **kwargs):
super(WXKeyboardHandler, self).__init__(*args, **kwargs) super(WXKeyboardHandler, self).__init__(*args, **kwargs)
self.parent = parent self.parent = parent
self.key_ids = {} self.key_ids = {}
self.replacement_keys = key_constants.keys self.replacement_keys = key_constants.keys
self.replacement_mods = key_constants.modifiers self.replacement_mods = key_constants.modifiers
@call_after @call_after
def register_key(self, key, function): def register_key(self, key, function):
super(WXKeyboardHandler, self).register_key(key, function) super(WXKeyboardHandler, self).register_key(key, function)
key_id = wx.NewId() key_id = wx.NewId()
parsed = self.parse_key(key) parsed = self.parse_key(key)
res = self.parent.RegisterHotKey(key_id, *parsed) res = self.parent.RegisterHotKey(key_id, *parsed)
if not res: if not res:
logger.warn("Failed to register hotkey: %s for function %r", key, function) logger.warn("Failed to register hotkey: %s for function %r", key, function)
self.parent.Bind(wx.EVT_HOTKEY, lambda evt: self.process_key(evt, key_id), id=key_id) self.parent.Bind(wx.EVT_HOTKEY, lambda evt: self.process_key(evt, key_id), id=key_id)
self.key_ids[key] = key_id self.key_ids[key] = key_id
return res return res
def parse_key (self, keystroke, separator="+"): def parse_key (self, keystroke, separator="+"):
keystroke = str(keystroke) #We don't want unicode keystroke = str(keystroke) #We don't want unicode
keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)] keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)]
mods = 0 mods = 0
for i in keystroke[:-1]: for i in keystroke[:-1]:
mods = mods | i #or everything together mods = mods | i #or everything together
return (mods, keystroke[-1]) return (mods, keystroke[-1])
@call_after @call_after
def unregister_key (self, key, function): def unregister_key (self, key, function):
super(WXKeyboardHandler, self).unregister_key(key, function) super(WXKeyboardHandler, self).unregister_key(key, function)
if key not in self.key_ids: if key not in self.key_ids:
return #there's nothing we can do. return #there's nothing we can do.
key_id = self.key_ids[key] key_id = self.key_ids[key]
self.parent.UnregisterHotKey(key_id) self.parent.UnregisterHotKey(key_id)
self.parent.Unbind( wx.EVT_HOTKEY, id=key_id) self.parent.Unbind( wx.EVT_HOTKEY, id=key_id)
self.key_ids.pop(key) self.key_ids.pop(key)
def process_key (self, evt, id): def process_key (self, evt, id):
evt.Skip() evt.Skip()
key_ids = self.key_ids.keys() key_ids = self.key_ids.keys()
for i in key_ids: for i in key_ids:
if self.key_ids.get(i) == id: if self.key_ids.get(i) == id:
self.handle_key(i) self.handle_key(i)
class WXControlKeyboardHandler(wx.StaticText, KeyboardHandler): class WXControlKeyboardHandler(wx.StaticText, KeyboardHandler):
def __init__(self, parent=None, *a, **k): def __init__(self, parent=None, *a, **k):
wx.StaticText.__init__(self, parent=parent) wx.StaticText.__init__(self, parent=parent)
KeyboardHandler.__init__(self, *a, **k) KeyboardHandler.__init__(self, *a, **k)
self.wx_replacements = {} self.wx_replacements = {}
for i in [d for d in dir(wx) if d.startswith('WXK_')]: for i in [d for d in dir(wx) if d.startswith('WXK_')]:
self.wx_replacements[getattr(wx, i)] = i[4:].lower() self.wx_replacements[getattr(wx, i)] = i[4:].lower()
self.Bind(wx.EVT_KEY_DOWN, self.process_key, self) self.Bind(wx.EVT_KEY_DOWN, self.process_key, self)
self.SetFocus() self.SetFocus()
def process_key(self, evt): def process_key(self, evt):
keycode = evt.GetKeyCode() keycode = evt.GetKeyCode()
keyname = self.wx_replacements.get(keycode, None) keyname = self.wx_replacements.get(keycode, None)
modifiers = "" modifiers = ""
replacements = ( (evt.ControlDown(), 'control+'), replacements = ( (evt.ControlDown(), 'control+'),
(evt.AltDown(), 'alt+'), (evt.AltDown(), 'alt+'),
(evt.ShiftDown(), 'shift+'), (evt.ShiftDown(), 'shift+'),
(evt.MetaDown(), 'win+') (evt.MetaDown(), 'win+')
) )
for mod, ch in (replacements): for mod, ch in (replacements):
if mod: if mod:
modifiers += ch modifiers += ch
if keyname is None: if keyname is None:
if 27 < keycode < 256: if 27 < keycode < 256:
keyname = chr(keycode).lower() keyname = chr(keycode).lower()
else: else:
keyname = "(%s)unknown" % keycode keyname = "(%s)unknown" % keycode
key = modifiers + keyname key = modifiers + keyname
self.handle_key(key) self.handle_key(key)

View File

@ -14,9 +14,9 @@ import paths
# lib = load_library("snapshot_api_keys64", x64_path=paths.app_path("keys/lib")) # lib = load_library("snapshot_api_keys64", x64_path=paths.app_path("keys/lib"))
#else: #else:
if platform.architecture()[0][:2] == "32": if platform.architecture()[0][:2] == "32":
lib = load_library("stable_api_keys32", x86_path=os.path.join(paths.app_path(), "keys", "lib")) lib = load_library("stable_api_keys32", x86_path=os.path.join(paths.app_path(), "keys", "lib"))
else: else:
lib = load_library("stable_api_keys64", x64_path=os.path.join(paths.app_path(), "keys", "lib")) lib = load_library("stable_api_keys64", x64_path=os.path.join(paths.app_path(), "keys", "lib"))
# import linuxKeys # import linuxKeys
# lib = linuxKeys # lib = linuxKeys
@ -24,20 +24,20 @@ else:
keyring = None keyring = None
def setup(): def setup():
global keyring global keyring
if keyring == None: if keyring == None:
keyring = Keyring() keyring = Keyring()
class Keyring(object): class Keyring(object):
def __init__(self): def __init__(self):
super(Keyring, self).__init__() super(Keyring, self).__init__()
def _call_method(self, function): def _call_method(self, function):
result = getattr(lib, function) result = getattr(lib, function)
result = c_char_p(result.__call__()) result = c_char_p(result.__call__())
return result.value return result.value
def get(self, func): def get(self, func):
if hasattr(application,func+"_override"): if hasattr(application,func+"_override"):
return getattr(application,func+'_override') return getattr(application,func+'_override')
return getattr(self, "_call_method")("get_"+func) return getattr(self, "_call_method")("get_"+func)

View File

@ -1,9 +1,9 @@
from __future__ import unicode_literals from __future__ import unicode_literals
def get_api_key(): def get_api_key():
return "8pDLbyOW3saYnvSZ4uLFg\0" return "8pDLbyOW3saYnvSZ4uLFg\0"
def get_api_secret(): def get_api_secret():
return "YsgdrzY9B4yyYvYsyee78rKI3GshjHpenVS9LnFJXY\0"; return "YsgdrzY9B4yyYvYsyee78rKI3GshjHpenVS9LnFJXY\0";
#char *get_dropbox_api_key(){ #char *get_dropbox_api_key(){
#return "key\0"; #return "key\0";

View File

@ -1,3 +1,3 @@
from __future__ import absolute_import from __future__ import absolute_import
from __future__ import unicode_literals from __future__ import unicode_literals
from .keystrokeEditor import KeystrokeEditor from .keystrokeEditor import KeystrokeEditor

View File

@ -1,60 +1,60 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals 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"),
"left": _(u"Go to the previous buffer"), "left": _(u"Go to the previous buffer"),
"right": _(u"Go to the next buffer"), "right": _(u"Go to the next buffer"),
"next_account": _(u"Focus the next session"), "next_account": _(u"Focus the next session"),
"previous_account": _(u"Focus the previous session"), "previous_account": _(u"Focus the previous session"),
"show_hide": _(u"Show or hide the GUI"), "show_hide": _(u"Show or hide the GUI"),
"post_tweet": _(u"New tweet"), "post_tweet": _(u"New tweet"),
"post_reply": _(u"Reply"), "post_reply": _(u"Reply"),
"post_retweet": _(u"Retweet"), "post_retweet": _(u"Retweet"),
"send_dm": _(u"Send direct message"), "send_dm": _(u"Send direct message"),
"add_to_favourites": _(u"Like a tweet"), "add_to_favourites": _(u"Like a tweet"),
"toggle_like": _(u"Like/unlike a tweet"), "toggle_like": _(u"Like/unlike a tweet"),
"remove_from_favourites": _(u"Unlike a tweet"), "remove_from_favourites": _(u"Unlike a tweet"),
"follow": _(u"Open the user actions dialogue"), "follow": _(u"Open the user actions dialogue"),
"user_details": _(u"See user details"), "user_details": _(u"See user details"),
"view_item": _(u"Show tweet"), "view_item": _(u"Show tweet"),
"exit": _(u"Quit"), "exit": _(u"Quit"),
"open_timeline": _(u"Open user timeline"), "open_timeline": _(u"Open user timeline"),
"remove_buffer": _(u"Destroy buffer"), "remove_buffer": _(u"Destroy buffer"),
"interact": _(u"Interact with the currently focused tweet."), "interact": _(u"Interact with the currently focused tweet."),
"url": _(u"Open URL"), "url": _(u"Open URL"),
"open_in_browser": _(u"View in Twitter"), "open_in_browser": _(u"View in Twitter"),
"volume_up": _(u"Increase volume by 5%"), "volume_up": _(u"Increase volume by 5%"),
"volume_down": _(u"Decrease volume by 5%"), "volume_down": _(u"Decrease volume by 5%"),
"go_home": _(u"Jump to the first element of a buffer"), "go_home": _(u"Jump to the first element of a buffer"),
"go_end": _(u"Jump to the last element of the current buffer"), "go_end": _(u"Jump to the last element of the current buffer"),
"go_page_up": _(u"Jump 20 elements up in the current buffer"), "go_page_up": _(u"Jump 20 elements up in the current buffer"),
"go_page_down": _(u"Jump 20 elements down in the current buffer"), "go_page_down": _(u"Jump 20 elements down in the current buffer"),
"update_profile": _(u"Edit profile"), "update_profile": _(u"Edit profile"),
"delete": _(u"Delete a tweet or direct message"), "delete": _(u"Delete a tweet or direct message"),
"clear_buffer": _(u"Empty the current buffer"), "clear_buffer": _(u"Empty the current buffer"),
"repeat_item": _(u"Repeat last item"), "repeat_item": _(u"Repeat last item"),
"copy_to_clipboard": _(u"Copy to clipboard"), "copy_to_clipboard": _(u"Copy to clipboard"),
"add_to_list": _(u"Add to list"), "add_to_list": _(u"Add to list"),
"remove_from_list": _(u"Remove from list"), "remove_from_list": _(u"Remove from list"),
"toggle_buffer_mute": _(u"Mute/unmute the active buffer"), "toggle_buffer_mute": _(u"Mute/unmute the active buffer"),
"toggle_session_mute": _(u"Mute/unmute the current session"), "toggle_session_mute": _(u"Mute/unmute the current session"),
"toggle_autoread": _(u"toggle the automatic reading of incoming tweets in the active buffer"), "toggle_autoread": _(u"toggle the automatic reading of incoming tweets in the active buffer"),
"search": _(u"Search on twitter"), "search": _(u"Search on twitter"),
"find": _(u"Find a string in the currently focused buffer"), "find": _(u"Find a string in the currently focused buffer"),
"edit_keystrokes": _(u"Show the keystroke editor"), "edit_keystrokes": _(u"Show the keystroke editor"),
"view_user_lists": _(u"Show lists for a specified user"), "view_user_lists": _(u"Show lists for a specified user"),
"get_more_items": _(u"load previous items"), "get_more_items": _(u"load previous items"),
"reverse_geocode": _(u"Get geolocation"), "reverse_geocode": _(u"Get geolocation"),
"view_reverse_geocode": _(u"Display the tweet's geolocation in a dialog"), "view_reverse_geocode": _(u"Display the tweet's geolocation in a dialog"),
"get_trending_topics": _(u"Create a trending topics buffer"), "get_trending_topics": _(u"Create a trending topics buffer"),
"open_conversation": _(u"View conversation"), "open_conversation": _(u"View conversation"),
"check_for_updates": _(u"Check and download updates"), "check_for_updates": _(u"Check and download updates"),
"lists_manager": _(u"Opens the list manager, which allows you to create, edit, delete and open lists in buffers."), "lists_manager": _(u"Opens the list manager, which allows you to create, edit, delete and open lists in buffers."),
"configuration": _(u"Opens the global settings dialogue"), "configuration": _(u"Opens the global settings dialogue"),
"list_manager": _(u"Opens the list manager"), "list_manager": _(u"Opens the list manager"),
"accountConfiguration": _(u"Opens the account settings dialogue"), "accountConfiguration": _(u"Opens the account settings dialogue"),
"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."),
} }

View File

@ -9,53 +9,53 @@ from . import constants
from pubsub import pub from pubsub import pub
class KeystrokeEditor(object): class KeystrokeEditor(object):
def __init__(self): def __init__(self):
super(KeystrokeEditor, self).__init__() super(KeystrokeEditor, self).__init__()
self.changed = False # Change it if the keyboard shorcuts are reassigned. self.changed = False # Change it if the keyboard shorcuts are reassigned.
self.dialog = wx_ui.keystrokeEditorDialog() self.dialog = wx_ui.keystrokeEditorDialog()
self.map = config.keymap["keymap"] self.map = config.keymap["keymap"]
# we need to copy the keymap before modify it, for unregistering the old keystrokes if is needed. # we need to copy the keymap before modify it, for unregistering the old keystrokes if is needed.
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.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()
def edit_keystroke(self, *args, **kwargs): def edit_keystroke(self, *args, **kwargs):
action = self.dialog.actions[self.dialog.get_action()] action = self.dialog.actions[self.dialog.get_action()]
edit_dialog = wx_ui.editKeystrokeDialog() edit_dialog = wx_ui.editKeystrokeDialog()
self.set_keystroke(self.map[action], edit_dialog) self.set_keystroke(self.map[action], edit_dialog)
answer = edit_dialog.get_response() answer = edit_dialog.get_response()
if answer == widgetUtils.OK: if answer == widgetUtils.OK:
new_keystroke = self.get_edited_keystroke(edit_dialog) new_keystroke = self.get_edited_keystroke(edit_dialog)
if new_keystroke != self.map[action]: if new_keystroke != self.map[action]:
self.changed = True self.changed = True
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 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):
dialog.set(i, True) dialog.set(i, True)
dialog.set("key", keystroke.split("+")[-1]) dialog.set("key", keystroke.split("+")[-1])
def get_edited_keystroke(self, dialog): def get_edited_keystroke(self, dialog):
keys = [] keys = []
if dialog.get("control") == True: if dialog.get("control") == True:
keys.append("control") keys.append("control")
if dialog.get("win") == True: if dialog.get("win") == True:
keys.append("win") keys.append("win")
if dialog.get("alt") == True: if dialog.get("alt") == True:
keys.append("alt") keys.append("alt")
if dialog.get("shift") == True: if dialog.get("shift") == True:
keys.append("shift") keys.append("shift")
if dialog.get("key") != "": if dialog.get("key") != "":
keys.append(dialog.get("key")) keys.append(dialog.get("key"))
else: else:
wx_ui.no_key() wx_ui.no_key()
return return
return "+".join(keys) return "+".join(keys)
def execute_action(self, *args, **kwargs): def execute_action(self, *args, **kwargs):
action = self.dialog.actions[self.dialog.get_action()] action = self.dialog.actions[self.dialog.get_action()]
pub.sendMessage("execute-action", action=action) pub.sendMessage("execute-action", action=action)

View File

@ -5,78 +5,78 @@ from multiplatform_widgets import widgets
from wxUI.dialogs import baseDialog from wxUI.dialogs import baseDialog
class keystrokeEditorDialog(baseDialog.BaseWXDialog): class keystrokeEditorDialog(baseDialog.BaseWXDialog):
def __init__(self): def __init__(self):
super(keystrokeEditorDialog, self).__init__(parent=None, id=-1, title=_(u"Keystroke editor")) super(keystrokeEditorDialog, self).__init__(parent=None, id=-1, title=_(u"Keystroke editor"))
panel = wx.Panel(self) panel = wx.Panel(self)
self.actions = [] self.actions = []
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
keysText = wx.StaticText(panel, -1, _(u"Select a keystroke to edit")) keysText = wx.StaticText(panel, -1, _(u"Select a keystroke to edit"))
self.keys = widgets.list(self, _(u"Action"), _(u"Keystroke"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL, size=(400, 450)) self.keys = widgets.list(self, _(u"Action"), _(u"Keystroke"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL, size=(400, 450))
self.keys.list.SetFocus() self.keys.list.SetFocus()
firstSizer = wx.BoxSizer(wx.HORIZONTAL) firstSizer = wx.BoxSizer(wx.HORIZONTAL)
firstSizer.Add(keysText, 0, wx.ALL, 5) firstSizer.Add(keysText, 0, wx.ALL, 5)
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.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)
secondSizer.Add(self.edit, 0, wx.ALL, 5) secondSizer.Add(self.edit, 0, wx.ALL, 5)
secondSizer.Add(self.execute, 0, wx.ALL, 5) secondSizer.Add(self.execute, 0, wx.ALL, 5)
secondSizer.Add(close, 0, wx.ALL, 5) secondSizer.Add(close, 0, wx.ALL, 5)
sizer.Add(firstSizer, 0, wx.ALL, 5) sizer.Add(firstSizer, 0, wx.ALL, 5)
sizer.Add(secondSizer, 0, wx.ALL, 5) sizer.Add(secondSizer, 0, wx.ALL, 5)
panel.SetSizer(sizer) panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin()) self.SetClientSize(sizer.CalcMin())
def put_keystrokes(self, actions, keystrokes): def put_keystrokes(self, actions, keystrokes):
selection = self.keys.get_selected() selection = self.keys.get_selected()
self.keys.clear() self.keys.clear()
for i in keystrokes: for i in keystrokes:
if (i in actions) == False: if (i in actions) == False:
continue continue
action = actions[i] action = actions[i]
self.actions.append(i) self.actions.append(i)
keystroke = keystrokes[i] keystroke = keystrokes[i]
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()
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"))
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
self.control = wx.CheckBox(panel, -1, _(u"Control")) self.control = wx.CheckBox(panel, -1, _(u"Control"))
self.alt = wx.CheckBox(panel, -1, _(u"Alt")) self.alt = wx.CheckBox(panel, -1, _(u"Alt"))
self.shift = wx.CheckBox(panel, -1, _(u"Shift")) self.shift = wx.CheckBox(panel, -1, _(u"Shift"))
self.win = wx.CheckBox(panel, -1, _(u"Windows")) self.win = wx.CheckBox(panel, -1, _(u"Windows"))
sizer1 = wx.BoxSizer(wx.HORIZONTAL) sizer1 = wx.BoxSizer(wx.HORIZONTAL)
sizer1.Add(self.control) sizer1.Add(self.control)
sizer1.Add(self.alt) sizer1.Add(self.alt)
sizer1.Add(self.shift) sizer1.Add(self.shift)
sizer1.Add(self.win) sizer1.Add(self.win)
charLabel = wx.StaticText(panel, -1, _(u"Key")) charLabel = wx.StaticText(panel, -1, _(u"Key"))
self.key = wx.TextCtrl(panel, -1) self.key = wx.TextCtrl(panel, -1)
sizer2 = wx.BoxSizer(wx.HORIZONTAL) sizer2 = wx.BoxSizer(wx.HORIZONTAL)
sizer2.Add(charLabel) sizer2.Add(charLabel)
sizer2.Add(self.key) sizer2.Add(self.key)
ok = wx.Button(panel, wx.ID_OK, _(u"OK")) ok = wx.Button(panel, wx.ID_OK, _(u"OK"))
ok.SetDefault() ok.SetDefault()
cancel = wx.Button(panel, wx.ID_CANCEL) cancel = wx.Button(panel, wx.ID_CANCEL)
sizer3 = wx.BoxSizer(wx.HORIZONTAL) sizer3 = wx.BoxSizer(wx.HORIZONTAL)
sizer3.Add(ok) sizer3.Add(ok)
sizer3.Add(cancel) sizer3.Add(cancel)
sizer.Add(sizer1) sizer.Add(sizer1)
sizer.Add(sizer2) sizer.Add(sizer2)
sizer.Add(sizer3) sizer.Add(sizer3)
panel.SetSizerAndFit(sizer) panel.SetSizerAndFit(sizer)
def no_win_message(): def no_win_message():
return wx.MessageDialog(None, _(u"You need to use the Windows key"), _(u"Invalid keystroke"), wx.OK|wx.ICON_ERROR).ShowModal() return wx.MessageDialog(None, _(u"You need to use the Windows key"), _(u"Invalid keystroke"), wx.OK|wx.ICON_ERROR).ShowModal()
def no_key(): def no_key():
return wx.MessageDialog(None, _(u"You must provide a character for the keystroke"), _(u"Invalid keystroke"), wx.ICON_ERROR).ShowModal() return wx.MessageDialog(None, _(u"You must provide a character for the keystroke"), _(u"Invalid keystroke"), wx.ICON_ERROR).ShowModal()

View File

@ -12,7 +12,7 @@ import gettext
import paths import paths
import platform import platform
import application import application
#a few Windows locale constants #a few Windows locale constants
LOCALE_SLANGUAGE=0x2 LOCALE_SLANGUAGE=0x2
LOCALE_SLANGDISPLAYNAME=0x6f LOCALE_SLANGDISPLAYNAME=0x6f
@ -20,195 +20,195 @@ LOCALE_SLANGDISPLAYNAME=0x6f
curLang="en" curLang="en"
def localeNameToWindowsLCID(localeName): def localeNameToWindowsLCID(localeName):
"""Retreave the Windows locale identifier (LCID) for the given locale name """Retreave the Windows locale identifier (LCID) for the given locale name
@param localeName: a string of 2letterLanguage_2letterCountry or or just 2letterLanguage @param localeName: a string of 2letterLanguage_2letterCountry or or just 2letterLanguage
@type localeName: string @type localeName: string
@returns: a Windows LCID @returns: a Windows LCID
@rtype: integer @rtype: integer
""" """
#Windows Vista is able to convert locale names to LCIDs #Windows Vista is able to convert locale names to LCIDs
func_LocaleNameToLCID=getattr(ctypes.windll.kernel32,'LocaleNameToLCID',None) func_LocaleNameToLCID=getattr(ctypes.windll.kernel32,'LocaleNameToLCID',None)
if func_LocaleNameToLCID is not None: if func_LocaleNameToLCID is not None:
localeName=localeName.replace('_','-') localeName=localeName.replace('_','-')
LCID=func_LocaleNameToLCID(str(localeName),0) LCID=func_LocaleNameToLCID(str(localeName),0)
else: #Windows doesn't have this functionality, manually search Python's windows_locale dictionary for the LCID else: #Windows doesn't have this functionality, manually search Python's windows_locale dictionary for the LCID
localeName=locale.normalize(localeName) localeName=locale.normalize(localeName)
if '.' in localeName: if '.' in localeName:
localeName=localeName.split('.')[0] localeName=localeName.split('.')[0]
LCList=[x[0] for x in locale.windows_locale.items() if x[1]==localeName] LCList=[x[0] for x in locale.windows_locale.items() if x[1]==localeName]
if len(LCList)>0: if len(LCList)>0:
LCID=LCList[0] LCID=LCList[0]
else: else:
LCID=0 LCID=0
return LCID return LCID
def getLanguageDescription(language): def getLanguageDescription(language):
"""Finds out the description (localized full name) of a given local name""" """Finds out the description (localized full name) of a given local name"""
desc=None desc=None
if platform.system() == "Windows": if platform.system() == "Windows":
LCID=localeNameToWindowsLCID(language) LCID=localeNameToWindowsLCID(language)
if LCID!=0: if LCID!=0:
buf=ctypes.create_unicode_buffer(1024) buf=ctypes.create_unicode_buffer(1024)
if '_' not in language: if '_' not in language:
res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGDISPLAYNAME,buf,1024) res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGDISPLAYNAME,buf,1024)
else: else:
res=0 res=0
if res==0: if res==0:
res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGUAGE,buf,1024) res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGUAGE,buf,1024)
desc=buf.value desc=buf.value
elif platform.system() == "Linux" or not desc: elif platform.system() == "Linux" or not desc:
desc={ desc={
"am":pgettext("languageName","Amharic"), "am":pgettext("languageName","Amharic"),
"an":pgettext("languageName","Aragonese"), "an":pgettext("languageName","Aragonese"),
"es":pgettext("languageName","Spanish"), "es":pgettext("languageName","Spanish"),
"pt":pgettext("languageName","Portuguese"), "pt":pgettext("languageName","Portuguese"),
"ru":pgettext("languageName","Russian"), "ru":pgettext("languageName","Russian"),
"it":pgettext("languageName","italian"), "it":pgettext("languageName","italian"),
"tr":pgettext("languageName","Turkey"), "tr":pgettext("languageName","Turkey"),
"gl":pgettext("languageName","Galician"), "gl":pgettext("languageName","Galician"),
"ca":pgettext("languageName","Catala"), "ca":pgettext("languageName","Catala"),
"eu":pgettext("languageName","Vasque"), "eu":pgettext("languageName","Vasque"),
"pl":pgettext("languageName","polish"), "pl":pgettext("languageName","polish"),
"ar":pgettext("languageName","Arabic"), "ar":pgettext("languageName","Arabic"),
"ne":pgettext("languageName","Nepali"), "ne":pgettext("languageName","Nepali"),
"sr":pgettext("languageName","Serbian (Latin)"), "sr":pgettext("languageName","Serbian (Latin)"),
"ja":pgettext("languageName","Japanese"), "ja":pgettext("languageName","Japanese"),
}.get(language,None) }.get(language,None)
return desc return desc
def getAvailableLanguages(): def getAvailableLanguages():
"""generates a list of locale names, plus their full localized language and country names. """generates a list of locale names, plus their full localized language and country names.
@rtype: list of tuples @rtype: list of tuples
""" """
#Make a list of all the locales found in NVDA's locale dir #Make a list of all the locales found in NVDA's locale dir
l=[x for x in os.listdir(paths.locale_path()) if not x.startswith('.')] l=[x for x in os.listdir(paths.locale_path()) if not x.startswith('.')]
l=[x for x in l if os.path.isfile(os.path.join(paths.locale_path(), '%s/LC_MESSAGES/%s.po' % (x, application.short_name)))] l=[x for x in l if os.path.isfile(os.path.join(paths.locale_path(), '%s/LC_MESSAGES/%s.po' % (x, application.short_name)))]
#Make sure that en (english) is in the list as it may not have any locale files, but is default #Make sure that en (english) is in the list as it may not have any locale files, but is default
if 'en' not in l: if 'en' not in l:
l.append('en') l.append('en')
l.sort() l.sort()
#For each locale, ask Windows for its human readable display name #For each locale, ask Windows for its human readable display name
d=[] d=[]
for i in l: for i in l:
desc=getLanguageDescription(i) desc=getLanguageDescription(i)
label="%s, %s"%(desc,i) if desc else i label="%s, %s"%(desc,i) if desc else i
d.append(label) d.append(label)
#include a 'user default, windows' language, which just represents the default language for this user account #include a 'user default, windows' language, which just represents the default language for this user account
l.append("system") l.append("system")
# Translators: the label for the Windows default NVDA interface language. # Translators: the label for the Windows default NVDA interface language.
d.append(_("User default")) d.append(_("User default"))
#return a zipped up version of both the lists (a list with tuples of locale,label) #return a zipped up version of both the lists (a list with tuples of locale,label)
return list(zip(l,d)) return list(zip(l,d))
def makePgettext(translations): def makePgettext(translations):
"""Obtaina pgettext function for use with a gettext translations instance. """Obtaina pgettext function for use with a gettext translations instance.
pgettext is used to support message contexts, pgettext is used to support message contexts,
but Python 2.7's gettext module doesn't support this, but Python 2.7's gettext module doesn't support this,
so NVDA must provide its own implementation. so NVDA must provide its own implementation.
""" """
if isinstance(translations, gettext.GNUTranslations): if isinstance(translations, gettext.GNUTranslations):
def pgettext(context, message): def pgettext(context, message):
message = str(message) message = str(message)
try: try:
# Look up the message with its context. # Look up the message with its context.
return translations._catalog["%s\x04%s" % (context, message)] return translations._catalog["%s\x04%s" % (context, message)]
except KeyError: except KeyError:
return message return message
else: else:
def pgettext(context, message): def pgettext(context, message):
return str(message) return str(message)
return pgettext return pgettext
def setLanguage(lang): def setLanguage(lang):
system = platform.system() system = platform.system()
global curLang global curLang
try: try:
if lang=="system": if lang=="system":
if system == "Windows": if system == "Windows":
windowsLCID=ctypes.windll.kernel32.GetUserDefaultUILanguage() windowsLCID=ctypes.windll.kernel32.GetUserDefaultUILanguage()
localeName=locale.windows_locale[windowsLCID] localeName=locale.windows_locale[windowsLCID]
elif system == "Darwin": elif system == "Darwin":
import Foundation import Foundation
localeName = Foundation.NSLocale.currentLocale().identifier() localeName = Foundation.NSLocale.currentLocale().identifier()
elif system == "Linux": elif system == "Linux":
localeName = locale.getdefaultlocale()[0] localeName = locale.getdefaultlocale()[0]
trans=gettext.translation(application.short_name, localedir=paths.locale_path(), languages=[localeName]) trans=gettext.translation(application.short_name, localedir=paths.locale_path(), languages=[localeName])
curLang=localeName curLang=localeName
# else: # else:
# localeName=locale.getdefaultlocale()[0] # localeName=locale.getdefaultlocale()[0]
# trans=gettext.translation('twblue', localedir=paths.locale_path(), languages=[localeName]) # trans=gettext.translation('twblue', localedir=paths.locale_path(), languages=[localeName])
# curLang=localeName # curLang=localeName
else: else:
trans=gettext.translation(application.short_name, localedir=paths.locale_path(), languages=[lang]) trans=gettext.translation(application.short_name, localedir=paths.locale_path(), languages=[lang])
curLang=lang curLang=lang
localeChanged=False localeChanged=False
#Try setting Python's locale to lang #Try setting Python's locale to lang
# try: # try:
if system == "Windows": if system == "Windows":
locale.setlocale(locale.LC_ALL, langToWindowsLocale(lang)) locale.setlocale(locale.LC_ALL, langToWindowsLocale(lang))
localeChanged=True localeChanged=True
else: else:
locale.setlocale(locale.LC_ALL, lang) locale.setlocale(locale.LC_ALL, lang)
localeChanged=True localeChanged=True
# except: # except:
# pass # pass
if not localeChanged and '_' in lang: if not localeChanged and '_' in lang:
#Python couldn'tsupport the language_country locale, just try language. #Python couldn'tsupport the language_country locale, just try language.
try: try:
locale.setlocale(locale.LC_ALL, lang.split('_')[0]) locale.setlocale(locale.LC_ALL, lang.split('_')[0])
except: except:
pass pass
#Set the windows locale for this thread (NVDA core) to this locale. #Set the windows locale for this thread (NVDA core) to this locale.
if system == "Windows": if system == "Windows":
LCID=localeNameToWindowsLCID(lang) LCID=localeNameToWindowsLCID(lang)
ctypes.windll.kernel32.SetThreadLocale(LCID) ctypes.windll.kernel32.SetThreadLocale(LCID)
except IOError: except IOError:
trans=gettext.translation(application.short_name, fallback=True) trans=gettext.translation(application.short_name, fallback=True)
curLang="en" curLang="en"
if sys.version[0] == "3": if sys.version[0] == "3":
trans.install() trans.install()
else: else:
trans.install(unicode=True) trans.install(unicode=True)
# Install our pgettext function. # Install our pgettext function.
# __builtin__.__dict__["pgettext"] = makePgettext(trans) # __builtin__.__dict__["pgettext"] = makePgettext(trans)
def getLanguage(): def getLanguage():
return curLang return curLang
def normalizeLanguage(lang): def normalizeLanguage(lang):
""" """
Normalizes a language-dialect string in to a standard form we can deal with. Normalizes a language-dialect string in to a standard form we can deal with.
Converts any dash to underline, and makes sure that language is lowercase and dialect is upercase. Converts any dash to underline, and makes sure that language is lowercase and dialect is upercase.
""" """
lang=lang.replace('-','_') lang=lang.replace('-','_')
ld=lang.split('_') ld=lang.split('_')
ld[0]=ld[0].lower() ld[0]=ld[0].lower()
#Filter out meta languages such as x-western #Filter out meta languages such as x-western
if ld[0]=='x': if ld[0]=='x':
return None return None
if len(ld)>=2: if len(ld)>=2:
ld[1]=ld[1].upper() ld[1]=ld[1].upper()
return "_".join(ld) return "_".join(ld)
def langToWindowsLocale(lang): def langToWindowsLocale(lang):
languages = {"en": "eng", languages = {"en": "eng",
"ar": "ara", "ar": "ara",
"ca": "cat", "ca": "cat",
"de": "deu", "de": "deu",
"es": "esp", "es": "esp",
"fi": "fin", "fi": "fin",
"fr": "fre_FRA", "fr": "fre_FRA",
"gl": "glc", "gl": "glc",
"eu": "euq", "eu": "euq",
"hu": "hun", "hu": "hun",
"hr": "hrv", "hr": "hrv",
"it": "ita", "it": "ita",
"ja": "jpn", "ja": "jpn",
"pl": "plk", "pl": "plk",
"pt": "ptb", "pt": "ptb",
"ru": "rus", "ru": "rus",
"tr": "trk", "tr": "trk",
"sr": "eng", "sr": "eng",
} }
return languages[lang] return languages[lang]

View File

@ -37,9 +37,9 @@ error_handler.setLevel(logging.ERROR)
logger.addHandler(error_handler) logger.addHandler(error_handler)
def handle_exception(exc_type, exc_value, exc_traceback): def handle_exception(exc_type, exc_value, exc_traceback):
if issubclass(exc_type, KeyboardInterrupt): if issubclass(exc_type, KeyboardInterrupt):
sys.__excepthook__(exc_type, exc_value, exc_traceback) sys.__excepthook__(exc_type, exc_value, exc_traceback)
return return
logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback)) logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
sys.excepthook = handle_exception sys.excepthook = handle_exception

View File

@ -7,19 +7,19 @@ from win32com.client import GetObject
system = platform.system() system = platform.system()
if system == "Windows": if system == "Windows":
import sys import sys
import os import os
#redirect the original stdout and stderr #redirect the original stdout and stderr
stdout=sys.stdout stdout=sys.stdout
stderr=sys.stderr stderr=sys.stderr
sys.stdout = open(os.path.join(os.getenv("temp"), "stdout.log"), "w") sys.stdout = open(os.path.join(os.getenv("temp"), "stdout.log"), "w")
sys.stderr = open(os.path.join(os.getenv("temp"), "stderr.log"), "w") sys.stderr = open(os.path.join(os.getenv("temp"), "stderr.log"), "w")
import languageHandler import languageHandler
import paths import paths
#check if TWBlue is installed (Windows only) #check if TWBlue is installed (Windows only)
# ToDo: Remove this soon as this is done already when importing the paths module. # ToDo: Remove this soon as this is done already when importing the paths module.
if os.path.exists(os.path.join(paths.app_path(), "Uninstall.exe")): if os.path.exists(os.path.join(paths.app_path(), "Uninstall.exe")):
paths.mode="installed" paths.mode="installed"
import commandline import commandline
import config import config
import output import output
@ -32,114 +32,114 @@ import widgetUtils
import webbrowser import webbrowser
from wxUI import commonMessageDialogs from wxUI import commonMessageDialogs
if system == "Windows": if system == "Windows":
from logger import logger from logger import logger
from update import updater from update import updater
stdout_temp=sys.stdout stdout_temp=sys.stdout
stderr_temp=sys.stderr stderr_temp=sys.stderr
#if it's a binary version #if it's a binary version
if hasattr(sys, 'frozen'): if hasattr(sys, 'frozen'):
sys.stderr = open(os.path.join(paths.logs_path(), "stderr.log"), 'w') sys.stderr = open(os.path.join(paths.logs_path(), "stderr.log"), 'w')
sys.stdout = open(os.path.join(paths.logs_path(), "stdout.log"), 'w') sys.stdout = open(os.path.join(paths.logs_path(), "stdout.log"), 'w')
else: else:
sys.stdout=stdout sys.stdout=stdout
sys.stderr=stderr sys.stderr=stderr
# We are running from source, let's prepare vlc module for that situation # We are running from source, let's prepare vlc module for that situation
if system=="Windows": if system=="Windows":
arch="x86" arch="x86"
if platform.architecture()[0][:2] == "64": if platform.architecture()[0][:2] == "64":
arch="x64" arch="x64"
os.environ['PYTHON_VLC_MODULE_PATH']=os.path.abspath(os.path.join(paths.app_path(), "..", "windows-dependencies", arch)) os.environ['PYTHON_VLC_MODULE_PATH']=os.path.abspath(os.path.join(paths.app_path(), "..", "windows-dependencies", arch))
os.environ['PYTHON_VLC_LIB_PATH']=os.path.abspath(os.path.join(paths.app_path(), "..", "windows-dependencies", arch, "libvlc.dll")) os.environ['PYTHON_VLC_LIB_PATH']=os.path.abspath(os.path.join(paths.app_path(), "..", "windows-dependencies", arch, "libvlc.dll"))
#the final log files have been opened succesfully, let's close the temporary files #the final log files have been opened succesfully, let's close the temporary files
stdout_temp.close() stdout_temp.close()
stderr_temp.close() stderr_temp.close()
#finally, remove the temporary files. TW Blue doesn't need them anymore, and we will get more free space on the harddrive #finally, remove the temporary files. TW Blue doesn't need them anymore, and we will get more free space on the harddrive
os.remove(stdout_temp.name) os.remove(stdout_temp.name)
os.remove(stderr_temp.name) os.remove(stderr_temp.name)
import sound import sound
if system == "Linux": if system == "Linux":
from gi.repository import Gdk, GObject, GLib from gi.repository import Gdk, GObject, GLib
log = logging.getLogger("main") log = logging.getLogger("main")
def setup(): def setup():
log.debug("Starting " + application.name + " %s" % (application.version,)) log.debug("Starting " + application.name + " %s" % (application.version,))
config.setup() config.setup()
proxy_setup() proxy_setup()
log.debug("Using %s %s" % (platform.system(), platform.architecture()[0])) log.debug("Using %s %s" % (platform.system(), platform.architecture()[0]))
log.debug("Application path is %s" % (paths.app_path(),)) log.debug("Application path is %s" % (paths.app_path(),))
log.debug("config path is %s" % (paths.config_path(),)) log.debug("config path is %s" % (paths.config_path(),))
sound.setup() sound.setup()
languageHandler.setLanguage(config.app["app-settings"]["language"]) languageHandler.setLanguage(config.app["app-settings"]["language"])
fixes.setup() fixes.setup()
output.setup() output.setup()
keys.setup() keys.setup()
from controller import settings from controller import settings
from controller import mainController from controller import mainController
from sessionmanager import sessionManager from sessionmanager import sessionManager
app = widgetUtils.mainLoopObject() app = widgetUtils.mainLoopObject()
check_pid() check_pid()
if system == "Windows": if system == "Windows":
if config.app["app-settings"]["donation_dialog_displayed"] == False: if config.app["app-settings"]["donation_dialog_displayed"] == False:
donation() donation()
if config.app['app-settings']['check_for_updates']: if config.app['app-settings']['check_for_updates']:
updater.do_update() updater.do_update()
sm = sessionManager.sessionManagerController() sm = sessionManager.sessionManagerController()
sm.fill_list() sm.fill_list()
if len(sm.sessions) == 0: sm.show() if len(sm.sessions) == 0: sm.show()
else: else:
sm.do_ok() sm.do_ok()
if hasattr(sm.view, "destroy"): if hasattr(sm.view, "destroy"):
sm.view.destroy() sm.view.destroy()
del sm del sm
r = mainController.Controller() r = mainController.Controller()
r.view.show() r.view.show()
r.do_work() r.do_work()
r.check_invisible_at_startup() r.check_invisible_at_startup()
if system == "Windows": if system == "Windows":
call_threaded(r.start) call_threaded(r.start)
elif system == "Linux": elif system == "Linux":
GLib.idle_add(r.start) GLib.idle_add(r.start)
app.run() app.run()
def proxy_setup(): def proxy_setup():
if config.app["proxy"]["server"] != "" and config.app["proxy"]["type"] > 0: if config.app["proxy"]["server"] != "" and config.app["proxy"]["type"] > 0:
log.debug("Loading proxy settings") log.debug("Loading proxy settings")
proxy_url = config.app["proxy"]["server"] + ":" + str(config.app["proxy"]["port"]) proxy_url = config.app["proxy"]["server"] + ":" + str(config.app["proxy"]["port"])
if config.app["proxy"]["user"] != "" and config.app["proxy"]["password"] != "": if config.app["proxy"]["user"] != "" and config.app["proxy"]["password"] != "":
proxy_url = config.app["proxy"]["user"] + ":" + config.app["proxy"]["password"] + "@" + proxy_url proxy_url = config.app["proxy"]["user"] + ":" + config.app["proxy"]["password"] + "@" + proxy_url
elif config.app["proxy"]["user"] != "" and config.proxyTypes[config.app["proxy"]["type"]] in ["socks4", "socks4a"]: elif config.app["proxy"]["user"] != "" and config.proxyTypes[config.app["proxy"]["type"]] in ["socks4", "socks4a"]:
proxy_url = config.app["proxy"]["user"] + "@" + proxy_url proxy_url = config.app["proxy"]["user"] + "@" + proxy_url
proxy_url = config.proxyTypes[config.app["proxy"]["type"]] + "://" + proxy_url proxy_url = config.proxyTypes[config.app["proxy"]["type"]] + "://" + proxy_url
os.environ["HTTP_PROXY"] = proxy_url os.environ["HTTP_PROXY"] = proxy_url
os.environ["HTTPS_PROXY"] = proxy_url os.environ["HTTPS_PROXY"] = proxy_url
def donation(): def donation():
dlg = commonMessageDialogs.donation() dlg = commonMessageDialogs.donation()
if dlg == widgetUtils.YES: if dlg == widgetUtils.YES:
webbrowser.open_new_tab(_("https://twblue.es/donate")) webbrowser.open_new_tab(_("https://twblue.es/donate"))
config.app["app-settings"]["donation_dialog_displayed"] = True config.app["app-settings"]["donation_dialog_displayed"] = True
def is_running(pid): def is_running(pid):
"Check if the process with ID pid is running. Adapted from https://stackoverflow.com/a/568589" "Check if the process with ID pid is running. Adapted from https://stackoverflow.com/a/568589"
WMI = GetObject('winmgmts:') WMI = GetObject('winmgmts:')
processes = WMI.InstancesOf('Win32_Process') processes = WMI.InstancesOf('Win32_Process')
return [process.Properties_('ProcessID').Value for process in processes if process.Properties_('ProcessID').Value == pid] return [process.Properties_('ProcessID').Value for process in processes if process.Properties_('ProcessID').Value == pid]
def check_pid(): def check_pid():
"Insures that only one copy of the application is running at a time." "Insures that only one copy of the application is running at a time."
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):
with open(pidpath) as fin: with open(pidpath) as fin:
pid = int(fin.read()) pid = int(fin.read())
if is_running(pid): if is_running(pid):
# Display warning dialog # Display warning dialog
commonMessageDialogs.common_error(_(u"{0} is already running. Close the other instance before starting this one. If you're sure that {0} isn't running, try deleting the file at {1}. If you're unsure of how to do this, contact the {0} developers.").format(application.name, pidpath)) commonMessageDialogs.common_error(_(u"{0} is already running. Close the other instance before starting this one. If you're sure that {0} isn't running, try deleting the file at {1}. If you're unsure of how to do this, contact the {0} developers.").format(application.name, pidpath))
sys.exit(1) sys.exit(1)
else: else:
commonMessageDialogs.dead_pid() commonMessageDialogs.dead_pid()
# Write the new PID # Write the new PID
with open(pidpath,"w") as cam: with open(pidpath,"w") as cam:
cam.write(str(os.getpid())) cam.write(str(os.getpid()))
setup() setup()

View File

@ -1,3 +1,3 @@
from __future__ import absolute_import from __future__ import absolute_import
from __future__ import unicode_literals from __future__ import unicode_literals
from . import widgets from . import widgets

View File

@ -8,85 +8,85 @@ import logging
log = logging.getLogger("multiplatform_widgets.widgets") log = logging.getLogger("multiplatform_widgets.widgets")
class list(object): class list(object):
def __init__(self, parent, *columns, **listArguments): def __init__(self, parent, *columns, **listArguments):
self.system = platform.system() self.system = platform.system()
self.columns = columns self.columns = columns
self.listArguments = listArguments self.listArguments = listArguments
log.debug("Creating list: Columns: %s, arguments: %s" % (self.columns, self.listArguments)) log.debug("Creating list: Columns: %s, arguments: %s" % (self.columns, self.listArguments))
self.create_list(parent) self.create_list(parent)
# self.set_size() # self.set_size()
def set_windows_size(self, column, characters_max): def set_windows_size(self, column, characters_max):
# it = wx.ListItem() # it = wx.ListItem()
# dc = wx.WindowDC(self.list) # dc = wx.WindowDC(self.list)
# dc.SetFont(it.GetFont()) # dc.SetFont(it.GetFont())
# (x, y) = dc.GetTextExtent("r"*characters_max) # (x, y) = dc.GetTextExtent("r"*characters_max)
self.list.SetColumnWidth(column, characters_max*2) self.list.SetColumnWidth(column, characters_max*2)
def set_size(self): def set_size(self):
self.list.SetSize((self.list.GetBestSize()[0], 728)) self.list.SetSize((self.list.GetBestSize()[0], 728))
# self.list.SetSize((1439, 1000)) # self.list.SetSize((1439, 1000))
def create_list(self, parent): def create_list(self, parent):
if self.system == "Windows": if self.system == "Windows":
self.list = wx.ListCtrl(parent, -1, **self.listArguments) self.list = wx.ListCtrl(parent, -1, **self.listArguments)
for i in range(0, len(self.columns)): for i in range(0, len(self.columns)):
self.list.InsertColumn(i, u"%s" % (self.columns[i])) self.list.InsertColumn(i, u"%s" % (self.columns[i]))
else: else:
self.list = wx.ListBox(parent, -1, choices=[]) self.list = wx.ListBox(parent, -1, choices=[])
def insert_item(self, reversed, *item): def insert_item(self, reversed, *item):
""" Inserts an item on the list, depending on the OS.""" """ Inserts an item on the list, depending on the OS."""
if self.system == "Windows": if self.system == "Windows":
if reversed == False: items = self.list.GetItemCount() if reversed == False: items = self.list.GetItemCount()
else: items = 0 else: items = 0
self.list.InsertItem(items, item[0]) self.list.InsertItem(items, item[0])
for i in range(1, len(self.columns)): for i in range(1, len(self.columns)):
self.list.SetItem(items, i, item[i]) self.list.SetItem(items, i, item[i])
else: else:
self.list.Append(" ".join(item)) self.list.Append(" ".join(item))
def remove_item(self, pos): def remove_item(self, pos):
""" Deletes an item from the list.""" """ Deletes an item from the list."""
if self.system == "Windows": if self.system == "Windows":
if pos > 0: self.list.Focus(pos-1) if pos > 0: self.list.Focus(pos-1)
self.list.DeleteItem(pos) self.list.DeleteItem(pos)
else: else:
if pos > 0: self.list.SetSelection(pos-1) if pos > 0: self.list.SetSelection(pos-1)
self.list.Delete(pos) self.list.Delete(pos)
def clear(self): def clear(self):
if self.system == "Windows": if self.system == "Windows":
self.list.DeleteAllItems() self.list.DeleteAllItems()
else: else:
self.list.Clear() self.list.Clear()
def get_selected(self): def get_selected(self):
if self.system == "Windows": if self.system == "Windows":
return self.list.GetFocusedItem() return self.list.GetFocusedItem()
else: else:
return self.list.GetSelection() return self.list.GetSelection()
def select_item(self, pos): def select_item(self, pos):
if self.system == "Windows": if self.system == "Windows":
self.list.Focus(pos) self.list.Focus(pos)
else: else:
self.list.SetSelection(pos) self.list.SetSelection(pos)
def get_count(self): def get_count(self):
if self.system == "Windows": if self.system == "Windows":
selected = self.list.GetItemCount() selected = self.list.GetItemCount()
else: else:
selected = self.list.GetCount() selected = self.list.GetCount()
if selected == -1: if selected == -1:
return 0 return 0
else: else:
return selected return selected
def get_text_column(self, indexId, column): def get_text_column(self, indexId, column):
item = self.list.GetItem(indexId, column) item = self.list.GetItem(indexId, column)
return item.GetText() return item.GetText()
def set_text_column(self, indexId, column, text): def set_text_column(self, indexId, column, text):
item = self.list.SetStringItem(indexId, column, text) item = self.list.SetStringItem(indexId, column, text)
return item return item

View File

@ -10,35 +10,35 @@ from platform_utils import paths
RUN_REGKEY = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Run" RUN_REGKEY = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
def is_installed(app_subkey): def is_installed(app_subkey):
"""Checks if the currently running copy is installed or portable variant. Requires the name of the application subkey found under the uninstall section in Windows registry.""" """Checks if the currently running copy is installed or portable variant. Requires the name of the application subkey found under the uninstall section in Windows registry."""
try: try:
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s" % app_subkey) key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s" % app_subkey)
inst_dir = winreg.QueryValueEx(key,"InstallLocation")[0] inst_dir = winreg.QueryValueEx(key,"InstallLocation")[0]
except WindowsError: except WindowsError:
return False return False
winreg.CloseKey(key) winreg.CloseKey(key)
try: try:
return os.stat(inst_dir) == os.stat(paths.app_path()) return os.stat(inst_dir) == os.stat(paths.app_path())
except WindowsError: except WindowsError:
return False return False
def getAutoStart(app_name): def getAutoStart(app_name):
"""Queries if the automatic startup should be set for the application or not, depending on it's current state.""" """Queries if the automatic startup should be set for the application or not, depending on it's current state."""
try: try:
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, RUN_REGKEY) key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, RUN_REGKEY)
val = winreg.QueryValueEx(key, str(app_name))[0] val = winreg.QueryValueEx(key, str(app_name))[0]
return os.stat(val) == os.stat(sys.argv[0]) return os.stat(val) == os.stat(sys.argv[0])
except (WindowsError, OSError): except (WindowsError, OSError):
return False return False
def setAutoStart(app_name, enable=True): def setAutoStart(app_name, enable=True):
"""Configures automatic startup for the application, if the enable argument is set to True. If set to False, deletes the application AutoStart value.""" """Configures automatic startup for the application, if the enable argument is set to True. If set to False, deletes the application AutoStart value."""
if getAutoStart(app_name) == enable: if getAutoStart(app_name) == enable:
return return
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, RUN_REGKEY, 0, winreg.KEY_WRITE) key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, RUN_REGKEY, 0, winreg.KEY_WRITE)
if enable: if enable:
winreg.SetValueEx(key, str(app_name), None, winreg.REG_SZ, paths.get_executable()) winreg.SetValueEx(key, str(app_name), None, winreg.REG_SZ, paths.get_executable())
else: else:
winreg.DeleteValue(key, str(app_name)) winreg.DeleteValue(key, str(app_name))

View File

@ -5,14 +5,14 @@ import logging
log = logging.getLogger("mysc.localization") log = logging.getLogger("mysc.localization")
def get(rootFolder): def get(rootFolder):
log.debug("Getting documentation folder. RootFolder: %s" % (rootFolder,)) log.debug("Getting documentation folder. RootFolder: %s" % (rootFolder,))
defaultLocale = languageHandler.curLang defaultLocale = languageHandler.curLang
if len(defaultLocale) > 2: if len(defaultLocale) > 2:
defaultLocale = defaultLocale[:2] defaultLocale = defaultLocale[:2]
log.debug("Locale: %s" % (defaultLocale,)) log.debug("Locale: %s" % (defaultLocale,))
if os.path.exists(rootFolder+"/"+defaultLocale): if os.path.exists(rootFolder+"/"+defaultLocale):
return defaultLocale return defaultLocale
else: else:
log.debug("The folder does not exist, using the English folder...") log.debug("The folder does not exist, using the English folder...")
return "en" return "en"

View File

@ -4,34 +4,34 @@ import logging
log = logging.getLogger("mysc.repeating_timer") log = logging.getLogger("mysc.repeating_timer")
class RepeatingTimer(threading.Thread): class RepeatingTimer(threading.Thread):
"""Call a function after a specified number of seconds, it will then repeat again after the specified number of seconds """Call a function after a specified number of seconds, it will then repeat again after the specified number of seconds
Note: If the function provided takes time to execute, this time is NOT taken from the next wait period Note: If the function provided takes time to execute, this time is NOT taken from the next wait period
t = RepeatingTimer(30.0, f, args=[], kwargs={}) t = RepeatingTimer(30.0, f, args=[], kwargs={})
t.start() t.start()
t.cancel() # stop the timer's actions t.cancel() # stop the timer's actions
""" """
def __init__(self, interval, function, daemon=True, *args, **kwargs): def __init__(self, interval, function, daemon=True, *args, **kwargs):
threading.Thread.__init__(self) threading.Thread.__init__(self)
self.daemon = daemon self.daemon = daemon
self.interval = float(interval) self.interval = float(interval)
self.function = function self.function = function
self.args = args self.args = args
self.kwargs = kwargs self.kwargs = kwargs
self.finished = threading.Event() self.finished = threading.Event()
def cancel(self): def cancel(self):
"""Stop the timer if it hasn't finished yet""" """Stop the timer if it hasn't finished yet"""
log.debug("Stopping repeater for %s" % (self.function,)) log.debug("Stopping repeater for %s" % (self.function,))
self.finished.set() self.finished.set()
stop = cancel stop = cancel
def run(self): def run(self):
while not self.finished.is_set(): while not self.finished.is_set():
self.finished.wait(self.interval) self.finished.wait(self.interval)
if not self.finished.is_set(): #In case someone has canceled while waiting if not self.finished.is_set(): #In case someone has canceled while waiting
try: try:
self.function(*self.args, **self.kwargs) self.function(*self.args, **self.kwargs)
except: except:
log.exception("Execution failed. Function: %r args: %r and kwargs: %r" % (self.function, self.args, self.kwargs)) log.exception("Execution failed. Function: %r args: %r and kwargs: %r" % (self.function, self.args, self.kwargs))

View File

@ -4,13 +4,13 @@ import sys, os
import application import application
def restart_program(): def restart_program():
""" Function that restarts the application if is executed.""" """ Function that restarts the application if is executed."""
args = sys.argv[:] args = sys.argv[:]
if not hasattr(sys, "frozen"): if not hasattr(sys, "frozen"):
args.insert(0, sys.executable) args.insert(0, sys.executable)
if sys.platform == 'win32': if sys.platform == 'win32':
args = ['"%s"' % arg for arg in args] args = ['"%s"' % arg for arg in args]
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)
os.execv(sys.executable, args) os.execv(sys.executable, args)

View File

@ -6,14 +6,14 @@ import wx
from pubsub import pub from pubsub import pub
def call_threaded(func, *args, **kwargs): def call_threaded(func, *args, **kwargs):
#Call the given function in a daemonized thread and return the thread. #Call the given function in a daemonized thread and return the thread.
def new_func(*a, **k): def new_func(*a, **k):
try: try:
func(*a, **k) func(*a, **k)
except: except:
log.exception("Thread %d with function %r, args of %r, and kwargs of %r failed to run." % (threading.current_thread().ident, func, a, k)) log.exception("Thread %d with function %r, args of %r, and kwargs of %r failed to run." % (threading.current_thread().ident, func, a, k))
# pass # pass
thread = threading.Thread(target=new_func, args=args, kwargs=kwargs) thread = threading.Thread(target=new_func, args=args, kwargs=kwargs)
thread.daemon = True thread.daemon = True
thread.start() thread.start()
return thread return thread

View File

@ -8,16 +8,16 @@ import platform
notify = None notify = None
def setup(): def setup():
global notify global notify
if platform.system() == "Windows": if platform.system() == "Windows":
from . import windows from . import windows
notify = windows.notification() notify = windows.notification()
elif platform.system() == "Linux": elif platform.system() == "Linux":
from . import linux from . import linux
notify = linux.notification() notify = linux.notification()
def send(title, text): def send(title, text):
global notify global notify
if not notify or notify is None: if not notify or notify is None:
setup() setup()
notify.notify(title, text) notify.notify(title, text)

View File

@ -5,23 +5,23 @@ import dbus
import application import application
class notifications(object): class notifications(object):
"""Supports notifications on Linux. """Supports notifications on Linux.
""" """
def __init__(self): def __init__(self):
super(notifications, self).__init__() super(notifications, self).__init__()
self.item = "org.freedesktop.Notifications" self.item = "org.freedesktop.Notifications"
self.path = "/org/freedesktop/Notifications" self.path = "/org/freedesktop/Notifications"
self.interface = "org.freedesktop.Notifications" self.interface = "org.freedesktop.Notifications"
self.app_name = application.name self.app_name = application.name
self.id_num_to_replace = 0 self.id_num_to_replace = 0
self.icon = "/usr/share/icons/Tango/32x32/status/sunny.png" self.icon = "/usr/share/icons/Tango/32x32/status/sunny.png"
def notify(self, title="", text=""): def notify(self, title="", text=""):
actions_list = '' actions_list = ''
hint = '' hint = ''
time = 5000 # Use seconds x 1000 time = 5000 # Use seconds x 1000
bus = dbus.SessionBus() bus = dbus.SessionBus()
notif = bus.get_object(self.item, self.path) notif = bus.get_object(self.item, self.path)
notify = dbus.Interface(notif, self.interface) notify = dbus.Interface(notif, self.interface)
notify.Notify(self.app_name, self.id_num_to_replace, self.icon, title, text, actions_list, hint, time) notify.Notify(self.app_name, self.id_num_to_replace, self.icon, title, text, actions_list, hint, time)

View File

@ -5,5 +5,5 @@ import wx
class notification(object): class notification(object):
def notify(self, title, text): def notify(self, title, text):
wx.NotificationMessage(title, text).Show() wx.NotificationMessage(title, text).Show()

View File

@ -8,28 +8,28 @@ import sys
speaker = None speaker = None
def speak(text, interrupt=0, speech=True, braille=True): def speak(text, interrupt=0, speech=True, braille=True):
global speaker global speaker
if not speaker: if not speaker:
setup() setup()
if speech: if speech:
speaker.speak(text, interrupt) speaker.speak(text, interrupt)
if braille: if braille:
speaker.braille(text) speaker.braille(text)
def setup (): def setup ():
global speaker global speaker
logging.debug("Initializing output subsystem.") logging.debug("Initializing output subsystem.")
try: try:
# speaker = speech.Speaker(speech.outputs.Sapi5()) # speaker = speech.Speaker(speech.outputs.Sapi5())
# else: # else:
speaker = outputs.auto.Auto() speaker = outputs.auto.Auto()
except: except:
return logging.exception("Output: Error during initialization.") return logging.exception("Output: Error during initialization.")
def copy(text): def copy(text):
import win32clipboard import win32clipboard
#Copies text to the clipboard. #Copies text to the clipboard.
win32clipboard.OpenClipboard() win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard() win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(text, win32clipboard.CF_UNICODETEXT) win32clipboard.SetClipboardText(text, win32clipboard.CF_UNICODETEXT)
win32clipboard.CloseClipboard() win32clipboard.CloseClipboard()

View File

@ -10,58 +10,58 @@ directory = None
fsencoding = sys.getfilesystemencoding() fsencoding = sys.getfilesystemencoding()
if len(glob.glob("Uninstall.exe")) > 0: # installed copy if len(glob.glob("Uninstall.exe")) > 0: # installed copy
mode= "installed" mode= "installed"
def app_path(): def app_path():
return paths_.app_path() return paths_.app_path()
def config_path(): def config_path():
global mode, directory global mode, directory
if mode == "portable": if mode == "portable":
if directory != None: path = os.path.join(directory, "config") if directory != None: path = os.path.join(directory, "config")
elif directory == None: path = os.path.join(app_path(), "config") elif directory == None: path = os.path.join(app_path(), "config")
elif mode == "installed": elif mode == "installed":
path = os.path.join(data_path(), "config") path = os.path.join(data_path(), "config")
if not os.path.exists(path): if not os.path.exists(path):
# log.debug("%s path does not exist, creating..." % (path,)) # log.debug("%s path does not exist, creating..." % (path,))
os.mkdir(path) os.mkdir(path)
return path return path
def logs_path(): def logs_path():
global mode, directory global mode, directory
if mode == "portable": if mode == "portable":
if directory != None: path = os.path.join(directory, "logs") if directory != None: path = os.path.join(directory, "logs")
elif directory == None: path = os.path.join(app_path(), "logs") elif directory == None: path = os.path.join(app_path(), "logs")
elif mode == "installed": elif mode == "installed":
path = os.path.join(data_path(), "logs") path = os.path.join(data_path(), "logs")
if not os.path.exists(path): if not os.path.exists(path):
# log.debug("%s path does not exist, creating..." % (path,)) # log.debug("%s path does not exist, creating..." % (path,))
os.mkdir(path) os.mkdir(path)
return path return path
def data_path(app_name='socializer'): def data_path(app_name='socializer'):
if platform.system() == "Windows": if platform.system() == "Windows":
data_path = os.path.join(os.getenv("AppData"), app_name) data_path = os.path.join(os.getenv("AppData"), app_name)
else: else:
data_path = os.path.join(os.environ['HOME'], ".%s" % app_name) data_path = os.path.join(os.environ['HOME'], ".%s" % app_name)
if not os.path.exists(data_path): if not os.path.exists(data_path):
os.mkdir(data_path) os.mkdir(data_path)
return data_path return data_path
def locale_path(): def locale_path():
return os.path.join(app_path(), "locales") return os.path.join(app_path(), "locales")
def sound_path(): def sound_path():
return os.path.join(app_path(), "sounds") return os.path.join(app_path(), "sounds")
def com_path(): def com_path():
global mode, directory global mode, directory
if mode == "portable": if mode == "portable":
if directory != None: path = os.path.join(directory, "com_cache") if directory != None: path = os.path.join(directory, "com_cache")
elif directory == None: path = os.path.join(app_path(), "com_cache") elif directory == None: path = os.path.join(app_path(), "com_cache")
elif mode == "installed": elif mode == "installed":
path = os.path.join(data_path(), "com_cache") path = os.path.join(data_path(), "com_cache")
if not os.path.exists(path): if not os.path.exists(path):
# log.debug("%s path does not exist, creating..." % (path,)) # log.debug("%s path does not exist, creating..." % (path,))
os.mkdir(path) os.mkdir(path)
return path return path

View File

@ -7,4 +7,4 @@ Contents of this package:
manager: Handles multiple sessions, setting the configuration files and check if the session is valid. Part of the model. manager: Handles multiple sessions, setting the configuration files and check if the session is valid. Part of the model.
session: Creates a twitter session for an user. The other part of the model. session: Creates a twitter session for an user. The other part of the model.
""" """
from __future__ import unicode_literals from __future__ import unicode_literals

View File

@ -3,55 +3,55 @@ from gi.repository import Gtk
import widgetUtils import widgetUtils
class sessionManagerWindow(widgetUtils.baseDialog): class sessionManagerWindow(widgetUtils.baseDialog):
def __init__(self): def __init__(self):
super(sessionManagerWindow, self).__init__("Session Manager", None, 0, (Gtk.STOCK_OK, widgetUtils.OK, Gtk.STOCK_CANCEL, widgetUtils.CANCEL)) super(sessionManagerWindow, self).__init__("Session Manager", None, 0, (Gtk.STOCK_OK, widgetUtils.OK, Gtk.STOCK_CANCEL, widgetUtils.CANCEL))
self.list = widgetUtils.list("Session") self.list = widgetUtils.list("Session")
self.box.add(self.list.list) self.box.add(self.list.list)
btnBox = Gtk.Box(spacing=6) btnBox = Gtk.Box(spacing=6)
self.new = Gtk.Button("New account") self.new = Gtk.Button("New account")
self.remove = Gtk.Button("Remove account") self.remove = Gtk.Button("Remove account")
self.configuration = Gtk.Button("Configuration") self.configuration = Gtk.Button("Configuration")
btnBox.add(self.new) btnBox.add(self.new)
btnBox.add(self.remove) btnBox.add(self.remove)
btnBox.add(self.configuration) btnBox.add(self.configuration)
self.box.add(btnBox) self.box.add(btnBox)
self.show_all() self.show_all()
def fill_list(self, sessionsList): def fill_list(self, sessionsList):
for i in sessionsList: for i in sessionsList:
self.list.insert_item(False, i) self.list.insert_item(False, i)
if self.list.get_count() > 0: if self.list.get_count() > 0:
self.list.select_item(0) self.list.select_item(0)
def new_account_dialog(self): def new_account_dialog(self):
dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, "Authorization") dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, "Authorization")
dialog.format_secondary_text("The request to authorize your Twitter account will be opened in your browser. You only need to do this once. Would you like to continue?") dialog.format_secondary_text("The request to authorize your Twitter account will be opened in your browser. You only need to do this once. Would you like to continue?")
answer = dialog.run() answer = dialog.run()
dialog.destroy() dialog.destroy()
return answer return answer
def add_new_session_to_list(self): def add_new_session_to_list(self):
total = self.list.get_count() total = self.list.get_count()
name = "Authorized account %d" % (total+1) name = "Authorized account %d" % (total+1)
self.list.insert_item(name) self.list.insert_item(name)
if self.list.get_count() == 1: if self.list.get_count() == 1:
self.list.select_item(0) self.list.select_item(0)
def show_unauthorised_error(self): def show_unauthorised_error(self):
dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.CANCEL, "Invalid user token") dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.CANCEL, "Invalid user token")
dialog.format_secondary_text("Your access token is invalid or the authorization has failed. Please try again.") dialog.format_secondary_text("Your access token is invalid or the authorization has failed. Please try again.")
answer = dialog.run() answer = dialog.run()
return answer return answer
def remove_account_dialog(self): def remove_account_dialog(self):
dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, "Remove account") dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, "Remove account")
dialog.format_secondary_text("Do you really want delete this account?") dialog.format_secondary_text("Do you really want delete this account?")
answer = dialog.run() answer = dialog.run()
return answer return answer
def get_selected(self): def get_selected(self):
return self.list.get_selected() return self.list.get_selected()
def remove_session(self, sessionID): def remove_session(self, sessionID):
self.list.remove_item(sessionID) self.list.remove_item(sessionID)

View File

@ -11,41 +11,41 @@ from sessions import session_exceptions
manager = None manager = None
def setup(): def setup():
global manager global manager
if not manager: if not manager:
manager = sessionManager() manager = sessionManager()
class sessionManager(object): class sessionManager(object):
# def __init__(self): # def __init__(self):
# FILE = "sessions.conf" # FILE = "sessions.conf"
# SPEC = "app-configuration.defaults" # SPEC = "app-configuration.defaults"
# try: # try:
# self.main = Configuration(paths.config_path(FILE), paths.app_path(SPEC)) # self.main = Configuration(paths.config_path(FILE), paths.app_path(SPEC))
# except ConfigurationResetException: # except ConfigurationResetException:
# pass # pass
def get_current_session(self): def get_current_session(self):
if self.is_valid(config.app["sessions"]["current_session"]): if self.is_valid(config.app["sessions"]["current_session"]):
return config.app["sessions"]["current_session"] return config.app["sessions"]["current_session"]
else: else:
return False return False
def add_session(self, id): def add_session(self, id):
log.debug("Adding a new session: %s" % (id,)) log.debug("Adding a new session: %s" % (id,))
path = os.path.join(paths.config_path(), id) path = os.path.join(paths.config_path(), id)
if not os.path.exists(path): if not os.path.exists(path):
log.debug("Creating %s path" % (os.path.join(paths.config_path(), path),)) log.debug("Creating %s path" % (os.path.join(paths.config_path(), path),))
os.mkdir(path) os.mkdir(path)
config.app["sessions"]["sessions"].append(id) config.app["sessions"]["sessions"].append(id)
def set_current_session(self, sessionID): def set_current_session(self, sessionID):
config.app["sessions"]["current_session"] = sessionID config.app["sessions"]["current_session"] = sessionID
config.app.write() config.app.write()
def is_valid(self, id): def is_valid(self, id):
if not os.path.exists(os.path.join(paths.config_path(), id)): if not os.path.exists(os.path.join(paths.config_path(), id)):
raise session_exceptions.NonExistentSessionError("That session does not exist.") raise session_exceptions.NonExistentSessionError("That session does not exist.")
config.app["sessions"]["current_session"] = "" config.app["sessions"]["current_session"] = ""
return False return False
else: else:
return True return True

View File

@ -4,10 +4,10 @@ import widgetUtils
import platform import platform
import output import output
if platform.system() == "Windows": if platform.system() == "Windows":
from . import wxUI as view from . import wxUI as view
from controller import settings from controller import settings
elif platform.system() == "Linux": elif platform.system() == "Linux":
from . import gtkUI as view from . import gtkUI as view
import paths import paths
import time import time
import os import os
@ -21,106 +21,106 @@ from tweepy.error import TweepError
log = logging.getLogger("sessionmanager.sessionManager") log = logging.getLogger("sessionmanager.sessionManager")
class sessionManagerController(object): class sessionManagerController(object):
def __init__(self, started=False): def __init__(self, started=False):
super(sessionManagerController, self).__init__() super(sessionManagerController, self).__init__()
log.debug("Setting up the session manager.") log.debug("Setting up the session manager.")
self.started = started self.started = started
manager.setup() manager.setup()
self.view = view.sessionManagerWindow() self.view = view.sessionManagerWindow()
widgetUtils.connect_event(self.view.new, widgetUtils.BUTTON_PRESSED, self.manage_new_account) widgetUtils.connect_event(self.view.new, widgetUtils.BUTTON_PRESSED, self.manage_new_account)
widgetUtils.connect_event(self.view.remove, widgetUtils.BUTTON_PRESSED, self.remove) widgetUtils.connect_event(self.view.remove, widgetUtils.BUTTON_PRESSED, self.remove)
if self.started == False: if self.started == False:
widgetUtils.connect_event(self.view.configuration, widgetUtils.BUTTON_PRESSED, self.configuration) widgetUtils.connect_event(self.view.configuration, widgetUtils.BUTTON_PRESSED, self.configuration)
else: else:
self.view.hide_configuration() self.view.hide_configuration()
self.new_sessions = {} self.new_sessions = {}
self.removed_sessions = [] self.removed_sessions = []
def fill_list(self): def fill_list(self):
sessionsList = [] sessionsList = []
reserved_dirs = ["dicts"] reserved_dirs = ["dicts"]
log.debug("Filling the sessions list.") log.debug("Filling the sessions list.")
self.sessions = [] self.sessions = []
for i in os.listdir(paths.config_path()): for i in os.listdir(paths.config_path()):
if os.path.isdir(os.path.join(paths.config_path(), i)) and i not in reserved_dirs: if os.path.isdir(os.path.join(paths.config_path(), i)) and i not in reserved_dirs:
log.debug("Adding session %s" % (i,)) log.debug("Adding session %s" % (i,))
strconfig = "%s/session.conf" % (os.path.join(paths.config_path(), i)) strconfig = "%s/session.conf" % (os.path.join(paths.config_path(), i))
config_test = config_utils.load_config(strconfig) config_test = config_utils.load_config(strconfig)
if len(config_test) == 0: if len(config_test) == 0:
try: try:
log.debug("Deleting session %s" % (i,)) log.debug("Deleting session %s" % (i,))
shutil.rmtree(os.path.join(paths.config_path(), i)) shutil.rmtree(os.path.join(paths.config_path(), i))
continue continue
except: except:
output.speak("An exception was raised while attempting to clean malformed session data. See the error log for details. If this message persists, contact the developers.",True) output.speak("An exception was raised while attempting to clean malformed session data. See the error log for details. If this message persists, contact the developers.",True)
os.exception("Exception thrown while removing malformed session") os.exception("Exception thrown while removing malformed session")
continue continue
name = config_test["twitter"]["user_name"] name = config_test["twitter"]["user_name"]
if config_test["twitter"]["user_key"] != "" and config_test["twitter"]["user_secret"] != "": if config_test["twitter"]["user_key"] != "" and config_test["twitter"]["user_secret"] != "":
sessionsList.append(name) sessionsList.append(name)
self.sessions.append(i) self.sessions.append(i)
else: else:
try: try:
log.debug("Deleting session %s" % (i,)) log.debug("Deleting session %s" % (i,))
shutil.rmtree(os.path.join(paths.config_path(), i)) shutil.rmtree(os.path.join(paths.config_path(), i))
except: except:
output.speak("An exception was raised while attempting to clean malformed session data. See the error log for details. If this message persists, contact the developers.",True) output.speak("An exception was raised while attempting to clean malformed session data. See the error log for details. If this message persists, contact the developers.",True)
os.exception("Exception thrown while removing malformed session") os.exception("Exception thrown while removing malformed session")
self.view.fill_list(sessionsList) self.view.fill_list(sessionsList)
def show(self): def show(self):
if self.view.get_response() == widgetUtils.OK: if self.view.get_response() == widgetUtils.OK:
self.do_ok() self.do_ok()
# else: # else:
self.view.destroy() self.view.destroy()
def do_ok(self): def do_ok(self):
log.debug("Starting sessions...") log.debug("Starting sessions...")
for i in self.sessions: for i in self.sessions:
if (i in sessions.sessions) == True: continue if (i in sessions.sessions) == True: continue
s = session.Session(i) s = session.Session(i)
s.get_configuration() s.get_configuration()
if i not in config.app["sessions"]["ignored_sessions"]: if i not in config.app["sessions"]["ignored_sessions"]:
try: try:
s.login() s.login()
except TweepError: except TweepError:
self.show_auth_error(s.settings["twitter"]["user_name"]) self.show_auth_error(s.settings["twitter"]["user_name"])
continue continue
sessions.sessions[i] = s sessions.sessions[i] = s
self.new_sessions[i] = s self.new_sessions[i] = s
# self.view.destroy() # self.view.destroy()
def show_auth_error(self, user_name): def show_auth_error(self, user_name):
error = view.auth_error(user_name) error = view.auth_error(user_name)
def manage_new_account(self, *args, **kwargs): def manage_new_account(self, *args, **kwargs):
if self.view.new_account_dialog() == widgetUtils.YES: if self.view.new_account_dialog() == widgetUtils.YES:
location = (str(time.time())[-6:]) location = (str(time.time())[-6:])
log.debug("Creating session in the %s path" % (location,)) log.debug("Creating session in the %s path" % (location,))
s = session.Session(location) s = session.Session(location)
manager.manager.add_session(location) manager.manager.add_session(location)
s.get_configuration() s.get_configuration()
# try: # try:
s.authorise() s.authorise()
self.sessions.append(location) self.sessions.append(location)
self.view.add_new_session_to_list() self.view.add_new_session_to_list()
s.settings.write() s.settings.write()
# except: # except:
# log.exception("Error authorising the session") # log.exception("Error authorising the session")
# self.view.show_unauthorised_error() # self.view.show_unauthorised_error()
# return # return
def remove(self, *args, **kwargs): def remove(self, *args, **kwargs):
if self.view.remove_account_dialog() == widgetUtils.YES: if self.view.remove_account_dialog() == widgetUtils.YES:
selected_account = self.sessions[self.view.get_selected()] selected_account = self.sessions[self.view.get_selected()]
self.view.remove_session(self.view.get_selected()) self.view.remove_session(self.view.get_selected())
self.removed_sessions.append(selected_account) self.removed_sessions.append(selected_account)
self.sessions.remove(selected_account) self.sessions.remove(selected_account)
shutil.rmtree(path=os.path.join(paths.config_path(), selected_account), ignore_errors=True) shutil.rmtree(path=os.path.join(paths.config_path(), selected_account), ignore_errors=True)
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()
if d.response == widgetUtils.OK: if d.response == widgetUtils.OK:
d.save_configuration() d.save_configuration()

View File

@ -5,77 +5,77 @@ from multiplatform_widgets import widgets
import application import application
class sessionManagerWindow(wx.Dialog): class sessionManagerWindow(wx.Dialog):
def __init__(self): def __init__(self):
super(sessionManagerWindow, self).__init__(parent=None, title=_(u"Session manager"), size=wx.DefaultSize) super(sessionManagerWindow, self).__init__(parent=None, title=_(u"Session manager"), size=wx.DefaultSize)
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
label = wx.StaticText(panel, -1, _(u"Accounts list"), size=wx.DefaultSize) label = wx.StaticText(panel, -1, _(u"Accounts list"), size=wx.DefaultSize)
listSizer = wx.BoxSizer(wx.HORIZONTAL) listSizer = wx.BoxSizer(wx.HORIZONTAL)
self.list = widgets.list(panel, _(u"Account"), style=wx.LC_SINGLE_SEL|wx.LC_REPORT) self.list = widgets.list(panel, _(u"Account"), style=wx.LC_SINGLE_SEL|wx.LC_REPORT)
listSizer.Add(label, 0, wx.ALL, 5) listSizer.Add(label, 0, wx.ALL, 5)
listSizer.Add(self.list.list, 0, wx.ALL, 5) listSizer.Add(self.list.list, 0, wx.ALL, 5)
sizer.Add(listSizer, 0, wx.ALL, 5) sizer.Add(listSizer, 0, wx.ALL, 5)
self.new = wx.Button(panel, -1, _(u"New account"), size=wx.DefaultSize) self.new = wx.Button(panel, -1, _(u"New account"), size=wx.DefaultSize)
self.remove = wx.Button(panel, -1, _(u"Remove account")) self.remove = wx.Button(panel, -1, _(u"Remove account"))
self.configuration = wx.Button(panel, -1, _(u"Global Settings")) self.configuration = wx.Button(panel, -1, _(u"Global Settings"))
ok = wx.Button(panel, wx.ID_OK, size=wx.DefaultSize) ok = wx.Button(panel, wx.ID_OK, size=wx.DefaultSize)
ok.SetDefault() ok.SetDefault()
cancel = wx.Button(panel, wx.ID_CANCEL, size=wx.DefaultSize) cancel = wx.Button(panel, wx.ID_CANCEL, size=wx.DefaultSize)
buttons = wx.BoxSizer(wx.HORIZONTAL) buttons = wx.BoxSizer(wx.HORIZONTAL)
buttons.Add(self.new, 0, wx.ALL, 5) buttons.Add(self.new, 0, wx.ALL, 5)
buttons.Add(self.configuration, 0, wx.ALL, 5) buttons.Add(self.configuration, 0, wx.ALL, 5)
buttons.Add(ok, 0, wx.ALL, 5) buttons.Add(ok, 0, wx.ALL, 5)
buttons.Add(cancel, 0, wx.ALL, 5) buttons.Add(cancel, 0, wx.ALL, 5)
sizer.Add(buttons, 0, wx.ALL, 5) sizer.Add(buttons, 0, wx.ALL, 5)
panel.SetSizer(sizer) panel.SetSizer(sizer)
min = sizer.CalcMin() min = sizer.CalcMin()
self.SetClientSize(min) self.SetClientSize(min)
def fill_list(self, sessionsList): def fill_list(self, sessionsList):
for i in sessionsList: for i in sessionsList:
self.list.insert_item(False, i) self.list.insert_item(False, i)
if self.list.get_count() > 0: if self.list.get_count() > 0:
self.list.select_item(0) self.list.select_item(0)
self.list.list.SetSize(self.list.list.GetBestSize()) self.list.list.SetSize(self.list.list.GetBestSize())
def ok(self, ev): def ok(self, ev):
if self.list.get_count() == 0: if self.list.get_count() == 0:
wx.MessageDialog(None, _(u"You need to configure an account."), _(u"Account Error"), wx.ICON_ERROR).ShowModal() wx.MessageDialog(None, _(u"You need to configure an account."), _(u"Account Error"), wx.ICON_ERROR).ShowModal()
return return
self.controller.do_ok() self.controller.do_ok()
self.EndModal(wx.ID_OK) self.EndModal(wx.ID_OK)
def new_account_dialog(self): def new_account_dialog(self):
return wx.MessageDialog(self, _(u"The request to authorize your Twitter account will be opened in your browser. You only need to do this once. Would you like to continue?"), _(u"Authorization"), wx.YES_NO).ShowModal() return wx.MessageDialog(self, _(u"The request to authorize your Twitter account will be opened in your browser. You only need to do this once. Would you like to continue?"), _(u"Authorization"), wx.YES_NO).ShowModal()
def add_new_session_to_list(self): def add_new_session_to_list(self):
total = self.list.get_count() total = self.list.get_count()
name = _(u"Authorized account %d") % (total+1) name = _(u"Authorized account %d") % (total+1)
self.list.insert_item(False, name) self.list.insert_item(False, name)
if self.list.get_count() == 1: if self.list.get_count() == 1:
self.list.select_item(0) self.list.select_item(0)
def show_unauthorised_error(self): def show_unauthorised_error(self):
wx.MessageDialog(None, _(u"Your access token is invalid or the authorization has failed. Please try again."), _(u"Invalid user token"), wx.ICON_ERROR).ShowModal() wx.MessageDialog(None, _(u"Your access token is invalid or the authorization has failed. Please try again."), _(u"Invalid user token"), wx.ICON_ERROR).ShowModal()
def get_response(self): def get_response(self):
return self.ShowModal() return self.ShowModal()
def remove_account_dialog(self): def remove_account_dialog(self):
return wx.MessageDialog(self, _(u"Do you really want to delete this account?"), _(u"Remove account"), wx.YES_NO).ShowModal() return wx.MessageDialog(self, _(u"Do you really want to delete this account?"), _(u"Remove account"), wx.YES_NO).ShowModal()
def get_selected(self): def get_selected(self):
return self.list.get_selected() return self.list.get_selected()
def remove_session(self, sessionID): def remove_session(self, sessionID):
self.list.remove_item(sessionID) self.list.remove_item(sessionID)
def hide_configuration(self): def hide_configuration(self):
self.configuration.Hide() self.configuration.Hide()
def destroy(self): def destroy(self):
self.Destroy() self.Destroy()
def auth_error(user_name): def auth_error(user_name):
return wx.MessageDialog(None, _("TWBlue is unable to authenticate the account for {} in Twitter. It might be due to an invalid or expired token, revoqued access to the application, or after an account reactivation. Please remove the account manually from your Twitter sessions in order to stop seeing this message.").format(user_name,), _("Authentication error for session {}").format(user_name,), wx.OK).ShowModal() return wx.MessageDialog(None, _("TWBlue is unable to authenticate the account for {} in Twitter. It might be due to an invalid or expired token, revoqued access to the application, or after an account reactivation. Please remove the account manually from your Twitter sessions in order to stop seeing this message.").format(user_name,), _("Authentication error for session {}").format(user_name,), wx.OK).ShowModal()

View File

@ -3,4 +3,4 @@
In TWBlue, a session module defines everything a social network needs to be used in the program.""" In TWBlue, a session module defines everything a social network needs to be used in the program."""
from __future__ import unicode_literals from __future__ import unicode_literals
# let's define a global object for storing sessions across the program. # let's define a global object for storing sessions across the program.
sessions = {} sessions = {}

View File

@ -18,103 +18,103 @@ from . import session_exceptions as Exceptions
log = logging.getLogger("sessionmanager.session") log = logging.getLogger("sessionmanager.session")
class baseSession(object): class baseSession(object):
""" toDo: Decorators does not seem to be working when using them in an inherited class.""" """ toDo: Decorators does not seem to be working when using them in an inherited class."""
# Decorators. # Decorators.
def _require_login(fn): def _require_login(fn):
""" Decorator for checking if the user is logged in. """ Decorator for checking if the user is logged in.
Some functions may need this to avoid making unneeded calls.""" Some functions may need this to avoid making unneeded calls."""
def f(self, *args, **kwargs): def f(self, *args, **kwargs):
if self.logged == True: if self.logged == True:
fn(self, *args, **kwargs) fn(self, *args, **kwargs)
else: else:
raise Exceptions.NotLoggedSessionError("You are not logged in yet.") raise Exceptions.NotLoggedSessionError("You are not logged in yet.")
return f return f
def _require_configuration(fn): def _require_configuration(fn):
""" Check if the user has a configured session.""" """ Check if the user has a configured session."""
def f(self, *args, **kwargs): def f(self, *args, **kwargs):
if self.settings != None: if self.settings != None:
fn(self, *args, **kwargs) fn(self, *args, **kwargs)
else: else:
raise Exceptions.NotConfiguredSessionError("Not configured.") raise Exceptions.NotConfiguredSessionError("Not configured.")
return f return f
def __init__(self, session_id): def __init__(self, session_id):
""" session_id (str): The name of the folder inside the config directory where the session is located.""" """ session_id (str): The name of the folder inside the config directory where the session is located."""
super(baseSession, self).__init__() super(baseSession, self).__init__()
self.session_id = session_id self.session_id = session_id
self.logged = False self.logged = False
self.settings = None self.settings = None
self.db={} self.db={}
@property
def is_logged(self):
return self.logged
def get_configuration(self): @property
""" Get settings for a session.""" def is_logged(self):
file_ = "%s/session.conf" % (self.session_id,) return self.logged
log.debug("Creating config file %s" % (file_,))
self.settings = config_utils.load_config(os.path.join(paths.config_path(), file_), os.path.join(paths.app_path(), "Conf.defaults"))
self.init_sound()
self.deshelve()
def init_sound(self): def get_configuration(self):
try: self.sound = sound.soundSystem(self.settings["sound"]) """ Get settings for a session."""
except: pass file_ = "%s/session.conf" % (self.session_id,)
log.debug("Creating config file %s" % (file_,))
self.settings = config_utils.load_config(os.path.join(paths.config_path(), file_), os.path.join(paths.app_path(), "Conf.defaults"))
self.init_sound()
self.deshelve()
@_require_configuration def init_sound(self):
def login(self, verify_credentials=True): try: self.sound = sound.soundSystem(self.settings["sound"])
pass except: pass
@_require_configuration @_require_configuration
def authorise(self): def login(self, verify_credentials=True):
pass pass
def shelve(self): @_require_configuration
"""Shelve the database to allow for persistance.""" def authorise(self):
shelfname=os.path.join(paths.config_path(), str(self.session_id), "cache") pass
if self.settings["general"]["persist_size"] == 0:
if os.path.exists(shelfname+".dat"):
os.remove(shelfname+".dat")
return
try:
if not os.path.exists(shelfname+".dat"):
output.speak("Generating database, this might take a while.",True)
shelf=shelve.open(os.path.join(paths.config_path(), shelfname),'c')
for key, value in list(self.db.items()):
if type(key) != str and type(key) != str:
output.speak("Uh oh, while shelving the database, a key of type " + str(type(key)) + " has been found. It will be converted to type str, but this will cause all sorts of problems on deshelve. Please bring this to the attention of the " + application.name + " developers immediately. More information about the error will be written to the error log.",True)
log.error("Uh oh, " + str(key) + " is of type " + str(type(key)) + "!")
if type(value) == list and self.settings["general"]["persist_size"] != -1 and len(value) > self.settings["general"]["persist_size"]:
shelf[key]=value[self.settings["general"]["persist_size"]:]
else:
shelf[key]=value
shelf.close()
except:
output.speak("An exception occurred while shelving the " + application.name + " database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the " + application.name + " developers.",True)
log.exception("Exception while shelving" + shelfname)
os.remove(shelfname)
def deshelve(self): def shelve(self):
"""Import a shelved database.""" """Shelve the database to allow for persistance."""
shelfname=os.path.join(paths.config_path(), str(self.session_id)+"/cache") shelfname=os.path.join(paths.config_path(), str(self.session_id), "cache")
if self.settings["general"]["persist_size"] == 0: if self.settings["general"]["persist_size"] == 0:
if os.path.exists(shelfname+".dat"): if os.path.exists(shelfname+".dat"):
os.remove(shelfname+".dat") os.remove(shelfname+".dat")
return return
try: try:
shelf=shelve.open(os.path.join(paths.config_path(), shelfname),'c') if not os.path.exists(shelfname+".dat"):
for key,value in list(shelf.items()): output.speak("Generating database, this might take a while.",True)
self.db[key]=value shelf=shelve.open(os.path.join(paths.config_path(), shelfname),'c')
shelf.close() for key, value in list(self.db.items()):
except: if type(key) != str and type(key) != str:
output.speak("An exception occurred while deshelving the " + application.name + " database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the " + application.name + " developers.",True) output.speak("Uh oh, while shelving the database, a key of type " + str(type(key)) + " has been found. It will be converted to type str, but this will cause all sorts of problems on deshelve. Please bring this to the attention of the " + application.name + " developers immediately. More information about the error will be written to the error log.",True)
log.exception("Exception while deshelving" + shelfname) log.error("Uh oh, " + str(key) + " is of type " + str(type(key)) + "!")
try: if type(value) == list and self.settings["general"]["persist_size"] != -1 and len(value) > self.settings["general"]["persist_size"]:
os.remove(shelfname) shelf[key]=value[self.settings["general"]["persist_size"]:]
except: else:
pass shelf[key]=value
shelf.close()
except:
output.speak("An exception occurred while shelving the " + application.name + " database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the " + application.name + " developers.",True)
log.exception("Exception while shelving" + shelfname)
os.remove(shelfname)
def deshelve(self):
"""Import a shelved database."""
shelfname=os.path.join(paths.config_path(), str(self.session_id)+"/cache")
if self.settings["general"]["persist_size"] == 0:
if os.path.exists(shelfname+".dat"):
os.remove(shelfname+".dat")
return
try:
shelf=shelve.open(os.path.join(paths.config_path(), shelfname),'c')
for key,value in list(shelf.items()):
self.db[key]=value
shelf.close()
except:
output.speak("An exception occurred while deshelving the " + application.name + " database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the " + application.name + " developers.",True)
log.exception("Exception while deshelving" + shelfname)
try:
os.remove(shelfname)
except:
pass

View File

@ -6,4 +6,4 @@ class NonExistentSessionError(Exception): pass
class NotLoggedSessionError(BaseException): pass class NotLoggedSessionError(BaseException): pass
class NotConfiguredSessionError(BaseException): pass class NotConfiguredSessionError(BaseException): pass
class RequireCredentialsSessionError(BaseException): pass class RequireCredentialsSessionError(BaseException): pass
class AlreadyAuthorisedError(BaseException): pass class AlreadyAuthorisedError(BaseException): pass

View File

@ -1 +1 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-

View File

@ -1,11 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import unicode_literals
from future import standard_library
standard_library.install_aliases()
from builtins import str
from builtins import chr
from builtins import range
import platform import platform
system = platform.system() system = platform.system()
from . import utils from . import utils
@ -21,151 +14,151 @@ from .long_tweets import twishort, tweets
log = logging.getLogger("compose") log = logging.getLogger("compose")
def StripChars(s): def StripChars(s):
"""Converts any html entities in s to their unicode-decoded equivalents and returns a string.""" """Converts any html entities in s to their unicode-decoded equivalents and returns a string."""
entity_re = re.compile(r"&(#\d+|\w+);") entity_re = re.compile(r"&(#\d+|\w+);")
def matchFunc(match): def matchFunc(match):
"""Nested function to handle a match object. """Nested function to handle a match object.
If we match &blah; and it's not found, &blah; will be returned. If we match &blah; and it's not found, &blah; will be returned.
if we match #\d+, unichr(digits) will be returned. if we match #\d+, unichr(digits) will be returned.
Else, a unicode string will be returned.""" Else, a unicode string will be returned."""
if match.group(1).startswith('#'): return chr(int(match.group(1)[1:])) if match.group(1).startswith('#'): return chr(int(match.group(1)[1:]))
replacement = html.entities.entitydefs.get(match.group(1), "&%s;" % match.group(1)) replacement = html.entities.entitydefs.get(match.group(1), "&%s;" % match.group(1))
return replacement return replacement
return str(entity_re.sub(matchFunc, s)) return str(entity_re.sub(matchFunc, s))
chars = "abcdefghijklmnopqrstuvwxyz" chars = "abcdefghijklmnopqrstuvwxyz"
def compose_tweet(tweet, db, relative_times, show_screen_names=False, session=None): def compose_tweet(tweet, db, relative_times, show_screen_names=False, session=None):
""" It receives a tweet and returns a list with the user, text for the tweet or message, date and the client where user is.""" """ It receives a tweet and returns a list with the user, text for the tweet or message, date and the client where user is."""
if system == "Windows": if system == "Windows":
original_date = arrow.get(tweet.created_at, locale="en") original_date = arrow.get(tweet.created_at, locale="en")
if relative_times == True: if relative_times == True:
ts = original_date.humanize(locale=languageHandler.curLang[:2]) ts = original_date.humanize(locale=languageHandler.curLang[:2])
else: else:
ts = original_date.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2]) ts = original_date.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2])
else: else:
ts = tweet.created_at ts = tweet.created_at
if hasattr(tweet, "message"): if hasattr(tweet, "message"):
value = "message" value = "message"
elif hasattr(tweet, "full_text"): elif hasattr(tweet, "full_text"):
value = "full_text" value = "full_text"
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 = StripChars(getattr(tweet.retweeted_status, value))
else: else:
text = StripChars(getattr(tweet, value)) text = StripChars(getattr(tweet, value))
if show_screen_names: if show_screen_names:
user = tweet.user.screen_name user = tweet.user.screen_name
else: else:
user = tweet.user.name user = tweet.user.name
source = re.sub(r"(?s)<.*?>", "", tweet.source) source = re.sub(r"(?s)<.*?>", "", tweet.source)
if hasattr(tweet, "retweeted_status"): if hasattr(tweet, "retweeted_status"):
if (hasattr(tweet, "message")) == False and tweet.retweeted_status.is_quote_status == False: if (hasattr(tweet, "message")) == False and tweet.retweeted_status.is_quote_status == False:
text = "RT @%s: %s" % (tweet.retweeted_status.user.screen_name, text) text = "RT @%s: %s" % (tweet.retweeted_status.user.screen_name, text)
elif tweet.retweeted_status.is_quote_status: elif tweet.retweeted_status.is_quote_status:
text = "%s" % (text) text = "%s" % (text)
else: else:
text = "RT @%s: %s" % (tweet.retweeted_status.user.screen_name, text) text = "RT @%s: %s" % (tweet.retweeted_status.user.screen_name, text)
if not hasattr(tweet, "message"): if not hasattr(tweet, "message"):
if hasattr(tweet, "retweeted_status"): if hasattr(tweet, "retweeted_status"):
text = utils.expand_urls(text, tweet.retweeted_status.entities) text = utils.expand_urls(text, tweet.retweeted_status.entities)
else: else:
text = utils.expand_urls(text, tweet.entities) text = utils.expand_urls(text, tweet.entities)
if config.app['app-settings']['handle_longtweets']: pass if config.app['app-settings']['handle_longtweets']: pass
return [user+", ", text, ts+", ", source] return [user+", ", text, ts+", ", source]
def compose_direct_message(item, db, relative_times, show_screen_names=False, session=None): def compose_direct_message(item, db, relative_times, show_screen_names=False, session=None):
if system == "Windows": if system == "Windows":
# Let's remove the last 3 digits in the timestamp string. # Let's remove the last 3 digits in the timestamp string.
# Twitter sends their "epoch" timestamp with 3 digits for milliseconds and arrow doesn't like it. # Twitter sends their "epoch" timestamp with 3 digits for milliseconds and arrow doesn't like it.
original_date = arrow.get(int(item.created_timestamp)) original_date = arrow.get(int(item.created_timestamp))
if relative_times == True: if relative_times == True:
ts = original_date.humanize(locale=languageHandler.curLang[:2]) ts = original_date.humanize(locale=languageHandler.curLang[:2])
else: else:
ts = original_date.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2]) ts = original_date.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2])
else: else:
ts = item.created_timestamp ts = item.created_timestamp
text = StripChars(item.message_create["message_data"]["text"]) text = StripChars(item.message_create["message_data"]["text"])
source = "DM" source = "DM"
sender = session.get_user(item.message_create["sender_id"]) sender = session.get_user(item.message_create["sender_id"])
if db["user_name"] == sender.screen_name: if db["user_name"] == sender.screen_name:
if show_screen_names: if show_screen_names:
user = _(u"Dm to %s ") % (session.get_user(item.message_create["target"]["recipient_id"]).screen_name) user = _(u"Dm to %s ") % (session.get_user(item.message_create["target"]["recipient_id"]).screen_name)
else: else:
user = _(u"Dm to %s ") % (session.get_user(item.message_create["target"]["recipient_id"]).name) user = _(u"Dm to %s ") % (session.get_user(item.message_create["target"]["recipient_id"]).name)
else: else:
if show_screen_names: if show_screen_names:
user = sender.screen_name user = sender.screen_name
else: else:
user = sender.name user = sender.name
if text[-1] in chars: text=text+"." if text[-1] in chars: text=text+"."
text = utils.expand_urls(text, item.message_create["message_data"]["entities"]) text = utils.expand_urls(text, item.message_create["message_data"]["entities"])
return [user+", ", text, ts+", ", source] return [user+", ", text, ts+", ", source]
def compose_quoted_tweet(quoted_tweet, original_tweet, show_screen_names=False, session=None): def compose_quoted_tweet(quoted_tweet, original_tweet, show_screen_names=False, session=None):
""" It receives a tweet and returns a list with the user, text for the tweet or message, date and the client where user is.""" """ It receives a tweet and returns a list with the user, text for the tweet or message, date and the client where user is."""
if hasattr(quoted_tweet, "retweeted_status"): if hasattr(quoted_tweet, "retweeted_status"):
if hasattr(quoted_tweet.retweeted_status, "full_text"): if hasattr(quoted_tweet.retweeted_status, "full_text"):
value = "full_text" value = "full_text"
else: else:
value = "text" value = "text"
text = StripChars(getattr(quoted_tweet.retweeted_status, value)) text = StripChars(getattr(quoted_tweet.retweeted_status, value))
else: else:
if hasattr(quoted_tweet, "full_text"): if hasattr(quoted_tweet, "full_text"):
value = "full_text" value = "full_text"
else: else:
value = "text" value = "text"
text = StripChars(getattr(quoted_tweet, value)) text = StripChars(getattr(quoted_tweet, value))
if show_screen_names: if show_screen_names:
quoting_user = quoted_tweet.user.screen_name quoting_user = quoted_tweet.user.screen_name
else: else:
quoting_user = quoted_tweet.user.name quoting_user = quoted_tweet.user.name
source = quoted_tweet.source source = quoted_tweet.source
if hasattr(quoted_tweet, "retweeted_status"): if hasattr(quoted_tweet, "retweeted_status"):
text = "rt @%s: %s" % (quoted_tweet.retweeted_status.user.screen_name, text) text = "rt @%s: %s" % (quoted_tweet.retweeted_status.user.screen_name, text)
if text[-1] in chars: text=text+"." if text[-1] in chars: text=text+"."
original_user = original_tweet.user.screen_name original_user = original_tweet.user.screen_name
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 = StripChars(original_tweet.full_text)
else: else:
original_text = StripChars(original_tweet.text) original_text = 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)
quoted_tweet.entities["urls"].extend(original_tweet.entities["urls"]) quoted_tweet.entities["urls"].extend(original_tweet.entities["urls"])
return quoted_tweet return quoted_tweet
def compose_followers_list(tweet, db, relative_times=True, show_screen_names=False, session=None): def compose_followers_list(tweet, db, relative_times=True, show_screen_names=False, session=None):
if system == "Windows": if system == "Windows":
original_date = arrow.get(tweet.created_at, locale="en") original_date = arrow.get(tweet.created_at, locale="en")
if relative_times == True: if relative_times == True:
ts = original_date.humanize(locale=languageHandler.curLang[:2]) ts = original_date.humanize(locale=languageHandler.curLang[:2])
else: else:
ts = original_date.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2]) ts = original_date.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2])
else: else:
ts = tweet.created_at ts = tweet.created_at
if hasattr(tweet, "status"): if hasattr(tweet, "status"):
if system == "Windows": if system == "Windows":
original_date2 = arrow.get(tweet.status.created_at, locale="en") original_date2 = arrow.get(tweet.status.created_at, locale="en")
if relative_times: if relative_times:
ts2 = original_date2.humanize(locale=languageHandler.curLang[:2]) ts2 = original_date2.humanize(locale=languageHandler.curLang[:2])
else: else:
ts2 = original_date2.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2]) ts2 = original_date2.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2])
else: else:
ts2 = _("Unavailable") ts2 = _("Unavailable")
else: else:
ts2 = _("Unavailable") ts2 = _("Unavailable")
return [_(u"%s (@%s). %s followers, %s friends, %s tweets. Last tweeted %s. Joined Twitter %s") % (tweet.name, tweet.screen_name, tweet.followers_count, tweet.friends_count, tweet.statuses_count, ts2, ts)] return [_(u"%s (@%s). %s followers, %s friends, %s tweets. Last tweeted %s. Joined Twitter %s") % (tweet.name, tweet.screen_name, tweet.followers_count, tweet.friends_count, tweet.statuses_count, ts2, ts)]
def compose_list(list): def compose_list(list):
name = list.name name = list.name
if list.description == None: description = _(u"No description available") if list.description == None: description = _(u"No description available")
else: description = list.description else: description = list.description
user = list.user.name user = list.user.name
members = str(list.member_count) members = str(list.member_count)
if list.mode == "private": status = _(u"private") if list.mode == "private": status = _(u"private")
else: status = _(u"public") else: status = _(u"public")
return [name, description, user, members, status] return [name, description, user, members, status]

View File

@ -1,3 +1,3 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" this package holds different modules to extract information regarding long tweets. A long tweet contains more than one tweet (such a quoted tweet), or is made via services like twishort.""" """ this package holds different modules to extract information regarding long tweets. A long tweet contains more than one tweet (such a quoted tweet), or is made via services like twishort."""
from __future__ import unicode_literals from __future__ import unicode_literals

View File

@ -20,33 +20,33 @@ from __future__ import unicode_literals
from sessions.twitter import utils from sessions.twitter import utils
def is_long(tweet): def is_long(tweet):
""" Check if the passed tweet contains a quote in its metadata. """ Check if the passed tweet contains a quote in its metadata.
tweet dict: a tweet dictionary. tweet dict: a tweet dictionary.
returns True if a quote is detected, False otherwise.""" returns True if a quote is detected, False otherwise."""
if hasattr(tweet, "quoted_status_id") and hasattr(tweet, "quoted_status"): if hasattr(tweet, "quoted_status_id") and hasattr(tweet, "quoted_status"):
return tweet.quoted_status_id return tweet.quoted_status_id
elif hasattr(tweet, "retweeted_status") and hasattr(tweet.retweeted_status, "quoted_status_id") and hasattr(tweet.retweeted_status, "quoted_status"): elif hasattr(tweet, "retweeted_status") and hasattr(tweet.retweeted_status, "quoted_status_id") and hasattr(tweet.retweeted_status, "quoted_status"):
return tweet.retweeted_status.quoted_status_id return tweet.retweeted_status.quoted_status_id
return False return False
def clear_url(tweet): def clear_url(tweet):
""" Reads data from a quoted tweet and removes the link to the Status from the tweet's text. """ Reads data from a quoted tweet and removes the link to the Status from the tweet's text.
tweet dict: a tweet dictionary. tweet dict: a tweet dictionary.
returns a tweet dictionary without the URL to the status ID in its text to display.""" returns a tweet dictionary without the URL to the status ID in its text to display."""
if hasattr(tweet, "retweeted_status"): if hasattr(tweet, "retweeted_status"):
if hasattr(tweet.retweeted_status, "full_text"): if hasattr(tweet.retweeted_status, "full_text"):
value = "full_text" value = "full_text"
else: else:
value = "text" value = "text"
urls = utils.find_urls_in_text(getattr(tweet.retweeted_status, value)) urls = utils.find_urls_in_text(getattr(tweet.retweeted_status, value))
try: tweet.message = tweet.message.replace(urls[-1], "") try: tweet.message = tweet.message.replace(urls[-1], "")
except IndexError: pass except IndexError: pass
else: else:
if hasattr(tweet, "full_text"): if hasattr(tweet, "full_text"):
value = "full_text" value = "full_text"
else: else:
value = "text" value = "text"
urls = utils.find_urls_in_text(getattr(tweet, value)) urls = utils.find_urls_in_text(getattr(tweet, value))
try: tweet.message = tweet.message.replace(urls[-1], "") try: tweet.message = tweet.message.replace(urls[-1], "")
except IndexError: pass except IndexError: pass
return tweet return tweet

View File

@ -28,77 +28,77 @@ from sessions.twitter import utils
log = logging.getLogger("long_tweets.twishort") log = logging.getLogger("long_tweets.twishort")
def get_twishort_uri(url): def get_twishort_uri(url):
""" Takes A twishort URl and returns the twishort ID. """ Takes A twishort URl and returns the twishort ID.
url str: an url like http://twishort.com/id. url str: an url like http://twishort.com/id.
returns a twishort ID if the URL is valid, False otherwise.""" returns a twishort ID if the URL is valid, False otherwise."""
try: try:
return url.split("twishort.com/")[1] return url.split("twishort.com/")[1]
except ValueError: except ValueError:
return False return False
def is_long(tweet): def is_long(tweet):
""" Check if the passed tweet is made with Twishort. """ Check if the passed tweet is made with Twishort.
returns True if is a long tweet, False otherwise.""" returns True if is a long tweet, False otherwise."""
long = False long = False
for url in range(0, len(tweet.entities["urls"])): for url in range(0, len(tweet.entities["urls"])):
try: try:
if tweet.entities["urls"][url] != None and "twishort.com" in tweet.entities["urls"][url]["expanded_url"]: if tweet.entities["urls"][url] != None and "twishort.com" in tweet.entities["urls"][url]["expanded_url"]:
long = get_twishort_uri(tweet.entities["urls"][url]["expanded_url"]) long = get_twishort_uri(tweet.entities["urls"][url]["expanded_url"])
except IndexError: except IndexError:
pass pass
# sometimes Twitter returns URL's with None objects, so let's take it. # sometimes Twitter returns URL's with None objects, so let's take it.
# see https://github.com/manuelcortez/TWBlue/issues/103 # see https://github.com/manuelcortez/TWBlue/issues/103
except TypeError: except TypeError:
pass pass
if long == False and hasattr(tweet, "retweeted_status"): if long == False and hasattr(tweet, "retweeted_status"):
for url in range(0, len(tweet.retweeted_status.entities["urls"])): for url in range(0, len(tweet.retweeted_status.entities["urls"])):
try: try:
if tweet.retweeted_status.entities["urls"][url] != None and "twishort.com" in tweet.retweeted_status.entities["urls"][url]["expanded_url"]: if tweet.retweeted_status.entities["urls"][url] != None and "twishort.com" in tweet.retweeted_status.entities["urls"][url]["expanded_url"]:
long = get_twishort_uri(tweet.retweeted_status.entities["urls"][url]["expanded_url"]) long = get_twishort_uri(tweet.retweeted_status.entities["urls"][url]["expanded_url"])
except IndexError: except IndexError:
pass pass
except TypeError: except TypeError:
pass pass
return long return long
def get_full_text(uri): def get_full_text(uri):
""" Get Twishort's full text. """ Get Twishort's full text.
uri str: Twishort's identifier. uri str: Twishort's identifier.
returns the contents of the tweet.""" returns the contents of the tweet."""
try: try:
r = requests.get("http://api.twishort.com/1.1/get.json", params={"uri": uri, "api_key": keys.keyring.get("twishort_api_key")}) r = requests.get("http://api.twishort.com/1.1/get.json", params={"uri": uri, "api_key": keys.keyring.get("twishort_api_key")})
msg = r.json()["text"] msg = r.json()["text"]
# Try to parse possible HTML entities. # Try to parse possible HTML entities.
from sessions.twitter.compose import StripChars from sessions.twitter.compose import StripChars
msg = StripChars(msg) msg = StripChars(msg)
return msg return msg
except: except:
return False return False
def create_tweet(user_token, user_secret, text, media=0): def create_tweet(user_token, user_secret, text, media=0):
""" Send a tweet to be extended by using Twishort. """ Send a tweet to be extended by using Twishort.
user_token, user_secret str: Twitter user access key and secret, used by TWBlue to authorise against Twitter. user_token, user_secret str: Twitter user access key and secret, used by TWBlue to authorise against Twitter.
text str: Tweet text, max 10000 characters. text str: Tweet text, max 10000 characters.
media int: Not used currently. media int: Not used currently.
Returns text to be placed in the Tweet if the post has been succeeded, 0 otherwise.""" Returns text to be placed in the Tweet if the post has been succeeded, 0 otherwise."""
twitter = OAuth1Session(keys.keyring.get("api_key"), client_secret=keys.keyring.get("api_secret"), resource_owner_key=user_token, resource_owner_secret=user_secret) twitter = OAuth1Session(keys.keyring.get("api_key"), client_secret=keys.keyring.get("api_secret"), resource_owner_key=user_token, resource_owner_secret=user_secret)
twishort_key=keys.keyring.get("twishort_api_key") twishort_key=keys.keyring.get("twishort_api_key")
x_auth_service_provider = "https://api.twitter.com/1.1/account/verify_credentials.json" x_auth_service_provider = "https://api.twitter.com/1.1/account/verify_credentials.json"
twishort_post_url = "http://api.twishort.com/1.1/post.json" twishort_post_url = "http://api.twishort.com/1.1/post.json"
twishort_update_ids_url = "http://api.twishort.com/1.1/update_ids.json" twishort_update_ids_url = "http://api.twishort.com/1.1/update_ids.json"
r=requests.Request('GET', x_auth_service_provider) r=requests.Request('GET', x_auth_service_provider)
prep=twitter.prepare_request(r) prep=twitter.prepare_request(r)
resp=twitter.send(prep) resp=twitter.send(prep)
twitter.headers={ twitter.headers={
'X-Auth-Service-Provider':x_auth_service_provider, 'X-Auth-Service-Provider':x_auth_service_provider,
'X-Verify-Credentials-Authorization':prep.headers['Authorization'], 'X-Verify-Credentials-Authorization':prep.headers['Authorization'],
} }
data = {'api_key':twishort_key, data = {'api_key':twishort_key,
"text": text.encode("utf-8"), "text": text.encode("utf-8"),
"media": media} "media": media}
response = twitter.post(twishort_post_url, data=data) response = twitter.post(twishort_post_url, data=data)
try: try:
return response.json()["text_to_tweet"] return response.json()["text_to_tweet"]
except: except:
print("There was a problem creating a long tweet") print("There was a problem creating a long tweet")
return 0 return 0

View File

@ -22,432 +22,432 @@ from .wxUI import authorisationDialog
log = logging.getLogger("sessions.twitterSession") log = logging.getLogger("sessions.twitterSession")
class Session(base.baseSession): class Session(base.baseSession):
""" A session object where we will save configuration, the twitter object and a local storage for saving the items retrieved through the Twitter API methods""" """ A session object where we will save configuration, the twitter object and a local storage for saving the items retrieved through the Twitter API methods"""
def order_buffer(self, name, data, ignore_older=True): def order_buffer(self, name, data, ignore_older=True):
""" Put new items in the local database. """ Put new items in the local database.
name str: The name for the buffer stored in the dictionary. name str: The name for the buffer stored in the dictionary.
data list: A list with tweets. data list: A list with tweets.
ignore_older bool: if set to True, items older than the first element on the list will be ignored. ignore_older bool: if set to True, items older than the first element on the list will be ignored.
returns the number of items that have been added in this execution""" returns the number of items that have been added in this execution"""
if name == "direct_messages": if name == "direct_messages":
return self.order_direct_messages(data) return self.order_direct_messages(data)
num = 0 num = 0
last_id = None last_id = None
if (name in self.db) == False: if (name in self.db) == False:
self.db[name] = [] self.db[name] = []
if ("users" in self.db) == False: if ("users" in self.db) == False:
self.db["users"] = {} self.db["users"] = {}
if ignore_older and len(self.db[name]) > 0: if ignore_older and len(self.db[name]) > 0:
if self.settings["general"]["reverse_timelines"] == False: if self.settings["general"]["reverse_timelines"] == False:
last_id = self.db[name][0].id last_id = self.db[name][0].id
else: else:
last_id = self.db[name][-1].id last_id = self.db[name][-1].id
for i in data: for i in data:
if ignore_older and last_id != None: if ignore_older and last_id != None:
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.id, self.db[name]) == None and utils.is_allowed(i, self.settings, name) == True:
i = self.check_quoted_status(i) i = self.check_quoted_status(i)
i = self.check_long_tweet(i) i = self.check_long_tweet(i)
if i == False: continue if i == False: continue
if self.settings["general"]["reverse_timelines"] == False: self.db[name].append(i) if self.settings["general"]["reverse_timelines"] == False: self.db[name].append(i)
else: self.db[name].insert(0, i) else: self.db[name].insert(0, i)
num = num+1 num = num+1
if hasattr(i, "user"): if hasattr(i, "user"):
if (i.user.id in self.db["users"]) == False: if (i.user.id in self.db["users"]) == False:
self.db["users"][i.user.id] = i.user self.db["users"][i.user.id] = i.user
return num return num
def order_people(self, name, data): def order_people(self, name, data):
""" Put new items on the local database. Useful for cursored buffers (followers, friends, users of a list and searches) """ Put new items on the local database. Useful for cursored buffers (followers, friends, users of a list and searches)
name str: The name for the buffer stored in the dictionary. name str: The name for the buffer stored in the dictionary.
data list: A list with items and some information about cursors. data list: A list with items and some information about cursors.
returns the number of items that have been added in this execution""" returns the number of items that have been added in this execution"""
num = 0 num = 0
if (name in self.db) == False: if (name in self.db) == False:
self.db[name] = [] 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.id, self.db[name]) == None:
if self.settings["general"]["reverse_timelines"] == False: self.db[name].append(i) if self.settings["general"]["reverse_timelines"] == False: self.db[name].append(i)
else: self.db[name].insert(0, i) else: self.db[name].insert(0, i)
num = num+1 num = num+1
return num return num
def order_direct_messages(self, data): def order_direct_messages(self, data):
""" Add incoming and sent direct messages to their corresponding database items. """ Add incoming and sent direct messages to their corresponding database items.
data list: A list of direct messages to add. data list: A list of direct messages to add.
returns the number of incoming messages processed in this execution, and sends an event with data regarding amount of sent direct messages added.""" returns the number of incoming messages processed in this execution, and sends an event with data regarding amount of sent direct messages added."""
incoming = 0 incoming = 0
sent = 0 sent = 0
if ("direct_messages" in self.db) == False: if ("direct_messages" in self.db) == False:
self.db["direct_messages"] = [] self.db["direct_messages"] = []
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.id, self.db["sent_direct_messages"]) == None:
if self.settings["general"]["reverse_timelines"] == False: self.db["sent_direct_messages"].append(i) if self.settings["general"]["reverse_timelines"] == False: self.db["sent_direct_messages"].append(i)
else: self.db["sent_direct_messages"].insert(0, i) else: self.db["sent_direct_messages"].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.id, self.db["direct_messages"]) == None:
if self.settings["general"]["reverse_timelines"] == False: self.db["direct_messages"].append(i) if self.settings["general"]["reverse_timelines"] == False: self.db["direct_messages"].append(i)
else: self.db["direct_messages"].insert(0, i) else: self.db["direct_messages"].insert(0, i)
incoming = incoming+1 incoming = incoming+1
pub.sendMessage("sent-dms-updated", total=sent, account=self.db["user_name"]) pub.sendMessage("sent-dms-updated", total=sent, account=self.db["user_name"])
return incoming return incoming
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(Session, self).__init__(*args, **kwargs) super(Session, self).__init__(*args, **kwargs)
# Adds here the optional cursors objects. # Adds here the optional cursors objects.
cursors = dict(direct_messages=-1) cursors = dict(direct_messages=-1)
self.db["cursors"] = cursors self.db["cursors"] = cursors
self.reconnection_function_active = False self.reconnection_function_active = False
self.counter = 0 self.counter = 0
self.lists = [] self.lists = []
# @_require_configuration # @_require_configuration
def login(self, verify_credentials=True): def login(self, verify_credentials=True):
""" Log into twitter using credentials from settings. """ Log into twitter using credentials from settings.
if the user account isn't authorised, it needs to call self.authorise() before login.""" if the user account isn't authorised, it needs to call self.authorise() before login."""
if self.settings["twitter"]["user_key"] != None and self.settings["twitter"]["user_secret"] != None: if self.settings["twitter"]["user_key"] != None and self.settings["twitter"]["user_secret"] != None:
try: try:
log.debug("Logging in to twitter...") log.debug("Logging in to twitter...")
self.auth = tweepy.OAuthHandler(keyring.get("api_key"), keyring.get("api_secret")) self.auth = tweepy.OAuthHandler(keyring.get("api_key"), keyring.get("api_secret"))
self.auth.set_access_token(self.settings["twitter"]["user_key"], self.settings["twitter"]["user_secret"]) self.auth.set_access_token(self.settings["twitter"]["user_key"], self.settings["twitter"]["user_secret"])
self.twitter = tweepy.API(self.auth) self.twitter = tweepy.API(self.auth)
if verify_credentials == True: if verify_credentials == True:
self.credentials = self.twitter.verify_credentials() self.credentials = self.twitter.verify_credentials()
self.logged = True self.logged = True
log.debug("Logged.") log.debug("Logged.")
self.counter = 0 self.counter = 0
except IOError: except IOError:
log.error("The login attempt failed.") log.error("The login attempt failed.")
self.logged = False self.logged = False
else: else:
self.logged = False self.logged = False
raise Exceptions.RequireCredentialsSessionError raise Exceptions.RequireCredentialsSessionError
# @_require_configuration # @_require_configuration
def authorise(self): def authorise(self):
""" Authorises a Twitter account. This function needs to be called for each new session, after self.get_configuration() and before self.login()""" """ Authorises a Twitter account. This function needs to be called for each new session, after self.get_configuration() and before self.login()"""
if self.logged == True: if self.logged == True:
raise Exceptions.AlreadyAuthorisedError("The authorisation process is not needed at this time.") raise Exceptions.AlreadyAuthorisedError("The authorisation process is not needed at this time.")
else: else:
self.auth = tweepy.OAuthHandler(keyring.get("api_key"), keyring.get("api_secret")) self.auth = tweepy.OAuthHandler(keyring.get("api_key"), keyring.get("api_secret"))
redirect_url = self.auth.get_authorization_url() redirect_url = self.auth.get_authorization_url()
webbrowser.open_new_tab(redirect_url) webbrowser.open_new_tab(redirect_url)
self.authorisation_dialog = authorisationDialog() self.authorisation_dialog = authorisationDialog()
self.authorisation_dialog.cancel.Bind(wx.EVT_BUTTON, self.authorisation_cancelled) self.authorisation_dialog.cancel.Bind(wx.EVT_BUTTON, self.authorisation_cancelled)
self.authorisation_dialog.ok.Bind(wx.EVT_BUTTON, self.authorisation_accepted) self.authorisation_dialog.ok.Bind(wx.EVT_BUTTON, self.authorisation_accepted)
self.authorisation_dialog.ShowModal() self.authorisation_dialog.ShowModal()
def verify_authorisation(self, pincode): def verify_authorisation(self, pincode):
self.auth.get_access_token(pincode) self.auth.get_access_token(pincode)
self.settings["twitter"]["user_key"] = self.auth.access_token self.settings["twitter"]["user_key"] = self.auth.access_token
self.settings["twitter"]["user_secret"] = self.auth.access_token_secret self.settings["twitter"]["user_secret"] = self.auth.access_token_secret
self.settings.write() self.settings.write()
del self.auth del self.auth
def authorisation_cancelled(self, *args, **kwargs): def authorisation_cancelled(self, *args, **kwargs):
""" Destroy the authorization dialog. """ """ Destroy the authorization dialog. """
self.authorisation_dialog.Destroy() self.authorisation_dialog.Destroy()
del self.authorisation_dialog del self.authorisation_dialog
def authorisation_accepted(self, *args, **kwargs): def authorisation_accepted(self, *args, **kwargs):
""" Gets the PIN code entered by user and validate it through Twitter.""" """ Gets the PIN code entered by user and validate it through Twitter."""
pincode = self.authorisation_dialog.text.GetValue() pincode = self.authorisation_dialog.text.GetValue()
self.verify_authorisation(pincode) self.verify_authorisation(pincode)
self.authorisation_dialog.Destroy() self.authorisation_dialog.Destroy()
def get_more_items(self, update_function, users=False, dm=False, name=None, *args, **kwargs): def get_more_items(self, update_function, users=False, dm=False, name=None, *args, **kwargs):
""" Get more items for twitter objects. """ Get more items for twitter objects.
update_function str: function to call for getting more items. Must be member of self.twitter. update_function str: function to call for getting more items. Must be member of self.twitter.
users, dm bool: If any of these is set to True, the function will treat items as users or dm (they need different handling). users, dm bool: If any of these is set to True, the function will treat items as users or dm (they need different handling).
name str: name of the database item to put new element in.""" name str: name of the database item to put new element in."""
results = [] results = []
if "cursor" in kwargs and kwargs["cursor"] == 0: if "cursor" in kwargs and kwargs["cursor"] == 0:
output.speak(_(u"There are no more items to retrieve in this buffer.")) output.speak(_(u"There are no more items to retrieve in this buffer."))
return return
data = getattr(self.twitter, update_function)(*args, **kwargs) data = getattr(self.twitter, update_function)(*args, **kwargs)
if users == True: if users == True:
if type(data) == dict and "next_cursor" in data: if type(data) == dict and "next_cursor" in data:
if "next_cursor" in data: # There are more objects to retrieve. if "next_cursor" in data: # There are more objects to retrieve.
self.db[name]["cursor"] = data["next_cursor"] self.db[name]["cursor"] = data["next_cursor"]
else: # Set cursor to 0, wich means no more items available. else: # Set cursor to 0, wich means no more items available.
self.db[name]["cursor"] = 0 self.db[name]["cursor"] = 0
for i in data["users"]: results.append(i) for i in data["users"]: results.append(i)
elif type(data) == list: elif type(data) == list:
results.extend(data[1:]) results.extend(data[1:])
elif dm == True: elif dm == True:
if "next_cursor" in data: # There are more objects to retrieve. if "next_cursor" in data: # There are more objects to retrieve.
self.db[name]["cursor"] = data["next_cursor"] self.db[name]["cursor"] = data["next_cursor"]
else: # Set cursor to 0, wich means no more items available. else: # Set cursor to 0, wich means no more items available.
self.db[name]["cursor"] = 0 self.db[name]["cursor"] = 0
for i in data["events"]: results.append(i) for i in data["events"]: results.append(i)
else: else:
results.extend(data[1:]) results.extend(data[1:])
return results return results
def api_call(self, call_name, action="", _sound=None, report_success=False, report_failure=True, preexec_message="", *args, **kwargs): def api_call(self, call_name, action="", _sound=None, report_success=False, report_failure=True, preexec_message="", *args, **kwargs):
""" Make a call to the Twitter API. If there is a connectionError or another exception not related to Twitter, It will call the method again at least 25 times, waiting a while between calls. Useful for post methods. """ Make a call to the Twitter API. If there is a connectionError or another exception not related to Twitter, It will call the method again at least 25 times, waiting a while between calls. Useful for post methods.
If twitter returns an error, it will not call the method anymore. If twitter returns an error, it will not call the method anymore.
call_name str: The method to call call_name str: The method to call
action str: What you are doing on twitter, it will be reported to the user if report_success is set to True. action str: What you are doing on twitter, it will be reported to the user if report_success is set to True.
for example "following @tw_blue2" will be reported as "following @tw_blue2 succeeded". for example "following @tw_blue2" will be reported as "following @tw_blue2 succeeded".
_sound str: a sound to play if the call is executed properly. _sound str: a sound to play if the call is executed properly.
report_success and report_failure bool: These are self explanatory. True or False. report_success and report_failure bool: These are self explanatory. True or False.
preexec_message str: A message to speak to the user while the method is running, example: "trying to follow x user".""" preexec_message str: A message to speak to the user while the method is running, example: "trying to follow x user"."""
finished = False finished = False
tries = 0 tries = 0
if preexec_message: if preexec_message:
output.speak(preexec_message, True) output.speak(preexec_message, True)
while finished==False and tries < 25: while finished==False and tries < 25:
try: try:
val = getattr(self.twitter, call_name)(*args, **kwargs) val = getattr(self.twitter, call_name)(*args, **kwargs)
finished = True finished = True
except TweepError as e: except TweepError as e:
output.speak(e.reason) output.speak(e.reason)
val = None val = None
if e.error_code != 403 and e.error_code != 404: if e.error_code != 403 and e.error_code != 404:
tries = tries+1 tries = tries+1
time.sleep(5) time.sleep(5)
elif report_failure and hasattr(e, 'reason'): elif report_failure and hasattr(e, 'reason'):
output.speak(_("%s failed. Reason: %s") % (action, e.reason)) output.speak(_("%s failed. Reason: %s") % (action, e.reason))
finished = True finished = True
# except: # except:
# tries = tries + 1 # tries = tries + 1
# time.sleep(5) # time.sleep(5)
if report_success: if report_success:
output.speak(_("%s succeeded.") % action) output.speak(_("%s succeeded.") % action)
if _sound != None: self.sound.play(_sound) if _sound != None: self.sound.play(_sound)
return val return val
def search(self, name, *args, **kwargs): def search(self, name, *args, **kwargs):
""" Search in twitter, passing args and kwargs as arguments to the Twython function.""" """ Search in twitter, passing args and kwargs as arguments to the Twython function."""
tl = self.twitter.search(*args, **kwargs) tl = self.twitter.search(*args, **kwargs)
tl.reverse() tl.reverse()
return tl return tl
# @_require_login # @_require_login
def get_favourites_timeline(self, name, *args, **kwargs): def get_favourites_timeline(self, name, *args, **kwargs):
""" Gets favourites for the authenticated user or a friend or follower. """ Gets favourites for the authenticated user or a friend or follower.
name str: Name for storage in the database. name str: Name for storage in the database.
args and kwargs are passed directly to the Twython function.""" args and kwargs are passed directly to the Twython function."""
tl = self.call_paged("favorites", *args, **kwargs) tl = self.call_paged("favorites", *args, **kwargs)
return self.order_buffer(name, tl) return self.order_buffer(name, tl)
def call_paged(self, update_function, *args, **kwargs): def call_paged(self, update_function, *args, **kwargs):
""" Makes a call to the Twitter API methods several times. Useful for get methods. """ Makes a call to the Twitter API methods several times. Useful for get methods.
this function is needed for retrieving more than 200 items. this function is needed for retrieving more than 200 items.
update_function str: The function to call. This function must be child of self.twitter update_function str: The function to call. This function must be child of self.twitter
args and kwargs are passed to update_function. args and kwargs are passed to update_function.
returns a list with all items retrieved.""" returns a list with all items retrieved."""
max = 0 max = 0
results = [] results = []
data = getattr(self.twitter, update_function)(count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs) data = getattr(self.twitter, update_function)(count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs)
results.extend(data) results.extend(data)
for i in range(0, max): for i in range(0, max):
if i == 0: max_id = results[-1].id if i == 0: max_id = results[-1].id
else: max_id = results[0].id else: max_id = results[0].id
data = getattr(self.twitter, update_function)(max_id=max_id, count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs) data = getattr(self.twitter, update_function)(max_id=max_id, count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs)
results.extend(data) results.extend(data)
results.reverse() results.reverse()
return results return results
# @_require_login # @_require_login
def get_user_info(self): def get_user_info(self):
""" Retrieves some information required by TWBlue for setup.""" """ Retrieves some information required by TWBlue for setup."""
f = self.twitter.get_settings() f = self.twitter.get_settings()
sn = f["screen_name"] sn = f["screen_name"]
self.settings["twitter"]["user_name"] = sn self.settings["twitter"]["user_name"] = sn
self.db["user_name"] = sn self.db["user_name"] = sn
self.db["user_id"] = self.twitter.get_user(screen_name=sn).id self.db["user_id"] = self.twitter.get_user(screen_name=sn).id
try: try:
self.db["utc_offset"] = f["time_zone"]["utc_offset"] self.db["utc_offset"] = f["time_zone"]["utc_offset"]
except KeyError: except KeyError:
self.db["utc_offset"] = -time.timezone self.db["utc_offset"] = -time.timezone
# Get twitter's supported languages and save them in a global variable # Get twitter's supported languages and save them in a global variable
#so we won't call to this method once per session. #so we won't call to this method once per session.
if len(application.supported_languages) == 0: if len(application.supported_languages) == 0:
application.supported_languages = self.twitter.supported_languages() application.supported_languages = self.twitter.supported_languages()
self.get_lists() self.get_lists()
self.get_muted_users() self.get_muted_users()
self.settings.write() self.settings.write()
# @_require_login # @_require_login
def get_lists(self): def get_lists(self):
""" Gets the lists that the user is subscribed to and stores them in the database. Returns None.""" """ Gets the lists that the user is subscribed to and stores them in the database. Returns None."""
self.db["lists"] = self.twitter.lists_all(reverse=True) self.db["lists"] = self.twitter.lists_all(reverse=True)
# @_require_login # @_require_login
def get_muted_users(self): def get_muted_users(self):
""" Gets muted users (oh really?).""" """ Gets muted users (oh really?)."""
self.db["muted_users"] = self.twitter.mutes_ids() self.db["muted_users"] = self.twitter.mutes_ids()
# @_require_login # @_require_login
def get_stream(self, name, function, *args, **kwargs): def get_stream(self, name, function, *args, **kwargs):
""" Retrieves the items for a regular stream. """ Retrieves the items for a regular stream.
name str: Name to save items to the database. name str: Name to save items to the database.
function str: A function to get the items.""" function str: A function to get the items."""
last_id = -1 last_id = -1
if name in self.db: if name in self.db:
try: try:
if self.db[name][0]["id"] > self.db[name][-1]["id"]: if self.db[name][0]["id"] > self.db[name][-1]["id"]:
last_id = self.db[name][0]["id"] last_id = self.db[name][0]["id"]
else: else:
last_id = self.db[name][-1]["id"] last_id = self.db[name][-1]["id"]
except IndexError: except IndexError:
pass pass
tl = self.call_paged(function, sinze_id=last_id, *args, **kwargs) tl = self.call_paged(function, sinze_id=last_id, *args, **kwargs)
self.order_buffer(name, tl) self.order_buffer(name, tl)
def get_cursored_stream(self, name, function, items="users", get_previous=False, *args, **kwargs): def get_cursored_stream(self, name, function, items="users", get_previous=False, *args, **kwargs):
""" Gets items for API calls that require using cursors to paginate the results. """ Gets items for API calls that require using cursors to paginate the results.
name str: Name to save it in the database. name str: Name to save it in the database.
function str: Function that provides the items. function str: Function that provides the items.
items: When the function returns the list with results, items will tell how the order function should be look. for example get_followers_list returns a list and users are under list["users"], here the items should point to "users". items: When the function returns the list with results, items will tell how the order function should be look. for example get_followers_list returns a list and users are under list["users"], here the items should point to "users".
get_previous bool: wether this function will be used to get previous items in a buffer or load the buffer from scratch. get_previous bool: wether this function will be used to get previous items in a buffer or load the buffer from scratch.
returns number of items retrieved.""" returns number of items retrieved."""
items_ = [] items_ = []
try: try:
if "cursor" in self.db[name] and get_previous: if "cursor" in self.db[name] and get_previous:
cursor = self.db[name]["cursor"] cursor = self.db[name]["cursor"]
else: else:
cursor = -1 cursor = -1
except KeyError: except KeyError:
cursor = -1 cursor = -1
if cursor != -1: if cursor != -1:
tl = getattr(self.twitter, function)(cursor=cursor, count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs) tl = getattr(self.twitter, function)(cursor=cursor, count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs)
else: else:
tl = getattr(self.twitter, function)(count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs) tl = getattr(self.twitter, function)(count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs)
tl[items].reverse() tl[items].reverse()
num = self.order_cursored_buffer(name, tl[items]) num = self.order_cursored_buffer(name, tl[items])
# Recently, Twitter's new endpoints have cursor if there are more results. # Recently, Twitter's new endpoints have cursor if there are more results.
if "next_cursor" in tl: if "next_cursor" in tl:
self.db[name]["cursor"] = tl["next_cursor"] self.db[name]["cursor"] = tl["next_cursor"]
else: else:
self.db[name]["cursor"] = 0 self.db[name]["cursor"] = 0
return num return num
def check_connection(self): def check_connection(self):
""" Restart the Twitter object every 5 executions. It is useful for dealing with requests timeout and other oddities.""" """ Restart the Twitter object every 5 executions. It is useful for dealing with requests timeout and other oddities."""
log.debug("Executing check connection...") log.debug("Executing check connection...")
self.counter += 1 self.counter += 1
if self.counter >= 4: if self.counter >= 4:
log.debug("Restarting connection after 5 minutes.") log.debug("Restarting connection after 5 minutes.")
del self.twitter del self.twitter
self.logged = False self.logged = False
self.login(False) self.login(False)
self.counter = 0 self.counter = 0
def check_quoted_status(self, tweet): def check_quoted_status(self, tweet):
""" Helper for get_quoted_tweet. Get a quoted status inside a tweet and create a special tweet with all info available. """ Helper for get_quoted_tweet. Get a quoted status inside a tweet and create a special tweet with all info available.
tweet dict: A tweet dictionary. tweet dict: A tweet dictionary.
Returns a quoted tweet or the original tweet if is not a quote""" Returns a quoted tweet or the original tweet if is not a quote"""
status = tweets.is_long(tweet) status = tweets.is_long(tweet)
if status != False and config.app["app-settings"]["handle_longtweets"]: if status != False and config.app["app-settings"]["handle_longtweets"]:
quoted_tweet = self.get_quoted_tweet(tweet) quoted_tweet = self.get_quoted_tweet(tweet)
return quoted_tweet return quoted_tweet
return tweet return tweet
def get_quoted_tweet(self, tweet): def get_quoted_tweet(self, tweet):
""" Process a tweet and extract all information related to the quote. """ """ Process a tweet and extract all information related to the quote. """
quoted_tweet = tweet quoted_tweet = tweet
if hasattr(tweet, "full_text"): if hasattr(tweet, "full_text"):
value = "full_text" value = "full_text"
else: else:
value = "text" value = "text"
setattr(quoted_tweet, value, utils.expand_urls(getattr(quoted_tweet, value), quoted_tweet.entities)) setattr(quoted_tweet, value, utils.expand_urls(getattr(quoted_tweet, value), quoted_tweet.entities))
if quoted_tweet.is_quote_status == True and hasattr(quoted_tweet, "quoted_status"): if quoted_tweet.is_quote_status == True and hasattr(quoted_tweet, "quoted_status"):
original_tweet = quoted_tweet.quoted_status original_tweet = quoted_tweet.quoted_status
elif hasattr(quoted_tweet, "retweeted_status") and quoted_tweet.retweeted_status.is_quote_status == True and hasattr(quoted_tweet.retweeted_status, "quoted_status"): elif hasattr(quoted_tweet, "retweeted_status") and quoted_tweet.retweeted_status.is_quote_status == True and hasattr(quoted_tweet.retweeted_status, "quoted_status"):
original_tweet = quoted_tweet.retweeted_status.quoted_status original_tweet = quoted_tweet.retweeted_status.quoted_status
else: else:
return quoted_tweet return quoted_tweet
original_tweet = self.check_long_tweet(original_tweet) original_tweet = self.check_long_tweet(original_tweet)
if hasattr(original_tweet, "full_text"): if hasattr(original_tweet, "full_text"):
value = "full_text" value = "full_text"
elif hasattr(original_tweet, "message"): elif hasattr(original_tweet, "message"):
value = "message" value = "message"
else: else:
value = "text" value = "text"
setattr(original_tweet, value, utils.expand_urls(getattr(original_tweet, value), original_tweet.entities)) setattr(original_tweet, value, utils.expand_urls(getattr(original_tweet, value), original_tweet.entities))
return compose.compose_quoted_tweet(quoted_tweet, original_tweet) return compose.compose_quoted_tweet(quoted_tweet, original_tweet)
def check_long_tweet(self, tweet): def check_long_tweet(self, tweet):
""" Process a tweet and add extra info if it's a long tweet made with Twyshort. """ Process a tweet and add extra info if it's a long tweet made with Twyshort.
tweet dict: a tweet object. tweet dict: a tweet object.
returns a tweet with a new argument message, or original tweet if it's not a long tweet.""" returns a tweet with a new argument message, or original tweet if it's not a long tweet."""
long = twishort.is_long(tweet) long = twishort.is_long(tweet)
if long != False and config.app["app-settings"]["handle_longtweets"]: if long != False and config.app["app-settings"]["handle_longtweets"]:
message = twishort.get_full_text(long) message = twishort.get_full_text(long)
if hasattr(tweet, "quoted_status"): if hasattr(tweet, "quoted_status"):
tweet.quoted_status.message = message tweet.quoted_status.message = message
if tweet.quoted_status.message == False: return False if tweet.quoted_status.message == False: return False
tweet.quoted_status.twishort = True tweet.quoted_status.twishort = True
for i in tweet.quoted_status.entities["user_mentions"]: for i in tweet.quoted_status.entities["user_mentions"]:
if "@%s" % (i["screen_name"]) not in tweet.quoted_status.message and i["screen_name"] != tweet.user.screen_name: if "@%s" % (i["screen_name"]) not in tweet.quoted_status.message and i["screen_name"] != tweet.user.screen_name:
if hasattr(tweet.quoted_status, "retweeted_status") and tweet.retweeted_status.user.screen_name == i["screen_name"]: if hasattr(tweet.quoted_status, "retweeted_status") and tweet.retweeted_status.user.screen_name == i["screen_name"]:
continue continue
tweet.quoted_status.message = u"@%s %s" % (i["screen_name"], tweet.message) tweet.quoted_status.message = u"@%s %s" % (i["screen_name"], tweet.message)
else: else:
tweet.message = message tweet.message = message
if tweet.message == False: return False if tweet.message == False: return False
tweet.twishort = True tweet.twishort = True
for i in tweet.entities["user_mentions"]: for i in tweet.entities["user_mentions"]:
if "@%s" % (i["screen_name"]) not in tweet.message and i["screen_name"] != tweet.user.screen_name: if "@%s" % (i["screen_name"]) not in tweet.message and i["screen_name"] != tweet.user.screen_name:
if hasattr(tweet, "retweeted_status") and tweet.retweeted_status.user.screen_name == i["screen_name"]: if hasattr(tweet, "retweeted_status") and tweet.retweeted_status.user.screen_name == i["screen_name"]:
continue continue
return tweet return tweet
def get_user(self, id): def get_user(self, id):
""" Returns an user object associated with an ID. """ Returns an user object associated with an ID.
id str: User identifier, provided by Twitter. id str: User identifier, provided by Twitter.
returns a tweepy user object.""" returns a tweepy user object."""
if ("users" in self.db) == False or (id in self.db["users"]) == False: if ("users" in self.db) == False or (id in self.db["users"]) == False:
try: try:
user = self.twitter.get_user(id=id) user = self.twitter.get_user(id=id)
except TweepError as err: except TweepError as err:
user = UserModel(None) user = UserModel(None)
user.screen_name = "deleted_user" user.screen_name = "deleted_user"
user.id = id user.id = id
user.name = _("Deleted account") user.name = _("Deleted account")
user.id_str = id user.id_str = id
self.db["users"][user.id_str] = user self.db["users"][user.id_str] = user
return user return user
else: else:
return self.db["users"][id] return self.db["users"][id]
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.
screen_name str: User name, such as tw_blue2, provided by Twitter. screen_name str: User name, such as tw_blue2, provided by Twitter.
returns an user ID.""" returns an user ID."""
if ("users" in self.db) == False: if ("users" in self.db) == False:
user = utils.if_user_exists(self.twitter, screen_name) user = utils.if_user_exists(self.twitter, screen_name)
self.db["users"][user["id_str"]] = user self.db["users"][user["id_str"]] = user
return user["id_str"] return user["id_str"]
else: else:
for i in list(self.db["users"].keys()): for i in list(self.db["users"].keys()):
if self.db["users"][i].screen_name == screen_name: if self.db["users"][i].screen_name == screen_name:
return self.db["users"][i].id_str return self.db["users"][i].id_str
user = utils.if_user_exists(self.twitter, screen_name) user = utils.if_user_exists(self.twitter, screen_name)
self.db["users"][user.id_str] = user self.db["users"][user.id_str] = user
return user.id_str return user.id_str
def save_users(self, user_ids): def save_users(self, user_ids):
""" Adds all new users to the users database. """ """ Adds all new users to the users database. """
if len(user_ids) == 0: if len(user_ids) == 0:
return return
log.debug("Received %d user IDS to be added in the database." % (len(user_ids))) log.debug("Received %d user IDS to be added in the database." % (len(user_ids)))
users_to_retrieve = [user_id for user_id in user_ids if user_id not in self.db["users"]] users_to_retrieve = [user_id for user_id in user_ids if user_id not in self.db["users"]]
# Remove duplicates # Remove duplicates
users_to_retrieve = list(dict.fromkeys(users_to_retrieve)) users_to_retrieve = list(dict.fromkeys(users_to_retrieve))
if len(users_to_retrieve) == 0: if len(users_to_retrieve) == 0:
return return
log.debug("TWBlue will get %d new users from Twitter." % (len(users_to_retrieve))) log.debug("TWBlue will get %d new users from Twitter." % (len(users_to_retrieve)))
users = self.twitter.lookup_users(user_ids=users_to_retrieve, tweet_mode="extended") users = self.twitter.lookup_users(user_ids=users_to_retrieve, tweet_mode="extended")
for user in users: for user in users:
self.db["users"][user.id_str] = user self.db["users"][user.id_str] = user
log.debug("Added %d new users" % (len(users))) log.debug("Added %d new users" % (len(users)))

View File

@ -19,198 +19,198 @@ url_re2 = re.compile("(?:\w+://|www\.)[^ ,.?!#%=+][^ \\n\\t]*")
bad_chars = '\'\\\n.,[](){}:;"' bad_chars = '\'\\\n.,[](){}:;"'
def find_urls_in_text(text): def find_urls_in_text(text):
return url_re2.findall(text) return url_re2.findall(text)
def find_urls (tweet): def find_urls (tweet):
urls = [] urls = []
# Let's add URLS from tweet entities. # Let's add URLS from tweet entities.
if hasattr(tweet, "message_create"): if hasattr(tweet, "message_create"):
entities = tweet.message_create["message_data"]["entities"] entities = tweet.message_create["message_data"]["entities"]
else: else:
entities = tweet.entities entities = tweet.entities
for i in entities["urls"]: for i in entities["urls"]:
if i["expanded_url"] not in urls: if i["expanded_url"] not in urls:
urls.append(i["expanded_url"]) urls.append(i["expanded_url"])
if hasattr(tweet, "quoted_status"): if hasattr(tweet, "quoted_status"):
for i in tweet.quoted_status.entities["urls"]: for i in tweet.quoted_status.entities["urls"]:
if i["expanded_url"] not in urls: if i["expanded_url"] not in urls:
urls.append(i["expanded_url"]) urls.append(i["expanded_url"])
if hasattr(tweet, "retweeted_status"): if hasattr(tweet, "retweeted_status"):
for i in tweet.retweeted_status.entities["urls"]: for i in tweet.retweeted_status.entities["urls"]:
if i["expanded_url"] not in urls: if i["expanded_url"] not in urls:
urls.append(i["expanded_url"]) urls.append(i["expanded_url"])
if hasattr(tweet["retweeted_status"], "quoted_status"): if hasattr(tweet["retweeted_status"], "quoted_status"):
for i in tweet.retweeted_status.quoted_status.entities["urls"]: for i in tweet.retweeted_status.quoted_status.entities["urls"]:
if i["expanded_url"] not in urls: if i["expanded_url"] not in urls:
urls.append(i["expanded_url"]) urls.append(i["expanded_url"])
if hasattr(tweet, "message"): if hasattr(tweet, "message"):
i = "message" i = "message"
elif hasattr(tweet, "full_text"): elif hasattr(tweet, "full_text"):
i = "full_text" i = "full_text"
else: else:
i = "text" i = "text"
if hasattr(tweet, "message_create"): if hasattr(tweet, "message_create"):
extracted_urls = find_urls_in_text(tweet.message_create["message_data"]["text"]) extracted_urls = find_urls_in_text(tweet.message_create["message_data"]["text"])
else: else:
extracted_urls = find_urls_in_text(getattr(tweet, i)) extracted_urls = find_urls_in_text(getattr(tweet, i))
# Don't include t.co links (mostly they are photos or shortened versions of already added URLS). # Don't include t.co links (mostly they are photos or shortened versions of already added URLS).
for i in extracted_urls: for i in extracted_urls:
if i not in urls and "https://t.co" not in i: if i not in urls and "https://t.co" not in i:
urls.append(i) urls.append(i)
return urls return urls
def find_item(id, listItem): def find_item(id, listItem):
for i in range(0, len(listItem)): for i in range(0, len(listItem)):
if listItem[i].id == id: return i if listItem[i].id == id: return i
return None return None
def find_list(name, lists): def find_list(name, lists):
for i in range(0, len(lists)): for i in range(0, len(lists)):
if lists[i].name == name: return lists[i].id if lists[i].name == name: return lists[i].id
def is_audio(tweet): def is_audio(tweet):
try: try:
if len(find_urls(tweet)) < 1: if len(find_urls(tweet)) < 1:
return False return False
if hasattr(tweet, "message_create"): if hasattr(tweet, "message_create"):
entities = tweet.message_create["message_data"]["entities"] entities = tweet.message_create["message_data"]["entities"]
else: else:
entities = tweet.entities entities = tweet.entities
if len(entities["hashtags"]) > 0: if len(entities["hashtags"]) > 0:
for i in entities["hashtags"]: for i in entities["hashtags"]:
if i["text"] == "audio": if i["text"] == "audio":
return True return True
except IndexError: except IndexError:
print(tweet.entities["hashtags"]) print(tweet.entities["hashtags"])
log.exception("Exception while executing is_audio hashtag algorithm") log.exception("Exception while executing is_audio hashtag algorithm")
def is_geocoded(tweet): def is_geocoded(tweet):
if hasattr(tweet, "coordinates") and tweet.coordinates != None: if hasattr(tweet, "coordinates") and tweet.coordinates != None:
return True return True
def is_media(tweet): def is_media(tweet):
if hasattr(tweet, "message_create"): if hasattr(tweet, "message_create"):
entities = tweet.message_create["message_data"]["entities"] entities = tweet.message_create["message_data"]["entities"]
else: else:
entities = tweet.entities entities = tweet.entities
if entities.get("media") == None: if entities.get("media") == None:
return False return False
for i in entities["media"]: for i in entities["media"]:
if i.get("type") != None and i.get("type") == "photo": if i.get("type") != None and i.get("type") == "photo":
return True return True
return False return False
def get_all_mentioned(tweet, conf, field="screen_name"): def get_all_mentioned(tweet, conf, field="screen_name"):
""" Gets all users that have been mentioned.""" """ Gets all users that have been mentioned."""
results = [] results = []
for i in tweet.entities["user_mentions"]: for i in tweet.entities["user_mentions"]:
if i["screen_name"] != conf["user_name"] and i["screen_name"] != tweet.user.screen_name: if i["screen_name"] != conf["user_name"] and i["screen_name"] != tweet.user.screen_name:
if i.get(field) not in results: if i.get(field) not in results:
results.append(i.get(field)) results.append(i.get(field))
return results return results
def get_all_users(tweet, conf): def get_all_users(tweet, conf):
string = [] string = []
if hasattr(tweet, "retweeted_status"): if hasattr(tweet, "retweeted_status"):
string.append(tweet.user.screen_name) string.append(tweet.user.screen_name)
tweet = tweet.retweeted_status tweet = tweet.retweeted_status
if hasattr(tweet, "sender"): if hasattr(tweet, "sender"):
string.append(tweet.sender.screen_name) string.append(tweet.sender.screen_name)
else: else:
if tweet.user.screen_name != conf["user_name"]: if tweet.user.screen_name != conf["user_name"]:
string.append(tweet.user.screen_name) string.append(tweet.user.screen_name)
for i in tweet.entities["user_mentions"]: for i in tweet.entities["user_mentions"]:
if i["screen_name"] != conf["user_name"] and i["screen_name"] != tweet.user.screen_name: if i["screen_name"] != conf["user_name"] and i["screen_name"] != tweet.user.screen_name:
if i["screen_name"] not in string: if i["screen_name"] not in string:
string.append(i["screen_name"]) string.append(i["screen_name"])
if len(string) == 0: if len(string) == 0:
string.append(tweet.user.screen_name) string.append(tweet.user.screen_name)
return string return string
def if_user_exists(twitter, user): def if_user_exists(twitter, user):
try: try:
data = twitter.get_user(screen_name=user) data = twitter.get_user(screen_name=user)
return data return data
except TweepError as err: except TweepError as err:
if err.api_code == 50: if err.api_code == 50:
return None return None
else: else:
return user return user
def is_allowed(tweet, settings, buffer_name): def is_allowed(tweet, settings, buffer_name):
clients = settings["twitter"]["ignored_clients"] clients = settings["twitter"]["ignored_clients"]
if hasattr(tweet, "sender"): return True if hasattr(tweet, "sender"): return True
allowed = True allowed = True
tweet_data = {} tweet_data = {}
if hasattr(tweet, "retweeted_status"): if hasattr(tweet, "retweeted_status"):
tweet_data["retweet"] = True tweet_data["retweet"] = True
if tweet.in_reply_to_status_id_str != None: if tweet.in_reply_to_status_id_str != None:
tweet_data["reply"] = True tweet_data["reply"] = True
if hasattr(tweet, "quoted_status"): if hasattr(tweet, "quoted_status"):
tweet_data["quote"] = True tweet_data["quote"] = True
if hasattr(tweet, "retweeted_status"): if hasattr(tweet, "retweeted_status"):
tweet = tweet.retweeted_status tweet = tweet.retweeted_status
source = tweet.source source = tweet.source
for i in clients: for i in clients:
if i.lower() == source.lower(): if i.lower() == source.lower():
return False return False
return filter_tweet(tweet, tweet_data, settings, buffer_name) return filter_tweet(tweet, tweet_data, settings, buffer_name)
def filter_tweet(tweet, tweet_data, settings, buffer_name): def filter_tweet(tweet, tweet_data, settings, buffer_name):
if hasattr(tweet, "full_text"): if hasattr(tweet, "full_text"):
value = "full_text" value = "full_text"
else: else:
value = "text" value = "text"
for i in settings["filters"]: for i in settings["filters"]:
if settings["filters"][i]["in_buffer"] == buffer_name: if settings["filters"][i]["in_buffer"] == buffer_name:
regexp = settings["filters"][i]["regexp"] regexp = settings["filters"][i]["regexp"]
word = settings["filters"][i]["word"] word = settings["filters"][i]["word"]
# Added if/else for compatibility reasons. # Added if/else for compatibility reasons.
if "allow_rts" in settings["filters"][i]: if "allow_rts" in settings["filters"][i]:
allow_rts = settings["filters"][i]["allow_rts"] allow_rts = settings["filters"][i]["allow_rts"]
else: else:
allow_rts = "True" allow_rts = "True"
if "allow_quotes" in settings["filters"][i]: if "allow_quotes" in settings["filters"][i]:
allow_quotes = settings["filters"][i]["allow_quotes"] allow_quotes = settings["filters"][i]["allow_quotes"]
else: else:
allow_quotes = "True" allow_quotes = "True"
if "allow_replies" in settings["filters"][i]: if "allow_replies" in settings["filters"][i]:
allow_replies = settings["filters"][i]["allow_replies"] allow_replies = settings["filters"][i]["allow_replies"]
else: else:
allow_replies = "True" allow_replies = "True"
if allow_rts == "False" and "retweet" in tweet_data: if allow_rts == "False" and "retweet" in tweet_data:
return False return False
if allow_quotes == "False" and "quote" in tweet_data: if allow_quotes == "False" and "quote" in tweet_data:
return False return False
if allow_replies == "False" and "reply" in tweet_data: if allow_replies == "False" and "reply" in tweet_data:
return False return False
if word != "" and settings["filters"][i]["if_word_exists"]: if word != "" and settings["filters"][i]["if_word_exists"]:
if word in getattr(tweet, value): if word in getattr(tweet, value):
return False return False
elif word != "" and settings["filters"][i]["if_word_exists"] == False: elif word != "" and settings["filters"][i]["if_word_exists"] == False:
if word not in getattr(tweet, value): if word not in getattr(tweet, value):
return False return False
if settings["filters"][i]["in_lang"] == "True": if settings["filters"][i]["in_lang"] == "True":
if getattr(tweet, lang) not in settings["filters"][i]["languages"]: if getattr(tweet, lang) not in settings["filters"][i]["languages"]:
return False return False
elif settings["filters"][i]["in_lang"] == "False": elif settings["filters"][i]["in_lang"] == "False":
if tweet.lang in settings["filters"][i]["languages"]: if tweet.lang in settings["filters"][i]["languages"]:
return False return False
return True return True
def twitter_error(error): def twitter_error(error):
if error.api_code == 179: if error.api_code == 179:
msg = _(u"Sorry, you are not authorised to see this status.") msg = _(u"Sorry, you are not authorised to see this status.")
elif error.api_code == 144: elif error.api_code == 144:
msg = _(u"No status found with that ID") msg = _(u"No status found with that ID")
else: else:
msg = _(u"Error code {0}").format(error.api_code,) msg = _(u"Error code {0}").format(error.api_code,)
output.speak(msg) output.speak(msg)
def expand_urls(text, entities): def expand_urls(text, entities):
""" Expand all URLS present in text with information found in entities""" """ Expand all URLS present in text with information found in entities"""
urls = find_urls_in_text(text) urls = find_urls_in_text(text)
for url in entities["urls"]: for url in entities["urls"]:
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

View File

@ -1,18 +1,18 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import wx import wx
class authorisationDialog(wx.Dialog): class authorisationDialog(wx.Dialog):
def __init__(self): def __init__(self):
super(authorisationDialog, self).__init__(parent=None, title=_(u"Authorising account...")) super(authorisationDialog, self).__init__(parent=None, title=_(u"Authorising account..."))
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
static = wx.StaticText(panel, wx.NewId(), _(u"Enter your PIN code here")) static = wx.StaticText(panel, wx.NewId(), _(u"Enter your PIN code here"))
self.text = wx.TextCtrl(panel, -1) self.text = wx.TextCtrl(panel, -1)
self.ok = wx.Button(panel, wx.ID_OK) self.ok = wx.Button(panel, wx.ID_OK)
self.cancel = wx.Button(panel, wx.ID_CANCEL) self.cancel = wx.Button(panel, wx.ID_CANCEL)
sizer.Add(self.text, 0, wx.ALL, 5) sizer.Add(self.text, 0, wx.ALL, 5)
sizer.Add(self.cancel, 0, wx.ALL, 5) sizer.Add(self.cancel, 0, wx.ALL, 5)
panel.SetSizer(sizer) panel.SetSizer(sizer)
min = sizer.CalcMin() min = sizer.CalcMin()
self.SetClientSize(min) self.SetClientSize(min)

View File

@ -7,44 +7,44 @@ from cx_Freeze import setup, Executable
from requests import certs from requests import certs
def get_architecture_files(): def get_architecture_files():
if platform.architecture()[0][:2] == "32": if platform.architecture()[0][:2] == "32":
return ["../windows-dependencies/x86/oggenc2.exe", "../windows-dependencies/x86/bootstrap.exe", "../windows-dependencies/x86/libvlc.dll", "../windows-dependencies/x86/libvlccore.dll", "../windows-dependencies/x86/plugins", ["../windows-dependencies/dictionaries", "lib/enchant/data/mingw32/share/enchant/hunspell"], ["../windows-dependencies/x86/Microsoft.VC142.CRT", "."], ["../windows-dependencies/x86/Microsoft.VC142.MFC", "."]] return ["../windows-dependencies/x86/oggenc2.exe", "../windows-dependencies/x86/bootstrap.exe", "../windows-dependencies/x86/libvlc.dll", "../windows-dependencies/x86/libvlccore.dll", "../windows-dependencies/x86/plugins", ["../windows-dependencies/dictionaries", "lib/enchant/data/mingw32/share/enchant/hunspell"], ["../windows-dependencies/x86/Microsoft.VC142.CRT", "."], ["../windows-dependencies/x86/Microsoft.VC142.MFC", "."]]
elif platform.architecture()[0][:2] == "64": elif platform.architecture()[0][:2] == "64":
return ["../windows-dependencies/x64/oggenc2.exe", "../windows-dependencies/x64/bootstrap.exe", "../windows-dependencies/x64/libvlc.dll", "../windows-dependencies/x64/libvlccore.dll", "../windows-dependencies/x64/plugins", ["../windows-dependencies/dictionaries", "lib/enchant/data/mingw64/share/enchant/hunspell"], ["../windows-dependencies/x64/Microsoft.VC142.CRT", "."], ["../windows-dependencies/x64/Microsoft.VC142.MFC", "."]] return ["../windows-dependencies/x64/oggenc2.exe", "../windows-dependencies/x64/bootstrap.exe", "../windows-dependencies/x64/libvlc.dll", "../windows-dependencies/x64/libvlccore.dll", "../windows-dependencies/x64/plugins", ["../windows-dependencies/dictionaries", "lib/enchant/data/mingw64/share/enchant/hunspell"], ["../windows-dependencies/x64/Microsoft.VC142.CRT", "."], ["../windows-dependencies/x64/Microsoft.VC142.MFC", "."]]
def find_sound_lib_datafiles(): def find_sound_lib_datafiles():
import os import os
import platform import platform
import sound_lib import sound_lib
path = os.path.join(sound_lib.__path__[0], 'lib') path = os.path.join(sound_lib.__path__[0], 'lib')
if platform.architecture()[0] == '32bit' or platform.system() == 'Darwin': if platform.architecture()[0] == '32bit' or platform.system() == 'Darwin':
arch = 'x86' arch = 'x86'
else: else:
arch = 'x64' arch = 'x64'
dest_dir = os.path.join('sound_lib', 'lib', arch) dest_dir = os.path.join('sound_lib', 'lib', arch)
source = os.path.join(path, arch) source = os.path.join(path, arch)
return (source, dest_dir) return (source, dest_dir)
def find_accessible_output2_datafiles(): def find_accessible_output2_datafiles():
import os import os
import accessible_output2 import accessible_output2
path = os.path.join(accessible_output2.__path__[0], 'lib') path = os.path.join(accessible_output2.__path__[0], 'lib')
dest_dir = os.path.join('accessible_output2', 'lib') dest_dir = os.path.join('accessible_output2', 'lib')
return (path, dest_dir) return (path, dest_dir)
base = None base = None
if sys.platform == 'win32': if sys.platform == 'win32':
base = 'Win32GUI' base = 'Win32GUI'
build_exe_options = dict( 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=True,
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"],
) )
executables = [ executables = [
Executable('main.py', base=base, targetName="twblue") Executable('main.py', base=base, targetName="twblue")

View File

@ -15,11 +15,11 @@ from audio_services import youtube_utils
import application import application
system = platform.system() system = platform.system()
if system=="Windows" and not hasattr(sys, 'frozen'): # We are running from source on Windows if system=="Windows" and not hasattr(sys, 'frozen'): # We are running from source on Windows
current_dir=os.getcwd() current_dir=os.getcwd()
os.chdir(os.environ['PYTHON_VLC_MODULE_PATH']) os.chdir(os.environ['PYTHON_VLC_MODULE_PATH'])
import vlc import vlc
if system=="Windows" and not hasattr(sys, 'frozen'): # Restore the original folder if system=="Windows" and not hasattr(sys, 'frozen'): # Restore the original folder
os.chdir(current_dir) os.chdir(current_dir)
import sound_lib.output, sound_lib.input, sound_lib.stream, sound_lib.recording import sound_lib.output, sound_lib.input, sound_lib.stream, sound_lib.recording
from mysc.repeating_timer import RepeatingTimer from mysc.repeating_timer import RepeatingTimer
from mysc.thread_utils import call_threaded from mysc.thread_utils import call_threaded
@ -29,132 +29,132 @@ URLPlayer = None
log = original_logger.getLogger("sound") log = original_logger.getLogger("sound")
def setup(): def setup():
global URLPlayer global URLPlayer
if not URLPlayer: if not URLPlayer:
log.debug("creating stream URL player...") log.debug("creating stream URL player...")
URLPlayer = URLStream() URLPlayer = URLStream()
def recode_audio(filename, quality=4.5): def recode_audio(filename, quality=4.5):
global system global system
if system == "Windows": subprocess.call(r'"%s" -q %r "%s"' % (os.path.join(paths.app_path(), 'oggenc2.exe'), quality, filename)) if system == "Windows": subprocess.call(r'"%s" -q %r "%s"' % (os.path.join(paths.app_path(), 'oggenc2.exe'), quality, filename))
def recording(filename): def recording(filename):
# try: # try:
val = sound_lib.recording.WaveRecording(filename=filename) val = sound_lib.recording.WaveRecording(filename=filename)
# except sound_lib.main.BassError: # except sound_lib.main.BassError:
# sound_lib.input.Input() # sound_lib.input.Input()
# val = sound_lib.recording.WaveRecording(filename=filename) # val = sound_lib.recording.WaveRecording(filename=filename)
return val return val
class soundSystem(object): class soundSystem(object):
def check_soundpack(self): def check_soundpack(self):
""" Checks if the folder where live the current soundpack exists.""" """ Checks if the folder where live the current soundpack exists."""
self.soundpack_OK = False self.soundpack_OK = False
if os.path.exists(os.path.join(paths.sound_path(), self.config["current_soundpack"])): if os.path.exists(os.path.join(paths.sound_path(), self.config["current_soundpack"])):
self.path = os.path.join(paths.sound_path(), self.config["current_soundpack"]) self.path = os.path.join(paths.sound_path(), self.config["current_soundpack"])
self.soundpack_OK = True self.soundpack_OK = True
elif os.path.exists(os.path.join(paths.sound_path(), "default")): elif os.path.exists(os.path.join(paths.sound_path(), "default")):
log.error("The soundpack does not exist, using default...") log.error("The soundpack does not exist, using default...")
self.path = os.path.join(paths.sound_path(), "default") self.path = os.path.join(paths.sound_path(), "default")
self.soundpack_OK = True self.soundpack_OK = True
else: else:
log.error("The current soundpack could not be found and the default soundpack has been deleted, " + application.name + " will not play sounds.") log.error("The current soundpack could not be found and the default soundpack has been deleted, " + application.name + " will not play sounds.")
self.soundpack_OK = False self.soundpack_OK = False
def __init__(self, soundConfig): def __init__(self, soundConfig):
""" Sound Player.""" """ Sound Player."""
self.config = soundConfig self.config = soundConfig
# Set the output and input default devices. # Set the output and input default devices.
try: try:
self.output = sound_lib.output.Output() self.output = sound_lib.output.Output()
self.input = sound_lib.input.Input() self.input = sound_lib.input.Input()
except: except:
pass pass
# Try to use the selected device from the configuration. It can fail if the machine does not has a mic. # Try to use the selected device from the configuration. It can fail if the machine does not has a mic.
try: try:
log.debug("Setting input and output devices...") log.debug("Setting input and output devices...")
self.output.set_device(self.output.find_device_by_name(self.config["output_device"])) self.output.set_device(self.output.find_device_by_name(self.config["output_device"]))
self.input.set_device(self.input.find_device_by_name(self.config["input_device"])) self.input.set_device(self.input.find_device_by_name(self.config["input_device"]))
except: except:
log.error("Error in input or output devices, using defaults...") log.error("Error in input or output devices, using defaults...")
self.config["output_device"] = "Default" self.config["output_device"] = "Default"
self.config["input_device"] = "Default" self.config["input_device"] = "Default"
self.files = [] self.files = []
self.cleaner = RepeatingTimer(60, self.clear_list) self.cleaner = RepeatingTimer(60, self.clear_list)
self.cleaner.start() self.cleaner.start()
self.check_soundpack() self.check_soundpack()
def clear_list(self): def clear_list(self):
if len(self.files) == 0: return if len(self.files) == 0: return
try: try:
for i in range(0, len(self.files)): for i in range(0, len(self.files)):
if self.files[i].is_playing == False: if self.files[i].is_playing == False:
self.files[i].free() self.files[i].free()
self.files.pop(i) self.files.pop(i)
except IndexError: except IndexError:
pass pass
def play(self, sound, argument=False): def play(self, sound, argument=False):
if self.soundpack_OK == False: return if self.soundpack_OK == False: return
if self.config["session_mute"] == True: return if self.config["session_mute"] == True: return
sound_object = sound_lib.stream.FileStream(file="%s/%s" % (self.path, sound)) sound_object = sound_lib.stream.FileStream(file="%s/%s" % (self.path, sound))
sound_object.volume = float(self.config["volume"]) sound_object.volume = float(self.config["volume"])
self.files.append(sound_object) self.files.append(sound_object)
sound_object.play() sound_object.play()
class URLStream(object): class URLStream(object):
""" URL Stream Player implementation.""" """ URL Stream Player implementation."""
def __init__(self): def __init__(self):
# URL status. Should be True after URL expansion and transformation. # URL status. Should be True after URL expansion and transformation.
self.prepared = False self.prepared = False
log.debug("URL Player initialized") log.debug("URL Player initialized")
# LibVLC controls. # LibVLC controls.
self.instance = vlc.Instance() self.instance = vlc.Instance()
self.player = self.instance.media_player_new() self.player = self.instance.media_player_new()
def prepare(self, url): def prepare(self, url):
""" Takes an URL and prepares it to be streamed. This function will try to unshorten the passed URL and, if needed, to transform it into a valid URL.""" """ Takes an URL and prepares it to be streamed. This function will try to unshorten the passed URL and, if needed, to transform it into a valid URL."""
log.debug("Preparing URL: %s" % (url,)) log.debug("Preparing URL: %s" % (url,))
self.prepared = False self.prepared = False
self.url = url_shortener.unshorten(url) self.url = url_shortener.unshorten(url)
if self.url == None: if self.url == None:
self.url = url self.url = url
log.debug("Expanded URL: %s" % (self.url,)) log.debug("Expanded URL: %s" % (self.url,))
if self.url != None: if self.url != None:
transformer = audio_services.find_url_transformer(self.url) transformer = audio_services.find_url_transformer(self.url)
transformed_url = transformer(self.url) transformed_url = transformer(self.url)
self.url = transformed_url self.url = transformed_url
log.debug("Transformed URL: %s. Prepared" % (self.url,)) log.debug("Transformed URL: %s. Prepared" % (self.url,))
self.prepared = True self.prepared = True
def seek(self, step): def seek(self, step):
pos=self.player.get_time() pos=self.player.get_time()
pos+=step pos+=step
pos=self.player.set_time(pos) pos=self.player.set_time(pos)
def playpause(self): def playpause(self):
if self.player.is_playing() == True: if self.player.is_playing() == True:
self.player.pause() self.player.pause()
else: else:
self.player.play() self.player.play()
def play(self, url=None, volume=1.0, announce=True): def play(self, url=None, volume=1.0, announce=True):
if announce: if announce:
output.speak(_(u"Playing...")) output.speak(_(u"Playing..."))
log.debug("Attempting to play an URL...") log.debug("Attempting to play an URL...")
if url != None: if url != None:
self.prepare(url) self.prepare(url)
if self.prepared == True: if self.prepared == True:
media = self.instance.media_new(self.url) media = self.instance.media_new(self.url)
self.player.set_media(media) self.player.set_media(media)
self.player.audio_set_volume(int(volume*100)) self.player.audio_set_volume(int(volume*100))
self.player.play() self.player.play()
log.debug("played") log.debug("played")
self.prepared=False self.prepared=False
def stop_audio(self): def stop_audio(self):
output.speak(_(u"Stopped."), True) output.speak(_(u"Stopped."), True)
self.player.stop() self.player.stop()

View File

@ -4,10 +4,10 @@ import os.path
import platform import platform
def find_datafiles(): def find_datafiles():
system = platform.system() system = platform.system()
if system == 'Windows': if system == 'Windows':
file_ext = '*.exe' file_ext = '*.exe'
else: else:
file_ext = '*.sh' file_ext = '*.sh'
path = os.path.abspath(os.path.join(__path__[0], 'bootstrappers', file_ext)) path = os.path.abspath(os.path.join(__path__[0], 'bootstrappers', file_ext))
return [('', glob.glob(path))] return [('', glob.glob(path))]

View File

@ -12,116 +12,116 @@ from wxUI import commonMessageDialogs
import widgetUtils import widgetUtils
import webbrowser import webbrowser
try: try:
import czipfile as zipfile import czipfile as zipfile
except ImportError: except ImportError:
import zipfile import zipfile
from platform_utils import paths from platform_utils import paths
def perform_update(endpoint, current_version, app_name='', password=None, update_available_callback=None, progress_callback=None, update_complete_callback=None): def perform_update(endpoint, current_version, app_name='', password=None, update_available_callback=None, progress_callback=None, update_complete_callback=None):
requests_session = create_requests_session(app_name=app_name, version=current_version) requests_session = create_requests_session(app_name=app_name, version=current_version)
available_update = find_update(endpoint, requests_session=requests_session) available_update = find_update(endpoint, requests_session=requests_session)
if not available_update: if not available_update:
logger.debug("No update available") logger.debug("No update available")
return False return False
available_version = float(available_update['current_version']) available_version = float(available_update['current_version'])
if not float(available_version) > float(current_version) or platform.system()+platform.architecture()[0][:2] not in available_update['downloads']: if not float(available_version) > float(current_version) or platform.system()+platform.architecture()[0][:2] not in available_update['downloads']:
logger.debug("No update for this architecture") logger.debug("No update for this architecture")
return False return False
available_description = available_update.get('description', None) available_description = available_update.get('description', None)
available_date = available_update.get('date', None) available_date = available_update.get('date', None)
update_url = available_update ['downloads'][platform.system()+platform.architecture()[0][:2]] update_url = available_update ['downloads'][platform.system()+platform.architecture()[0][:2]]
logger.info("A new update is available. Version %s" % available_version) logger.info("A new update is available. Version %s" % available_version)
donation() donation()
if callable(update_available_callback) and not update_available_callback(version=available_version, description=available_description, date=available_date): #update_available_callback should return a falsy value to stop the process if callable(update_available_callback) and not update_available_callback(version=available_version, description=available_description, date=available_date): #update_available_callback should return a falsy value to stop the process
logger.info("User canceled update.") logger.info("User canceled update.")
return return
base_path = tempfile.mkdtemp() base_path = tempfile.mkdtemp()
download_path = os.path.join(base_path, 'update.zip') download_path = os.path.join(base_path, 'update.zip')
update_path = os.path.join(base_path, 'update') update_path = os.path.join(base_path, 'update')
downloaded = download_update(update_url, download_path, requests_session=requests_session, progress_callback=progress_callback) downloaded = download_update(update_url, download_path, requests_session=requests_session, progress_callback=progress_callback)
extracted = extract_update(downloaded, update_path, password=password) extracted = extract_update(downloaded, update_path, password=password)
bootstrap_path = move_bootstrap(extracted) bootstrap_path = move_bootstrap(extracted)
execute_bootstrap(bootstrap_path, extracted) execute_bootstrap(bootstrap_path, extracted)
logger.info("Update prepared for installation.") logger.info("Update prepared for installation.")
if callable(update_complete_callback): if callable(update_complete_callback):
update_complete_callback() update_complete_callback()
def create_requests_session(app_name=None, version=None): def create_requests_session(app_name=None, version=None):
user_agent = '' user_agent = ''
session = requests.session() session = requests.session()
if app_name: if app_name:
user_agent = ' %s/%r' % (app_name, version) user_agent = ' %s/%r' % (app_name, version)
session.headers['User-Agent'] = session.headers['User-Agent'] + user_agent session.headers['User-Agent'] = session.headers['User-Agent'] + user_agent
return session return session
def find_update(endpoint, requests_session): def find_update(endpoint, requests_session):
response = requests_session.get(endpoint) response = requests_session.get(endpoint)
response.raise_for_status() response.raise_for_status()
content = response.json() content = response.json()
return content return content
def download_update(update_url, update_destination, requests_session, progress_callback=None, chunk_size=io.DEFAULT_BUFFER_SIZE): def download_update(update_url, update_destination, requests_session, progress_callback=None, chunk_size=io.DEFAULT_BUFFER_SIZE):
total_downloaded = total_size = 0 total_downloaded = total_size = 0
with io.open(update_destination, 'w+b') as outfile: with io.open(update_destination, 'w+b') as outfile:
download = requests_session.get(update_url, stream=True) download = requests_session.get(update_url, stream=True)
total_size = int(download.headers.get('content-length', 0)) total_size = int(download.headers.get('content-length', 0))
logger.debug("Total update size: %d" % total_size) logger.debug("Total update size: %d" % total_size)
download.raise_for_status() download.raise_for_status()
for chunk in download.iter_content(chunk_size): for chunk in download.iter_content(chunk_size):
outfile.write(chunk) outfile.write(chunk)
total_downloaded += len(chunk) total_downloaded += len(chunk)
if callable(progress_callback): if callable(progress_callback):
call_callback(progress_callback, total_downloaded, total_size) call_callback(progress_callback, total_downloaded, total_size)
logger.debug("Update downloaded") logger.debug("Update downloaded")
return update_destination return update_destination
def extract_update(update_archive, destination, password=None): def extract_update(update_archive, destination, password=None):
"""Given an update archive, extracts it. Returns the directory to which it has been extracted""" """Given an update archive, extracts it. Returns the directory to which it has been extracted"""
with contextlib.closing(zipfile.ZipFile(update_archive)) as archive: with contextlib.closing(zipfile.ZipFile(update_archive)) as archive:
if password: if password:
archive.setpassword(password) archive.setpassword(password)
archive.extractall(path=destination) archive.extractall(path=destination)
logger.debug("Update extracted") logger.debug("Update extracted")
return destination return destination
def move_bootstrap(extracted_path): def move_bootstrap(extracted_path):
working_path = os.path.abspath(os.path.join(extracted_path, '..')) working_path = os.path.abspath(os.path.join(extracted_path, '..'))
if platform.system() == 'Darwin': if platform.system() == 'Darwin':
extracted_path = os.path.join(extracted_path, 'Contents', 'Resources') extracted_path = os.path.join(extracted_path, 'Contents', 'Resources')
downloaded_bootstrap = os.path.join(extracted_path, bootstrap_name()) downloaded_bootstrap = os.path.join(extracted_path, bootstrap_name())
new_bootstrap_path = os.path.join(working_path, bootstrap_name()) new_bootstrap_path = os.path.join(working_path, bootstrap_name())
os.rename(downloaded_bootstrap, new_bootstrap_path) os.rename(downloaded_bootstrap, new_bootstrap_path)
return new_bootstrap_path return new_bootstrap_path
def execute_bootstrap(bootstrap_path, source_path): def execute_bootstrap(bootstrap_path, source_path):
arguments = r'"%s" "%s" "%s" "%s"' % (os.getpid(), source_path, paths.app_path(), paths.get_executable()) arguments = r'"%s" "%s" "%s" "%s"' % (os.getpid(), source_path, paths.app_path(), paths.get_executable())
if platform.system() == 'Windows': if platform.system() == 'Windows':
import win32api import win32api
win32api.ShellExecute(0, 'open', bootstrap_path, arguments, '', 5) win32api.ShellExecute(0, 'open', bootstrap_path, arguments, '', 5)
else: else:
import subprocess import subprocess
make_executable(bootstrap_path) make_executable(bootstrap_path)
subprocess.Popen(['%s %s' % (bootstrap_path, arguments)], shell=True) subprocess.Popen(['%s %s' % (bootstrap_path, arguments)], shell=True)
logger.info("Bootstrap executed") logger.info("Bootstrap executed")
def bootstrap_name(): def bootstrap_name():
if platform.system() == 'Windows': return 'bootstrap.exe' if platform.system() == 'Windows': return 'bootstrap.exe'
if platform.system() == 'Darwin': return 'bootstrap-mac.sh' if platform.system() == 'Darwin': return 'bootstrap-mac.sh'
return 'bootstrap-lin.sh' return 'bootstrap-lin.sh'
def make_executable(path): def make_executable(path):
import stat import stat
st = os.stat(path) st = os.stat(path)
os.chmod(path, st.st_mode | stat.S_IEXEC) os.chmod(path, st.st_mode | stat.S_IEXEC)
def call_callback(callback, *args, **kwargs): def call_callback(callback, *args, **kwargs):
# try: # try:
callback(*args, **kwargs) callback(*args, **kwargs)
# except: # except:
# logger.exception("Failed calling callback %r with args %r and kwargs %r" % (callback, args, kwargs)) # logger.exception("Failed calling callback %r with args %r and kwargs %r" % (callback, args, kwargs))
def donation(): def donation():
dlg = commonMessageDialogs.donation() dlg = commonMessageDialogs.donation()
if dlg == widgetUtils.YES: if dlg == widgetUtils.YES:
webbrowser.open_new_tab("http://twblue.es/?q=donate") webbrowser.open_new_tab("http://twblue.es/?q=donate")

View File

@ -11,13 +11,13 @@ from .wxUpdater import *
logger = logging.getLogger("updater") logger = logging.getLogger("updater")
def do_update(endpoint=application.update_url): def do_update(endpoint=application.update_url):
try: try:
result = update.perform_update(endpoint=endpoint, current_version=application.version, app_name=application.name, update_available_callback=available_update_dialog, progress_callback=progress_callback, update_complete_callback=update_finished) result = update.perform_update(endpoint=endpoint, current_version=application.version, app_name=application.name, update_available_callback=available_update_dialog, progress_callback=progress_callback, update_complete_callback=update_finished)
except: except:
if endpoint == application.update_url: if endpoint == application.update_url:
logger.error("Update failed! Using mirror URL...") logger.error("Update failed! Using mirror URL...")
return do_update(endpoint=application.mirror_update_url) return do_update(endpoint=application.mirror_update_url)
else: else:
logger.exception("Update failed.") logger.exception("Update failed.")
output.speak("An exception occurred while attempting to update " + application.name + ". If this message persists, contact the " + application.name + " developers. More information about the exception has been written to the error log.",True) output.speak("An exception occurred while attempting to update " + application.name + ". If this message persists, contact the " + application.name + " developers. More information about the exception has been written to the error log.",True)
return result return result

Some files were not shown because too many files have changed in this diff Show More