mirror of
https://github.com/MCV-Software/TWBlue.git
synced 2024-11-22 19:28:09 -06:00
Made code indentation to comply with PEP8
This commit is contained in:
parent
2aaa4eced3
commit
39e1fb017c
@ -5,13 +5,13 @@ name = 'TWBlue'
|
||||
short_name='twblue'
|
||||
snapshot = True
|
||||
if snapshot == False:
|
||||
version = "0.95"
|
||||
update_url = 'https://twblue.es/updates/stable.php'
|
||||
mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json'
|
||||
version = "0.95"
|
||||
update_url = 'https://twblue.es/updates/stable.php'
|
||||
mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json'
|
||||
else:
|
||||
version = "5"
|
||||
update_url = 'https://twblue.es/updates/snapshot.php'
|
||||
mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.json'
|
||||
version = "5"
|
||||
update_url = 'https://twblue.es/updates/snapshot.php'
|
||||
mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.json'
|
||||
authors = ["Manuel Cortéz", "José Manuel Delicado"]
|
||||
authorEmail = "manuel@manuelcortez.net"
|
||||
copyright = "Copyright (C) 2013-2021, Manuel cortéz."
|
||||
|
@ -2,22 +2,22 @@ from __future__ import unicode_literals
|
||||
from functools import wraps
|
||||
|
||||
def matches_url(url):
|
||||
def url_setter(func):
|
||||
@wraps(func)
|
||||
def internal_url_setter(*args, **kwargs):
|
||||
return func(*args, **kwargs)
|
||||
internal_url_setter.url = url
|
||||
return internal_url_setter
|
||||
return url_setter
|
||||
def url_setter(func):
|
||||
@wraps(func)
|
||||
def internal_url_setter(*args, **kwargs):
|
||||
return func(*args, **kwargs)
|
||||
internal_url_setter.url = url
|
||||
return internal_url_setter
|
||||
return url_setter
|
||||
|
||||
def find_url_transformer(url):
|
||||
from audio_services import services
|
||||
funcs = []
|
||||
for i in dir(services):
|
||||
possible = getattr(services, i)
|
||||
if callable(possible) and hasattr(possible, 'url'):
|
||||
funcs.append(possible)
|
||||
for f in funcs:
|
||||
if url.lower().startswith(f.url.lower()):
|
||||
return f
|
||||
return services.convert_generic_audio
|
||||
from audio_services import services
|
||||
funcs = []
|
||||
for i in dir(services):
|
||||
possible = getattr(services, i)
|
||||
if callable(possible) and hasattr(possible, 'url'):
|
||||
funcs.append(possible)
|
||||
for f in funcs:
|
||||
if url.lower().startswith(f.url.lower()):
|
||||
return f
|
||||
return services.convert_generic_audio
|
||||
|
@ -5,37 +5,37 @@ from . import youtube_utils
|
||||
|
||||
@matches_url('https://audioboom.com')
|
||||
def convert_audioboom(url):
|
||||
if "audioboom.com" not in url.lower():
|
||||
raise TypeError('%r is not a valid URL' % url)
|
||||
audio_id = url.split('.com/')[-1]
|
||||
return 'https://audioboom.com/%s.mp3' % audio_id
|
||||
if "audioboom.com" not in url.lower():
|
||||
raise TypeError('%r is not a valid URL' % url)
|
||||
audio_id = url.split('.com/')[-1]
|
||||
return 'https://audioboom.com/%s.mp3' % audio_id
|
||||
|
||||
@matches_url ('https://soundcloud.com/')
|
||||
def convert_soundcloud (url):
|
||||
client_id = "df8113ca95c157b6c9731f54b105b473"
|
||||
with requests.get('http://api.soundcloud.com/resolve.json', client_id=client_id, url=url) as permalink:
|
||||
if permalink.status_code==404:
|
||||
raise TypeError('%r is not a valid URL' % permalink.url)
|
||||
else:
|
||||
resolved_url = permalink.url
|
||||
with requests.get(resolved_url) as track_url:
|
||||
track_data = track_url.json()
|
||||
client_id = "df8113ca95c157b6c9731f54b105b473"
|
||||
with requests.get('http://api.soundcloud.com/resolve.json', client_id=client_id, url=url) as permalink:
|
||||
if permalink.status_code==404:
|
||||
raise TypeError('%r is not a valid URL' % permalink.url)
|
||||
else:
|
||||
resolved_url = permalink.url
|
||||
with requests.get(resolved_url) as track_url:
|
||||
track_data = track_url.json()
|
||||
|
||||
if track_data ['streamable']:
|
||||
return track_data ['stream_url'] + "?client_id=%s" %client_id
|
||||
else:
|
||||
raise TypeError('%r is not streamable' % url)
|
||||
if track_data ['streamable']:
|
||||
return track_data ['stream_url'] + "?client_id=%s" %client_id
|
||||
else:
|
||||
raise TypeError('%r is not streamable' % url)
|
||||
|
||||
@matches_url ('https://www.youtube.com/watch')
|
||||
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')
|
||||
def convert_anyaudio(url):
|
||||
values = url.split("audio=")
|
||||
if len(values) != 2:
|
||||
raise TypeError('%r is not streamable' % url)
|
||||
return "http://anyaudio.net/audiodownload?audio=%s" % (values[1],)
|
||||
values = url.split("audio=")
|
||||
if len(values) != 2:
|
||||
raise TypeError('%r is not streamable' % url)
|
||||
return "http://anyaudio.net/audiodownload?audio=%s" % (values[1],)
|
||||
|
||||
def convert_generic_audio(url):
|
||||
return url
|
||||
return url
|
||||
|
@ -3,11 +3,11 @@ from __future__ import unicode_literals
|
||||
import youtube_dl
|
||||
|
||||
def get_video_url(url):
|
||||
ydl = youtube_dl.YoutubeDL({'quiet': True, 'format': 'bestaudio/best', 'outtmpl': u'%(id)s%(ext)s'})
|
||||
with ydl:
|
||||
result = ydl.extract_info(url, download=False)
|
||||
if 'entries' in result:
|
||||
video = result['entries'][0]
|
||||
else:
|
||||
video = result
|
||||
return video["formats"][0]["url"]
|
||||
ydl = youtube_dl.YoutubeDL({'quiet': True, 'format': 'bestaudio/best', 'outtmpl': u'%(id)s%(ext)s'})
|
||||
with ydl:
|
||||
result = ydl.extract_info(url, download=False)
|
||||
if 'entries' in result:
|
||||
video = result['entries'][0]
|
||||
else:
|
||||
video = result
|
||||
return video["formats"][0]["url"]
|
||||
|
@ -15,14 +15,14 @@ keymap=None
|
||||
changed_keymap = False
|
||||
|
||||
def setup ():
|
||||
global app
|
||||
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))
|
||||
log.debug("Loading keymap...")
|
||||
global keymap
|
||||
if float(platform.version()[:2]) >= 10 and app["app-settings"]["load_keymap"] == "default.keymap":
|
||||
app["app-settings"]["load_keymap"] = "Windows 10.keymap"
|
||||
app.write()
|
||||
global changed_keymap
|
||||
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)
|
||||
global app
|
||||
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))
|
||||
log.debug("Loading keymap...")
|
||||
global keymap
|
||||
if float(platform.version()[:2]) >= 10 and app["app-settings"]["load_keymap"] == "default.keymap":
|
||||
app["app-settings"]["load_keymap"] = "Windows 10.keymap"
|
||||
app.write()
|
||||
global changed_keymap
|
||||
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)
|
||||
|
@ -9,69 +9,69 @@ log = getLogger("config_utils")
|
||||
class ConfigLoadError(Exception): pass
|
||||
|
||||
def load_config(config_path, configspec_path=None, copy=True, *args, **kwargs):
|
||||
spec = ConfigObj(configspec_path, encoding='UTF8', list_values=False, _inspec=True)
|
||||
try:
|
||||
config = ConfigObj(infile=config_path, configspec=spec, create_empty=True, encoding='UTF8', *args, **kwargs)
|
||||
except ParseError:
|
||||
raise ConfigLoadError("Unable to load %r" % config_path)
|
||||
validator = Validator()
|
||||
validated = config.validate(validator, preserve_errors=False, copy=copy)
|
||||
if validated == True:
|
||||
config.write()
|
||||
return config
|
||||
else:
|
||||
log.exception("Error in config file: {0}".format(validated,))
|
||||
spec = ConfigObj(configspec_path, encoding='UTF8', list_values=False, _inspec=True)
|
||||
try:
|
||||
config = ConfigObj(infile=config_path, configspec=spec, create_empty=True, encoding='UTF8', *args, **kwargs)
|
||||
except ParseError:
|
||||
raise ConfigLoadError("Unable to load %r" % config_path)
|
||||
validator = Validator()
|
||||
validated = config.validate(validator, preserve_errors=False, copy=copy)
|
||||
if validated == True:
|
||||
config.write()
|
||||
return config
|
||||
else:
|
||||
log.exception("Error in config file: {0}".format(validated,))
|
||||
|
||||
def is_blank(arg):
|
||||
"Check if a line is blank."
|
||||
for c in arg:
|
||||
if c not in string.whitespace:
|
||||
return False
|
||||
return True
|
||||
"Check if a line is blank."
|
||||
for c in arg:
|
||||
if c not in string.whitespace:
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_keys(path):
|
||||
"Gets the keys of a configobj config file."
|
||||
res=[]
|
||||
fin=open(path)
|
||||
for line in fin:
|
||||
if not is_blank(line):
|
||||
res.append(line[0:line.find('=')].strip())
|
||||
fin.close()
|
||||
return res
|
||||
"Gets the keys of a configobj config file."
|
||||
res=[]
|
||||
fin=open(path)
|
||||
for line in fin:
|
||||
if not is_blank(line):
|
||||
res.append(line[0:line.find('=')].strip())
|
||||
fin.close()
|
||||
return res
|
||||
|
||||
def hist(keys):
|
||||
"Generates a histogram of an iterable."
|
||||
res={}
|
||||
for k in keys:
|
||||
res[k]=res.setdefault(k,0)+1
|
||||
return res
|
||||
"Generates a histogram of an iterable."
|
||||
res={}
|
||||
for k in keys:
|
||||
res[k]=res.setdefault(k,0)+1
|
||||
return res
|
||||
|
||||
def find_problems(hist):
|
||||
"Takes a histogram and returns a list of items occurring more than once."
|
||||
res=[]
|
||||
for k,v in hist.items():
|
||||
if v>1:
|
||||
res.append(k)
|
||||
return res
|
||||
"Takes a histogram and returns a list of items occurring more than once."
|
||||
res=[]
|
||||
for k,v in hist.items():
|
||||
if v>1:
|
||||
res.append(k)
|
||||
return res
|
||||
|
||||
def clean_config(path):
|
||||
"Cleans a config file. If duplicate values are found, delete all of them and just use the default."
|
||||
orig=[]
|
||||
cleaned=[]
|
||||
fin=open(path)
|
||||
for line in fin:
|
||||
orig.append(line)
|
||||
fin.close()
|
||||
for p in find_problems(hist(get_keys(path))):
|
||||
for o in orig:
|
||||
o.strip()
|
||||
if p not in o:
|
||||
cleaned.append(o)
|
||||
if len(cleaned) != 0:
|
||||
cam=open(path,'w')
|
||||
for c in cleaned:
|
||||
cam.write(c)
|
||||
cam.close()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
"Cleans a config file. If duplicate values are found, delete all of them and just use the default."
|
||||
orig=[]
|
||||
cleaned=[]
|
||||
fin=open(path)
|
||||
for line in fin:
|
||||
orig.append(line)
|
||||
fin.close()
|
||||
for p in find_problems(hist(get_keys(path))):
|
||||
for o in orig:
|
||||
o.strip()
|
||||
if p not in o:
|
||||
cleaned.append(o)
|
||||
if len(cleaned) != 0:
|
||||
cam=open(path,'w')
|
||||
for c in cleaned:
|
||||
cam.write(c)
|
||||
cam.close()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
@ -8,33 +8,33 @@ from wxUI.dialogs import attach as gui
|
||||
log = logging.getLogger("controller.attach")
|
||||
|
||||
class attach(object):
|
||||
def __init__(self):
|
||||
self.attachments = list()
|
||||
self.dialog = gui.attachDialog()
|
||||
widgetUtils.connect_event(self.dialog.photo, widgetUtils.BUTTON_PRESSED, self.upload_image)
|
||||
widgetUtils.connect_event(self.dialog.remove, widgetUtils.BUTTON_PRESSED, self.remove_attachment)
|
||||
self.dialog.get_response()
|
||||
log.debug("Attachments controller started.")
|
||||
def __init__(self):
|
||||
self.attachments = list()
|
||||
self.dialog = gui.attachDialog()
|
||||
widgetUtils.connect_event(self.dialog.photo, widgetUtils.BUTTON_PRESSED, self.upload_image)
|
||||
widgetUtils.connect_event(self.dialog.remove, widgetUtils.BUTTON_PRESSED, self.remove_attachment)
|
||||
self.dialog.get_response()
|
||||
log.debug("Attachments controller started.")
|
||||
|
||||
def upload_image(self, *args, **kwargs):
|
||||
image, description = self.dialog.get_image()
|
||||
if image != None:
|
||||
imageInfo = {"type": "photo", "file": image, "description": description}
|
||||
log.debug("Image data to upload: %r" % (imageInfo,))
|
||||
self.attachments.append(imageInfo)
|
||||
info = [_(u"Photo"), description]
|
||||
self.dialog.attachments.insert_item(False, *info)
|
||||
self.dialog.remove.Enable(True)
|
||||
def upload_image(self, *args, **kwargs):
|
||||
image, description = self.dialog.get_image()
|
||||
if image != None:
|
||||
imageInfo = {"type": "photo", "file": image, "description": description}
|
||||
log.debug("Image data to upload: %r" % (imageInfo,))
|
||||
self.attachments.append(imageInfo)
|
||||
info = [_(u"Photo"), description]
|
||||
self.dialog.attachments.insert_item(False, *info)
|
||||
self.dialog.remove.Enable(True)
|
||||
|
||||
def remove_attachment(self, *args, **kwargs):
|
||||
current_item = self.dialog.attachments.get_selected()
|
||||
log.debug("Removing item %d" % (current_item,))
|
||||
if current_item == -1: current_item = 0
|
||||
self.attachments.pop(current_item)
|
||||
self.dialog.attachments.remove_item(current_item)
|
||||
self.check_remove_status()
|
||||
log.debug("Removed")
|
||||
def remove_attachment(self, *args, **kwargs):
|
||||
current_item = self.dialog.attachments.get_selected()
|
||||
log.debug("Removing item %d" % (current_item,))
|
||||
if current_item == -1: current_item = 0
|
||||
self.attachments.pop(current_item)
|
||||
self.dialog.attachments.remove_item(current_item)
|
||||
self.check_remove_status()
|
||||
log.debug("Removed")
|
||||
|
||||
def check_remove_status(self):
|
||||
if len(self.attachments) == 0 and self.dialog.attachments.get_count() == 0:
|
||||
self.dialog.remove.Enable(False)
|
||||
def check_remove_status(self):
|
||||
if len(self.attachments) == 0 and self.dialog.attachments.get_count() == 0:
|
||||
self.dialog.remove.Enable(False)
|
||||
|
@ -14,196 +14,196 @@ from wxUI import buffers
|
||||
log = logging.getLogger("controller.buffers.baseBuffers")
|
||||
|
||||
def _items_exist(function):
|
||||
""" A decorator to execute a function only if the selected buffer contains at least one item."""
|
||||
def function_(self, *args, **kwargs):
|
||||
if self.buffer.list.get_count() > 0:
|
||||
function(self, *args, **kwargs)
|
||||
return function_
|
||||
""" A decorator to execute a function only if the selected buffer contains at least one item."""
|
||||
def function_(self, *args, **kwargs):
|
||||
if self.buffer.list.get_count() > 0:
|
||||
function(self, *args, **kwargs)
|
||||
return function_
|
||||
|
||||
class 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):
|
||||
"""Inits the main controller for 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.
|
||||
@ session sessionmanager.session object or None: Session handler for settings, database and data access.
|
||||
"""
|
||||
super(buffer, self).__init__()
|
||||
self.function = function
|
||||
# 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)
|
||||
# Read more about compose functions in twitter/compose.py.
|
||||
self.compose_function = None
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
# This will be used as a reference to the wx.Panel object wich stores the buffer GUI.
|
||||
self.buffer = None
|
||||
# This should countains the account associated to this buffer.
|
||||
self.account = ""
|
||||
# This controls whether the start_stream function should be called when starting the program.
|
||||
self.needs_init = True
|
||||
# if this is set to False, the buffer will be ignored on the invisible interface.
|
||||
self.invisible = False
|
||||
# Control variable, used to track time of execution for calls to start_stream.
|
||||
self.execution_time = 0
|
||||
def __init__(self, parent=None, function=None, session=None, *args, **kwargs):
|
||||
"""Inits the main controller for 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.
|
||||
@ session sessionmanager.session object or None: Session handler for settings, database and data access.
|
||||
"""
|
||||
super(buffer, self).__init__()
|
||||
self.function = function
|
||||
# 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)
|
||||
# Read more about compose functions in twitter/compose.py.
|
||||
self.compose_function = None
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
# This will be used as a reference to the wx.Panel object wich stores the buffer GUI.
|
||||
self.buffer = None
|
||||
# This should countains the account associated to this buffer.
|
||||
self.account = ""
|
||||
# This controls whether the start_stream function should be called when starting the program.
|
||||
self.needs_init = True
|
||||
# if this is set to False, the buffer will be ignored on the invisible interface.
|
||||
self.invisible = False
|
||||
# Control variable, used to track time of execution for calls to start_stream.
|
||||
self.execution_time = 0
|
||||
|
||||
def clear_list(self):
|
||||
pass
|
||||
def clear_list(self):
|
||||
pass
|
||||
|
||||
def get_event(self, ev):
|
||||
""" Catch key presses in the WX interface and generate the corresponding event names."""
|
||||
if ev.GetKeyCode() == wx.WXK_RETURN and ev.ControlDown(): event = "audio"
|
||||
elif ev.GetKeyCode() == wx.WXK_RETURN: event = "url"
|
||||
elif ev.GetKeyCode() == wx.WXK_F5: event = "volume_down"
|
||||
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: event = "destroy_status"
|
||||
# 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
|
||||
elif ev.GetKeyCode() == wx.WXK_F10 and ev.ShiftDown(): event = "show_menu"
|
||||
else:
|
||||
event = None
|
||||
ev.Skip()
|
||||
if event != None:
|
||||
try:
|
||||
### ToDo: Remove after WX fixes issue #353 in the widgets.
|
||||
if event == "show_menu":
|
||||
return self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition())
|
||||
getattr(self, event)()
|
||||
except AttributeError:
|
||||
pass
|
||||
def get_event(self, ev):
|
||||
""" Catch key presses in the WX interface and generate the corresponding event names."""
|
||||
if ev.GetKeyCode() == wx.WXK_RETURN and ev.ControlDown(): event = "audio"
|
||||
elif ev.GetKeyCode() == wx.WXK_RETURN: event = "url"
|
||||
elif ev.GetKeyCode() == wx.WXK_F5: event = "volume_down"
|
||||
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: event = "destroy_status"
|
||||
# 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
|
||||
elif ev.GetKeyCode() == wx.WXK_F10 and ev.ShiftDown(): event = "show_menu"
|
||||
else:
|
||||
event = None
|
||||
ev.Skip()
|
||||
if event != None:
|
||||
try:
|
||||
### ToDo: Remove after WX fixes issue #353 in the widgets.
|
||||
if event == "show_menu":
|
||||
return self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition())
|
||||
getattr(self, event)()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def volume_down(self):
|
||||
""" Decreases volume by 5%"""
|
||||
if self.session.settings["sound"]["volume"] > 0.0:
|
||||
if self.session.settings["sound"]["volume"] <= 0.05:
|
||||
self.session.settings["sound"]["volume"] = 0.0
|
||||
else:
|
||||
self.session.settings["sound"]["volume"] -=0.05
|
||||
sound.URLPlayer.player.audio_set_volume(int(self.session.settings["sound"]["volume"]*100.0))
|
||||
self.session.sound.play("volume_changed.ogg")
|
||||
self.session.settings.write()
|
||||
def volume_down(self):
|
||||
""" Decreases volume by 5%"""
|
||||
if self.session.settings["sound"]["volume"] > 0.0:
|
||||
if self.session.settings["sound"]["volume"] <= 0.05:
|
||||
self.session.settings["sound"]["volume"] = 0.0
|
||||
else:
|
||||
self.session.settings["sound"]["volume"] -=0.05
|
||||
sound.URLPlayer.player.audio_set_volume(int(self.session.settings["sound"]["volume"]*100.0))
|
||||
self.session.sound.play("volume_changed.ogg")
|
||||
self.session.settings.write()
|
||||
|
||||
def volume_up(self):
|
||||
""" Increases volume by 5%."""
|
||||
if self.session.settings["sound"]["volume"] < 1.0:
|
||||
if self.session.settings["sound"]["volume"] >= 0.95:
|
||||
self.session.settings["sound"]["volume"] = 1.0
|
||||
else:
|
||||
self.session.settings["sound"]["volume"] +=0.05
|
||||
sound.URLPlayer.player.audio_set_volume(int(self.session.settings["sound"]["volume"]*100))
|
||||
self.session.sound.play("volume_changed.ogg")
|
||||
self.session.settings.write()
|
||||
def volume_up(self):
|
||||
""" Increases volume by 5%."""
|
||||
if self.session.settings["sound"]["volume"] < 1.0:
|
||||
if self.session.settings["sound"]["volume"] >= 0.95:
|
||||
self.session.settings["sound"]["volume"] = 1.0
|
||||
else:
|
||||
self.session.settings["sound"]["volume"] +=0.05
|
||||
sound.URLPlayer.player.audio_set_volume(int(self.session.settings["sound"]["volume"]*100))
|
||||
self.session.sound.play("volume_changed.ogg")
|
||||
self.session.settings.write()
|
||||
|
||||
def start_stream(self, mandatory=False, play_sound=True):
|
||||
pass
|
||||
def start_stream(self, mandatory=False, play_sound=True):
|
||||
pass
|
||||
|
||||
def get_more_items(self):
|
||||
output.speak(_(u"This action is not supported for this buffer"), True)
|
||||
def get_more_items(self):
|
||||
output.speak(_(u"This action is not supported for this buffer"), True)
|
||||
|
||||
def put_items_on_list(self, items):
|
||||
pass
|
||||
def put_items_on_list(self, items):
|
||||
pass
|
||||
|
||||
def remove_buffer(self):
|
||||
return False
|
||||
def remove_buffer(self):
|
||||
return False
|
||||
|
||||
def remove_item(self, item):
|
||||
f = self.buffer.list.get_selected()
|
||||
self.buffer.list.remove_item(item)
|
||||
self.buffer.list.select_item(f)
|
||||
def remove_item(self, item):
|
||||
f = self.buffer.list.get_selected()
|
||||
self.buffer.list.remove_item(item)
|
||||
self.buffer.list.select_item(f)
|
||||
|
||||
def bind_events(self):
|
||||
pass
|
||||
def bind_events(self):
|
||||
pass
|
||||
|
||||
def get_object(self):
|
||||
return self.buffer
|
||||
def get_object(self):
|
||||
return self.buffer
|
||||
|
||||
def get_message(self):
|
||||
pass
|
||||
def get_message(self):
|
||||
pass
|
||||
|
||||
def set_list_position(self, reversed=False):
|
||||
if reversed == False:
|
||||
self.buffer.list.select_item(-1)
|
||||
else:
|
||||
self.buffer.list.select_item(0)
|
||||
def set_list_position(self, reversed=False):
|
||||
if reversed == False:
|
||||
self.buffer.list.select_item(-1)
|
||||
else:
|
||||
self.buffer.list.select_item(0)
|
||||
|
||||
def reply(self):
|
||||
pass
|
||||
def reply(self):
|
||||
pass
|
||||
|
||||
def send_message(self):
|
||||
pass
|
||||
def send_message(self):
|
||||
pass
|
||||
|
||||
def share_item(self):
|
||||
pass
|
||||
def share_item(self):
|
||||
pass
|
||||
|
||||
def destroy_status(self):
|
||||
pass
|
||||
def destroy_status(self):
|
||||
pass
|
||||
|
||||
def post_status(self, *args, **kwargs):
|
||||
pass
|
||||
def post_status(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def save_positions(self):
|
||||
try:
|
||||
self.session.db[self.name+"_pos"]=self.buffer.list.get_selected()
|
||||
except AttributeError:
|
||||
pass
|
||||
def save_positions(self):
|
||||
try:
|
||||
self.session.db[self.name+"_pos"]=self.buffer.list.get_selected()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
class accountPanel(buffer):
|
||||
def __init__(self, parent, name, account, account_id):
|
||||
super(accountPanel, self).__init__(parent, None, name)
|
||||
log.debug("Initializing buffer %s, account %s" % (name, account,))
|
||||
self.buffer = buffers.accountPanel(parent, name)
|
||||
self.type = self.buffer.type
|
||||
self.compose_function = None
|
||||
self.session = None
|
||||
self.needs_init = False
|
||||
self.account = account
|
||||
self.buffer.account = account
|
||||
self.name = name
|
||||
self.account_id = account_id
|
||||
def __init__(self, parent, name, account, account_id):
|
||||
super(accountPanel, self).__init__(parent, None, name)
|
||||
log.debug("Initializing buffer %s, account %s" % (name, account,))
|
||||
self.buffer = buffers.accountPanel(parent, name)
|
||||
self.type = self.buffer.type
|
||||
self.compose_function = None
|
||||
self.session = None
|
||||
self.needs_init = False
|
||||
self.account = account
|
||||
self.buffer.account = account
|
||||
self.name = name
|
||||
self.account_id = account_id
|
||||
|
||||
def setup_account(self):
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.CHECKBOX, self.autostart, menuitem=self.buffer.autostart_account)
|
||||
if self.account_id in config.app["sessions"]["ignored_sessions"]:
|
||||
self.buffer.change_autostart(False)
|
||||
else:
|
||||
self.buffer.change_autostart(True)
|
||||
if not hasattr(self, "logged"):
|
||||
self.buffer.change_login(login=False)
|
||||
widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.logout)
|
||||
else:
|
||||
self.buffer.change_login(login=True)
|
||||
widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.login)
|
||||
def setup_account(self):
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.CHECKBOX, self.autostart, menuitem=self.buffer.autostart_account)
|
||||
if self.account_id in config.app["sessions"]["ignored_sessions"]:
|
||||
self.buffer.change_autostart(False)
|
||||
else:
|
||||
self.buffer.change_autostart(True)
|
||||
if not hasattr(self, "logged"):
|
||||
self.buffer.change_login(login=False)
|
||||
widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.logout)
|
||||
else:
|
||||
self.buffer.change_login(login=True)
|
||||
widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.login)
|
||||
|
||||
def login(self, *args, **kwargs):
|
||||
del self.logged
|
||||
self.setup_account()
|
||||
pub.sendMessage("login", session_id=self.account_id)
|
||||
def login(self, *args, **kwargs):
|
||||
del self.logged
|
||||
self.setup_account()
|
||||
pub.sendMessage("login", session_id=self.account_id)
|
||||
|
||||
def logout(self, *args, **kwargs):
|
||||
self.logged = False
|
||||
self.setup_account()
|
||||
pub.sendMessage("logout", session_id=self.account_id)
|
||||
def logout(self, *args, **kwargs):
|
||||
self.logged = False
|
||||
self.setup_account()
|
||||
pub.sendMessage("logout", session_id=self.account_id)
|
||||
|
||||
def autostart(self, *args, **kwargs):
|
||||
if self.account_id in config.app["sessions"]["ignored_sessions"]:
|
||||
self.buffer.change_autostart(True)
|
||||
config.app["sessions"]["ignored_sessions"].remove(self.account_id)
|
||||
else:
|
||||
self.buffer.change_autostart(False)
|
||||
config.app["sessions"]["ignored_sessions"].append(self.account_id)
|
||||
config.app.write()
|
||||
def autostart(self, *args, **kwargs):
|
||||
if self.account_id in config.app["sessions"]["ignored_sessions"]:
|
||||
self.buffer.change_autostart(True)
|
||||
config.app["sessions"]["ignored_sessions"].remove(self.account_id)
|
||||
else:
|
||||
self.buffer.change_autostart(False)
|
||||
config.app["sessions"]["ignored_sessions"].append(self.account_id)
|
||||
config.app.write()
|
||||
|
||||
class emptyPanel(buffer):
|
||||
def __init__(self, parent, name, account):
|
||||
super(emptyPanel, self).__init__(parent=parent)
|
||||
log.debug("Initializing buffer %s, account %s" % (name, account,))
|
||||
self.buffer = buffers.emptyPanel(parent, name)
|
||||
self.type = self.buffer.type
|
||||
self.compose_function = None
|
||||
self.account = account
|
||||
self.buffer.account = account
|
||||
self.name = name
|
||||
self.session = None
|
||||
self.needs_init = True
|
||||
def __init__(self, parent, name, account):
|
||||
super(emptyPanel, self).__init__(parent=parent)
|
||||
log.debug("Initializing buffer %s, account %s" % (name, account,))
|
||||
self.buffer = buffers.emptyPanel(parent, name)
|
||||
self.type = self.buffer.type
|
||||
self.compose_function = None
|
||||
self.account = account
|
||||
self.buffer.account = account
|
||||
self.name = name
|
||||
self.session = None
|
||||
self.needs_init = True
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,71 +8,71 @@ from wxUI.dialogs import filterDialogs
|
||||
from wxUI import commonMessageDialogs
|
||||
|
||||
class filter(object):
|
||||
def __init__(self, buffer, filter_title=None, if_word_exists=None, in_lang=None, regexp=None, word=None, in_buffer=None):
|
||||
self.buffer = buffer
|
||||
self.dialog = filterDialogs.filterDialog(languages=[i["name"] for i in application.supported_languages])
|
||||
if self.dialog.get_response() == widgetUtils.OK:
|
||||
title = self.dialog.get("title")
|
||||
contains = self.dialog.get("contains")
|
||||
term = self.dialog.get("term")
|
||||
regexp = self.dialog.get("regexp")
|
||||
allow_rts = self.dialog.get("allow_rts")
|
||||
allow_quotes = self.dialog.get("allow_quotes")
|
||||
allow_replies = self.dialog.get("allow_replies")
|
||||
load_language = self.dialog.get("load_language")
|
||||
ignore_language = self.dialog.get("ignore_language")
|
||||
lang_option = None
|
||||
if ignore_language:
|
||||
lang_option = False
|
||||
elif load_language:
|
||||
lang_option = True
|
||||
langs = self.dialog.get_selected_langs()
|
||||
langcodes = []
|
||||
for i in application.supported_languages:
|
||||
if i["name"] in langs:
|
||||
langcodes.append(i["code"])
|
||||
d = dict(in_buffer=self.buffer.name, word=term, regexp=regexp, in_lang=lang_option, languages=langcodes, if_word_exists=contains, allow_rts=allow_rts, allow_quotes=allow_quotes, allow_replies=allow_replies)
|
||||
if title in self.buffer.session.settings["filters"]:
|
||||
return commonMessageDialogs.existing_filter()
|
||||
self.buffer.session.settings["filters"][title] = d
|
||||
self.buffer.session.settings.write()
|
||||
def __init__(self, buffer, filter_title=None, if_word_exists=None, in_lang=None, regexp=None, word=None, in_buffer=None):
|
||||
self.buffer = buffer
|
||||
self.dialog = filterDialogs.filterDialog(languages=[i["name"] for i in application.supported_languages])
|
||||
if self.dialog.get_response() == widgetUtils.OK:
|
||||
title = self.dialog.get("title")
|
||||
contains = self.dialog.get("contains")
|
||||
term = self.dialog.get("term")
|
||||
regexp = self.dialog.get("regexp")
|
||||
allow_rts = self.dialog.get("allow_rts")
|
||||
allow_quotes = self.dialog.get("allow_quotes")
|
||||
allow_replies = self.dialog.get("allow_replies")
|
||||
load_language = self.dialog.get("load_language")
|
||||
ignore_language = self.dialog.get("ignore_language")
|
||||
lang_option = None
|
||||
if ignore_language:
|
||||
lang_option = False
|
||||
elif load_language:
|
||||
lang_option = True
|
||||
langs = self.dialog.get_selected_langs()
|
||||
langcodes = []
|
||||
for i in application.supported_languages:
|
||||
if i["name"] in langs:
|
||||
langcodes.append(i["code"])
|
||||
d = dict(in_buffer=self.buffer.name, word=term, regexp=regexp, in_lang=lang_option, languages=langcodes, if_word_exists=contains, allow_rts=allow_rts, allow_quotes=allow_quotes, allow_replies=allow_replies)
|
||||
if title in self.buffer.session.settings["filters"]:
|
||||
return commonMessageDialogs.existing_filter()
|
||||
self.buffer.session.settings["filters"][title] = d
|
||||
self.buffer.session.settings.write()
|
||||
|
||||
class filterManager(object):
|
||||
|
||||
def __init__(self, session):
|
||||
self.session = session
|
||||
self.dialog = filterDialogs.filterManagerDialog()
|
||||
self.insert_filters(self.session.settings["filters"])
|
||||
if self.dialog.filters.get_count() == 0:
|
||||
self.dialog.edit.Enable(False)
|
||||
self.dialog.delete.Enable(False)
|
||||
else:
|
||||
widgetUtils.connect_event(self.dialog.edit, widgetUtils.BUTTON_PRESSED, self.edit_filter)
|
||||
widgetUtils.connect_event(self.dialog.delete, widgetUtils.BUTTON_PRESSED, self.delete_filter)
|
||||
response = self.dialog.get_response()
|
||||
def __init__(self, session):
|
||||
self.session = session
|
||||
self.dialog = filterDialogs.filterManagerDialog()
|
||||
self.insert_filters(self.session.settings["filters"])
|
||||
if self.dialog.filters.get_count() == 0:
|
||||
self.dialog.edit.Enable(False)
|
||||
self.dialog.delete.Enable(False)
|
||||
else:
|
||||
widgetUtils.connect_event(self.dialog.edit, widgetUtils.BUTTON_PRESSED, self.edit_filter)
|
||||
widgetUtils.connect_event(self.dialog.delete, widgetUtils.BUTTON_PRESSED, self.delete_filter)
|
||||
response = self.dialog.get_response()
|
||||
|
||||
def insert_filters(self, filters):
|
||||
self.dialog.filters.clear()
|
||||
for f in list(filters.keys()):
|
||||
filterName = f
|
||||
buffer = filters[f]["in_buffer"]
|
||||
if filters[f]["if_word_exists"] == "True" and filters[f]["word"] != "":
|
||||
filter_by_word = "True"
|
||||
else:
|
||||
filter_by_word = "False"
|
||||
filter_by_lang = ""
|
||||
if filters[f]["in_lang"] != "None":
|
||||
filter_by_lang = "True"
|
||||
b = [f, buffer, filter_by_word, filter_by_lang]
|
||||
self.dialog.filters.insert_item(False, *b)
|
||||
def insert_filters(self, filters):
|
||||
self.dialog.filters.clear()
|
||||
for f in list(filters.keys()):
|
||||
filterName = f
|
||||
buffer = filters[f]["in_buffer"]
|
||||
if filters[f]["if_word_exists"] == "True" and filters[f]["word"] != "":
|
||||
filter_by_word = "True"
|
||||
else:
|
||||
filter_by_word = "False"
|
||||
filter_by_lang = ""
|
||||
if filters[f]["in_lang"] != "None":
|
||||
filter_by_lang = "True"
|
||||
b = [f, buffer, filter_by_word, filter_by_lang]
|
||||
self.dialog.filters.insert_item(False, *b)
|
||||
|
||||
def edit_filter(self, *args, **kwargs):
|
||||
pass
|
||||
def edit_filter(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def delete_filter(self, *args, **kwargs):
|
||||
filter_title = self.dialog.filters.get_text_column(self.dialog.filters.get_selected(), 0)
|
||||
response = commonMessageDialogs.delete_filter()
|
||||
if response == widgetUtils.YES:
|
||||
self.session.settings["filters"].pop(filter_title)
|
||||
self.session.settings.write()
|
||||
self.insert_filters(self.session.settings["filters"])
|
||||
def delete_filter(self, *args, **kwargs):
|
||||
filter_title = self.dialog.filters.get_text_column(self.dialog.filters.get_selected(), 0)
|
||||
response = commonMessageDialogs.delete_filter()
|
||||
if response == widgetUtils.YES:
|
||||
self.session.settings["filters"].pop(filter_title)
|
||||
self.session.settings.write()
|
||||
self.insert_filters(self.session.settings["filters"])
|
||||
|
@ -10,101 +10,101 @@ from pubsub import pub
|
||||
log = logging.getLogger("controller.listsController")
|
||||
|
||||
class listsController(object):
|
||||
def __init__(self, session, user=None):
|
||||
super(listsController, self).__init__()
|
||||
self.session = session
|
||||
if user == None:
|
||||
self.dialog = lists.listViewer()
|
||||
self.dialog.populate_list(self.get_all_lists())
|
||||
widgetUtils.connect_event(self.dialog.createBtn, widgetUtils.BUTTON_PRESSED, self.create_list)
|
||||
widgetUtils.connect_event(self.dialog.editBtn, widgetUtils.BUTTON_PRESSED, self.edit_list)
|
||||
widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.remove_list)
|
||||
widgetUtils.connect_event(self.dialog.view, widgetUtils.BUTTON_PRESSED, self.open_list_as_buffer)
|
||||
widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.remove_list)
|
||||
else:
|
||||
self.dialog = lists.userListViewer(user)
|
||||
self.dialog.populate_list(self.get_user_lists(user))
|
||||
widgetUtils.connect_event(self.dialog.createBtn, widgetUtils.BUTTON_PRESSED, self.subscribe)
|
||||
widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.unsubscribe)
|
||||
self.dialog.get_response()
|
||||
def __init__(self, session, user=None):
|
||||
super(listsController, self).__init__()
|
||||
self.session = session
|
||||
if user == None:
|
||||
self.dialog = lists.listViewer()
|
||||
self.dialog.populate_list(self.get_all_lists())
|
||||
widgetUtils.connect_event(self.dialog.createBtn, widgetUtils.BUTTON_PRESSED, self.create_list)
|
||||
widgetUtils.connect_event(self.dialog.editBtn, widgetUtils.BUTTON_PRESSED, self.edit_list)
|
||||
widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.remove_list)
|
||||
widgetUtils.connect_event(self.dialog.view, widgetUtils.BUTTON_PRESSED, self.open_list_as_buffer)
|
||||
widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.remove_list)
|
||||
else:
|
||||
self.dialog = lists.userListViewer(user)
|
||||
self.dialog.populate_list(self.get_user_lists(user))
|
||||
widgetUtils.connect_event(self.dialog.createBtn, widgetUtils.BUTTON_PRESSED, self.subscribe)
|
||||
widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.unsubscribe)
|
||||
self.dialog.get_response()
|
||||
|
||||
def get_all_lists(self):
|
||||
return [compose.compose_list(item) for item in self.session.db["lists"]]
|
||||
def get_all_lists(self):
|
||||
return [compose.compose_list(item) for item in self.session.db["lists"]]
|
||||
|
||||
def get_user_lists(self, user):
|
||||
self.lists = self.session.twitter.lists_all(reverse=True, screen_name=user)
|
||||
return [compose.compose_list(item) for item in self.lists]
|
||||
def get_user_lists(self, user):
|
||||
self.lists = self.session.twitter.lists_all(reverse=True, screen_name=user)
|
||||
return [compose.compose_list(item) for item in self.lists]
|
||||
|
||||
def create_list(self, *args, **kwargs):
|
||||
dialog = lists.createListDialog()
|
||||
if dialog.get_response() == widgetUtils.OK:
|
||||
name = dialog.get("name")
|
||||
description = dialog.get("description")
|
||||
p = dialog.get("public")
|
||||
if p == True:
|
||||
mode = "public"
|
||||
else:
|
||||
mode = "private"
|
||||
try:
|
||||
new_list = self.session.twitter.create_list(name=name, description=description, mode=mode)
|
||||
self.session.db["lists"].append(new_list)
|
||||
self.dialog.lista.insert_item(False, *compose.compose_list(new_list))
|
||||
except TweepError as e:
|
||||
output.speak("error %s: %s" % (e.api_code, e.reason))
|
||||
log.exception("error %s: %s" % (e.api_code, e.reason))
|
||||
dialog.destroy()
|
||||
def create_list(self, *args, **kwargs):
|
||||
dialog = lists.createListDialog()
|
||||
if dialog.get_response() == widgetUtils.OK:
|
||||
name = dialog.get("name")
|
||||
description = dialog.get("description")
|
||||
p = dialog.get("public")
|
||||
if p == True:
|
||||
mode = "public"
|
||||
else:
|
||||
mode = "private"
|
||||
try:
|
||||
new_list = self.session.twitter.create_list(name=name, description=description, mode=mode)
|
||||
self.session.db["lists"].append(new_list)
|
||||
self.dialog.lista.insert_item(False, *compose.compose_list(new_list))
|
||||
except TweepError as e:
|
||||
output.speak("error %s: %s" % (e.api_code, e.reason))
|
||||
log.exception("error %s: %s" % (e.api_code, e.reason))
|
||||
dialog.destroy()
|
||||
|
||||
def edit_list(self, *args, **kwargs):
|
||||
if self.dialog.lista.get_count() == 0: return
|
||||
list = self.session.db["lists"][self.dialog.get_item()]
|
||||
dialog = lists.editListDialog(list)
|
||||
if dialog.get_response() == widgetUtils.OK:
|
||||
name = dialog.get("name")
|
||||
description = dialog.get("description")
|
||||
p = dialog.get("public")
|
||||
if p == True:
|
||||
mode = "public"
|
||||
else:
|
||||
mode = "private"
|
||||
try:
|
||||
self.session.twitter.update_list(list_id=list.id, name=name, description=description, mode=mode)
|
||||
self.session.get_lists()
|
||||
self.dialog.populate_list(self.get_all_lists(), True)
|
||||
except TweepError as e:
|
||||
output.speak("error %s: %s" % (e.api_code, e.reason))
|
||||
dialog.destroy()
|
||||
def edit_list(self, *args, **kwargs):
|
||||
if self.dialog.lista.get_count() == 0: return
|
||||
list = self.session.db["lists"][self.dialog.get_item()]
|
||||
dialog = lists.editListDialog(list)
|
||||
if dialog.get_response() == widgetUtils.OK:
|
||||
name = dialog.get("name")
|
||||
description = dialog.get("description")
|
||||
p = dialog.get("public")
|
||||
if p == True:
|
||||
mode = "public"
|
||||
else:
|
||||
mode = "private"
|
||||
try:
|
||||
self.session.twitter.update_list(list_id=list.id, name=name, description=description, mode=mode)
|
||||
self.session.get_lists()
|
||||
self.dialog.populate_list(self.get_all_lists(), True)
|
||||
except TweepError as e:
|
||||
output.speak("error %s: %s" % (e.api_code, e.reason))
|
||||
dialog.destroy()
|
||||
|
||||
def remove_list(self, *args, **kwargs):
|
||||
if self.dialog.lista.get_count() == 0: return
|
||||
list = self.session.db["lists"][self.dialog.get_item()].id
|
||||
if lists.remove_list() == widgetUtils.YES:
|
||||
try:
|
||||
self.session.twitter.destroy_list(list_id=list)
|
||||
self.session.db["lists"].pop(self.dialog.get_item())
|
||||
self.dialog.lista.remove_item(self.dialog.get_item())
|
||||
except TweepError as e:
|
||||
output.speak("error %s: %s" % (e.api_code, e.reason))
|
||||
def remove_list(self, *args, **kwargs):
|
||||
if self.dialog.lista.get_count() == 0: return
|
||||
list = self.session.db["lists"][self.dialog.get_item()].id
|
||||
if lists.remove_list() == widgetUtils.YES:
|
||||
try:
|
||||
self.session.twitter.destroy_list(list_id=list)
|
||||
self.session.db["lists"].pop(self.dialog.get_item())
|
||||
self.dialog.lista.remove_item(self.dialog.get_item())
|
||||
except TweepError as e:
|
||||
output.speak("error %s: %s" % (e.api_code, e.reason))
|
||||
|
||||
def open_list_as_buffer(self, *args, **kwargs):
|
||||
if self.dialog.lista.get_count() == 0: return
|
||||
list = self.session.db["lists"][self.dialog.get_item()]
|
||||
pub.sendMessage("create-new-buffer", buffer="list", account=self.session.db["user_name"], create=list.name)
|
||||
def open_list_as_buffer(self, *args, **kwargs):
|
||||
if self.dialog.lista.get_count() == 0: return
|
||||
list = self.session.db["lists"][self.dialog.get_item()]
|
||||
pub.sendMessage("create-new-buffer", buffer="list", account=self.session.db["user_name"], create=list.name)
|
||||
|
||||
def subscribe(self, *args, **kwargs):
|
||||
if self.dialog.lista.get_count() == 0: return
|
||||
list_id = self.lists[self.dialog.get_item()].id
|
||||
try:
|
||||
list = self.session.twitter.subscribe_list(list_id=list_id)
|
||||
item = utils.find_item(list.id, self.session.db["lists"])
|
||||
self.session.db["lists"].append(list)
|
||||
except TweepError as e:
|
||||
output.speak("error %s: %s" % (e.api_code, e.reason))
|
||||
def subscribe(self, *args, **kwargs):
|
||||
if self.dialog.lista.get_count() == 0: return
|
||||
list_id = self.lists[self.dialog.get_item()].id
|
||||
try:
|
||||
list = self.session.twitter.subscribe_list(list_id=list_id)
|
||||
item = utils.find_item(list.id, self.session.db["lists"])
|
||||
self.session.db["lists"].append(list)
|
||||
except TweepError as e:
|
||||
output.speak("error %s: %s" % (e.api_code, e.reason))
|
||||
|
||||
def unsubscribe(self, *args, **kwargs):
|
||||
if self.dialog.lista.get_count() == 0: return
|
||||
list_id = self.lists[self.dialog.get_item()].id
|
||||
try:
|
||||
list = self.session.twitter.unsubscribe_list(list_id=list_id)
|
||||
self.session.db["lists"].remove(list)
|
||||
except TweepError as e:
|
||||
output.speak("error %s: %s" % (e.api_code, e.reason))
|
||||
def unsubscribe(self, *args, **kwargs):
|
||||
if self.dialog.lista.get_count() == 0: return
|
||||
list_id = self.lists[self.dialog.get_item()].id
|
||||
try:
|
||||
list = self.session.twitter.unsubscribe_list(list_id=list_id)
|
||||
self.session.db["lists"].remove(list)
|
||||
except TweepError as e:
|
||||
output.speak("error %s: %s" % (e.api_code, e.reason))
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,281 +12,281 @@ import config
|
||||
from pubsub import pub
|
||||
from twitter_text import parse_tweet
|
||||
if system == "Windows":
|
||||
from wxUI.dialogs import message, urlList
|
||||
from wxUI import commonMessageDialogs
|
||||
from extra import translator, SpellChecker, autocompletionUsers
|
||||
from extra.AudioUploader import audioUploader
|
||||
from wxUI.dialogs import message, urlList
|
||||
from wxUI import commonMessageDialogs
|
||||
from extra import translator, SpellChecker, autocompletionUsers
|
||||
from extra.AudioUploader import audioUploader
|
||||
elif system == "Linux":
|
||||
from gtkUI.dialogs import message
|
||||
from gtkUI.dialogs import message
|
||||
from sessions.twitter import utils
|
||||
from . import attach
|
||||
|
||||
class basicTweet(object):
|
||||
""" This class handles the tweet main features. Other classes should derive from this class."""
|
||||
def __init__(self, session, title, caption, text, messageType="tweet", max=280, *args, **kwargs):
|
||||
super(basicTweet, self).__init__()
|
||||
self.max = max
|
||||
self.title = title
|
||||
self.session = session
|
||||
self.message = getattr(message, messageType)(title, caption, text, *args, **kwargs)
|
||||
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.text, widgetUtils.ENTERED_TEXT, self.text_processor)
|
||||
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.translateButton, widgetUtils.BUTTON_PRESSED, self.translate)
|
||||
if hasattr(self.message, "long_tweet"):
|
||||
widgetUtils.connect_event(self.message.long_tweet, widgetUtils.CHECKBOX, self.text_processor)
|
||||
if config.app["app-settings"]["remember_mention_and_longtweet"]:
|
||||
self.message.long_tweet.SetValue(config.app["app-settings"]["longtweet"])
|
||||
self.attachments = []
|
||||
""" This class handles the tweet main features. Other classes should derive from this class."""
|
||||
def __init__(self, session, title, caption, text, messageType="tweet", max=280, *args, **kwargs):
|
||||
super(basicTweet, self).__init__()
|
||||
self.max = max
|
||||
self.title = title
|
||||
self.session = session
|
||||
self.message = getattr(message, messageType)(title, caption, text, *args, **kwargs)
|
||||
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.text, widgetUtils.ENTERED_TEXT, self.text_processor)
|
||||
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.translateButton, widgetUtils.BUTTON_PRESSED, self.translate)
|
||||
if hasattr(self.message, "long_tweet"):
|
||||
widgetUtils.connect_event(self.message.long_tweet, widgetUtils.CHECKBOX, self.text_processor)
|
||||
if config.app["app-settings"]["remember_mention_and_longtweet"]:
|
||||
self.message.long_tweet.SetValue(config.app["app-settings"]["longtweet"])
|
||||
self.attachments = []
|
||||
|
||||
def translate(self, event=None):
|
||||
dlg = translator.gui.translateDialog()
|
||||
if dlg.get_response() == widgetUtils.OK:
|
||||
text_to_translate = self.message.get_text()
|
||||
language_dict = translator.translator.available_languages()
|
||||
for k in language_dict:
|
||||
if language_dict[k] == dlg.dest_lang.GetStringSelection():
|
||||
dst = k
|
||||
msg = translator.translator.translate(text=text_to_translate, target=dst)
|
||||
self.message.set_text(msg)
|
||||
self.text_processor()
|
||||
self.message.text_focus()
|
||||
output.speak(_(u"Translated"))
|
||||
else:
|
||||
return
|
||||
def translate(self, event=None):
|
||||
dlg = translator.gui.translateDialog()
|
||||
if dlg.get_response() == widgetUtils.OK:
|
||||
text_to_translate = self.message.get_text()
|
||||
language_dict = translator.translator.available_languages()
|
||||
for k in language_dict:
|
||||
if language_dict[k] == dlg.dest_lang.GetStringSelection():
|
||||
dst = k
|
||||
msg = translator.translator.translate(text=text_to_translate, target=dst)
|
||||
self.message.set_text(msg)
|
||||
self.text_processor()
|
||||
self.message.text_focus()
|
||||
output.speak(_(u"Translated"))
|
||||
else:
|
||||
return
|
||||
|
||||
def shorten(self, event=None):
|
||||
urls = utils.find_urls_in_text(self.message.get_text())
|
||||
if len(urls) == 0:
|
||||
output.speak(_(u"There's no URL to be shortened"))
|
||||
self.message.text_focus()
|
||||
elif len(urls) == 1:
|
||||
self.message.set_text(self.message.get_text().replace(urls[0], url_shortener.shorten(urls[0])))
|
||||
output.speak(_(u"URL shortened"))
|
||||
self.text_processor()
|
||||
self.message.text_focus()
|
||||
elif len(urls) > 1:
|
||||
list_urls = urlList.urlList()
|
||||
list_urls.populate_list(urls)
|
||||
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())))
|
||||
output.speak(_(u"URL shortened"))
|
||||
self.text_processor()
|
||||
self.message.text_focus()
|
||||
def shorten(self, event=None):
|
||||
urls = utils.find_urls_in_text(self.message.get_text())
|
||||
if len(urls) == 0:
|
||||
output.speak(_(u"There's no URL to be shortened"))
|
||||
self.message.text_focus()
|
||||
elif len(urls) == 1:
|
||||
self.message.set_text(self.message.get_text().replace(urls[0], url_shortener.shorten(urls[0])))
|
||||
output.speak(_(u"URL shortened"))
|
||||
self.text_processor()
|
||||
self.message.text_focus()
|
||||
elif len(urls) > 1:
|
||||
list_urls = urlList.urlList()
|
||||
list_urls.populate_list(urls)
|
||||
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())))
|
||||
output.speak(_(u"URL shortened"))
|
||||
self.text_processor()
|
||||
self.message.text_focus()
|
||||
|
||||
def unshorten(self, event=None):
|
||||
urls = utils.find_urls_in_text(self.message.get_text())
|
||||
if len(urls) == 0:
|
||||
output.speak(_(u"There's no URL to be expanded"))
|
||||
self.message.text_focus()
|
||||
elif len(urls) == 1:
|
||||
self.message.set_text(self.message.get_text().replace(urls[0], url_shortener.unshorten(urls[0])))
|
||||
output.speak(_(u"URL expanded"))
|
||||
self.text_processor()
|
||||
self.message.text_focus()
|
||||
elif len(urls) > 1:
|
||||
list_urls = urlList.urlList()
|
||||
list_urls.populate_list(urls)
|
||||
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())))
|
||||
output.speak(_(u"URL expanded"))
|
||||
self.text_processor()
|
||||
self.message.text_focus()
|
||||
def unshorten(self, event=None):
|
||||
urls = utils.find_urls_in_text(self.message.get_text())
|
||||
if len(urls) == 0:
|
||||
output.speak(_(u"There's no URL to be expanded"))
|
||||
self.message.text_focus()
|
||||
elif len(urls) == 1:
|
||||
self.message.set_text(self.message.get_text().replace(urls[0], url_shortener.unshorten(urls[0])))
|
||||
output.speak(_(u"URL expanded"))
|
||||
self.text_processor()
|
||||
self.message.text_focus()
|
||||
elif len(urls) > 1:
|
||||
list_urls = urlList.urlList()
|
||||
list_urls.populate_list(urls)
|
||||
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())))
|
||||
output.speak(_(u"URL expanded"))
|
||||
self.text_processor()
|
||||
self.message.text_focus()
|
||||
|
||||
def text_processor(self, *args, **kwargs):
|
||||
if len(self.message.get_text()) > 1:
|
||||
self.message.enable_button("shortenButton")
|
||||
self.message.enable_button("unshortenButton")
|
||||
else:
|
||||
self.message.disable_button("shortenButton")
|
||||
self.message.disable_button("unshortenButton")
|
||||
if self.message.get("long_tweet") == False:
|
||||
text = self.message.get_text()
|
||||
results = parse_tweet(text)
|
||||
self.message.set_title(_(u"%s - %s of %d characters") % (self.title, results.weightedLength, self.max))
|
||||
if results.weightedLength > self.max:
|
||||
self.session.sound.play("max_length.ogg")
|
||||
else:
|
||||
self.message.set_title(_(u"%s - %s characters") % (self.title, len(self.message.get_text())))
|
||||
def text_processor(self, *args, **kwargs):
|
||||
if len(self.message.get_text()) > 1:
|
||||
self.message.enable_button("shortenButton")
|
||||
self.message.enable_button("unshortenButton")
|
||||
else:
|
||||
self.message.disable_button("shortenButton")
|
||||
self.message.disable_button("unshortenButton")
|
||||
if self.message.get("long_tweet") == False:
|
||||
text = self.message.get_text()
|
||||
results = parse_tweet(text)
|
||||
self.message.set_title(_(u"%s - %s of %d characters") % (self.title, results.weightedLength, self.max))
|
||||
if results.weightedLength > self.max:
|
||||
self.session.sound.play("max_length.ogg")
|
||||
else:
|
||||
self.message.set_title(_(u"%s - %s characters") % (self.title, len(self.message.get_text())))
|
||||
|
||||
def spellcheck(self, event=None):
|
||||
text = self.message.get_text()
|
||||
checker = SpellChecker.spellchecker.spellChecker(text, "")
|
||||
if hasattr(checker, "fixed_text"):
|
||||
self.message.set_text(checker.fixed_text)
|
||||
self.text_processor()
|
||||
self.message.text_focus()
|
||||
def spellcheck(self, event=None):
|
||||
text = self.message.get_text()
|
||||
checker = SpellChecker.spellchecker.spellChecker(text, "")
|
||||
if hasattr(checker, "fixed_text"):
|
||||
self.message.set_text(checker.fixed_text)
|
||||
self.text_processor()
|
||||
self.message.text_focus()
|
||||
|
||||
def attach(self, *args, **kwargs):
|
||||
def completed_callback(dlg):
|
||||
url = dlg.uploaderFunction.get_url()
|
||||
pub.unsubscribe(dlg.uploaderDialog.update, "uploading")
|
||||
dlg.uploaderDialog.destroy()
|
||||
if "sndup.net/" in url:
|
||||
self.message.set_text(self.message.get_text()+url+" #audio")
|
||||
self.text_processor()
|
||||
else:
|
||||
commonMessageDialogs.common_error(url)
|
||||
def attach(self, *args, **kwargs):
|
||||
def completed_callback(dlg):
|
||||
url = dlg.uploaderFunction.get_url()
|
||||
pub.unsubscribe(dlg.uploaderDialog.update, "uploading")
|
||||
dlg.uploaderDialog.destroy()
|
||||
if "sndup.net/" in url:
|
||||
self.message.set_text(self.message.get_text()+url+" #audio")
|
||||
self.text_processor()
|
||||
else:
|
||||
commonMessageDialogs.common_error(url)
|
||||
|
||||
dlg.cleanup()
|
||||
dlg = audioUploader.audioUploader(self.session.settings, completed_callback)
|
||||
self.message.text_focus()
|
||||
dlg.cleanup()
|
||||
dlg = audioUploader.audioUploader(self.session.settings, completed_callback)
|
||||
self.message.text_focus()
|
||||
|
||||
class tweet(basicTweet):
|
||||
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)
|
||||
self.image = None
|
||||
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)
|
||||
self.text_processor()
|
||||
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)
|
||||
self.image = None
|
||||
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)
|
||||
self.text_processor()
|
||||
|
||||
def upload_image(self, *args, **kwargs):
|
||||
a = attach.attach()
|
||||
if len(a.attachments) != 0:
|
||||
self.attachments = a.attachments
|
||||
def upload_image(self, *args, **kwargs):
|
||||
a = attach.attach()
|
||||
if len(a.attachments) != 0:
|
||||
self.attachments = a.attachments
|
||||
|
||||
def autocomplete_users(self, *args, **kwargs):
|
||||
c = autocompletionUsers.completion.autocompletionUsers(self.message, self.session.session_id)
|
||||
c.show_menu()
|
||||
def autocomplete_users(self, *args, **kwargs):
|
||||
c = autocompletionUsers.completion.autocompletionUsers(self.message, self.session.session_id)
|
||||
c.show_menu()
|
||||
|
||||
class reply(tweet):
|
||||
def __init__(self, session, title, caption, text, users=[], ids=[]):
|
||||
super(reply, self).__init__(session, title, caption, text, messageType="reply", users=users)
|
||||
self.ids = ids
|
||||
self.users = users
|
||||
if len(users) > 0:
|
||||
widgetUtils.connect_event(self.message.mentionAll, widgetUtils.CHECKBOX, self.mention_all)
|
||||
self.message.enable_button("mentionAll")
|
||||
if config.app["app-settings"]["remember_mention_and_longtweet"]:
|
||||
self.message.mentionAll.SetValue(config.app["app-settings"]["mention_all"])
|
||||
self.mention_all()
|
||||
self.message.set_cursor_at_end()
|
||||
self.text_processor()
|
||||
def __init__(self, session, title, caption, text, users=[], ids=[]):
|
||||
super(reply, self).__init__(session, title, caption, text, messageType="reply", users=users)
|
||||
self.ids = ids
|
||||
self.users = users
|
||||
if len(users) > 0:
|
||||
widgetUtils.connect_event(self.message.mentionAll, widgetUtils.CHECKBOX, self.mention_all)
|
||||
self.message.enable_button("mentionAll")
|
||||
if config.app["app-settings"]["remember_mention_and_longtweet"]:
|
||||
self.message.mentionAll.SetValue(config.app["app-settings"]["mention_all"])
|
||||
self.mention_all()
|
||||
self.message.set_cursor_at_end()
|
||||
self.text_processor()
|
||||
|
||||
def mention_all(self, *args, **kwargs):
|
||||
if self.message.mentionAll.GetValue() == True:
|
||||
for i in self.message.checkboxes:
|
||||
i.SetValue(True)
|
||||
i.Hide()
|
||||
else:
|
||||
for i in self.message.checkboxes:
|
||||
i.SetValue(False)
|
||||
i.Show()
|
||||
def mention_all(self, *args, **kwargs):
|
||||
if self.message.mentionAll.GetValue() == True:
|
||||
for i in self.message.checkboxes:
|
||||
i.SetValue(True)
|
||||
i.Hide()
|
||||
else:
|
||||
for i in self.message.checkboxes:
|
||||
i.SetValue(False)
|
||||
i.Show()
|
||||
|
||||
def get_ids(self):
|
||||
excluded_ids = ""
|
||||
for i in range(0, len(self.message.checkboxes)):
|
||||
if self.message.checkboxes[i].GetValue() == False:
|
||||
excluded_ids = excluded_ids + "{0},".format(self.ids[i],)
|
||||
return excluded_ids
|
||||
def get_ids(self):
|
||||
excluded_ids = ""
|
||||
for i in range(0, len(self.message.checkboxes)):
|
||||
if self.message.checkboxes[i].GetValue() == False:
|
||||
excluded_ids = excluded_ids + "{0},".format(self.ids[i],)
|
||||
return excluded_ids
|
||||
|
||||
def get_people(self):
|
||||
people = ""
|
||||
for i in range(0, len(self.message.checkboxes)):
|
||||
if self.message.checkboxes[i].GetValue() == True:
|
||||
people = people + "{0} ".format(self.message.checkboxes[i].GetLabel(),)
|
||||
return people
|
||||
def get_people(self):
|
||||
people = ""
|
||||
for i in range(0, len(self.message.checkboxes)):
|
||||
if self.message.checkboxes[i].GetValue() == True:
|
||||
people = people + "{0} ".format(self.message.checkboxes[i].GetLabel(),)
|
||||
return people
|
||||
|
||||
class dm(basicTweet):
|
||||
def __init__(self, session, title, caption, text):
|
||||
super(dm, self).__init__(session, title, caption, text, messageType="dm", max=10000)
|
||||
widgetUtils.connect_event(self.message.autocompletionButton, widgetUtils.BUTTON_PRESSED, self.autocomplete_users)
|
||||
self.text_processor()
|
||||
widgetUtils.connect_event(self.message.cb, widgetUtils.ENTERED_TEXT, self.user_changed)
|
||||
def __init__(self, session, title, caption, text):
|
||||
super(dm, self).__init__(session, title, caption, text, messageType="dm", max=10000)
|
||||
widgetUtils.connect_event(self.message.autocompletionButton, widgetUtils.BUTTON_PRESSED, self.autocomplete_users)
|
||||
self.text_processor()
|
||||
widgetUtils.connect_event(self.message.cb, widgetUtils.ENTERED_TEXT, self.user_changed)
|
||||
|
||||
def user_changed(self, *args, **kwargs):
|
||||
self.title = _("Direct message to %s") % (self.message.get_user())
|
||||
self.text_processor()
|
||||
def user_changed(self, *args, **kwargs):
|
||||
self.title = _("Direct message to %s") % (self.message.get_user())
|
||||
self.text_processor()
|
||||
|
||||
def autocomplete_users(self, *args, **kwargs):
|
||||
c = autocompletionUsers.completion.autocompletionUsers(self.message, self.session.session_id)
|
||||
c.show_menu("dm")
|
||||
def autocomplete_users(self, *args, **kwargs):
|
||||
c = autocompletionUsers.completion.autocompletionUsers(self.message, self.session.session_id)
|
||||
c.show_menu("dm")
|
||||
|
||||
class viewTweet(basicTweet):
|
||||
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.
|
||||
param tweet: A dictionary that represents a full tweet or a string for non-tweets.
|
||||
param tweetList: If is_tweet is set to True, this could be a list of quoted tweets.
|
||||
param is_tweet: True or false, depending wether the passed object is a tweet or not."""
|
||||
if is_tweet == True:
|
||||
self.title = _(u"Tweet")
|
||||
image_description = []
|
||||
text = ""
|
||||
for i in range(0, len(tweetList)):
|
||||
# tweets with message keys are longer tweets, the message value is the full messaje taken from twishort.
|
||||
if hasattr(tweetList[i], "message") and tweetList[i].is_quote_status == False:
|
||||
value = "message"
|
||||
else:
|
||||
value = "full_text"
|
||||
if hasattr(tweetList[i], "retweeted_status") and tweetList[i].is_quote_status == False:
|
||||
if not hasattr(tweetList[i], "message"):
|
||||
text = text + "rt @%s: %s\n" % (tweetList[i].retweeted_status.user.screen_name, tweetList[i].retweeted_status.full_text)
|
||||
else:
|
||||
text = text + "rt @%s: %s\n" % (tweetList[i].retweeted_status.user.screen_name, getattr(tweetList[i], value))
|
||||
else:
|
||||
text = text + " @%s: %s\n" % (tweetList[i].user.screen_name, getattr(tweetList[i], value))
|
||||
# tweets with extended_entities could include image descriptions.
|
||||
if hasattr(tweetList[i], "extended_entities") and "media" in tweetList[i].extended_entities:
|
||||
for z in tweetList[i].extended_entities["media"]:
|
||||
if "ext_alt_text" in z and z["ext_alt_text"] != None:
|
||||
image_description.append(z["ext_alt_text"])
|
||||
if hasattr(tweetList[i], "retweeted_status") and hasattr(tweetList[i].retweeted_status, "extended_entities") and "media" in tweetList[i].retweeted_status["extended_entities"]:
|
||||
for z in tweetList[i].retweeted_status.extended_entities["media"]:
|
||||
if "ext_alt_text" in z and z["ext_alt_text"] != None:
|
||||
image_description.append(z["ext_alt_text"])
|
||||
# set rt and likes counters.
|
||||
rt_count = str(tweet.retweet_count)
|
||||
favs_count = str(tweet.favorite_count)
|
||||
# Gets the client from where this tweet was made.
|
||||
source = tweet.source
|
||||
original_date = arrow.get(tweet.created_at, locale="en")
|
||||
date = original_date.shift(seconds=utc_offset).format(_(u"MMM D, YYYY. H:m"), locale=languageHandler.getLanguage())
|
||||
if text == "":
|
||||
if hasattr(tweet, "message"):
|
||||
value = "message"
|
||||
else:
|
||||
value = "full_text"
|
||||
if hasattr(tweet, "retweeted_status"):
|
||||
if not hasattr(tweet, "message"):
|
||||
text = "rt @%s: %s" % (tweet.retweeted_status.user.screen_name, tweet.retweeted_status.full_text)
|
||||
else:
|
||||
text = "rt @%s: %s" % (tweet.retweeted_status.user.screen_name, getattr(tweet, value))
|
||||
else:
|
||||
text = getattr(tweet, value)
|
||||
text = self.clear_text(text)
|
||||
if hasattr(tweet, "extended_entities") and "media" in tweet.extended_entities:
|
||||
for z in tweet.extended_entities["media"]:
|
||||
if "ext_alt_text" in z and z["ext_alt_text"] != None:
|
||||
image_description.append(z["ext_alt_text"])
|
||||
if hasattr(tweet, "retweeted_status") and hasattr(tweet.retweeted_status, "extended_entities") and "media" in tweet.retweeted_status.extended_entities:
|
||||
for z in tweet.retweeted_status.extended_entities["media"]:
|
||||
if "ext_alt_text" in z and z["ext_alt_text"] != None:
|
||||
image_description.append(z["ext_alt_text"])
|
||||
self.message = message.viewTweet(text, rt_count, favs_count, source, date)
|
||||
results = parse_tweet(text)
|
||||
self.message.set_title(results.weightedLength)
|
||||
[self.message.set_image_description(i) for i in image_description]
|
||||
else:
|
||||
self.title = _(u"View item")
|
||||
text = tweet
|
||||
self.message = message.viewNonTweet(text, date)
|
||||
widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck)
|
||||
widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate)
|
||||
if self.contain_urls() == True:
|
||||
self.message.enable_button("unshortenButton")
|
||||
widgetUtils.connect_event(self.message.unshortenButton, widgetUtils.BUTTON_PRESSED, self.unshorten)
|
||||
self.message.get_response()
|
||||
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.
|
||||
param tweet: A dictionary that represents a full tweet or a string for non-tweets.
|
||||
param tweetList: If is_tweet is set to True, this could be a list of quoted tweets.
|
||||
param is_tweet: True or false, depending wether the passed object is a tweet or not."""
|
||||
if is_tweet == True:
|
||||
self.title = _(u"Tweet")
|
||||
image_description = []
|
||||
text = ""
|
||||
for i in range(0, len(tweetList)):
|
||||
# tweets with message keys are longer tweets, the message value is the full messaje taken from twishort.
|
||||
if hasattr(tweetList[i], "message") and tweetList[i].is_quote_status == False:
|
||||
value = "message"
|
||||
else:
|
||||
value = "full_text"
|
||||
if hasattr(tweetList[i], "retweeted_status") and tweetList[i].is_quote_status == False:
|
||||
if not hasattr(tweetList[i], "message"):
|
||||
text = text + "rt @%s: %s\n" % (tweetList[i].retweeted_status.user.screen_name, tweetList[i].retweeted_status.full_text)
|
||||
else:
|
||||
text = text + "rt @%s: %s\n" % (tweetList[i].retweeted_status.user.screen_name, getattr(tweetList[i], value))
|
||||
else:
|
||||
text = text + " @%s: %s\n" % (tweetList[i].user.screen_name, getattr(tweetList[i], value))
|
||||
# tweets with extended_entities could include image descriptions.
|
||||
if hasattr(tweetList[i], "extended_entities") and "media" in tweetList[i].extended_entities:
|
||||
for z in tweetList[i].extended_entities["media"]:
|
||||
if "ext_alt_text" in z and z["ext_alt_text"] != None:
|
||||
image_description.append(z["ext_alt_text"])
|
||||
if hasattr(tweetList[i], "retweeted_status") and hasattr(tweetList[i].retweeted_status, "extended_entities") and "media" in tweetList[i].retweeted_status["extended_entities"]:
|
||||
for z in tweetList[i].retweeted_status.extended_entities["media"]:
|
||||
if "ext_alt_text" in z and z["ext_alt_text"] != None:
|
||||
image_description.append(z["ext_alt_text"])
|
||||
# set rt and likes counters.
|
||||
rt_count = str(tweet.retweet_count)
|
||||
favs_count = str(tweet.favorite_count)
|
||||
# Gets the client from where this tweet was made.
|
||||
source = tweet.source
|
||||
original_date = arrow.get(tweet.created_at, locale="en")
|
||||
date = original_date.shift(seconds=utc_offset).format(_(u"MMM D, YYYY. H:m"), locale=languageHandler.getLanguage())
|
||||
if text == "":
|
||||
if hasattr(tweet, "message"):
|
||||
value = "message"
|
||||
else:
|
||||
value = "full_text"
|
||||
if hasattr(tweet, "retweeted_status"):
|
||||
if not hasattr(tweet, "message"):
|
||||
text = "rt @%s: %s" % (tweet.retweeted_status.user.screen_name, tweet.retweeted_status.full_text)
|
||||
else:
|
||||
text = "rt @%s: %s" % (tweet.retweeted_status.user.screen_name, getattr(tweet, value))
|
||||
else:
|
||||
text = getattr(tweet, value)
|
||||
text = self.clear_text(text)
|
||||
if hasattr(tweet, "extended_entities") and "media" in tweet.extended_entities:
|
||||
for z in tweet.extended_entities["media"]:
|
||||
if "ext_alt_text" in z and z["ext_alt_text"] != None:
|
||||
image_description.append(z["ext_alt_text"])
|
||||
if hasattr(tweet, "retweeted_status") and hasattr(tweet.retweeted_status, "extended_entities") and "media" in tweet.retweeted_status.extended_entities:
|
||||
for z in tweet.retweeted_status.extended_entities["media"]:
|
||||
if "ext_alt_text" in z and z["ext_alt_text"] != None:
|
||||
image_description.append(z["ext_alt_text"])
|
||||
self.message = message.viewTweet(text, rt_count, favs_count, source, date)
|
||||
results = parse_tweet(text)
|
||||
self.message.set_title(results.weightedLength)
|
||||
[self.message.set_image_description(i) for i in image_description]
|
||||
else:
|
||||
self.title = _(u"View item")
|
||||
text = tweet
|
||||
self.message = message.viewNonTweet(text, date)
|
||||
widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck)
|
||||
widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate)
|
||||
if self.contain_urls() == True:
|
||||
self.message.enable_button("unshortenButton")
|
||||
widgetUtils.connect_event(self.message.unshortenButton, widgetUtils.BUTTON_PRESSED, self.unshorten)
|
||||
self.message.get_response()
|
||||
|
||||
def contain_urls(self):
|
||||
if len(utils.find_urls_in_text(self.message.get_text())) > 0:
|
||||
return True
|
||||
return False
|
||||
def contain_urls(self):
|
||||
if len(utils.find_urls_in_text(self.message.get_text())) > 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
def clear_text(self, text):
|
||||
urls = utils.find_urls_in_text(text)
|
||||
for i in urls:
|
||||
if "https://twitter.com/" in i:
|
||||
text = text.replace(i, "\n")
|
||||
return text
|
||||
def clear_text(self, text):
|
||||
urls = utils.find_urls_in_text(text)
|
||||
for i in urls:
|
||||
if "https://twitter.com/" in i:
|
||||
text = text.replace(i, "\n")
|
||||
return text
|
||||
|
@ -24,202 +24,202 @@ from collections import OrderedDict
|
||||
from mysc import autostart as autostart_windows
|
||||
|
||||
class globalSettingsController(object):
|
||||
def __init__(self):
|
||||
super(globalSettingsController, self).__init__()
|
||||
self.dialog = configuration.configurationDialog()
|
||||
self.create_config()
|
||||
self.needs_restart = False
|
||||
self.is_started = True
|
||||
def __init__(self):
|
||||
super(globalSettingsController, self).__init__()
|
||||
self.dialog = configuration.configurationDialog()
|
||||
self.create_config()
|
||||
self.needs_restart = False
|
||||
self.is_started = True
|
||||
|
||||
def make_kmmap(self):
|
||||
res={}
|
||||
for i in os.listdir(os.path.join(paths.app_path(), 'keymaps')):
|
||||
if ".keymap" not in i:
|
||||
continue
|
||||
try:
|
||||
res[i[:-7]] =i
|
||||
except:
|
||||
log.exception("Exception while loading keymap " + i)
|
||||
return res
|
||||
def make_kmmap(self):
|
||||
res={}
|
||||
for i in os.listdir(os.path.join(paths.app_path(), 'keymaps')):
|
||||
if ".keymap" not in i:
|
||||
continue
|
||||
try:
|
||||
res[i[:-7]] =i
|
||||
except:
|
||||
log.exception("Exception while loading keymap " + i)
|
||||
return res
|
||||
|
||||
def create_config(self):
|
||||
self.kmmap=self.make_kmmap()
|
||||
self.langs = languageHandler.getAvailableLanguages()
|
||||
langs = []
|
||||
[langs.append(i[1]) for i in self.langs]
|
||||
self.codes = []
|
||||
[self.codes.append(i[0]) for i in self.langs]
|
||||
id = self.codes.index(config.app["app-settings"]["language"])
|
||||
self.kmfriendlies=[]
|
||||
self.kmnames=[]
|
||||
for k,v in list(self.kmmap.items()):
|
||||
self.kmfriendlies.append(k)
|
||||
self.kmnames.append(v)
|
||||
self.kmid=self.kmnames.index(config.app['app-settings']['load_keymap'])
|
||||
self.dialog.create_general(langs,self.kmfriendlies)
|
||||
self.dialog.general.language.SetSelection(id)
|
||||
self.dialog.general.km.SetSelection(self.kmid)
|
||||
if paths.mode == "installed":
|
||||
self.dialog.set_value("general", "autostart", config.app["app-settings"]["autostart"])
|
||||
else:
|
||||
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", "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", "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", "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", "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", "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"])
|
||||
proxyTypes = [_("System default"), _("HTTP"), _("SOCKS v4"), _("SOCKS v4 with DNS support"), _("SOCKS v5"), _("SOCKS v5 with DNS support")]
|
||||
self.dialog.create_proxy(proxyTypes)
|
||||
try:
|
||||
self.dialog.proxy.type.SetSelection(config.app["proxy"]["type"])
|
||||
except:
|
||||
self.dialog.proxy.type.SetSelection(0)
|
||||
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", "user", config.app["proxy"]["user"])
|
||||
self.dialog.set_value("proxy", "password", config.app["proxy"]["password"])
|
||||
def create_config(self):
|
||||
self.kmmap=self.make_kmmap()
|
||||
self.langs = languageHandler.getAvailableLanguages()
|
||||
langs = []
|
||||
[langs.append(i[1]) for i in self.langs]
|
||||
self.codes = []
|
||||
[self.codes.append(i[0]) for i in self.langs]
|
||||
id = self.codes.index(config.app["app-settings"]["language"])
|
||||
self.kmfriendlies=[]
|
||||
self.kmnames=[]
|
||||
for k,v in list(self.kmmap.items()):
|
||||
self.kmfriendlies.append(k)
|
||||
self.kmnames.append(v)
|
||||
self.kmid=self.kmnames.index(config.app['app-settings']['load_keymap'])
|
||||
self.dialog.create_general(langs,self.kmfriendlies)
|
||||
self.dialog.general.language.SetSelection(id)
|
||||
self.dialog.general.km.SetSelection(self.kmid)
|
||||
if paths.mode == "installed":
|
||||
self.dialog.set_value("general", "autostart", config.app["app-settings"]["autostart"])
|
||||
else:
|
||||
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", "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", "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", "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", "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", "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"])
|
||||
proxyTypes = [_("System default"), _("HTTP"), _("SOCKS v4"), _("SOCKS v4 with DNS support"), _("SOCKS v5"), _("SOCKS v5 with DNS support")]
|
||||
self.dialog.create_proxy(proxyTypes)
|
||||
try:
|
||||
self.dialog.proxy.type.SetSelection(config.app["proxy"]["type"])
|
||||
except:
|
||||
self.dialog.proxy.type.SetSelection(0)
|
||||
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", "user", config.app["proxy"]["user"])
|
||||
self.dialog.set_value("proxy", "password", config.app["proxy"]["password"])
|
||||
|
||||
self.dialog.realize()
|
||||
self.response = self.dialog.get_response()
|
||||
self.dialog.realize()
|
||||
self.response = self.dialog.get_response()
|
||||
|
||||
def save_configuration(self):
|
||||
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()]
|
||||
languageHandler.setLanguage(config.app["app-settings"]["language"])
|
||||
self.needs_restart = True
|
||||
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()]
|
||||
kmFile = open(os.path.join(paths.config_path(), "keymap.keymap"), "w")
|
||||
kmFile.close()
|
||||
self.needs_restart = True
|
||||
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")
|
||||
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"):
|
||||
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"))
|
||||
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")
|
||||
self.needs_restart = True
|
||||
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")
|
||||
self.needs_restart = True
|
||||
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"]["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"]["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"]["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")
|
||||
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:
|
||||
self.needs_restart = True
|
||||
config.app["proxy"]["type"] = self.dialog.proxy.type.Selection
|
||||
config.app["proxy"]["server"] = self.dialog.get_value("proxy", "server")
|
||||
config.app["proxy"]["port"] = self.dialog.get_value("proxy", "port")
|
||||
config.app["proxy"]["user"] = self.dialog.get_value("proxy", "user")
|
||||
config.app["proxy"]["password"] = self.dialog.get_value("proxy", "password")
|
||||
config.app.write()
|
||||
def save_configuration(self):
|
||||
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()]
|
||||
languageHandler.setLanguage(config.app["app-settings"]["language"])
|
||||
self.needs_restart = True
|
||||
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()]
|
||||
kmFile = open(os.path.join(paths.config_path(), "keymap.keymap"), "w")
|
||||
kmFile.close()
|
||||
self.needs_restart = True
|
||||
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")
|
||||
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"):
|
||||
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"))
|
||||
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")
|
||||
self.needs_restart = True
|
||||
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")
|
||||
self.needs_restart = True
|
||||
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"]["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"]["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"]["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")
|
||||
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:
|
||||
self.needs_restart = True
|
||||
config.app["proxy"]["type"] = self.dialog.proxy.type.Selection
|
||||
config.app["proxy"]["server"] = self.dialog.get_value("proxy", "server")
|
||||
config.app["proxy"]["port"] = self.dialog.get_value("proxy", "port")
|
||||
config.app["proxy"]["user"] = self.dialog.get_value("proxy", "user")
|
||||
config.app["proxy"]["password"] = self.dialog.get_value("proxy", "password")
|
||||
config.app.write()
|
||||
|
||||
class accountSettingsController(globalSettingsController):
|
||||
def __init__(self, buffer, window):
|
||||
self.user = buffer.session.db["user_name"]
|
||||
self.buffer = buffer
|
||||
self.window = window
|
||||
self.config = buffer.session.settings
|
||||
super(accountSettingsController, self).__init__()
|
||||
def __init__(self, buffer, window):
|
||||
self.user = buffer.session.db["user_name"]
|
||||
self.buffer = buffer
|
||||
self.window = window
|
||||
self.config = buffer.session.settings
|
||||
super(accountSettingsController, self).__init__()
|
||||
|
||||
def create_config(self):
|
||||
self.dialog.create_general_account()
|
||||
widgetUtils.connect_event(self.dialog.general.au, widgetUtils.BUTTON_PRESSED, self.manage_autocomplete)
|
||||
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", "itemsPerApiCall", self.config["general"]["max_tweets_per_call"])
|
||||
self.dialog.set_value("general", "reverse_timelines", self.config["general"]["reverse_timelines"])
|
||||
rt = self.config["general"]["retweet_mode"]
|
||||
if rt == "ask":
|
||||
self.dialog.set_value("general", "retweet_mode", _(u"Ask"))
|
||||
elif rt == "direct":
|
||||
self.dialog.set_value("general", "retweet_mode", _(u"Retweet without comments"))
|
||||
else:
|
||||
self.dialog.set_value("general", "retweet_mode", _(u"Retweet with comments"))
|
||||
self.dialog.set_value("general", "persist_size", str(self.config["general"]["persist_size"]))
|
||||
self.dialog.create_reporting()
|
||||
self.dialog.set_value("reporting", "speech_reporting", self.config["reporting"]["speech_reporting"])
|
||||
self.dialog.set_value("reporting", "braille_reporting", self.config["reporting"]["braille_reporting"])
|
||||
self.dialog.create_other_buffers()
|
||||
buffer_values = self.get_buffers_list()
|
||||
self.dialog.buffers.insert_buffers(buffer_values)
|
||||
self.dialog.buffers.connect_hook_func(self.toggle_buffer_active)
|
||||
widgetUtils.connect_event(self.dialog.buffers.toggle_state, widgetUtils.BUTTON_PRESSED, self.toggle_state)
|
||||
widgetUtils.connect_event(self.dialog.buffers.up, widgetUtils.BUTTON_PRESSED, self.dialog.buffers.move_up)
|
||||
widgetUtils.connect_event(self.dialog.buffers.down, widgetUtils.BUTTON_PRESSED, self.dialog.buffers.move_down)
|
||||
def create_config(self):
|
||||
self.dialog.create_general_account()
|
||||
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", "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", "reverse_timelines", self.config["general"]["reverse_timelines"])
|
||||
rt = self.config["general"]["retweet_mode"]
|
||||
if rt == "ask":
|
||||
self.dialog.set_value("general", "retweet_mode", _(u"Ask"))
|
||||
elif rt == "direct":
|
||||
self.dialog.set_value("general", "retweet_mode", _(u"Retweet without comments"))
|
||||
else:
|
||||
self.dialog.set_value("general", "retweet_mode", _(u"Retweet with comments"))
|
||||
self.dialog.set_value("general", "persist_size", str(self.config["general"]["persist_size"]))
|
||||
self.dialog.create_reporting()
|
||||
self.dialog.set_value("reporting", "speech_reporting", self.config["reporting"]["speech_reporting"])
|
||||
self.dialog.set_value("reporting", "braille_reporting", self.config["reporting"]["braille_reporting"])
|
||||
self.dialog.create_other_buffers()
|
||||
buffer_values = self.get_buffers_list()
|
||||
self.dialog.buffers.insert_buffers(buffer_values)
|
||||
self.dialog.buffers.connect_hook_func(self.toggle_buffer_active)
|
||||
widgetUtils.connect_event(self.dialog.buffers.toggle_state, widgetUtils.BUTTON_PRESSED, self.toggle_state)
|
||||
widgetUtils.connect_event(self.dialog.buffers.up, widgetUtils.BUTTON_PRESSED, self.dialog.buffers.move_up)
|
||||
widgetUtils.connect_event(self.dialog.buffers.down, widgetUtils.BUTTON_PRESSED, self.dialog.buffers.move_down)
|
||||
|
||||
|
||||
self.dialog.create_ignored_clients(self.config["twitter"]["ignored_clients"])
|
||||
widgetUtils.connect_event(self.dialog.ignored_clients.add, widgetUtils.BUTTON_PRESSED, self.add_ignored_client)
|
||||
widgetUtils.connect_event(self.dialog.ignored_clients.remove, widgetUtils.BUTTON_PRESSED, self.remove_ignored_client)
|
||||
self.input_devices = sound_lib.input.Input.get_device_names()
|
||||
self.output_devices = sound_lib.output.Output.get_device_names()
|
||||
self.soundpacks = []
|
||||
[self.soundpacks.append(i) for i in os.listdir(paths.sound_path()) if os.path.isdir(os.path.join(paths.sound_path(), i)) == True ]
|
||||
self.dialog.create_sound(self.input_devices, self.output_devices, self.soundpacks)
|
||||
self.dialog.set_value("sound", "volumeCtrl", self.config["sound"]["volume"]*100)
|
||||
self.dialog.set_value("sound", "input", self.config["sound"]["input_device"])
|
||||
self.dialog.set_value("sound", "output", self.config["sound"]["output_device"])
|
||||
self.dialog.set_value("sound", "session_mute", self.config["sound"]["session_mute"])
|
||||
self.dialog.set_value("sound", "soundpack", self.config["sound"]["current_soundpack"])
|
||||
self.dialog.set_value("sound", "indicate_audio", self.config["sound"]["indicate_audio"])
|
||||
self.dialog.set_value("sound", "indicate_geo", self.config["sound"]["indicate_geo"])
|
||||
self.dialog.set_value("sound", "indicate_img", self.config["sound"]["indicate_img"])
|
||||
self.dialog.create_extras(OCRSpace.translatable_langs)
|
||||
self.dialog.set_value("extras", "sndup_apiKey", self.config["sound"]["sndup_api_key"])
|
||||
language_index = OCRSpace.OcrLangs.index(self.config["mysc"]["ocr_language"])
|
||||
self.dialog.extras.ocr_lang.SetSelection(language_index)
|
||||
self.dialog.realize()
|
||||
self.dialog.set_title(_(u"Account settings for %s") % (self.user,))
|
||||
self.response = self.dialog.get_response()
|
||||
self.dialog.create_ignored_clients(self.config["twitter"]["ignored_clients"])
|
||||
widgetUtils.connect_event(self.dialog.ignored_clients.add, widgetUtils.BUTTON_PRESSED, self.add_ignored_client)
|
||||
widgetUtils.connect_event(self.dialog.ignored_clients.remove, widgetUtils.BUTTON_PRESSED, self.remove_ignored_client)
|
||||
self.input_devices = sound_lib.input.Input.get_device_names()
|
||||
self.output_devices = sound_lib.output.Output.get_device_names()
|
||||
self.soundpacks = []
|
||||
[self.soundpacks.append(i) for i in os.listdir(paths.sound_path()) if os.path.isdir(os.path.join(paths.sound_path(), i)) == True ]
|
||||
self.dialog.create_sound(self.input_devices, self.output_devices, self.soundpacks)
|
||||
self.dialog.set_value("sound", "volumeCtrl", self.config["sound"]["volume"]*100)
|
||||
self.dialog.set_value("sound", "input", self.config["sound"]["input_device"])
|
||||
self.dialog.set_value("sound", "output", self.config["sound"]["output_device"])
|
||||
self.dialog.set_value("sound", "session_mute", self.config["sound"]["session_mute"])
|
||||
self.dialog.set_value("sound", "soundpack", self.config["sound"]["current_soundpack"])
|
||||
self.dialog.set_value("sound", "indicate_audio", self.config["sound"]["indicate_audio"])
|
||||
self.dialog.set_value("sound", "indicate_geo", self.config["sound"]["indicate_geo"])
|
||||
self.dialog.set_value("sound", "indicate_img", self.config["sound"]["indicate_img"])
|
||||
self.dialog.create_extras(OCRSpace.translatable_langs)
|
||||
self.dialog.set_value("extras", "sndup_apiKey", self.config["sound"]["sndup_api_key"])
|
||||
language_index = OCRSpace.OcrLangs.index(self.config["mysc"]["ocr_language"])
|
||||
self.dialog.extras.ocr_lang.SetSelection(language_index)
|
||||
self.dialog.realize()
|
||||
self.dialog.set_title(_(u"Account settings for %s") % (self.user,))
|
||||
self.response = self.dialog.get_response()
|
||||
|
||||
def save_configuration(self):
|
||||
if self.config["general"]["relative_times"] != self.dialog.get_value("general", "relative_time"):
|
||||
self.needs_restart = True
|
||||
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"]["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.dialog.get_value("general", "persist_size") == '':
|
||||
self.config["general"]["persist_size"] =-1
|
||||
else:
|
||||
try:
|
||||
self.config["general"]["persist_size"] = int(self.dialog.get_value("general", "persist_size"))
|
||||
except ValueError:
|
||||
output.speak("Invalid cache size, setting to default.",True)
|
||||
self.config["general"]["persist_size"] =1764
|
||||
def save_configuration(self):
|
||||
if self.config["general"]["relative_times"] != self.dialog.get_value("general", "relative_time"):
|
||||
self.needs_restart = True
|
||||
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"]["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.dialog.get_value("general", "persist_size") == '':
|
||||
self.config["general"]["persist_size"] =-1
|
||||
else:
|
||||
try:
|
||||
self.config["general"]["persist_size"] = int(self.dialog.get_value("general", "persist_size"))
|
||||
except ValueError:
|
||||
output.speak("Invalid cache size, setting to default.",True)
|
||||
self.config["general"]["persist_size"] =1764
|
||||
|
||||
if self.config["general"]["reverse_timelines"] != self.dialog.get_value("general", "reverse_timelines"):
|
||||
self.needs_restart = True
|
||||
self.config["general"]["reverse_timelines"] = self.dialog.get_value("general", "reverse_timelines")
|
||||
rt = self.dialog.get_value("general", "retweet_mode")
|
||||
if rt == _(u"Ask"):
|
||||
self.config["general"]["retweet_mode"] = "ask"
|
||||
elif rt == _(u"Retweet without comments"):
|
||||
self.config["general"]["retweet_mode"] = "direct"
|
||||
else:
|
||||
self.config["general"]["retweet_mode"] = "comment"
|
||||
buffers_list = self.dialog.buffers.get_list()
|
||||
if buffers_list != self.config["general"]["buffer_order"]:
|
||||
self.needs_restart = True
|
||||
self.config["general"]["buffer_order"] = buffers_list
|
||||
self.config["reporting"]["speech_reporting"] = self.dialog.get_value("reporting", "speech_reporting")
|
||||
self.config["reporting"]["braille_reporting"] = self.dialog.get_value("reporting", "braille_reporting")
|
||||
self.config["mysc"]["ocr_language"] = OCRSpace.OcrLangs[self.dialog.extras.ocr_lang.GetSelection()]
|
||||
if self.config["general"]["reverse_timelines"] != self.dialog.get_value("general", "reverse_timelines"):
|
||||
self.needs_restart = True
|
||||
self.config["general"]["reverse_timelines"] = self.dialog.get_value("general", "reverse_timelines")
|
||||
rt = self.dialog.get_value("general", "retweet_mode")
|
||||
if rt == _(u"Ask"):
|
||||
self.config["general"]["retweet_mode"] = "ask"
|
||||
elif rt == _(u"Retweet without comments"):
|
||||
self.config["general"]["retweet_mode"] = "direct"
|
||||
else:
|
||||
self.config["general"]["retweet_mode"] = "comment"
|
||||
buffers_list = self.dialog.buffers.get_list()
|
||||
if buffers_list != self.config["general"]["buffer_order"]:
|
||||
self.needs_restart = True
|
||||
self.config["general"]["buffer_order"] = buffers_list
|
||||
self.config["reporting"]["speech_reporting"] = self.dialog.get_value("reporting", "speech_reporting")
|
||||
self.config["reporting"]["braille_reporting"] = self.dialog.get_value("reporting", "braille_reporting")
|
||||
self.config["mysc"]["ocr_language"] = OCRSpace.OcrLangs[self.dialog.extras.ocr_lang.GetSelection()]
|
||||
# if self.config["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"])
|
||||
@ -238,75 +238,75 @@ class accountSettingsController(globalSettingsController):
|
||||
# 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")
|
||||
# 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"):
|
||||
self.config["sound"]["input_device"] = self.dialog.sound.get("input")
|
||||
try:
|
||||
self.buffer.session.sound.input.set_device(self.buffer.session.sound.input.find_device_by_name(self.config["sound"]["input_device"]))
|
||||
except:
|
||||
self.config["sound"]["input_device"] = "default"
|
||||
if self.config["sound"]["output_device"] != self.dialog.sound.get("output"):
|
||||
self.config["sound"]["output_device"] = self.dialog.sound.get("output")
|
||||
try:
|
||||
self.buffer.session.sound.output.set_device(self.buffer.session.sound.output.find_device_by_name(self.config["sound"]["output_device"]))
|
||||
except:
|
||||
self.config["sound"]["output_device"] = "default"
|
||||
self.config["sound"]["volume"] = self.dialog.get_value("sound", "volumeCtrl")/100.0
|
||||
self.config["sound"]["session_mute"] = self.dialog.get_value("sound", "session_mute")
|
||||
self.config["sound"]["current_soundpack"] = self.dialog.sound.get("soundpack")
|
||||
self.config["sound"]["indicate_audio"] = self.dialog.get_value("sound", "indicate_audio")
|
||||
self.config["sound"]["indicate_geo"] = self.dialog.get_value("sound", "indicate_geo")
|
||||
self.config["sound"]["indicate_img"] = self.dialog.get_value("sound", "indicate_img")
|
||||
self.config["sound"]["sndup_api_key"] = self.dialog.get_value("extras", "sndup_apiKey")
|
||||
self.buffer.session.sound.config = self.config["sound"]
|
||||
self.buffer.session.sound.check_soundpack()
|
||||
self.config.write()
|
||||
if self.config["sound"]["input_device"] != self.dialog.sound.get("input"):
|
||||
self.config["sound"]["input_device"] = self.dialog.sound.get("input")
|
||||
try:
|
||||
self.buffer.session.sound.input.set_device(self.buffer.session.sound.input.find_device_by_name(self.config["sound"]["input_device"]))
|
||||
except:
|
||||
self.config["sound"]["input_device"] = "default"
|
||||
if self.config["sound"]["output_device"] != self.dialog.sound.get("output"):
|
||||
self.config["sound"]["output_device"] = self.dialog.sound.get("output")
|
||||
try:
|
||||
self.buffer.session.sound.output.set_device(self.buffer.session.sound.output.find_device_by_name(self.config["sound"]["output_device"]))
|
||||
except:
|
||||
self.config["sound"]["output_device"] = "default"
|
||||
self.config["sound"]["volume"] = self.dialog.get_value("sound", "volumeCtrl")/100.0
|
||||
self.config["sound"]["session_mute"] = self.dialog.get_value("sound", "session_mute")
|
||||
self.config["sound"]["current_soundpack"] = self.dialog.sound.get("soundpack")
|
||||
self.config["sound"]["indicate_audio"] = self.dialog.get_value("sound", "indicate_audio")
|
||||
self.config["sound"]["indicate_geo"] = self.dialog.get_value("sound", "indicate_geo")
|
||||
self.config["sound"]["indicate_img"] = self.dialog.get_value("sound", "indicate_img")
|
||||
self.config["sound"]["sndup_api_key"] = self.dialog.get_value("extras", "sndup_apiKey")
|
||||
self.buffer.session.sound.config = self.config["sound"]
|
||||
self.buffer.session.sound.check_soundpack()
|
||||
self.config.write()
|
||||
|
||||
def toggle_state(self,*args,**kwargs):
|
||||
return self.dialog.buffers.change_selected_item()
|
||||
def toggle_state(self,*args,**kwargs):
|
||||
return self.dialog.buffers.change_selected_item()
|
||||
|
||||
def manage_autocomplete(self, *args, **kwargs):
|
||||
configuration = settings.autocompletionSettings(self.buffer.session.settings, self.buffer, self.window)
|
||||
def manage_autocomplete(self, *args, **kwargs):
|
||||
configuration = settings.autocompletionSettings(self.buffer.session.settings, self.buffer, self.window)
|
||||
|
||||
def add_ignored_client(self, *args, **kwargs):
|
||||
client = commonMessageDialogs.get_ignored_client()
|
||||
if client == None: return
|
||||
if client not in self.config["twitter"]["ignored_clients"]:
|
||||
self.config["twitter"]["ignored_clients"].append(client)
|
||||
self.dialog.ignored_clients.append(client)
|
||||
def add_ignored_client(self, *args, **kwargs):
|
||||
client = commonMessageDialogs.get_ignored_client()
|
||||
if client == None: return
|
||||
if client not in self.config["twitter"]["ignored_clients"]:
|
||||
self.config["twitter"]["ignored_clients"].append(client)
|
||||
self.dialog.ignored_clients.append(client)
|
||||
|
||||
def remove_ignored_client(self, *args, **kwargs):
|
||||
if self.dialog.ignored_clients.get_clients() == 0: return
|
||||
id = self.dialog.ignored_clients.get_client_id()
|
||||
self.config["twitter"]["ignored_clients"].pop(id)
|
||||
self.dialog.ignored_clients.remove_(id)
|
||||
def remove_ignored_client(self, *args, **kwargs):
|
||||
if self.dialog.ignored_clients.get_clients() == 0: return
|
||||
id = self.dialog.ignored_clients.get_client_id()
|
||||
self.config["twitter"]["ignored_clients"].pop(id)
|
||||
self.dialog.ignored_clients.remove_(id)
|
||||
|
||||
def get_buffers_list(self):
|
||||
all_buffers=OrderedDict()
|
||||
all_buffers['home']=_(u"Home")
|
||||
all_buffers['mentions']=_(u"Mentions")
|
||||
all_buffers['dm']=_(u"Direct Messages")
|
||||
all_buffers['sent_dm']=_(u"Sent direct messages")
|
||||
all_buffers['sent_tweets']=_(u"Sent tweets")
|
||||
all_buffers['favorites']=_(u"Likes")
|
||||
all_buffers['followers']=_(u"Followers")
|
||||
all_buffers['friends']=_(u"Friends")
|
||||
all_buffers['blocks']=_(u"Blocked users")
|
||||
all_buffers['muted']=_(u"Muted users")
|
||||
list_buffers = []
|
||||
hidden_buffers=[]
|
||||
all_buffers_keys = list(all_buffers.keys())
|
||||
# Check buffers shown first.
|
||||
for i in self.config["general"]["buffer_order"]:
|
||||
if i in all_buffers_keys:
|
||||
list_buffers.append((i, all_buffers[i], True))
|
||||
# This second pass will retrieve all hidden buffers.
|
||||
for i in all_buffers_keys:
|
||||
if i not in self.config["general"]["buffer_order"]:
|
||||
hidden_buffers.append((i, all_buffers[i], False))
|
||||
list_buffers.extend(hidden_buffers)
|
||||
return list_buffers
|
||||
def get_buffers_list(self):
|
||||
all_buffers=OrderedDict()
|
||||
all_buffers['home']=_(u"Home")
|
||||
all_buffers['mentions']=_(u"Mentions")
|
||||
all_buffers['dm']=_(u"Direct Messages")
|
||||
all_buffers['sent_dm']=_(u"Sent direct messages")
|
||||
all_buffers['sent_tweets']=_(u"Sent tweets")
|
||||
all_buffers['favorites']=_(u"Likes")
|
||||
all_buffers['followers']=_(u"Followers")
|
||||
all_buffers['friends']=_(u"Friends")
|
||||
all_buffers['blocks']=_(u"Blocked users")
|
||||
all_buffers['muted']=_(u"Muted users")
|
||||
list_buffers = []
|
||||
hidden_buffers=[]
|
||||
all_buffers_keys = list(all_buffers.keys())
|
||||
# Check buffers shown first.
|
||||
for i in self.config["general"]["buffer_order"]:
|
||||
if i in all_buffers_keys:
|
||||
list_buffers.append((i, all_buffers[i], True))
|
||||
# This second pass will retrieve all hidden buffers.
|
||||
for i in all_buffers_keys:
|
||||
if i not in self.config["general"]["buffer_order"]:
|
||||
hidden_buffers.append((i, all_buffers[i], False))
|
||||
list_buffers.extend(hidden_buffers)
|
||||
return list_buffers
|
||||
|
||||
def toggle_buffer_active(self, ev):
|
||||
change = self.dialog.buffers.get_event(ev)
|
||||
if change == True:
|
||||
self.dialog.buffers.change_selected_item()
|
||||
def toggle_buffer_active(self, ev):
|
||||
change = self.dialog.buffers.get_event(ev)
|
||||
if change == True:
|
||||
self.dialog.buffers.change_selected_item()
|
||||
|
@ -3,43 +3,43 @@ from wxUI.dialogs import trends
|
||||
import widgetUtils
|
||||
|
||||
class trendingTopicsController(object):
|
||||
def __init__(self, session):
|
||||
super(trendingTopicsController, self).__init__()
|
||||
self.countries = {}
|
||||
self.cities = {}
|
||||
self.dialog = trends.trendingTopicsDialog()
|
||||
self.information = session.twitter.trends_available()
|
||||
self.split_information()
|
||||
widgetUtils.connect_event(self.dialog.country, widgetUtils.RADIOBUTTON, self.get_places)
|
||||
widgetUtils.connect_event(self.dialog.city, widgetUtils.RADIOBUTTON, self.get_places)
|
||||
self.get_places()
|
||||
def __init__(self, session):
|
||||
super(trendingTopicsController, self).__init__()
|
||||
self.countries = {}
|
||||
self.cities = {}
|
||||
self.dialog = trends.trendingTopicsDialog()
|
||||
self.information = session.twitter.trends_available()
|
||||
self.split_information()
|
||||
widgetUtils.connect_event(self.dialog.country, widgetUtils.RADIOBUTTON, self.get_places)
|
||||
widgetUtils.connect_event(self.dialog.city, widgetUtils.RADIOBUTTON, self.get_places)
|
||||
self.get_places()
|
||||
|
||||
def split_information(self):
|
||||
for i in self.information:
|
||||
if i["placeType"]["name"] == "Country":
|
||||
self.countries[i["name"]] = i["woeid"]
|
||||
else:
|
||||
self.cities[i["name"]] = i["woeid"]
|
||||
def split_information(self):
|
||||
for i in self.information:
|
||||
if i["placeType"]["name"] == "Country":
|
||||
self.countries[i["name"]] = i["woeid"]
|
||||
else:
|
||||
self.cities[i["name"]] = i["woeid"]
|
||||
|
||||
def get_places(self, event=None):
|
||||
values = []
|
||||
if self.dialog.get_active() == "country":
|
||||
for i in self.information:
|
||||
if i["placeType"]["name"] == "Country":
|
||||
values.append(i["name"])
|
||||
elif self.dialog.get_active() == "city":
|
||||
for i in self.information:
|
||||
if i["placeType"]["name"] != "Country":
|
||||
values.append(i["name"])
|
||||
self.dialog.set(values)
|
||||
def get_places(self, event=None):
|
||||
values = []
|
||||
if self.dialog.get_active() == "country":
|
||||
for i in self.information:
|
||||
if i["placeType"]["name"] == "Country":
|
||||
values.append(i["name"])
|
||||
elif self.dialog.get_active() == "city":
|
||||
for i in self.information:
|
||||
if i["placeType"]["name"] != "Country":
|
||||
values.append(i["name"])
|
||||
self.dialog.set(values)
|
||||
|
||||
def get_woeid(self):
|
||||
selected = self.dialog.get_item()
|
||||
if self.dialog.get_active() == "country":
|
||||
woeid = self.countries[selected]
|
||||
else:
|
||||
woeid = self.cities[selected]
|
||||
return woeid
|
||||
def get_woeid(self):
|
||||
selected = self.dialog.get_item()
|
||||
if self.dialog.get_active() == "country":
|
||||
woeid = self.countries[selected]
|
||||
else:
|
||||
woeid = self.cities[selected]
|
||||
return woeid
|
||||
|
||||
def get_string(self):
|
||||
return self.dialog.get_item()
|
||||
def get_string(self):
|
||||
return self.dialog.get_item()
|
||||
|
@ -10,119 +10,119 @@ from tweepy.error import TweepError
|
||||
from sessions.twitter import utils
|
||||
|
||||
class profileController(object):
|
||||
def __init__(self, session, user=None):
|
||||
super(profileController, self).__init__()
|
||||
self.file = None
|
||||
self.session = session
|
||||
self.user = user
|
||||
if user == None:
|
||||
self.get_data(screen_name=self.session.db["user_name"])
|
||||
self.dialog = update_profile.updateProfileDialog()
|
||||
self.fill_profile_fields()
|
||||
self.uploaded = False
|
||||
widgetUtils.connect_event(self.dialog.upload_image, widgetUtils.BUTTON_PRESSED, self.upload_image)
|
||||
else:
|
||||
try:
|
||||
self.get_data(screen_name=self.user)
|
||||
except TweepError as err:
|
||||
if err.api_code == 50:
|
||||
wx.MessageDialog(None, _(u"That user does not exist"), _(u"Error"), wx.ICON_ERROR).ShowModal()
|
||||
if err.api_code == 403:
|
||||
wx.MessageDialog(None, _(u"User has been suspended"), _(u"Error"), wx.ICON_ERROR).ShowModal()
|
||||
log.error("error %d: %s" % (err.api_code, err.reason))
|
||||
return
|
||||
self.dialog = show_user.showUserProfile()
|
||||
string = self.get_user_info()
|
||||
self.dialog.set("text", string)
|
||||
self.dialog.set_title(_(u"Information for %s") % (self.data.screen_name))
|
||||
if self.data.url != None:
|
||||
self.dialog.enable_url()
|
||||
widgetUtils.connect_event(self.dialog.url, widgetUtils.BUTTON_PRESSED, self.visit_url)
|
||||
if self.dialog.get_response() == widgetUtils.OK and self.user == None:
|
||||
self.do_update()
|
||||
def __init__(self, session, user=None):
|
||||
super(profileController, self).__init__()
|
||||
self.file = None
|
||||
self.session = session
|
||||
self.user = user
|
||||
if user == None:
|
||||
self.get_data(screen_name=self.session.db["user_name"])
|
||||
self.dialog = update_profile.updateProfileDialog()
|
||||
self.fill_profile_fields()
|
||||
self.uploaded = False
|
||||
widgetUtils.connect_event(self.dialog.upload_image, widgetUtils.BUTTON_PRESSED, self.upload_image)
|
||||
else:
|
||||
try:
|
||||
self.get_data(screen_name=self.user)
|
||||
except TweepError as err:
|
||||
if err.api_code == 50:
|
||||
wx.MessageDialog(None, _(u"That user does not exist"), _(u"Error"), wx.ICON_ERROR).ShowModal()
|
||||
if err.api_code == 403:
|
||||
wx.MessageDialog(None, _(u"User has been suspended"), _(u"Error"), wx.ICON_ERROR).ShowModal()
|
||||
log.error("error %d: %s" % (err.api_code, err.reason))
|
||||
return
|
||||
self.dialog = show_user.showUserProfile()
|
||||
string = self.get_user_info()
|
||||
self.dialog.set("text", string)
|
||||
self.dialog.set_title(_(u"Information for %s") % (self.data.screen_name))
|
||||
if self.data.url != None:
|
||||
self.dialog.enable_url()
|
||||
widgetUtils.connect_event(self.dialog.url, widgetUtils.BUTTON_PRESSED, self.visit_url)
|
||||
if self.dialog.get_response() == widgetUtils.OK and self.user == None:
|
||||
self.do_update()
|
||||
|
||||
def get_data(self, screen_name):
|
||||
self.data = self.session.twitter.get_user(screen_name=screen_name)
|
||||
if screen_name != self.session.db["user_name"]:
|
||||
self.friendship_status = self.session.twitter.show_friendship(source_screen_name=self.session.db["user_name"], target_screen_name=screen_name)
|
||||
def get_data(self, screen_name):
|
||||
self.data = self.session.twitter.get_user(screen_name=screen_name)
|
||||
if screen_name != self.session.db["user_name"]:
|
||||
self.friendship_status = self.session.twitter.show_friendship(source_screen_name=self.session.db["user_name"], target_screen_name=screen_name)
|
||||
|
||||
def fill_profile_fields(self):
|
||||
self.dialog.set_name(self.data.name)
|
||||
if self.data.url != None:
|
||||
self.dialog.set_url(self.data.url)
|
||||
if len(self.data.location) > 0:
|
||||
self.dialog.set_location(self.data.location)
|
||||
if len(self.data.description) > 0:
|
||||
self.dialog.set_description(self.data.description)
|
||||
def fill_profile_fields(self):
|
||||
self.dialog.set_name(self.data.name)
|
||||
if self.data.url != None:
|
||||
self.dialog.set_url(self.data.url)
|
||||
if len(self.data.location) > 0:
|
||||
self.dialog.set_location(self.data.location)
|
||||
if len(self.data.description) > 0:
|
||||
self.dialog.set_description(self.data.description)
|
||||
|
||||
def get_image(self):
|
||||
file = self.dialog.upload_picture()
|
||||
if file != None:
|
||||
self.file = open(file, "rb")
|
||||
self.uploaded = True
|
||||
self.dialog.change_upload_button(self.uploaded)
|
||||
def get_image(self):
|
||||
file = self.dialog.upload_picture()
|
||||
if file != None:
|
||||
self.file = open(file, "rb")
|
||||
self.uploaded = True
|
||||
self.dialog.change_upload_button(self.uploaded)
|
||||
|
||||
def discard_image(self):
|
||||
self.file = None
|
||||
output.speak(_(u"Discarded"))
|
||||
self.uploaded = False
|
||||
self.dialog.change_upload_button(self.uploaded)
|
||||
def discard_image(self):
|
||||
self.file = None
|
||||
output.speak(_(u"Discarded"))
|
||||
self.uploaded = False
|
||||
self.dialog.change_upload_button(self.uploaded)
|
||||
|
||||
def upload_image(self, *args, **kwargs):
|
||||
if self.uploaded == False:
|
||||
self.get_image()
|
||||
elif self.uploaded == True:
|
||||
self.discard_image()
|
||||
def upload_image(self, *args, **kwargs):
|
||||
if self.uploaded == False:
|
||||
self.get_image()
|
||||
elif self.uploaded == True:
|
||||
self.discard_image()
|
||||
|
||||
def do_update(self):
|
||||
if self.user != None: return
|
||||
name = self.dialog.get("name")
|
||||
description = self.dialog.get("description")
|
||||
location = self.dialog.get("location")
|
||||
url = self.dialog.get("url")
|
||||
if self.file != None:
|
||||
try:
|
||||
self.session.twitter.update_profile_image(image=self.file)
|
||||
except TweepError as e:
|
||||
output.speak(u"Error %s. %s" % (e.api_code, e.reason))
|
||||
try:
|
||||
self.session.twitter.update_profile(name=name, description=description, location=location, url=url)
|
||||
except TweepError as e:
|
||||
output.speak(u"Error %s. %s" % (e.api_code, e.reason))
|
||||
def do_update(self):
|
||||
if self.user != None: return
|
||||
name = self.dialog.get("name")
|
||||
description = self.dialog.get("description")
|
||||
location = self.dialog.get("location")
|
||||
url = self.dialog.get("url")
|
||||
if self.file != None:
|
||||
try:
|
||||
self.session.twitter.update_profile_image(image=self.file)
|
||||
except TweepError as e:
|
||||
output.speak(u"Error %s. %s" % (e.api_code, e.reason))
|
||||
try:
|
||||
self.session.twitter.update_profile(name=name, description=description, location=location, url=url)
|
||||
except TweepError as e:
|
||||
output.speak(u"Error %s. %s" % (e.api_code, e.reason))
|
||||
|
||||
def get_user_info(self):
|
||||
string = u""
|
||||
string = string + _(u"Username: @%s\n") % (self.data.screen_name)
|
||||
string = string + _(u"Name: %s\n") % (self.data.name)
|
||||
if self.data.location != "":
|
||||
string = string + _(u"Location: %s\n") % (self.data.location)
|
||||
if self.data.url != None:
|
||||
string = string+ _(u"URL: %s\n") % (self.data.entities["url"]["urls"][0]["expanded_url"])
|
||||
if self.data.description != "":
|
||||
if self.data.entities.get("description") != None and self.data.entities["description"].get("urls"):
|
||||
self.data.description = utils.expand_urls(self.data.description, self.data.entities["description"])
|
||||
string = string+ _(u"Bio: %s\n") % (self.data.description)
|
||||
if self.data.protected == True: protected = _(u"Yes")
|
||||
else: protected = _(u"No")
|
||||
string = string+ _(u"Protected: %s\n") % (protected)
|
||||
if hasattr(self, "friendship_status"):
|
||||
relation = False
|
||||
friendship = "Relationship: "
|
||||
if self.friendship_status[0].following:
|
||||
friendship += _(u"You follow {0}. ").format(self.data.name,)
|
||||
relation = True
|
||||
if self.friendship_status[1].following:
|
||||
friendship += _(u"{0} is following you.").format(self.data.name,)
|
||||
relation = True
|
||||
if relation == True:
|
||||
string = string+friendship+"\n"
|
||||
string = string+_(u"Followers: %s\n Friends: %s\n") % (self.data.followers_count, self.data.friends_count)
|
||||
if self.data.verified == True: verified = _(u"Yes")
|
||||
else: verified = _(u"No")
|
||||
string = string+ _(u"Verified: %s\n") % (verified)
|
||||
string = string+ _(u"Tweets: %s\n") % (self.data.statuses_count)
|
||||
string = string+ _(u"Likes: %s") % (self.data.favourites_count)
|
||||
return string
|
||||
def get_user_info(self):
|
||||
string = u""
|
||||
string = string + _(u"Username: @%s\n") % (self.data.screen_name)
|
||||
string = string + _(u"Name: %s\n") % (self.data.name)
|
||||
if self.data.location != "":
|
||||
string = string + _(u"Location: %s\n") % (self.data.location)
|
||||
if self.data.url != None:
|
||||
string = string+ _(u"URL: %s\n") % (self.data.entities["url"]["urls"][0]["expanded_url"])
|
||||
if self.data.description != "":
|
||||
if self.data.entities.get("description") != None and self.data.entities["description"].get("urls"):
|
||||
self.data.description = utils.expand_urls(self.data.description, self.data.entities["description"])
|
||||
string = string+ _(u"Bio: %s\n") % (self.data.description)
|
||||
if self.data.protected == True: protected = _(u"Yes")
|
||||
else: protected = _(u"No")
|
||||
string = string+ _(u"Protected: %s\n") % (protected)
|
||||
if hasattr(self, "friendship_status"):
|
||||
relation = False
|
||||
friendship = "Relationship: "
|
||||
if self.friendship_status[0].following:
|
||||
friendship += _(u"You follow {0}. ").format(self.data.name,)
|
||||
relation = True
|
||||
if self.friendship_status[1].following:
|
||||
friendship += _(u"{0} is following you.").format(self.data.name,)
|
||||
relation = True
|
||||
if relation == True:
|
||||
string = string+friendship+"\n"
|
||||
string = string+_(u"Followers: %s\n Friends: %s\n") % (self.data.followers_count, self.data.friends_count)
|
||||
if self.data.verified == True: verified = _(u"Yes")
|
||||
else: verified = _(u"No")
|
||||
string = string+ _(u"Verified: %s\n") % (verified)
|
||||
string = string+ _(u"Tweets: %s\n") % (self.data.statuses_count)
|
||||
string = string+ _(u"Likes: %s") % (self.data.favourites_count)
|
||||
return string
|
||||
|
||||
def visit_url(self, *args, **kwargs):
|
||||
webbrowser.open_new_tab(self.data.url)
|
||||
def visit_url(self, *args, **kwargs):
|
||||
webbrowser.open_new_tab(self.data.url)
|
||||
|
@ -7,73 +7,73 @@ from tweepy.error import TweepError
|
||||
from extra import autocompletionUsers
|
||||
|
||||
class userActionsController(object):
|
||||
def __init__(self, buffer, users=[], default="follow"):
|
||||
super(userActionsController, self).__init__()
|
||||
self.buffer = buffer
|
||||
self.session = buffer.session
|
||||
self.dialog = userActions.UserActionsDialog(users, default)
|
||||
widgetUtils.connect_event(self.dialog.autocompletion, widgetUtils.BUTTON_PRESSED, self.autocomplete_users)
|
||||
if self.dialog.get_response() == widgetUtils.OK:
|
||||
self.process_action()
|
||||
def __init__(self, buffer, users=[], default="follow"):
|
||||
super(userActionsController, self).__init__()
|
||||
self.buffer = buffer
|
||||
self.session = buffer.session
|
||||
self.dialog = userActions.UserActionsDialog(users, default)
|
||||
widgetUtils.connect_event(self.dialog.autocompletion, widgetUtils.BUTTON_PRESSED, self.autocomplete_users)
|
||||
if self.dialog.get_response() == widgetUtils.OK:
|
||||
self.process_action()
|
||||
|
||||
def autocomplete_users(self, *args, **kwargs):
|
||||
c = autocompletionUsers.completion.autocompletionUsers(self.dialog, self.session.session_id)
|
||||
c.show_menu("dm")
|
||||
def autocomplete_users(self, *args, **kwargs):
|
||||
c = autocompletionUsers.completion.autocompletionUsers(self.dialog, self.session.session_id)
|
||||
c.show_menu("dm")
|
||||
|
||||
def process_action(self):
|
||||
action = self.dialog.get_action()
|
||||
user = self.dialog.get_user()
|
||||
if user == "": return
|
||||
getattr(self, action)(user)
|
||||
def process_action(self):
|
||||
action = self.dialog.get_action()
|
||||
user = self.dialog.get_user()
|
||||
if user == "": return
|
||||
getattr(self, action)(user)
|
||||
|
||||
def follow(self, user):
|
||||
try:
|
||||
self.session.twitter.create_friendship(screen_name=user )
|
||||
except TweepError as err:
|
||||
output.speak("Error %s: %s" % (err.api_code, err.reason), True)
|
||||
def follow(self, user):
|
||||
try:
|
||||
self.session.twitter.create_friendship(screen_name=user )
|
||||
except TweepError as err:
|
||||
output.speak("Error %s: %s" % (err.api_code, err.reason), True)
|
||||
|
||||
def unfollow(self, user):
|
||||
try:
|
||||
id = self.session.twitter.destroy_friendship(screen_name=user )
|
||||
except TweepError as err:
|
||||
output.speak("Error %s: %s" % (err.api_code, err.reason), True)
|
||||
def unfollow(self, user):
|
||||
try:
|
||||
id = self.session.twitter.destroy_friendship(screen_name=user )
|
||||
except TweepError as err:
|
||||
output.speak("Error %s: %s" % (err.api_code, err.reason), True)
|
||||
|
||||
def mute(self, user):
|
||||
try:
|
||||
id = self.session.twitter.create_mute(screen_name=user )
|
||||
except TweepError as err:
|
||||
output.speak("Error %s: %s" % (err.api_code, err.reason), True)
|
||||
def mute(self, user):
|
||||
try:
|
||||
id = self.session.twitter.create_mute(screen_name=user )
|
||||
except TweepError as err:
|
||||
output.speak("Error %s: %s" % (err.api_code, err.reason), True)
|
||||
|
||||
def unmute(self, user):
|
||||
try:
|
||||
id = self.session.twitter.destroy_mute(screen_name=user )
|
||||
except TweepError as err:
|
||||
output.speak("Error %s: %s" % (err.api_code, err.reason), True)
|
||||
def unmute(self, user):
|
||||
try:
|
||||
id = self.session.twitter.destroy_mute(screen_name=user )
|
||||
except TweepError as err:
|
||||
output.speak("Error %s: %s" % (err.api_code, err.reason), True)
|
||||
|
||||
def report(self, user):
|
||||
try:
|
||||
id = self.session.twitter.report_spam(screen_name=user )
|
||||
except TweepError as err:
|
||||
output.speak("Error %s: %s" % (err.api_code, err.reason), True)
|
||||
def report(self, user):
|
||||
try:
|
||||
id = self.session.twitter.report_spam(screen_name=user )
|
||||
except TweepError as err:
|
||||
output.speak("Error %s: %s" % (err.api_code, err.reason), True)
|
||||
|
||||
def block(self, user):
|
||||
try:
|
||||
id = self.session.twitter.create_block(screen_name=user )
|
||||
except TweepError as err:
|
||||
output.speak("Error %s: %s" % (err.api_code, err.reason), True)
|
||||
def block(self, user):
|
||||
try:
|
||||
id = self.session.twitter.create_block(screen_name=user )
|
||||
except TweepError as err:
|
||||
output.speak("Error %s: %s" % (err.api_code, err.reason), True)
|
||||
|
||||
def unblock(self, user):
|
||||
try:
|
||||
id = self.session.twitter.destroy_block(screen_name=user )
|
||||
except TweepError as err:
|
||||
output.speak("Error %s: %s" % (err.api_code, err.reason), True)
|
||||
def unblock(self, user):
|
||||
try:
|
||||
id = self.session.twitter.destroy_block(screen_name=user )
|
||||
except TweepError as err:
|
||||
output.speak("Error %s: %s" % (err.api_code, err.reason), True)
|
||||
|
||||
def ignore_client(self, user):
|
||||
tweet = self.buffer.get_right_tweet()
|
||||
if hasattr(tweet, "sender"):
|
||||
output.speak(_(u"You can't ignore direct messages"))
|
||||
return
|
||||
client = tweet.source
|
||||
if client not in self.session.settings["twitter"]["ignored_clients"]:
|
||||
self.session.settings["twitter"]["ignored_clients"].append(client)
|
||||
self.session.settings.write()
|
||||
def ignore_client(self, user):
|
||||
tweet = self.buffer.get_right_tweet()
|
||||
if hasattr(tweet, "sender"):
|
||||
output.speak(_(u"You can't ignore direct messages"))
|
||||
return
|
||||
client = tweet.source
|
||||
if client not in self.session.settings["twitter"]["ignored_clients"]:
|
||||
self.session.settings["twitter"]["ignored_clients"].append(client)
|
||||
self.session.settings.write()
|
||||
|
@ -37,146 +37,146 @@ import logging
|
||||
log = logging.getLogger("extra.AudioUploader.audioUploader")
|
||||
|
||||
class audioUploader(object):
|
||||
def __init__(self, configFile, completed_callback):
|
||||
self.config = configFile
|
||||
super(audioUploader, self).__init__()
|
||||
self.dialog = wx_ui.audioDialog(services=self.get_available_services())
|
||||
self.file = None
|
||||
self.recorded = False
|
||||
self.recording = None
|
||||
self.playing = None
|
||||
widgetUtils.connect_event(self.dialog.play, widgetUtils.BUTTON_PRESSED, self.on_play)
|
||||
widgetUtils.connect_event(self.dialog.pause, widgetUtils.BUTTON_PRESSED, self.on_pause)
|
||||
widgetUtils.connect_event(self.dialog.record, widgetUtils.BUTTON_PRESSED, self.on_record)
|
||||
widgetUtils.connect_event(self.dialog.attach_exists, widgetUtils.BUTTON_PRESSED, self.on_attach_exists)
|
||||
widgetUtils.connect_event(self.dialog.discard, widgetUtils.BUTTON_PRESSED, self.on_discard)
|
||||
if self.dialog.get_response() == widgetUtils.OK:
|
||||
self.postprocess()
|
||||
log.debug("Uploading file %s to %s..." % (self.file, self.dialog.get("services")))
|
||||
self.uploaderDialog = wx_transfer_dialogs.UploadDialog(self.file)
|
||||
output.speak(_(u"Attaching..."))
|
||||
if self.dialog.get("services") == "SNDUp":
|
||||
base_url = "https://sndup.net/post.php"
|
||||
if len(self.config["sound"]["sndup_api_key"]) > 0:
|
||||
url = base_url + '?apikey=' + self.config['sound']['sndup_api_key']
|
||||
else:
|
||||
url = base_url
|
||||
self.uploaderFunction = transfer.Upload(obj=self, field='file', url=url, filename=self.file, completed_callback=completed_callback)
|
||||
pub.subscribe(self.uploaderDialog.update, "uploading")
|
||||
self.uploaderDialog.get_response(self.uploaderFunction.perform_threaded)
|
||||
def __init__(self, configFile, completed_callback):
|
||||
self.config = configFile
|
||||
super(audioUploader, self).__init__()
|
||||
self.dialog = wx_ui.audioDialog(services=self.get_available_services())
|
||||
self.file = None
|
||||
self.recorded = False
|
||||
self.recording = None
|
||||
self.playing = None
|
||||
widgetUtils.connect_event(self.dialog.play, widgetUtils.BUTTON_PRESSED, self.on_play)
|
||||
widgetUtils.connect_event(self.dialog.pause, widgetUtils.BUTTON_PRESSED, self.on_pause)
|
||||
widgetUtils.connect_event(self.dialog.record, widgetUtils.BUTTON_PRESSED, self.on_record)
|
||||
widgetUtils.connect_event(self.dialog.attach_exists, widgetUtils.BUTTON_PRESSED, self.on_attach_exists)
|
||||
widgetUtils.connect_event(self.dialog.discard, widgetUtils.BUTTON_PRESSED, self.on_discard)
|
||||
if self.dialog.get_response() == widgetUtils.OK:
|
||||
self.postprocess()
|
||||
log.debug("Uploading file %s to %s..." % (self.file, self.dialog.get("services")))
|
||||
self.uploaderDialog = wx_transfer_dialogs.UploadDialog(self.file)
|
||||
output.speak(_(u"Attaching..."))
|
||||
if self.dialog.get("services") == "SNDUp":
|
||||
base_url = "https://sndup.net/post.php"
|
||||
if len(self.config["sound"]["sndup_api_key"]) > 0:
|
||||
url = base_url + '?apikey=' + self.config['sound']['sndup_api_key']
|
||||
else:
|
||||
url = base_url
|
||||
self.uploaderFunction = transfer.Upload(obj=self, field='file', url=url, filename=self.file, completed_callback=completed_callback)
|
||||
pub.subscribe(self.uploaderDialog.update, "uploading")
|
||||
self.uploaderDialog.get_response(self.uploaderFunction.perform_threaded)
|
||||
|
||||
def get_available_services(self):
|
||||
services = []
|
||||
services.append("SNDUp")
|
||||
return services
|
||||
def get_available_services(self):
|
||||
services = []
|
||||
services.append("SNDUp")
|
||||
return services
|
||||
|
||||
def on_pause(self, *args, **kwargs):
|
||||
if self.dialog.get("pause") == _(u"Pause"):
|
||||
self.recording.pause()
|
||||
self.dialog.set("pause", _(u"&Resume"))
|
||||
elif self.dialog.get("pause") == _(u"Resume"):
|
||||
self.recording.play()
|
||||
self.dialog.set("pause", _(U"&Pause"))
|
||||
def on_pause(self, *args, **kwargs):
|
||||
if self.dialog.get("pause") == _(u"Pause"):
|
||||
self.recording.pause()
|
||||
self.dialog.set("pause", _(u"&Resume"))
|
||||
elif self.dialog.get("pause") == _(u"Resume"):
|
||||
self.recording.play()
|
||||
self.dialog.set("pause", _(U"&Pause"))
|
||||
|
||||
def on_record(self, *args, **kwargs):
|
||||
if self.recording != None:
|
||||
self.stop_recording()
|
||||
self.dialog.disable_control("pause")
|
||||
else:
|
||||
self.start_recording()
|
||||
self.dialog.enable_control("pause")
|
||||
def on_record(self, *args, **kwargs):
|
||||
if self.recording != None:
|
||||
self.stop_recording()
|
||||
self.dialog.disable_control("pause")
|
||||
else:
|
||||
self.start_recording()
|
||||
self.dialog.enable_control("pause")
|
||||
|
||||
def start_recording(self):
|
||||
self.dialog.disable_control("attach_exists")
|
||||
self.file = tempfile.mktemp(suffix='.wav')
|
||||
self.recording = sound.recording(self.file)
|
||||
self.recording.play()
|
||||
self.dialog.set("record", _(u"&Stop"))
|
||||
output.speak(_(u"Recording"))
|
||||
def start_recording(self):
|
||||
self.dialog.disable_control("attach_exists")
|
||||
self.file = tempfile.mktemp(suffix='.wav')
|
||||
self.recording = sound.recording(self.file)
|
||||
self.recording.play()
|
||||
self.dialog.set("record", _(u"&Stop"))
|
||||
output.speak(_(u"Recording"))
|
||||
|
||||
def stop_recording(self):
|
||||
self.recording.stop()
|
||||
self.recording.free()
|
||||
output.speak(_(u"Stopped"))
|
||||
self.recorded = True
|
||||
self.dialog.set("record", _(u"&Record"))
|
||||
self.file_attached()
|
||||
def stop_recording(self):
|
||||
self.recording.stop()
|
||||
self.recording.free()
|
||||
output.speak(_(u"Stopped"))
|
||||
self.recorded = True
|
||||
self.dialog.set("record", _(u"&Record"))
|
||||
self.file_attached()
|
||||
|
||||
def file_attached(self):
|
||||
self.dialog.set("pause", _(u"&Pause"))
|
||||
self.dialog.disable_control("record")
|
||||
self.dialog.enable_control("play")
|
||||
self.dialog.enable_control("discard")
|
||||
self.dialog.disable_control("attach_exists")
|
||||
self.dialog.enable_control("attach")
|
||||
self.dialog.play.SetFocus()
|
||||
def file_attached(self):
|
||||
self.dialog.set("pause", _(u"&Pause"))
|
||||
self.dialog.disable_control("record")
|
||||
self.dialog.enable_control("play")
|
||||
self.dialog.enable_control("discard")
|
||||
self.dialog.disable_control("attach_exists")
|
||||
self.dialog.enable_control("attach")
|
||||
self.dialog.play.SetFocus()
|
||||
|
||||
def on_discard(self, *args, **kwargs):
|
||||
if self.playing:
|
||||
self._stop()
|
||||
if self.recording != None:
|
||||
self.cleanup()
|
||||
self.dialog.disable_control("attach")
|
||||
self.dialog.disable_control("play")
|
||||
self.file = None
|
||||
self.dialog.enable_control("record")
|
||||
self.dialog.enable_control("attach_exists")
|
||||
self.dialog.record.SetFocus()
|
||||
self.dialog.disable_control("discard")
|
||||
self.recording = None
|
||||
output.speak(_(u"Discarded"))
|
||||
def on_discard(self, *args, **kwargs):
|
||||
if self.playing:
|
||||
self._stop()
|
||||
if self.recording != None:
|
||||
self.cleanup()
|
||||
self.dialog.disable_control("attach")
|
||||
self.dialog.disable_control("play")
|
||||
self.file = None
|
||||
self.dialog.enable_control("record")
|
||||
self.dialog.enable_control("attach_exists")
|
||||
self.dialog.record.SetFocus()
|
||||
self.dialog.disable_control("discard")
|
||||
self.recording = None
|
||||
output.speak(_(u"Discarded"))
|
||||
|
||||
def on_play(self, *args, **kwargs):
|
||||
if not self.playing:
|
||||
call_threaded(self._play)
|
||||
else:
|
||||
self._stop()
|
||||
def on_play(self, *args, **kwargs):
|
||||
if not self.playing:
|
||||
call_threaded(self._play)
|
||||
else:
|
||||
self._stop()
|
||||
|
||||
def _play(self):
|
||||
output.speak(_(u"Playing..."))
|
||||
def _play(self):
|
||||
output.speak(_(u"Playing..."))
|
||||
# try:
|
||||
self.playing = sound_lib.stream.FileStream(file=str(self.file), flags=sound_lib.stream.BASS_UNICODE)
|
||||
self.playing.play()
|
||||
self.dialog.set("play", _(u"&Stop"))
|
||||
try:
|
||||
while self.playing.is_playing:
|
||||
pass
|
||||
self.dialog.set("play", _(u"&Play"))
|
||||
self.playing.free()
|
||||
self.playing = None
|
||||
except:
|
||||
pass
|
||||
self.playing = sound_lib.stream.FileStream(file=str(self.file), flags=sound_lib.stream.BASS_UNICODE)
|
||||
self.playing.play()
|
||||
self.dialog.set("play", _(u"&Stop"))
|
||||
try:
|
||||
while self.playing.is_playing:
|
||||
pass
|
||||
self.dialog.set("play", _(u"&Play"))
|
||||
self.playing.free()
|
||||
self.playing = None
|
||||
except:
|
||||
pass
|
||||
|
||||
def _stop(self):
|
||||
output.speak(_(u"Stopped"))
|
||||
self.playing.stop()
|
||||
self.playing.free()
|
||||
self.dialog.set("play", _(u"&Play"))
|
||||
self.playing = None
|
||||
def _stop(self):
|
||||
output.speak(_(u"Stopped"))
|
||||
self.playing.stop()
|
||||
self.playing.free()
|
||||
self.dialog.set("play", _(u"&Play"))
|
||||
self.playing = None
|
||||
|
||||
def postprocess(self):
|
||||
if self.file.lower().endswith('.wav'):
|
||||
output.speak(_(u"Recoding audio..."))
|
||||
sound.recode_audio(self.file)
|
||||
self.wav_file = self.file
|
||||
self.file = '%s.ogg' % self.file[:-4]
|
||||
def postprocess(self):
|
||||
if self.file.lower().endswith('.wav'):
|
||||
output.speak(_(u"Recoding audio..."))
|
||||
sound.recode_audio(self.file)
|
||||
self.wav_file = self.file
|
||||
self.file = '%s.ogg' % self.file[:-4]
|
||||
|
||||
def cleanup(self):
|
||||
if self.playing and self.playing.is_playing:
|
||||
self.playing.stop()
|
||||
if self.recording != None:
|
||||
if self.recording.is_playing:
|
||||
self.recording.stop()
|
||||
try:
|
||||
self.recording.free()
|
||||
except:
|
||||
pass
|
||||
os.remove(self.file)
|
||||
if hasattr(self, 'wav_file'):
|
||||
os.remove(self.wav_file)
|
||||
def cleanup(self):
|
||||
if self.playing and self.playing.is_playing:
|
||||
self.playing.stop()
|
||||
if self.recording != None:
|
||||
if self.recording.is_playing:
|
||||
self.recording.stop()
|
||||
try:
|
||||
self.recording.free()
|
||||
except:
|
||||
pass
|
||||
os.remove(self.file)
|
||||
if hasattr(self, 'wav_file'):
|
||||
os.remove(self.wav_file)
|
||||
|
||||
def on_attach_exists(self, *args, **kwargs):
|
||||
self.file = self.dialog.get_file()
|
||||
if self.file != False:
|
||||
self.file_attached()
|
||||
def on_attach_exists(self, *args, **kwargs):
|
||||
self.file = self.dialog.get_file()
|
||||
if self.file != False:
|
||||
self.file_attached()
|
||||
|
||||
|
@ -15,74 +15,74 @@ from requests_toolbelt.multipart.encoder import MultipartEncoder, MultipartEncod
|
||||
import requests
|
||||
import os
|
||||
class Upload(object):
|
||||
def __init__(self, field=None, obj=None, url=None, filename=None, follow_location=True, completed_callback=None, verbose=False, *args, **kwargs):
|
||||
super(Upload, self).__init__(*args, **kwargs)
|
||||
self.url=url
|
||||
self.filename=filename
|
||||
log.debug("Uploading audio to %s, filename %s" % (url, filename))
|
||||
self.start_time = None
|
||||
self.completed_callback = completed_callback
|
||||
self.background_thread = None
|
||||
self.transfer_rate = 0
|
||||
self.local_filename=os.path.basename(self.filename)
|
||||
if isinstance(self.local_filename, str):
|
||||
self.local_filename=self.local_filename.encode(sys.getfilesystemencoding())
|
||||
self.fin=open(self.filename, 'rb')
|
||||
self.m = MultipartEncoder(fields={field:(self.local_filename, self.fin, "application/octet-stream")})
|
||||
self.monitor = MultipartEncoderMonitor(self.m, self.progress_callback)
|
||||
self.response=None
|
||||
self.obj=obj
|
||||
self.follow_location=follow_location
|
||||
#the verbose parameter is deprecated and will be removed soon
|
||||
def __init__(self, field=None, obj=None, url=None, filename=None, follow_location=True, completed_callback=None, verbose=False, *args, **kwargs):
|
||||
super(Upload, self).__init__(*args, **kwargs)
|
||||
self.url=url
|
||||
self.filename=filename
|
||||
log.debug("Uploading audio to %s, filename %s" % (url, filename))
|
||||
self.start_time = None
|
||||
self.completed_callback = completed_callback
|
||||
self.background_thread = None
|
||||
self.transfer_rate = 0
|
||||
self.local_filename=os.path.basename(self.filename)
|
||||
if isinstance(self.local_filename, str):
|
||||
self.local_filename=self.local_filename.encode(sys.getfilesystemencoding())
|
||||
self.fin=open(self.filename, 'rb')
|
||||
self.m = MultipartEncoder(fields={field:(self.local_filename, self.fin, "application/octet-stream")})
|
||||
self.monitor = MultipartEncoderMonitor(self.m, self.progress_callback)
|
||||
self.response=None
|
||||
self.obj=obj
|
||||
self.follow_location=follow_location
|
||||
#the verbose parameter is deprecated and will be removed soon
|
||||
|
||||
def elapsed_time(self):
|
||||
if not self.start_time:
|
||||
return 0
|
||||
return time.time() - self.start_time
|
||||
def elapsed_time(self):
|
||||
if not self.start_time:
|
||||
return 0
|
||||
return time.time() - self.start_time
|
||||
|
||||
def progress_callback(self, monitor):
|
||||
progress = {}
|
||||
progress["total"] = monitor.len
|
||||
progress["current"] = monitor.bytes_read
|
||||
if progress["current"] == 0:
|
||||
progress["percent"] = 0
|
||||
self.transfer_rate = 0
|
||||
else:
|
||||
progress["percent"] = int((float(progress["current"]) / progress["total"]) * 100)
|
||||
self.transfer_rate = old_div(progress["current"], self.elapsed_time())
|
||||
progress["speed"] = '%s/s' % convert_bytes(self.transfer_rate)
|
||||
if self.transfer_rate:
|
||||
progress["eta"] = old_div((progress["total"] - progress["current"]), self.transfer_rate)
|
||||
else:
|
||||
progress["eta"] = 0
|
||||
pub.sendMessage("uploading", data=progress)
|
||||
def progress_callback(self, monitor):
|
||||
progress = {}
|
||||
progress["total"] = monitor.len
|
||||
progress["current"] = monitor.bytes_read
|
||||
if progress["current"] == 0:
|
||||
progress["percent"] = 0
|
||||
self.transfer_rate = 0
|
||||
else:
|
||||
progress["percent"] = int((float(progress["current"]) / progress["total"]) * 100)
|
||||
self.transfer_rate = old_div(progress["current"], self.elapsed_time())
|
||||
progress["speed"] = '%s/s' % convert_bytes(self.transfer_rate)
|
||||
if self.transfer_rate:
|
||||
progress["eta"] = old_div((progress["total"] - progress["current"]), self.transfer_rate)
|
||||
else:
|
||||
progress["eta"] = 0
|
||||
pub.sendMessage("uploading", data=progress)
|
||||
|
||||
def perform_transfer(self):
|
||||
log.debug("starting upload...")
|
||||
self.start_time = time.time()
|
||||
self.response=requests.post(url=self.url, data=self.monitor, headers={"Content-Type":self.m.content_type}, allow_redirects=self.follow_location, stream=True)
|
||||
log.debug("Upload finished.")
|
||||
self.complete_transfer()
|
||||
def perform_transfer(self):
|
||||
log.debug("starting upload...")
|
||||
self.start_time = time.time()
|
||||
self.response=requests.post(url=self.url, data=self.monitor, headers={"Content-Type":self.m.content_type}, allow_redirects=self.follow_location, stream=True)
|
||||
log.debug("Upload finished.")
|
||||
self.complete_transfer()
|
||||
|
||||
def perform_threaded(self, *args, **kwargs):
|
||||
self.background_thread = threading.Thread(target=self.perform_transfer)
|
||||
self.background_thread.daemon = True
|
||||
self.background_thread.start()
|
||||
def perform_threaded(self, *args, **kwargs):
|
||||
self.background_thread = threading.Thread(target=self.perform_transfer)
|
||||
self.background_thread.daemon = True
|
||||
self.background_thread.start()
|
||||
|
||||
def complete_transfer(self):
|
||||
if callable(self.completed_callback):
|
||||
self.completed_callback(self.obj)
|
||||
if hasattr(self,'fin') and callable(self.fin.close):
|
||||
self.fin.close()
|
||||
def complete_transfer(self):
|
||||
if callable(self.completed_callback):
|
||||
self.completed_callback(self.obj)
|
||||
if hasattr(self,'fin') and callable(self.fin.close):
|
||||
self.fin.close()
|
||||
|
||||
def get_url(self):
|
||||
try:
|
||||
data = self.response.json()
|
||||
except:
|
||||
return _("Error in file upload: {0}").format(self.data.content,)
|
||||
if "url" in data and data["url"] != "0":
|
||||
return data["url"]
|
||||
elif "error" in data and data["error"] != "0":
|
||||
return data["error"]
|
||||
else:
|
||||
return _("Error in file upload: {0}").format(self.data.content,)
|
||||
def get_url(self):
|
||||
try:
|
||||
data = self.response.json()
|
||||
except:
|
||||
return _("Error in file upload: {0}").format(self.data.content,)
|
||||
if "url" in data and data["url"] != "0":
|
||||
return data["url"]
|
||||
elif "error" in data and data["error"] != "0":
|
||||
return data["error"]
|
||||
else:
|
||||
return _("Error in file upload: {0}").format(self.data.content,)
|
||||
|
@ -3,42 +3,42 @@
|
||||
from __future__ import unicode_literals
|
||||
from builtins import str
|
||||
def convert_bytes(n):
|
||||
K, M, G, T, P = 1 << 10, 1 << 20, 1 << 30, 1 << 40, 1 << 50
|
||||
if n >= P:
|
||||
return '%.2fPb' % (float(n) / T)
|
||||
elif n >= T:
|
||||
return '%.2fTb' % (float(n) / T)
|
||||
elif n >= G:
|
||||
return '%.2fGb' % (float(n) / G)
|
||||
elif n >= M:
|
||||
return '%.2fMb' % (float(n) / M)
|
||||
elif n >= K:
|
||||
return '%.2fKb' % (float(n) / K)
|
||||
else:
|
||||
return '%d' % n
|
||||
K, M, G, T, P = 1 << 10, 1 << 20, 1 << 30, 1 << 40, 1 << 50
|
||||
if n >= P:
|
||||
return '%.2fPb' % (float(n) / T)
|
||||
elif n >= T:
|
||||
return '%.2fTb' % (float(n) / T)
|
||||
elif n >= G:
|
||||
return '%.2fGb' % (float(n) / G)
|
||||
elif n >= M:
|
||||
return '%.2fMb' % (float(n) / M)
|
||||
elif n >= K:
|
||||
return '%.2fKb' % (float(n) / K)
|
||||
else:
|
||||
return '%d' % n
|
||||
|
||||
def seconds_to_string(seconds, precision=0):
|
||||
day = seconds // 86400
|
||||
hour = seconds // 3600
|
||||
min = (seconds // 60) % 60
|
||||
sec = seconds - (hour * 3600) - (min * 60)
|
||||
sec_spec = "." + str(precision) + "f"
|
||||
sec_string = sec.__format__(sec_spec)
|
||||
string = ""
|
||||
if day == 1:
|
||||
string += _(u"%d day, ") % day
|
||||
elif day >= 2:
|
||||
string += _(u"%d days, ") % day
|
||||
if (hour == 1):
|
||||
string += _(u"%d hour, ") % hour
|
||||
elif (hour >= 2):
|
||||
string += _("%d hours, ") % hour
|
||||
if (min == 1):
|
||||
string += _(u"%d minute, ") % min
|
||||
elif (min >= 2):
|
||||
string += _(u"%d minutes, ") % min
|
||||
if sec >= 0 and sec <= 2:
|
||||
string += _(u"%s second") % sec_string
|
||||
else:
|
||||
string += _(u"%s seconds") % sec_string
|
||||
return string
|
||||
day = seconds // 86400
|
||||
hour = seconds // 3600
|
||||
min = (seconds // 60) % 60
|
||||
sec = seconds - (hour * 3600) - (min * 60)
|
||||
sec_spec = "." + str(precision) + "f"
|
||||
sec_string = sec.__format__(sec_spec)
|
||||
string = ""
|
||||
if day == 1:
|
||||
string += _(u"%d day, ") % day
|
||||
elif day >= 2:
|
||||
string += _(u"%d days, ") % day
|
||||
if (hour == 1):
|
||||
string += _(u"%d hour, ") % hour
|
||||
elif (hour >= 2):
|
||||
string += _("%d hours, ") % hour
|
||||
if (min == 1):
|
||||
string += _(u"%d minute, ") % min
|
||||
elif (min >= 2):
|
||||
string += _(u"%d minutes, ") % min
|
||||
if sec >= 0 and sec <= 2:
|
||||
string += _(u"%s second") % sec_string
|
||||
else:
|
||||
string += _(u"%s seconds") % sec_string
|
||||
return string
|
||||
|
@ -7,57 +7,57 @@ import widgetUtils
|
||||
|
||||
class UploadDialog(widgetUtils.BaseDialog):
|
||||
|
||||
def __init__(self, filename, *args, **kwargs):
|
||||
super(UploadDialog, self).__init__(parent=None, id=wx.ID_ANY, *args, **kwargs)
|
||||
self.pane = wx.Panel(self)
|
||||
self.progress_bar = wx.Gauge(parent=self.pane)
|
||||
fileBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
fileLabel = wx.StaticText(self.pane, -1, _(u"File"))
|
||||
self.file = wx.TextCtrl(self.pane, -1, value=filename, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(200, 100))
|
||||
self.file.SetFocus()
|
||||
fileBox.Add(fileLabel)
|
||||
fileBox.Add(self.file)
|
||||
currentAmountBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
current_amount_label = wx.StaticText(self.pane, -1, _(u"Transferred"))
|
||||
self.current_amount = wx.TextCtrl(self.pane, -1, value='0', style=wx.TE_READONLY|wx.TE_MULTILINE)
|
||||
currentAmountBox.Add(current_amount_label)
|
||||
currentAmountBox.Add(self.current_amount)
|
||||
totalSizeBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
total_size_label = wx.StaticText(self.pane, -1, _(u"Total file size"))
|
||||
self.total_size = wx.TextCtrl(self.pane, -1, value='0', style=wx.TE_READONLY|wx.TE_MULTILINE)
|
||||
totalSizeBox.Add(total_size_label)
|
||||
totalSizeBox.Add(self.total_size)
|
||||
speedBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
speedLabel = wx.StaticText(self.pane, -1, _(u"Transfer rate"))
|
||||
self.speed = wx.TextCtrl(self.pane, -1, style=wx.TE_READONLY|wx.TE_MULTILINE, value="0 Kb/s")
|
||||
speedBox.Add(speedLabel)
|
||||
speedBox.Add(self.speed)
|
||||
etaBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
etaLabel = wx.StaticText(self.pane, -1, _(u"Time left"))
|
||||
self.eta = wx.TextCtrl(self.pane, -1, style=wx.TE_READONLY|wx.TE_MULTILINE, value="Unknown", size=(200, 100))
|
||||
etaBox.Add(etaLabel)
|
||||
etaBox.Add(self.eta)
|
||||
self.create_buttons()
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
sizer.Add(fileBox)
|
||||
sizer.Add(currentAmountBox)
|
||||
sizer.Add(totalSizeBox)
|
||||
sizer.Add(speedBox)
|
||||
sizer.Add(etaBox)
|
||||
sizer.Add(self.progress_bar)
|
||||
self.pane.SetSizerAndFit(sizer)
|
||||
def __init__(self, filename, *args, **kwargs):
|
||||
super(UploadDialog, self).__init__(parent=None, id=wx.ID_ANY, *args, **kwargs)
|
||||
self.pane = wx.Panel(self)
|
||||
self.progress_bar = wx.Gauge(parent=self.pane)
|
||||
fileBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
fileLabel = wx.StaticText(self.pane, -1, _(u"File"))
|
||||
self.file = wx.TextCtrl(self.pane, -1, value=filename, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(200, 100))
|
||||
self.file.SetFocus()
|
||||
fileBox.Add(fileLabel)
|
||||
fileBox.Add(self.file)
|
||||
currentAmountBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
current_amount_label = wx.StaticText(self.pane, -1, _(u"Transferred"))
|
||||
self.current_amount = wx.TextCtrl(self.pane, -1, value='0', style=wx.TE_READONLY|wx.TE_MULTILINE)
|
||||
currentAmountBox.Add(current_amount_label)
|
||||
currentAmountBox.Add(self.current_amount)
|
||||
totalSizeBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
total_size_label = wx.StaticText(self.pane, -1, _(u"Total file size"))
|
||||
self.total_size = wx.TextCtrl(self.pane, -1, value='0', style=wx.TE_READONLY|wx.TE_MULTILINE)
|
||||
totalSizeBox.Add(total_size_label)
|
||||
totalSizeBox.Add(self.total_size)
|
||||
speedBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
speedLabel = wx.StaticText(self.pane, -1, _(u"Transfer rate"))
|
||||
self.speed = wx.TextCtrl(self.pane, -1, style=wx.TE_READONLY|wx.TE_MULTILINE, value="0 Kb/s")
|
||||
speedBox.Add(speedLabel)
|
||||
speedBox.Add(self.speed)
|
||||
etaBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
etaLabel = wx.StaticText(self.pane, -1, _(u"Time left"))
|
||||
self.eta = wx.TextCtrl(self.pane, -1, style=wx.TE_READONLY|wx.TE_MULTILINE, value="Unknown", size=(200, 100))
|
||||
etaBox.Add(etaLabel)
|
||||
etaBox.Add(self.eta)
|
||||
self.create_buttons()
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
sizer.Add(fileBox)
|
||||
sizer.Add(currentAmountBox)
|
||||
sizer.Add(totalSizeBox)
|
||||
sizer.Add(speedBox)
|
||||
sizer.Add(etaBox)
|
||||
sizer.Add(self.progress_bar)
|
||||
self.pane.SetSizerAndFit(sizer)
|
||||
|
||||
def update(self, data):
|
||||
wx.CallAfter(self.progress_bar.SetValue, data["percent"])
|
||||
wx.CallAfter(self.current_amount.SetValue, '%s (%d%%)' % (convert_bytes(data["current"]), data["percent"]))
|
||||
wx.CallAfter(self.total_size.SetValue, convert_bytes(data["total"]))
|
||||
wx.CallAfter(self.speed.SetValue, data["speed"])
|
||||
if data["eta"]:
|
||||
wx.CallAfter(self.eta.SetValue, seconds_to_string(data["eta"]))
|
||||
def update(self, data):
|
||||
wx.CallAfter(self.progress_bar.SetValue, data["percent"])
|
||||
wx.CallAfter(self.current_amount.SetValue, '%s (%d%%)' % (convert_bytes(data["current"]), data["percent"]))
|
||||
wx.CallAfter(self.total_size.SetValue, convert_bytes(data["total"]))
|
||||
wx.CallAfter(self.speed.SetValue, data["speed"])
|
||||
if data["eta"]:
|
||||
wx.CallAfter(self.eta.SetValue, seconds_to_string(data["eta"]))
|
||||
|
||||
def create_buttons(self):
|
||||
self.cancel_button = wx.Button(parent=self.pane, id=wx.ID_CANCEL)
|
||||
def create_buttons(self):
|
||||
self.cancel_button = wx.Button(parent=self.pane, id=wx.ID_CANCEL)
|
||||
|
||||
def get_response(self, fn):
|
||||
wx.CallAfter(fn, 0.01)
|
||||
self.ShowModal()
|
||||
def get_response(self, fn):
|
||||
wx.CallAfter(fn, 0.01)
|
||||
self.ShowModal()
|
||||
|
@ -24,56 +24,56 @@ import logging
|
||||
log = logging.getLogger("extra.AudioUploader.wx_UI")
|
||||
|
||||
class audioDialog(widgetUtils.BaseDialog):
|
||||
def __init__(self, services):
|
||||
log.debug("creating audio dialog.")
|
||||
super(audioDialog, self).__init__(None, -1, _(u"Attach audio"))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
btnSizer2 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
def __init__(self, services):
|
||||
log.debug("creating audio dialog.")
|
||||
super(audioDialog, self).__init__(None, -1, _(u"Attach audio"))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
btnSizer2 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.play = wx.Button(panel, -1, _(u"&Play"))
|
||||
self.play.Disable()
|
||||
self.pause = wx.Button(panel, -1, _(u"&Pause"))
|
||||
self.pause.Disable()
|
||||
self.record = wx.Button(panel, -1, _(u"&Record"))
|
||||
self.record.SetFocus()
|
||||
self.attach_exists = wx.Button(panel, -1, _(u"&Add an existing file"))
|
||||
self.discard = wx.Button(panel, -1, _(u"&Discard"))
|
||||
self.discard.Disable()
|
||||
label = wx.StaticText(panel, -1, _(u"Upload to"))
|
||||
self.services = wx.ComboBox(panel, -1, choices=services, value=services[0], style=wx.CB_READONLY)
|
||||
servicesBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
servicesBox.Add(label, 0, wx.ALL, 5)
|
||||
servicesBox.Add(self.services, 0, wx.ALL, 5)
|
||||
self.attach = wx.Button(panel, wx.ID_OK, _(u"Attach"))
|
||||
self.attach.Disable()
|
||||
cancel = wx.Button(panel, wx.ID_CANCEL, _(u"&Cancel"))
|
||||
btnSizer.Add(self.play, 0, wx.ALL, 5)
|
||||
btnSizer.Add(self.pause, 0, wx.ALL, 5)
|
||||
btnSizer.Add(self.record, 0, wx.ALL, 5)
|
||||
btnSizer2.Add(self.attach_exists, 0, wx.ALL, 5)
|
||||
btnSizer2.Add(self.discard, 0, wx.ALL, 5)
|
||||
btnSizer2.Add(self.attach, 0, wx.ALL, 5)
|
||||
btnSizer2.Add(cancel, 0, wx.ALL, 5)
|
||||
sizer.Add(servicesBox, 0, wx.ALL, 5)
|
||||
sizer.Add(btnSizer, 0, wx.ALL, 5)
|
||||
sizer.Add(btnSizer2, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
self.SetClientSize(sizer.CalcMin())
|
||||
self.play = wx.Button(panel, -1, _(u"&Play"))
|
||||
self.play.Disable()
|
||||
self.pause = wx.Button(panel, -1, _(u"&Pause"))
|
||||
self.pause.Disable()
|
||||
self.record = wx.Button(panel, -1, _(u"&Record"))
|
||||
self.record.SetFocus()
|
||||
self.attach_exists = wx.Button(panel, -1, _(u"&Add an existing file"))
|
||||
self.discard = wx.Button(panel, -1, _(u"&Discard"))
|
||||
self.discard.Disable()
|
||||
label = wx.StaticText(panel, -1, _(u"Upload to"))
|
||||
self.services = wx.ComboBox(panel, -1, choices=services, value=services[0], style=wx.CB_READONLY)
|
||||
servicesBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
servicesBox.Add(label, 0, wx.ALL, 5)
|
||||
servicesBox.Add(self.services, 0, wx.ALL, 5)
|
||||
self.attach = wx.Button(panel, wx.ID_OK, _(u"Attach"))
|
||||
self.attach.Disable()
|
||||
cancel = wx.Button(panel, wx.ID_CANCEL, _(u"&Cancel"))
|
||||
btnSizer.Add(self.play, 0, wx.ALL, 5)
|
||||
btnSizer.Add(self.pause, 0, wx.ALL, 5)
|
||||
btnSizer.Add(self.record, 0, wx.ALL, 5)
|
||||
btnSizer2.Add(self.attach_exists, 0, wx.ALL, 5)
|
||||
btnSizer2.Add(self.discard, 0, wx.ALL, 5)
|
||||
btnSizer2.Add(self.attach, 0, wx.ALL, 5)
|
||||
btnSizer2.Add(cancel, 0, wx.ALL, 5)
|
||||
sizer.Add(servicesBox, 0, wx.ALL, 5)
|
||||
sizer.Add(btnSizer, 0, wx.ALL, 5)
|
||||
sizer.Add(btnSizer2, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
self.SetClientSize(sizer.CalcMin())
|
||||
|
||||
def enable_control(self, control):
|
||||
log.debug("Enabling control %s" % (control,))
|
||||
if hasattr(self, control):
|
||||
getattr(self, control).Enable()
|
||||
def enable_control(self, control):
|
||||
log.debug("Enabling control %s" % (control,))
|
||||
if hasattr(self, control):
|
||||
getattr(self, control).Enable()
|
||||
|
||||
def disable_control(self, control):
|
||||
log.debug("Disabling control %s" % (control,))
|
||||
if hasattr(self, control):
|
||||
getattr(self, control).Disable()
|
||||
def disable_control(self, control):
|
||||
log.debug("Disabling control %s" % (control,))
|
||||
if hasattr(self, control):
|
||||
getattr(self, control).Disable()
|
||||
|
||||
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)
|
||||
if openFileDialog.ShowModal() == wx.ID_CANCEL:
|
||||
return False
|
||||
return openFileDialog.GetPath()
|
||||
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)
|
||||
if openFileDialog.ShowModal() == wx.ID_CANCEL:
|
||||
return False
|
||||
return openFileDialog.GetPath()
|
||||
|
@ -4,23 +4,23 @@ from gi.repository import Gtk
|
||||
import widgetUtils
|
||||
|
||||
class soundsTutorialDialog(Gtk.Dialog):
|
||||
def __init__(self, actions):
|
||||
super(soundsTutorialDialog, self).__init__("Sounds tutorial", None, 0, (Gtk.STOCK_CANCEL, widgetUtils.CANCEL))
|
||||
box = self.get_content_area()
|
||||
label = Gtk.Label("Press enter for listen the sound")
|
||||
self.list = widgetUtils.list("Action")
|
||||
self.populate_actions(actions)
|
||||
lBox = Gtk.Box(spacing=6)
|
||||
lBox.add(label)
|
||||
lBox.add(self.list.list)
|
||||
box.add(lBox)
|
||||
self.play = Gtk.Button("Play")
|
||||
box.add(self.play)
|
||||
self.show_all()
|
||||
def __init__(self, actions):
|
||||
super(soundsTutorialDialog, self).__init__("Sounds tutorial", None, 0, (Gtk.STOCK_CANCEL, widgetUtils.CANCEL))
|
||||
box = self.get_content_area()
|
||||
label = Gtk.Label("Press enter for listen the sound")
|
||||
self.list = widgetUtils.list("Action")
|
||||
self.populate_actions(actions)
|
||||
lBox = Gtk.Box(spacing=6)
|
||||
lBox.add(label)
|
||||
lBox.add(self.list.list)
|
||||
box.add(lBox)
|
||||
self.play = Gtk.Button("Play")
|
||||
box.add(self.play)
|
||||
self.show_all()
|
||||
|
||||
def populate_actions(self, actions):
|
||||
for i in actions:
|
||||
self.list.insert_item(i)
|
||||
def populate_actions(self, actions):
|
||||
for i in actions:
|
||||
self.list.insert_item(i)
|
||||
|
||||
def get_selected(self):
|
||||
return self.list.get_selected()
|
||||
def get_selected(self):
|
||||
return self.list.get_selected()
|
||||
|
@ -10,28 +10,28 @@ import logging
|
||||
log = logging.getLogger("extra.SoundsTutorial.soundsTutorial")
|
||||
from . import soundsTutorial_constants
|
||||
if platform.system() == "Windows":
|
||||
from . import wx_ui as UI
|
||||
from . import wx_ui as UI
|
||||
elif platform.system() == "Linux":
|
||||
from . import gtk_ui as UI
|
||||
from . import gtk_ui as UI
|
||||
|
||||
class soundsTutorial(object):
|
||||
def __init__(self, sessionObject):
|
||||
log.debug("Creating sounds tutorial object...")
|
||||
super(soundsTutorial, self).__init__()
|
||||
self.session = sessionObject
|
||||
self.actions = []
|
||||
log.debug("Loading actions for sounds tutorial...")
|
||||
[self.actions.append(i[1]) for i in soundsTutorial_constants.actions]
|
||||
self.files = []
|
||||
log.debug("Searching sound files...")
|
||||
[self.files.append(i[0]) for i in soundsTutorial_constants.actions]
|
||||
log.debug("Creating dialog...")
|
||||
self.dialog = UI.soundsTutorialDialog(self.actions)
|
||||
widgetUtils.connect_event(self.dialog.play, widgetUtils.BUTTON_PRESSED, self.on_play)
|
||||
self.dialog.get_response()
|
||||
def __init__(self, sessionObject):
|
||||
log.debug("Creating sounds tutorial object...")
|
||||
super(soundsTutorial, self).__init__()
|
||||
self.session = sessionObject
|
||||
self.actions = []
|
||||
log.debug("Loading actions for sounds tutorial...")
|
||||
[self.actions.append(i[1]) for i in soundsTutorial_constants.actions]
|
||||
self.files = []
|
||||
log.debug("Searching sound files...")
|
||||
[self.files.append(i[0]) for i in soundsTutorial_constants.actions]
|
||||
log.debug("Creating dialog...")
|
||||
self.dialog = UI.soundsTutorialDialog(self.actions)
|
||||
widgetUtils.connect_event(self.dialog.play, widgetUtils.BUTTON_PRESSED, self.on_play)
|
||||
self.dialog.get_response()
|
||||
|
||||
def on_play(self, *args, **kwargs):
|
||||
try:
|
||||
self.session.sound.play(self.files[self.dialog.get_selection()]+".ogg")
|
||||
except:
|
||||
log.exception("Error playing the %s sound" % (self.files[self.dialog.items.GetSelection()],))
|
||||
def on_play(self, *args, **kwargs):
|
||||
try:
|
||||
self.session.sound.play(self.files[self.dialog.get_selection()]+".ogg")
|
||||
except:
|
||||
log.exception("Error playing the %s sound" % (self.files[self.dialog.items.GetSelection()],))
|
||||
|
@ -5,27 +5,27 @@ from __future__ import unicode_literals
|
||||
from . import reverse_sort
|
||||
import application
|
||||
actions = reverse_sort.reverse_sort([ ("audio", _(u"Audio tweet.")),
|
||||
("create_timeline", _(u"User timeline buffer created.")),
|
||||
("delete_timeline", _(u"Buffer destroied.")),
|
||||
("dm_received", _(u"Direct message received.")),
|
||||
("dm_sent", _(u"Direct message sent.")),
|
||||
("error", _(u"Error.")),
|
||||
("favourite", _(u"Tweet liked.")),
|
||||
("favourites_timeline_updated", _(u"Likes buffer updated.")),
|
||||
("geo", _(u"Geotweet.")),
|
||||
("image", _("Tweet contains one or more images")),
|
||||
("limit", _(u"Boundary reached.")),
|
||||
("list_tweet", _(u"List updated.")),
|
||||
("max_length", _(u"Too many characters.")),
|
||||
("mention_received", _(u"Mention received.")),
|
||||
("new_event", _(u"New event.")),
|
||||
("ready", _(u"{0} is ready.").format(application.name,)),
|
||||
("reply_send", _(u"Mention sent.")),
|
||||
("retweet_send", _(u"Tweet retweeted.")),
|
||||
("search_updated", _(u"Search buffer updated.")),
|
||||
("tweet_received", _(u"Tweet received.")),
|
||||
("tweet_send", _(u"Tweet sent.")),
|
||||
("trends_updated", _(u"Trending topics buffer updated.")),
|
||||
("tweet_timeline", _(u"New tweet in user timeline buffer.")),
|
||||
("update_followers", _(u"New follower.")),
|
||||
("volume_changed", _(u"Volume changed."))])
|
||||
("create_timeline", _(u"User timeline buffer created.")),
|
||||
("delete_timeline", _(u"Buffer destroied.")),
|
||||
("dm_received", _(u"Direct message received.")),
|
||||
("dm_sent", _(u"Direct message sent.")),
|
||||
("error", _(u"Error.")),
|
||||
("favourite", _(u"Tweet liked.")),
|
||||
("favourites_timeline_updated", _(u"Likes buffer updated.")),
|
||||
("geo", _(u"Geotweet.")),
|
||||
("image", _("Tweet contains one or more images")),
|
||||
("limit", _(u"Boundary reached.")),
|
||||
("list_tweet", _(u"List updated.")),
|
||||
("max_length", _(u"Too many characters.")),
|
||||
("mention_received", _(u"Mention received.")),
|
||||
("new_event", _(u"New event.")),
|
||||
("ready", _(u"{0} is ready.").format(application.name,)),
|
||||
("reply_send", _(u"Mention sent.")),
|
||||
("retweet_send", _(u"Tweet retweeted.")),
|
||||
("search_updated", _(u"Search buffer updated.")),
|
||||
("tweet_received", _(u"Tweet received.")),
|
||||
("tweet_send", _(u"Tweet sent.")),
|
||||
("trends_updated", _(u"Trending topics buffer updated.")),
|
||||
("tweet_timeline", _(u"New tweet in user timeline buffer.")),
|
||||
("update_followers", _(u"New follower.")),
|
||||
("volume_changed", _(u"Volume changed."))])
|
||||
|
@ -4,27 +4,27 @@ import wx
|
||||
import widgetUtils
|
||||
|
||||
class soundsTutorialDialog(widgetUtils.BaseDialog):
|
||||
def __init__(self, actions):
|
||||
super(soundsTutorialDialog, self).__init__(None, -1)
|
||||
self.SetTitle(_(u"Sounds tutorial"))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
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.SetSelection(0)
|
||||
listBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
listBox.Add(label)
|
||||
listBox.Add(self.items)
|
||||
self.play = wx.Button(panel, 1, (u"Play"))
|
||||
self.play.SetDefault()
|
||||
close = wx.Button(panel, wx.ID_CANCEL)
|
||||
btnBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
btnBox.Add(self.play)
|
||||
btnBox.Add(close)
|
||||
sizer.Add(listBox)
|
||||
sizer.Add(btnBox)
|
||||
panel.SetSizer(sizer)
|
||||
self.SetClientSize(sizer.CalcMin())
|
||||
def __init__(self, actions):
|
||||
super(soundsTutorialDialog, self).__init__(None, -1)
|
||||
self.SetTitle(_(u"Sounds tutorial"))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
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.SetSelection(0)
|
||||
listBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
listBox.Add(label)
|
||||
listBox.Add(self.items)
|
||||
self.play = wx.Button(panel, 1, (u"Play"))
|
||||
self.play.SetDefault()
|
||||
close = wx.Button(panel, wx.ID_CANCEL)
|
||||
btnBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
btnBox.Add(self.play)
|
||||
btnBox.Add(close)
|
||||
sizer.Add(listBox)
|
||||
sizer.Add(btnBox)
|
||||
panel.SetSizer(sizer)
|
||||
self.SetClientSize(sizer.CalcMin())
|
||||
|
||||
def get_selection(self):
|
||||
return self.items.GetSelection()
|
||||
def get_selection(self):
|
||||
return self.items.GetSelection()
|
||||
|
@ -3,4 +3,4 @@ from __future__ import unicode_literals
|
||||
from . import spellchecker
|
||||
import platform
|
||||
if platform.system() == "Windows":
|
||||
from .wx_ui import *
|
||||
from .wx_ui import *
|
||||
|
@ -19,69 +19,69 @@ from enchant import tokenize
|
||||
log = logging.getLogger("extra.SpellChecker.spellChecker")
|
||||
|
||||
class spellChecker(object):
|
||||
def __init__(self, text, dictionary):
|
||||
super(spellChecker, self).__init__()
|
||||
# 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
|
||||
def __init__(self, text, dictionary):
|
||||
super(spellChecker, self).__init__()
|
||||
# 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
|
||||
# dict_path = enchant.get_param("enchant.myspell.dictionary.path")
|
||||
# if dict_path == None:
|
||||
# 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("Creating the SpellChecker object. Dictionary: %s" % (dictionary,))
|
||||
self.active = True
|
||||
try:
|
||||
if config.app["app-settings"]["language"] == "system":
|
||||
log.debug("Using the system language")
|
||||
self.dict = enchant.DictWithPWL(languageHandler.curLang[:2], os.path.join(paths.config_path(), "wordlist.dict"))
|
||||
else:
|
||||
log.debug("Using language: %s" % (languageHandler.getLanguage(),))
|
||||
self.dict = enchant.DictWithPWL(languageHandler.getLanguage()[:2], os.path.join(paths.config_path(), "wordlist.dict"))
|
||||
except DictNotFoundError:
|
||||
log.exception("Dictionary for language %s not found." % (dictionary,))
|
||||
wx_ui.dict_not_found_error()
|
||||
self.active = False
|
||||
self.checker = SpellChecker(self.dict, filters=[twitterFilter.TwitterFilter, tokenize.EmailFilter, tokenize.URLFilter])
|
||||
self.checker.set_text(text)
|
||||
if self.active == True:
|
||||
log.debug("Creating dialog...")
|
||||
self.dialog = wx_ui.spellCheckerDialog()
|
||||
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.replace, widgetUtils.BUTTON_PRESSED, self.replace)
|
||||
widgetUtils.connect_event(self.dialog.replaceAll, widgetUtils.BUTTON_PRESSED, self.replaceAll)
|
||||
widgetUtils.connect_event(self.dialog.add, widgetUtils.BUTTON_PRESSED, self.add)
|
||||
self.check()
|
||||
self.dialog.get_response()
|
||||
self.fixed_text = self.checker.get_text()
|
||||
log.debug("Creating the SpellChecker object. Dictionary: %s" % (dictionary,))
|
||||
self.active = True
|
||||
try:
|
||||
if config.app["app-settings"]["language"] == "system":
|
||||
log.debug("Using the system language")
|
||||
self.dict = enchant.DictWithPWL(languageHandler.curLang[:2], os.path.join(paths.config_path(), "wordlist.dict"))
|
||||
else:
|
||||
log.debug("Using language: %s" % (languageHandler.getLanguage(),))
|
||||
self.dict = enchant.DictWithPWL(languageHandler.getLanguage()[:2], os.path.join(paths.config_path(), "wordlist.dict"))
|
||||
except DictNotFoundError:
|
||||
log.exception("Dictionary for language %s not found." % (dictionary,))
|
||||
wx_ui.dict_not_found_error()
|
||||
self.active = False
|
||||
self.checker = SpellChecker(self.dict, filters=[twitterFilter.TwitterFilter, tokenize.EmailFilter, tokenize.URLFilter])
|
||||
self.checker.set_text(text)
|
||||
if self.active == True:
|
||||
log.debug("Creating dialog...")
|
||||
self.dialog = wx_ui.spellCheckerDialog()
|
||||
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.replace, widgetUtils.BUTTON_PRESSED, self.replace)
|
||||
widgetUtils.connect_event(self.dialog.replaceAll, widgetUtils.BUTTON_PRESSED, self.replaceAll)
|
||||
widgetUtils.connect_event(self.dialog.add, widgetUtils.BUTTON_PRESSED, self.add)
|
||||
self.check()
|
||||
self.dialog.get_response()
|
||||
self.fixed_text = self.checker.get_text()
|
||||
|
||||
def check(self):
|
||||
try:
|
||||
next(self.checker)
|
||||
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))
|
||||
self.dialog.set_title(textToSay)
|
||||
output.speak(textToSay)
|
||||
self.dialog.set_word_and_suggestions(word=self.checker.word, context=context, suggestions=self.checker.suggest())
|
||||
except StopIteration:
|
||||
log.debug("Process finished.")
|
||||
wx_ui.finished()
|
||||
self.dialog.Destroy()
|
||||
def check(self):
|
||||
try:
|
||||
next(self.checker)
|
||||
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))
|
||||
self.dialog.set_title(textToSay)
|
||||
output.speak(textToSay)
|
||||
self.dialog.set_word_and_suggestions(word=self.checker.word, context=context, suggestions=self.checker.suggest())
|
||||
except StopIteration:
|
||||
log.debug("Process finished.")
|
||||
wx_ui.finished()
|
||||
self.dialog.Destroy()
|
||||
|
||||
def ignore(self, ev):
|
||||
self.check()
|
||||
def ignore(self, ev):
|
||||
self.check()
|
||||
|
||||
def ignoreAll(self, ev):
|
||||
self.checker.ignore_always(word=self.checker.word)
|
||||
self.check()
|
||||
def ignoreAll(self, ev):
|
||||
self.checker.ignore_always(word=self.checker.word)
|
||||
self.check()
|
||||
|
||||
def replace(self, ev):
|
||||
self.checker.replace(self.dialog.get_selected_suggestion())
|
||||
self.check()
|
||||
def replace(self, ev):
|
||||
self.checker.replace(self.dialog.get_selected_suggestion())
|
||||
self.check()
|
||||
|
||||
def replaceAll(self, ev):
|
||||
self.checker.replace_always(self.dialog.get_selected_suggestion())
|
||||
self.check()
|
||||
def replaceAll(self, ev):
|
||||
self.checker.replace_always(self.dialog.get_selected_suggestion())
|
||||
self.check()
|
||||
|
||||
def add(self, ev):
|
||||
self.checker.add()
|
||||
self.check()
|
||||
def add(self, ev):
|
||||
self.checker.add()
|
||||
self.check()
|
||||
|
@ -21,63 +21,63 @@ import wx
|
||||
import application
|
||||
|
||||
class spellCheckerDialog(wx.Dialog):
|
||||
def __init__(self):
|
||||
super(spellCheckerDialog, self).__init__(None, 1)
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
word = wx.StaticText(panel, -1, _(u"Misspelled word"))
|
||||
self.word = wx.TextCtrl(panel, -1)
|
||||
wordBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
wordBox.Add(word, 0, wx.ALL, 5)
|
||||
wordBox.Add(self.word, 0, wx.ALL, 5)
|
||||
context = wx.StaticText(panel, -1, _(u"Context"))
|
||||
self.context = wx.TextCtrl(panel, -1)
|
||||
contextBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
contextBox.Add(context, 0, wx.ALL, 5)
|
||||
contextBox.Add(self.context, 0, wx.ALL, 5)
|
||||
suggest = wx.StaticText(panel, -1, _(u"Suggestions"))
|
||||
self.suggestions = wx.ListBox(panel, -1, choices=[], style=wx.LB_SINGLE)
|
||||
suggestionsBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
suggestionsBox.Add(suggest, 0, wx.ALL, 5)
|
||||
suggestionsBox.Add(self.suggestions, 0, wx.ALL, 5)
|
||||
self.ignore = wx.Button(panel, -1, _(u"&Ignore"))
|
||||
self.ignoreAll = wx.Button(panel, -1, _(u"I&gnore all"))
|
||||
self.replace = wx.Button(panel, -1, _(u"&Replace"))
|
||||
self.replaceAll = wx.Button(panel, -1, _(u"R&eplace all"))
|
||||
self.add = wx.Button(panel, -1, _(u"&Add to personal dictionary"))
|
||||
close = wx.Button(panel, wx.ID_CANCEL)
|
||||
btnBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
btnBox.Add(self.ignore, 0, wx.ALL, 5)
|
||||
btnBox.Add(self.ignoreAll, 0, wx.ALL, 5)
|
||||
btnBox.Add(self.replace, 0, wx.ALL, 5)
|
||||
btnBox.Add(self.replaceAll, 0, wx.ALL, 5)
|
||||
btnBox.Add(self.add, 0, wx.ALL, 5)
|
||||
btnBox.Add(close, 0, wx.ALL, 5)
|
||||
sizer.Add(wordBox, 0, wx.ALL, 5)
|
||||
sizer.Add(contextBox, 0, wx.ALL, 5)
|
||||
sizer.Add(suggestionsBox, 0, wx.ALL, 5)
|
||||
sizer.Add(btnBox, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
self.SetClientSize(sizer.CalcMin())
|
||||
def __init__(self):
|
||||
super(spellCheckerDialog, self).__init__(None, 1)
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
word = wx.StaticText(panel, -1, _(u"Misspelled word"))
|
||||
self.word = wx.TextCtrl(panel, -1)
|
||||
wordBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
wordBox.Add(word, 0, wx.ALL, 5)
|
||||
wordBox.Add(self.word, 0, wx.ALL, 5)
|
||||
context = wx.StaticText(panel, -1, _(u"Context"))
|
||||
self.context = wx.TextCtrl(panel, -1)
|
||||
contextBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
contextBox.Add(context, 0, wx.ALL, 5)
|
||||
contextBox.Add(self.context, 0, wx.ALL, 5)
|
||||
suggest = wx.StaticText(panel, -1, _(u"Suggestions"))
|
||||
self.suggestions = wx.ListBox(panel, -1, choices=[], style=wx.LB_SINGLE)
|
||||
suggestionsBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
suggestionsBox.Add(suggest, 0, wx.ALL, 5)
|
||||
suggestionsBox.Add(self.suggestions, 0, wx.ALL, 5)
|
||||
self.ignore = wx.Button(panel, -1, _(u"&Ignore"))
|
||||
self.ignoreAll = wx.Button(panel, -1, _(u"I&gnore all"))
|
||||
self.replace = wx.Button(panel, -1, _(u"&Replace"))
|
||||
self.replaceAll = wx.Button(panel, -1, _(u"R&eplace all"))
|
||||
self.add = wx.Button(panel, -1, _(u"&Add to personal dictionary"))
|
||||
close = wx.Button(panel, wx.ID_CANCEL)
|
||||
btnBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
btnBox.Add(self.ignore, 0, wx.ALL, 5)
|
||||
btnBox.Add(self.ignoreAll, 0, wx.ALL, 5)
|
||||
btnBox.Add(self.replace, 0, wx.ALL, 5)
|
||||
btnBox.Add(self.replaceAll, 0, wx.ALL, 5)
|
||||
btnBox.Add(self.add, 0, wx.ALL, 5)
|
||||
btnBox.Add(close, 0, wx.ALL, 5)
|
||||
sizer.Add(wordBox, 0, wx.ALL, 5)
|
||||
sizer.Add(contextBox, 0, wx.ALL, 5)
|
||||
sizer.Add(suggestionsBox, 0, wx.ALL, 5)
|
||||
sizer.Add(btnBox, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
self.SetClientSize(sizer.CalcMin())
|
||||
|
||||
|
||||
def get_response(self):
|
||||
return self.ShowModal()
|
||||
def get_response(self):
|
||||
return self.ShowModal()
|
||||
|
||||
def set_title(self, title):
|
||||
return self.SetTitle(title)
|
||||
def set_title(self, title):
|
||||
return self.SetTitle(title)
|
||||
|
||||
def set_word_and_suggestions(self, word, context, suggestions):
|
||||
self.word.SetValue(word)
|
||||
self.context.ChangeValue(context)
|
||||
self.suggestions.Set(suggestions)
|
||||
self.suggestions.SetFocus()
|
||||
def set_word_and_suggestions(self, word, context, suggestions):
|
||||
self.word.SetValue(word)
|
||||
self.context.ChangeValue(context)
|
||||
self.suggestions.Set(suggestions)
|
||||
self.suggestions.SetFocus()
|
||||
|
||||
def get_selected_suggestion(self):
|
||||
return self.suggestions.GetStringSelection()
|
||||
def get_selected_suggestion(self):
|
||||
return self.suggestions.GetStringSelection()
|
||||
|
||||
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():
|
||||
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()
|
||||
|
@ -4,44 +4,44 @@ from . import storage
|
||||
from . import wx_menu
|
||||
|
||||
class autocompletionUsers(object):
|
||||
def __init__(self, window, session_id):
|
||||
super(autocompletionUsers, self).__init__()
|
||||
self.window = window
|
||||
self.db = storage.storage(session_id)
|
||||
def __init__(self, window, session_id):
|
||||
super(autocompletionUsers, self).__init__()
|
||||
self.window = window
|
||||
self.db = storage.storage(session_id)
|
||||
|
||||
def show_menu(self, mode="tweet"):
|
||||
position = self.window.get_position()
|
||||
if mode == "tweet":
|
||||
text = self.window.get_text()
|
||||
text = text[:position]
|
||||
try:
|
||||
pattern = text.split()[-1]
|
||||
except IndexError:
|
||||
output.speak(_(u"You have to start writing"))
|
||||
return
|
||||
if pattern.startswith("@") == True:
|
||||
menu = wx_menu.menu(self.window.text, pattern[1:], mode=mode)
|
||||
users = self.db.get_users(pattern[1:])
|
||||
if len(users) > 0:
|
||||
menu.append_options(users)
|
||||
self.window.popup_menu(menu)
|
||||
menu.destroy()
|
||||
else:
|
||||
output.speak(_(u"There are no results in your users database"))
|
||||
else:
|
||||
output.speak(_(u"Autocompletion only works for users."))
|
||||
elif mode == "dm":
|
||||
text = self.window.get_user()
|
||||
try:
|
||||
pattern = text.split()[-1]
|
||||
except IndexError:
|
||||
output.speak(_(u"You have to start writing"))
|
||||
return
|
||||
menu = wx_menu.menu(self.window.cb, pattern, mode=mode)
|
||||
users = self.db.get_users(pattern)
|
||||
if len(users) > 0:
|
||||
menu.append_options(users)
|
||||
self.window.popup_menu(menu)
|
||||
menu.destroy()
|
||||
else:
|
||||
output.speak(_(u"There are no results in your users database"))
|
||||
def show_menu(self, mode="tweet"):
|
||||
position = self.window.get_position()
|
||||
if mode == "tweet":
|
||||
text = self.window.get_text()
|
||||
text = text[:position]
|
||||
try:
|
||||
pattern = text.split()[-1]
|
||||
except IndexError:
|
||||
output.speak(_(u"You have to start writing"))
|
||||
return
|
||||
if pattern.startswith("@") == True:
|
||||
menu = wx_menu.menu(self.window.text, pattern[1:], mode=mode)
|
||||
users = self.db.get_users(pattern[1:])
|
||||
if len(users) > 0:
|
||||
menu.append_options(users)
|
||||
self.window.popup_menu(menu)
|
||||
menu.destroy()
|
||||
else:
|
||||
output.speak(_(u"There are no results in your users database"))
|
||||
else:
|
||||
output.speak(_(u"Autocompletion only works for users."))
|
||||
elif mode == "dm":
|
||||
text = self.window.get_user()
|
||||
try:
|
||||
pattern = text.split()[-1]
|
||||
except IndexError:
|
||||
output.speak(_(u"You have to start writing"))
|
||||
return
|
||||
menu = wx_menu.menu(self.window.cb, pattern, mode=mode)
|
||||
users = self.db.get_users(pattern)
|
||||
if len(users) > 0:
|
||||
menu.append_options(users)
|
||||
self.window.popup_menu(menu)
|
||||
menu.destroy()
|
||||
else:
|
||||
output.speak(_(u"There are no results in your users database"))
|
||||
|
@ -4,39 +4,39 @@ from . import storage, wx_manage
|
||||
from wxUI import commonMessageDialogs
|
||||
|
||||
class autocompletionManage(object):
|
||||
def __init__(self, session):
|
||||
super(autocompletionManage, self).__init__()
|
||||
self.session = session
|
||||
self.dialog = wx_manage.autocompletionManageDialog()
|
||||
self.database = storage.storage(self.session.session_id)
|
||||
self.users = self.database.get_all_users()
|
||||
self.dialog.put_users(self.users)
|
||||
widgetUtils.connect_event(self.dialog.add, widgetUtils.BUTTON_PRESSED, self.add_user)
|
||||
widgetUtils.connect_event(self.dialog.remove, widgetUtils.BUTTON_PRESSED, self.remove_user)
|
||||
self.dialog.get_response()
|
||||
def __init__(self, session):
|
||||
super(autocompletionManage, self).__init__()
|
||||
self.session = session
|
||||
self.dialog = wx_manage.autocompletionManageDialog()
|
||||
self.database = storage.storage(self.session.session_id)
|
||||
self.users = self.database.get_all_users()
|
||||
self.dialog.put_users(self.users)
|
||||
widgetUtils.connect_event(self.dialog.add, widgetUtils.BUTTON_PRESSED, self.add_user)
|
||||
widgetUtils.connect_event(self.dialog.remove, widgetUtils.BUTTON_PRESSED, self.remove_user)
|
||||
self.dialog.get_response()
|
||||
|
||||
def update_list(self):
|
||||
item = self.dialog.users.get_selected()
|
||||
self.dialog.users.clear()
|
||||
self.users = self.database.get_all_users()
|
||||
self.dialog.put_users(self.users)
|
||||
self.dialog.users.select_item(item)
|
||||
def update_list(self):
|
||||
item = self.dialog.users.get_selected()
|
||||
self.dialog.users.clear()
|
||||
self.users = self.database.get_all_users()
|
||||
self.dialog.put_users(self.users)
|
||||
self.dialog.users.select_item(item)
|
||||
|
||||
def add_user(self, *args, **kwargs):
|
||||
usr = self.dialog.get_user()
|
||||
if usr == False:
|
||||
return
|
||||
try:
|
||||
data = self.session.twitter.twitter.get_user(screen_name=usr)
|
||||
except:
|
||||
self.dialog.show_invalid_user_error()
|
||||
return
|
||||
self.database.set_user(data.screen_name, data.name, 0)
|
||||
self.update_list()
|
||||
def add_user(self, *args, **kwargs):
|
||||
usr = self.dialog.get_user()
|
||||
if usr == False:
|
||||
return
|
||||
try:
|
||||
data = self.session.twitter.twitter.get_user(screen_name=usr)
|
||||
except:
|
||||
self.dialog.show_invalid_user_error()
|
||||
return
|
||||
self.database.set_user(data.screen_name, data.name, 0)
|
||||
self.update_list()
|
||||
|
||||
def remove_user(self, ev):
|
||||
if commonMessageDialogs.delete_user_from_db() == widgetUtils.YES:
|
||||
item = self.dialog.users.get_selected()
|
||||
user = self.users[item]
|
||||
self.database.remove_user(user[0])
|
||||
self.update_list()
|
||||
def remove_user(self, ev):
|
||||
if commonMessageDialogs.delete_user_from_db() == widgetUtils.YES:
|
||||
item = self.dialog.users.get_selected()
|
||||
user = self.users[item]
|
||||
self.database.remove_user(user[0])
|
||||
self.update_list()
|
||||
|
@ -7,53 +7,53 @@ from . import storage
|
||||
from mysc.thread_utils import call_threaded
|
||||
|
||||
class autocompletionSettings(object):
|
||||
def __init__(self, config, buffer, window):
|
||||
super(autocompletionSettings, self).__init__()
|
||||
self.config = config
|
||||
self.buffer = buffer
|
||||
self.window = window
|
||||
self.dialog = wx_settings.autocompletionSettingsDialog()
|
||||
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"])
|
||||
widgetUtils.connect_event(self.dialog.viewList, widgetUtils.BUTTON_PRESSED, self.view_list)
|
||||
if self.dialog.get_response() == widgetUtils.OK:
|
||||
call_threaded(self.add_users_to_database)
|
||||
def __init__(self, config, buffer, window):
|
||||
super(autocompletionSettings, self).__init__()
|
||||
self.config = config
|
||||
self.buffer = buffer
|
||||
self.window = window
|
||||
self.dialog = wx_settings.autocompletionSettingsDialog()
|
||||
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"])
|
||||
widgetUtils.connect_event(self.dialog.viewList, widgetUtils.BUTTON_PRESSED, self.view_list)
|
||||
if self.dialog.get_response() == widgetUtils.OK:
|
||||
call_threaded(self.add_users_to_database)
|
||||
|
||||
def add_users_to_database(self):
|
||||
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")
|
||||
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)
|
||||
if self.dialog.get("followers_buffer") == True:
|
||||
buffer = self.window.search_buffer("followers", self.config["twitter"]["user_name"])
|
||||
for i in buffer.session.db[buffer.name]:
|
||||
database.set_user(i.screen_name, i.name, 1)
|
||||
else:
|
||||
database.remove_by_buffer(1)
|
||||
if self.dialog.get("friends_buffer") == True:
|
||||
buffer = self.window.search_buffer("friends", self.config["twitter"]["user_name"])
|
||||
for i in buffer.session.db[buffer.name]:
|
||||
database.set_user(i.screen_name, i.name, 2)
|
||||
else:
|
||||
database.remove_by_buffer(2)
|
||||
wx_settings.show_success_dialog()
|
||||
self.dialog.destroy()
|
||||
def add_users_to_database(self):
|
||||
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")
|
||||
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)
|
||||
if self.dialog.get("followers_buffer") == True:
|
||||
buffer = self.window.search_buffer("followers", self.config["twitter"]["user_name"])
|
||||
for i in buffer.session.db[buffer.name]:
|
||||
database.set_user(i.screen_name, i.name, 1)
|
||||
else:
|
||||
database.remove_by_buffer(1)
|
||||
if self.dialog.get("friends_buffer") == True:
|
||||
buffer = self.window.search_buffer("friends", self.config["twitter"]["user_name"])
|
||||
for i in buffer.session.db[buffer.name]:
|
||||
database.set_user(i.screen_name, i.name, 2)
|
||||
else:
|
||||
database.remove_by_buffer(2)
|
||||
wx_settings.show_success_dialog()
|
||||
self.dialog.destroy()
|
||||
|
||||
def view_list(self, ev):
|
||||
q = manage.autocompletionManage(self.buffer.session)
|
||||
def view_list(self, ev):
|
||||
q = manage.autocompletionManage(self.buffer.session)
|
||||
|
||||
|
||||
def execute_at_startup(window, buffer, config):
|
||||
database = storage.storage(buffer.session.session_id)
|
||||
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"])
|
||||
for i in buffer.session.db[buffer.name]:
|
||||
database.set_user(i.screen_name, i.name, 1)
|
||||
else:
|
||||
database.remove_by_buffer(1)
|
||||
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"])
|
||||
for i in buffer.session.db[buffer.name]:
|
||||
database.set_user(i.screen_name, i.name, 2)
|
||||
else:
|
||||
database.remove_by_buffer(2)
|
||||
database = storage.storage(buffer.session.session_id)
|
||||
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"])
|
||||
for i in buffer.session.db[buffer.name]:
|
||||
database.set_user(i.screen_name, i.name, 1)
|
||||
else:
|
||||
database.remove_by_buffer(1)
|
||||
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"])
|
||||
for i in buffer.session.db[buffer.name]:
|
||||
database.set_user(i.screen_name, i.name, 2)
|
||||
else:
|
||||
database.remove_by_buffer(2)
|
||||
|
@ -2,51 +2,51 @@
|
||||
import os, sqlite3, paths
|
||||
|
||||
class storage(object):
|
||||
def __init__(self, session_id):
|
||||
self.connection = sqlite3.connect(os.path.join(paths.config_path(), "%s/autocompletionUsers.dat" % (session_id)))
|
||||
self.cursor = self.connection.cursor()
|
||||
if self.table_exist("users") == False:
|
||||
self.create_table()
|
||||
def __init__(self, session_id):
|
||||
self.connection = sqlite3.connect(os.path.join(paths.config_path(), "%s/autocompletionUsers.dat" % (session_id)))
|
||||
self.cursor = self.connection.cursor()
|
||||
if self.table_exist("users") == False:
|
||||
self.create_table()
|
||||
|
||||
def table_exist(self, table):
|
||||
ask = self.cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='%s'" % (table))
|
||||
answer = ask.fetchone()
|
||||
if answer == None:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
def table_exist(self, table):
|
||||
ask = self.cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='%s'" % (table))
|
||||
answer = ask.fetchone()
|
||||
if answer == None:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def get_all_users(self):
|
||||
self.cursor.execute("""select * from users""")
|
||||
return self.cursor.fetchall()
|
||||
def get_all_users(self):
|
||||
self.cursor.execute("""select * from users""")
|
||||
return self.cursor.fetchall()
|
||||
|
||||
def get_users(self, term):
|
||||
self.cursor.execute("""SELECT * FROM users WHERE user LIKE ?""", ('{}%'.format(term),))
|
||||
return self.cursor.fetchall()
|
||||
def get_users(self, term):
|
||||
self.cursor.execute("""SELECT * FROM users WHERE user LIKE ?""", ('{}%'.format(term),))
|
||||
return self.cursor.fetchall()
|
||||
|
||||
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.connection.commit()
|
||||
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.connection.commit()
|
||||
|
||||
def remove_user(self, user):
|
||||
self.cursor.execute("""DELETE FROM users WHERE user = ?""", (user,))
|
||||
self.connection.commit()
|
||||
return self.cursor.fetchone()
|
||||
def remove_user(self, user):
|
||||
self.cursor.execute("""DELETE FROM users WHERE user = ?""", (user,))
|
||||
self.connection.commit()
|
||||
return self.cursor.fetchone()
|
||||
|
||||
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"""
|
||||
self.cursor.execute("""DELETE FROM users WHERE from_a_buffer = ?""", (bufferType,))
|
||||
self.connection.commit()
|
||||
return self.cursor.fetchone()
|
||||
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"""
|
||||
self.cursor.execute("""DELETE FROM users WHERE from_a_buffer = ?""", (bufferType,))
|
||||
self.connection.commit()
|
||||
return self.cursor.fetchone()
|
||||
|
||||
def create_table(self):
|
||||
self.cursor.execute("""
|
||||
def create_table(self):
|
||||
self.cursor.execute("""
|
||||
create table users(
|
||||
user TEXT UNIQUE,
|
||||
name TEXT,
|
||||
from_a_buffer INTEGER
|
||||
)""")
|
||||
|
||||
def __del__(self):
|
||||
self.cursor.close()
|
||||
self.connection.close()
|
||||
def __del__(self):
|
||||
self.cursor.close()
|
||||
self.connection.close()
|
||||
|
@ -5,40 +5,40 @@ from multiplatform_widgets import widgets
|
||||
import application
|
||||
|
||||
class autocompletionManageDialog(widgetUtils.BaseDialog):
|
||||
def __init__(self):
|
||||
super(autocompletionManageDialog, self).__init__(parent=None, id=-1, title=_(u"Manage Autocompletion database"))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
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)
|
||||
sizer.Add(label, 0, wx.ALL, 5)
|
||||
sizer.Add(self.users.list, 0, wx.ALL, 5)
|
||||
self.add = wx.Button(panel, -1, _(u"Add user"))
|
||||
self.remove = wx.Button(panel, -1, _(u"Remove user"))
|
||||
optionsBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
optionsBox.Add(self.add, 0, wx.ALL, 5)
|
||||
optionsBox.Add(self.remove, 0, wx.ALL, 5)
|
||||
sizer.Add(optionsBox, 0, wx.ALL, 5)
|
||||
ok = wx.Button(panel, wx.ID_OK)
|
||||
cancel = wx.Button(panel, wx.ID_CANCEL)
|
||||
sizerBtn = wx.BoxSizer(wx.HORIZONTAL)
|
||||
sizerBtn.Add(ok, 0, wx.ALL, 5)
|
||||
sizer.Add(cancel, 0, wx.ALL, 5)
|
||||
sizer.Add(sizerBtn, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
self.SetClientSize(sizer.CalcMin())
|
||||
def __init__(self):
|
||||
super(autocompletionManageDialog, self).__init__(parent=None, id=-1, title=_(u"Manage Autocompletion database"))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
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)
|
||||
sizer.Add(label, 0, wx.ALL, 5)
|
||||
sizer.Add(self.users.list, 0, wx.ALL, 5)
|
||||
self.add = wx.Button(panel, -1, _(u"Add user"))
|
||||
self.remove = wx.Button(panel, -1, _(u"Remove user"))
|
||||
optionsBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
optionsBox.Add(self.add, 0, wx.ALL, 5)
|
||||
optionsBox.Add(self.remove, 0, wx.ALL, 5)
|
||||
sizer.Add(optionsBox, 0, wx.ALL, 5)
|
||||
ok = wx.Button(panel, wx.ID_OK)
|
||||
cancel = wx.Button(panel, wx.ID_CANCEL)
|
||||
sizerBtn = wx.BoxSizer(wx.HORIZONTAL)
|
||||
sizerBtn.Add(ok, 0, wx.ALL, 5)
|
||||
sizer.Add(cancel, 0, wx.ALL, 5)
|
||||
sizer.Add(sizerBtn, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
self.SetClientSize(sizer.CalcMin())
|
||||
|
||||
def put_users(self, users):
|
||||
for i in users:
|
||||
j = [i[0], i[1]]
|
||||
self.users.insert_item(False, *j)
|
||||
def put_users(self, users):
|
||||
for i in users:
|
||||
j = [i[0], i[1]]
|
||||
self.users.insert_item(False, *j)
|
||||
|
||||
def get_user(self):
|
||||
usr = False
|
||||
userDlg = wx.TextEntryDialog(None, _(u"Twitter username"), _(u"Add user to database"))
|
||||
if userDlg.ShowModal() == wx.ID_OK:
|
||||
usr = userDlg.GetValue()
|
||||
return usr
|
||||
def get_user(self):
|
||||
usr = False
|
||||
userDlg = wx.TextEntryDialog(None, _(u"Twitter username"), _(u"Add user to database"))
|
||||
if userDlg.ShowModal() == wx.ID_OK:
|
||||
usr = userDlg.GetValue()
|
||||
return usr
|
||||
|
||||
def show_invalid_user_error(self):
|
||||
wx.MessageDialog(None, _(u"The user does not exist"), _(u"Error!"), wx.ICON_ERROR).ShowModal()
|
||||
def show_invalid_user_error(self):
|
||||
wx.MessageDialog(None, _(u"The user does not exist"), _(u"Error!"), wx.ICON_ERROR).ShowModal()
|
||||
|
@ -2,24 +2,24 @@
|
||||
import wx
|
||||
|
||||
class menu(wx.Menu):
|
||||
def __init__(self, window, pattern, mode):
|
||||
super(menu, self).__init__()
|
||||
self.window = window
|
||||
self.pattern = pattern
|
||||
self.mode = mode
|
||||
def __init__(self, window, pattern, mode):
|
||||
super(menu, self).__init__()
|
||||
self.window = window
|
||||
self.pattern = pattern
|
||||
self.mode = mode
|
||||
|
||||
def append_options(self, options):
|
||||
for i in options:
|
||||
item = wx.MenuItem(self, wx.ID_ANY, "%s (@%s)" % (i[1], i[0]))
|
||||
self.AppendItem(item)
|
||||
self.Bind(wx.EVT_MENU, lambda evt, temp=i[0]: self.select_text(evt, temp), item)
|
||||
def append_options(self, options):
|
||||
for i in options:
|
||||
item = wx.MenuItem(self, wx.ID_ANY, "%s (@%s)" % (i[1], i[0]))
|
||||
self.AppendItem(item)
|
||||
self.Bind(wx.EVT_MENU, lambda evt, temp=i[0]: self.select_text(evt, temp), item)
|
||||
|
||||
def select_text(self, ev, text):
|
||||
if self.mode == "tweet":
|
||||
self.window.ChangeValue(self.window.GetValue().replace("@"+self.pattern, "@"+text+" "))
|
||||
elif self.mode == "dm":
|
||||
self.window.SetValue(self.window.GetValue().replace(self.pattern, text))
|
||||
self.window.SetInsertionPointEnd()
|
||||
def select_text(self, ev, text):
|
||||
if self.mode == "tweet":
|
||||
self.window.ChangeValue(self.window.GetValue().replace("@"+self.pattern, "@"+text+" "))
|
||||
elif self.mode == "dm":
|
||||
self.window.SetValue(self.window.GetValue().replace(self.pattern, text))
|
||||
self.window.SetInsertionPointEnd()
|
||||
|
||||
def destroy(self):
|
||||
self.Destroy()
|
||||
def destroy(self):
|
||||
self.Destroy()
|
||||
|
@ -4,24 +4,24 @@ import widgetUtils
|
||||
import application
|
||||
|
||||
class autocompletionSettingsDialog(widgetUtils.BaseDialog):
|
||||
def __init__(self):
|
||||
super(autocompletionSettingsDialog, self).__init__(parent=None, id=-1, title=_(u"Autocomplete users' settings"))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
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"))
|
||||
sizer.Add(self.followers_buffer, 0, wx.ALL, 5)
|
||||
sizer.Add(self.friends_buffer, 0, wx.ALL, 5)
|
||||
self.viewList = wx.Button(panel, -1, _(u"Manage database..."))
|
||||
sizer.Add(self.viewList, 0, wx.ALL, 5)
|
||||
ok = wx.Button(panel, wx.ID_OK)
|
||||
cancel = wx.Button(panel, wx.ID_CANCEL)
|
||||
sizerBtn = wx.BoxSizer(wx.HORIZONTAL)
|
||||
sizerBtn.Add(ok, 0, wx.ALL, 5)
|
||||
sizer.Add(cancel, 0, wx.ALL, 5)
|
||||
sizer.Add(sizerBtn, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
self.SetClientSize(sizer.CalcMin())
|
||||
def __init__(self):
|
||||
super(autocompletionSettingsDialog, self).__init__(parent=None, id=-1, title=_(u"Autocomplete users' settings"))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
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"))
|
||||
sizer.Add(self.followers_buffer, 0, wx.ALL, 5)
|
||||
sizer.Add(self.friends_buffer, 0, wx.ALL, 5)
|
||||
self.viewList = wx.Button(panel, -1, _(u"Manage database..."))
|
||||
sizer.Add(self.viewList, 0, wx.ALL, 5)
|
||||
ok = wx.Button(panel, wx.ID_OK)
|
||||
cancel = wx.Button(panel, wx.ID_CANCEL)
|
||||
sizerBtn = wx.BoxSizer(wx.HORIZONTAL)
|
||||
sizerBtn.Add(ok, 0, wx.ALL, 5)
|
||||
sizer.Add(cancel, 0, wx.ALL, 5)
|
||||
sizer.Add(sizerBtn, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
self.SetClientSize(sizer.CalcMin())
|
||||
|
||||
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()
|
||||
|
@ -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"]
|
||||
|
||||
class APIError(Exception):
|
||||
pass
|
||||
pass
|
||||
|
||||
class OCRSpaceAPI(object):
|
||||
|
||||
def __init__(self, key="4e72ae996f88957", url='https://api.ocr.space/parse/image'):
|
||||
self.key = key
|
||||
self.url = url
|
||||
def __init__(self, key="4e72ae996f88957", url='https://api.ocr.space/parse/image'):
|
||||
self.key = key
|
||||
self.url = url
|
||||
|
||||
def OCR_URL(self, url, overlay=False, lang=None):
|
||||
payload = {
|
||||
'url': url,
|
||||
'isOverlayRequired': overlay,
|
||||
'apikey': self.key,
|
||||
}
|
||||
if lang != None:
|
||||
payload.update(language=lang)
|
||||
r = requests.post(self.url, data=payload)
|
||||
result = r.json()['ParsedResults'][0]
|
||||
if result['ErrorMessage']:
|
||||
raise APIError(result['ErrorMessage'])
|
||||
return result
|
||||
def OCR_URL(self, url, overlay=False, lang=None):
|
||||
payload = {
|
||||
'url': url,
|
||||
'isOverlayRequired': overlay,
|
||||
'apikey': self.key,
|
||||
}
|
||||
if lang != None:
|
||||
payload.update(language=lang)
|
||||
r = requests.post(self.url, data=payload)
|
||||
result = r.json()['ParsedResults'][0]
|
||||
if result['ErrorMessage']:
|
||||
raise APIError(result['ErrorMessage'])
|
||||
return result
|
||||
|
||||
def OCR_file(self, fileobj, overlay=False):
|
||||
payload = {
|
||||
'isOverlayRequired': overlay,
|
||||
'apikey': self.key,
|
||||
'lang': 'es',
|
||||
}
|
||||
r = requests.post(self.url, data=payload, files={'file': fileobj})
|
||||
results = r.json()['ParsedResults']
|
||||
if results[0]['ErrorMessage']:
|
||||
raise APIError(results[0]['ErrorMessage'])
|
||||
return results
|
||||
def OCR_file(self, fileobj, overlay=False):
|
||||
payload = {
|
||||
'isOverlayRequired': overlay,
|
||||
'apikey': self.key,
|
||||
'lang': 'es',
|
||||
}
|
||||
r = requests.post(self.url, data=payload, files={'file': fileobj})
|
||||
results = r.json()['ParsedResults']
|
||||
if results[0]['ErrorMessage']:
|
||||
raise APIError(results[0]['ErrorMessage'])
|
||||
return results
|
||||
|
||||
|
@ -4,5 +4,5 @@ from __future__ import unicode_literals
|
||||
from . import translator
|
||||
import platform
|
||||
if platform.system() == "Windows":
|
||||
from . import wx_ui as gui
|
||||
from . import wx_ui as gui
|
||||
|
@ -9,108 +9,108 @@ log = logging.getLogger("extras.translator")
|
||||
t = None
|
||||
|
||||
def translate(text="", target="en"):
|
||||
global t
|
||||
log.debug("Received translation request for language %s, text=%s" % (target, text))
|
||||
if t == None:
|
||||
t = Translator()
|
||||
vars = dict(text=text, dest=target)
|
||||
return t.translate(**vars).text
|
||||
global t
|
||||
log.debug("Received translation request for language %s, text=%s" % (target, text))
|
||||
if t == None:
|
||||
t = Translator()
|
||||
vars = dict(text=text, dest=target)
|
||||
return t.translate(**vars).text
|
||||
|
||||
supported_langs = None
|
||||
|
||||
languages = {
|
||||
"af": _(u"Afrikaans"),
|
||||
"sq": _(u"Albanian"),
|
||||
"am": _(u"Amharic"),
|
||||
"ar": _(u"Arabic"),
|
||||
"hy": _(u"Armenian"),
|
||||
"az": _(u"Azerbaijani"),
|
||||
"eu": _(u"Basque"),
|
||||
"be": _(u"Belarusian"),
|
||||
"bn": _(u"Bengali"),
|
||||
"bh": _(u"Bihari"),
|
||||
"bg": _(u"Bulgarian"),
|
||||
"my": _(u"Burmese"),
|
||||
"ca": _(u"Catalan"),
|
||||
"chr": _(u"Cherokee"),
|
||||
"zh": _(u"Chinese"),
|
||||
"zh-CN": _(u"Chinese_simplified"),
|
||||
"zh-TW": _(u"Chinese_traditional"),
|
||||
"hr": _(u"Croatian"),
|
||||
"cs": _(u"Czech"),
|
||||
"da": _(u"Danish"),
|
||||
"dv": _(u"Dhivehi"),
|
||||
"nl": _(u"Dutch"),
|
||||
"en": _(u"English"),
|
||||
"eo": _(u"Esperanto"),
|
||||
"et": _(u"Estonian"),
|
||||
"tl": _(u"Filipino"),
|
||||
"fi": _(u"Finnish"),
|
||||
"fr": _(u"French"),
|
||||
"gl": _(u"Galician"),
|
||||
"ka": _(u"Georgian"),
|
||||
"de": _(u"German"),
|
||||
"el": _(u"Greek"),
|
||||
"gn": _(u"Guarani"),
|
||||
"gu": _(u"Gujarati"),
|
||||
"iw": _(u"Hebrew"),
|
||||
"hi": _(u"Hindi"),
|
||||
"hu": _(u"Hungarian"),
|
||||
"is": _(u"Icelandic"),
|
||||
"id": _(u"Indonesian"),
|
||||
"iu": _(u"Inuktitut"),
|
||||
"ga": _(u"Irish"),
|
||||
"it": _(u"Italian"),
|
||||
"ja": _(u"Japanese"),
|
||||
"kn": _(u"Kannada"),
|
||||
"kk": _(u"Kazakh"),
|
||||
"km": _(u"Khmer"),
|
||||
"ko": _(u"Korean"),
|
||||
"ku": _(u"Kurdish"),
|
||||
"ky": _(u"Kyrgyz"),
|
||||
"lo": _(u"Laothian"),
|
||||
"lv": _(u"Latvian"),
|
||||
"lt": _(u"Lithuanian"),
|
||||
"mk": _(u"Macedonian"),
|
||||
"ms": _(u"Malay"),
|
||||
"ml": _(u"Malayalam"),
|
||||
"mt": _(u"Maltese"),
|
||||
"mr": _(u"Marathi"),
|
||||
"mn": _(u"Mongolian"),
|
||||
"ne": _(u"Nepali"),
|
||||
"no": _(u"Norwegian"),
|
||||
"or": _(u"Oriya"),
|
||||
"ps": _(u"Pashto"),
|
||||
"fa": _(u"Persian"),
|
||||
"pl": _(u"Polish"),
|
||||
"pt": _(u"Portuguese"),
|
||||
"pa": _(u"Punjabi"),
|
||||
"ro": _(u"Romanian"),
|
||||
"ru": _(u"Russian"),
|
||||
"sa": _(u"Sanskrit"),
|
||||
"sr": _(u"Serbian"),
|
||||
"sd": _(u"Sindhi"),
|
||||
"si": _(u"Sinhalese"),
|
||||
"sk": _(u"Slovak"),
|
||||
"sl": _(u"Slovenian"),
|
||||
"es": _(u"Spanish"),
|
||||
"sw": _(u"Swahili"),
|
||||
"sv": _(u"Swedish"),
|
||||
"tg": _(u"Tajik"),
|
||||
"ta": _(u"Tamil"),
|
||||
"tl": _(u"Tagalog"),
|
||||
"te": _(u"Telugu"),
|
||||
"th": _(u"Thai"),
|
||||
"bo": _(u"Tibetan"),
|
||||
"tr": _(u"Turkish"),
|
||||
"uk": _(u"Ukrainian"),
|
||||
"ur": _(u"Urdu"),
|
||||
"uz": _(u"Uzbek"),
|
||||
"ug": _(u"Uighur"),
|
||||
"vi": _(u"Vietnamese"),
|
||||
"cy": _(u"Welsh"),
|
||||
"yi": _(u"Yiddish")
|
||||
"af": _(u"Afrikaans"),
|
||||
"sq": _(u"Albanian"),
|
||||
"am": _(u"Amharic"),
|
||||
"ar": _(u"Arabic"),
|
||||
"hy": _(u"Armenian"),
|
||||
"az": _(u"Azerbaijani"),
|
||||
"eu": _(u"Basque"),
|
||||
"be": _(u"Belarusian"),
|
||||
"bn": _(u"Bengali"),
|
||||
"bh": _(u"Bihari"),
|
||||
"bg": _(u"Bulgarian"),
|
||||
"my": _(u"Burmese"),
|
||||
"ca": _(u"Catalan"),
|
||||
"chr": _(u"Cherokee"),
|
||||
"zh": _(u"Chinese"),
|
||||
"zh-CN": _(u"Chinese_simplified"),
|
||||
"zh-TW": _(u"Chinese_traditional"),
|
||||
"hr": _(u"Croatian"),
|
||||
"cs": _(u"Czech"),
|
||||
"da": _(u"Danish"),
|
||||
"dv": _(u"Dhivehi"),
|
||||
"nl": _(u"Dutch"),
|
||||
"en": _(u"English"),
|
||||
"eo": _(u"Esperanto"),
|
||||
"et": _(u"Estonian"),
|
||||
"tl": _(u"Filipino"),
|
||||
"fi": _(u"Finnish"),
|
||||
"fr": _(u"French"),
|
||||
"gl": _(u"Galician"),
|
||||
"ka": _(u"Georgian"),
|
||||
"de": _(u"German"),
|
||||
"el": _(u"Greek"),
|
||||
"gn": _(u"Guarani"),
|
||||
"gu": _(u"Gujarati"),
|
||||
"iw": _(u"Hebrew"),
|
||||
"hi": _(u"Hindi"),
|
||||
"hu": _(u"Hungarian"),
|
||||
"is": _(u"Icelandic"),
|
||||
"id": _(u"Indonesian"),
|
||||
"iu": _(u"Inuktitut"),
|
||||
"ga": _(u"Irish"),
|
||||
"it": _(u"Italian"),
|
||||
"ja": _(u"Japanese"),
|
||||
"kn": _(u"Kannada"),
|
||||
"kk": _(u"Kazakh"),
|
||||
"km": _(u"Khmer"),
|
||||
"ko": _(u"Korean"),
|
||||
"ku": _(u"Kurdish"),
|
||||
"ky": _(u"Kyrgyz"),
|
||||
"lo": _(u"Laothian"),
|
||||
"lv": _(u"Latvian"),
|
||||
"lt": _(u"Lithuanian"),
|
||||
"mk": _(u"Macedonian"),
|
||||
"ms": _(u"Malay"),
|
||||
"ml": _(u"Malayalam"),
|
||||
"mt": _(u"Maltese"),
|
||||
"mr": _(u"Marathi"),
|
||||
"mn": _(u"Mongolian"),
|
||||
"ne": _(u"Nepali"),
|
||||
"no": _(u"Norwegian"),
|
||||
"or": _(u"Oriya"),
|
||||
"ps": _(u"Pashto"),
|
||||
"fa": _(u"Persian"),
|
||||
"pl": _(u"Polish"),
|
||||
"pt": _(u"Portuguese"),
|
||||
"pa": _(u"Punjabi"),
|
||||
"ro": _(u"Romanian"),
|
||||
"ru": _(u"Russian"),
|
||||
"sa": _(u"Sanskrit"),
|
||||
"sr": _(u"Serbian"),
|
||||
"sd": _(u"Sindhi"),
|
||||
"si": _(u"Sinhalese"),
|
||||
"sk": _(u"Slovak"),
|
||||
"sl": _(u"Slovenian"),
|
||||
"es": _(u"Spanish"),
|
||||
"sw": _(u"Swahili"),
|
||||
"sv": _(u"Swedish"),
|
||||
"tg": _(u"Tajik"),
|
||||
"ta": _(u"Tamil"),
|
||||
"tl": _(u"Tagalog"),
|
||||
"te": _(u"Telugu"),
|
||||
"th": _(u"Thai"),
|
||||
"bo": _(u"Tibetan"),
|
||||
"tr": _(u"Turkish"),
|
||||
"uk": _(u"Ukrainian"),
|
||||
"ur": _(u"Urdu"),
|
||||
"uz": _(u"Uzbek"),
|
||||
"ug": _(u"Uighur"),
|
||||
"vi": _(u"Vietnamese"),
|
||||
"cy": _(u"Welsh"),
|
||||
"yi": _(u"Yiddish")
|
||||
}
|
||||
|
||||
def available_languages():
|
||||
return dict(sorted(languages.items(), key=lambda x: x[1]))
|
||||
return dict(sorted(languages.items(), key=lambda x: x[1]))
|
||||
|
@ -21,25 +21,25 @@ import wx
|
||||
from wxUI.dialogs import baseDialog
|
||||
|
||||
class translateDialog(baseDialog.BaseWXDialog):
|
||||
def __init__(self):
|
||||
languages = []
|
||||
language_dict = translator.available_languages()
|
||||
for k in language_dict:
|
||||
languages.append(language_dict[k])
|
||||
super(translateDialog, self).__init__(None, -1, title=_(u"Translate message"))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
staticDest = wx.StaticText(panel, -1, _(u"Target language"))
|
||||
self.dest_lang = wx.ComboBox(panel, -1, choices=languages, style = wx.CB_READONLY)
|
||||
self.dest_lang.SetFocus()
|
||||
self.dest_lang.SetSelection(0)
|
||||
listSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
listSizer.Add(staticDest)
|
||||
listSizer.Add(self.dest_lang)
|
||||
ok = wx.Button(panel, wx.ID_OK)
|
||||
ok.SetDefault()
|
||||
cancel = wx.Button(panel, wx.ID_CANCEL)
|
||||
self.SetEscapeId(wx.ID_CANCEL)
|
||||
def __init__(self):
|
||||
languages = []
|
||||
language_dict = translator.available_languages()
|
||||
for k in language_dict:
|
||||
languages.append(language_dict[k])
|
||||
super(translateDialog, self).__init__(None, -1, title=_(u"Translate message"))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
staticDest = wx.StaticText(panel, -1, _(u"Target language"))
|
||||
self.dest_lang = wx.ComboBox(panel, -1, choices=languages, style = wx.CB_READONLY)
|
||||
self.dest_lang.SetFocus()
|
||||
self.dest_lang.SetSelection(0)
|
||||
listSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
listSizer.Add(staticDest)
|
||||
listSizer.Add(self.dest_lang)
|
||||
ok = wx.Button(panel, wx.ID_OK)
|
||||
ok.SetDefault()
|
||||
cancel = wx.Button(panel, wx.ID_CANCEL)
|
||||
self.SetEscapeId(wx.ID_CANCEL)
|
||||
|
||||
def get(self, control):
|
||||
return getattr(self, control).GetSelection()
|
||||
def get(self, control):
|
||||
return getattr(self, control).GetSelection()
|
||||
|
@ -9,11 +9,11 @@ from . import fix_urllib3_warnings # Avoiding some SSL warnings related to Twyth
|
||||
from . import fix_win32com
|
||||
#from . import fix_requests #fix cacert.pem location for TWBlue binary copies
|
||||
def setup():
|
||||
fix_arrow.fix()
|
||||
if hasattr(sys, "frozen"):
|
||||
fix_libloader.fix()
|
||||
fix_win32com.fix()
|
||||
fix_arrow.fix()
|
||||
if hasattr(sys, "frozen"):
|
||||
fix_libloader.fix()
|
||||
fix_win32com.fix()
|
||||
# fix_requests.fix()
|
||||
# else:
|
||||
# fix_requests.fix(False)
|
||||
fix_urllib3_warnings.fix()
|
||||
fix_urllib3_warnings.fix()
|
||||
|
@ -16,27 +16,27 @@ log = logging.getLogger("fixes.fix_libloader")
|
||||
fixed=False
|
||||
|
||||
def patched_getmodule(modname):
|
||||
mod=__import__(modname)
|
||||
return sys.modules[modname]
|
||||
mod=__import__(modname)
|
||||
return sys.modules[modname]
|
||||
|
||||
def load_com(*names):
|
||||
global fixed
|
||||
if fixed==False:
|
||||
gencache._GetModule=patched_getmodule
|
||||
com.prepare_gencache()
|
||||
fixed=True
|
||||
result = None
|
||||
for name in names:
|
||||
try:
|
||||
result = gencache.EnsureDispatch(name)
|
||||
break
|
||||
except com_error:
|
||||
continue
|
||||
if result is None:
|
||||
raise com_error("Unable to load any of the provided com objects.")
|
||||
return result
|
||||
global fixed
|
||||
if fixed==False:
|
||||
gencache._GetModule=patched_getmodule
|
||||
com.prepare_gencache()
|
||||
fixed=True
|
||||
result = None
|
||||
for name in names:
|
||||
try:
|
||||
result = gencache.EnsureDispatch(name)
|
||||
break
|
||||
except com_error:
|
||||
continue
|
||||
if result is None:
|
||||
raise com_error("Unable to load any of the provided com objects.")
|
||||
return result
|
||||
|
||||
def fix():
|
||||
log.debug("Applying fix for Libloader...")
|
||||
com.load_com = load_com
|
||||
log.debug("Load_com has been mapped correctly.")
|
||||
log.debug("Applying fix for Libloader...")
|
||||
com.load_com = load_com
|
||||
log.debug("Load_com has been mapped correctly.")
|
||||
|
@ -7,6 +7,6 @@ import logging
|
||||
log = logging.getLogger("fixes.fix_requests")
|
||||
|
||||
def fix():
|
||||
log.debug("Applying fix for requests...")
|
||||
os.environ["REQUESTS_CA_BUNDLE"] = os.path.join(paths.app_path(), "certifi", "cacert.pem")#.encode(paths.fsencoding)
|
||||
log.debug("Applying fix for requests...")
|
||||
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)))
|
@ -8,8 +8,8 @@ import six
|
||||
import urllib.request, urllib.parse, urllib.error
|
||||
|
||||
def fix():
|
||||
urllib3.disable_warnings()
|
||||
fields.format_header_param=patched_format_header_param
|
||||
urllib3.disable_warnings()
|
||||
fields.format_header_param=patched_format_header_param
|
||||
|
||||
def patched_format_header_param(name, value):
|
||||
if not any(ch in value for ch in '"\\\r\n'):
|
||||
|
@ -1,6 +1,6 @@
|
||||
from __future__ import unicode_literals
|
||||
import win32com.client
|
||||
def fix():
|
||||
if win32com.client.gencache.is_readonly == True:
|
||||
win32com.client.gencache.is_readonly = False
|
||||
win32com.client.gencache.Rebuild()
|
||||
if win32com.client.gencache.is_readonly == True:
|
||||
win32com.client.gencache.is_readonly = False
|
||||
win32com.client.gencache.Rebuild()
|
||||
|
@ -27,40 +27,40 @@ from suds.client import Client
|
||||
import constants
|
||||
|
||||
class reportBug(object):
|
||||
def __init__(self, user_name):
|
||||
self.user_name = user_name
|
||||
self.categories = [_(u"General")]
|
||||
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.dialog = wx_ui.reportBugDialog(self.categories, self.reproducibilities, self.severities)
|
||||
widgetUtils.connect_event(self.dialog.ok, widgetUtils.BUTTON_PRESSED, self.send)
|
||||
self.dialog.get_response()
|
||||
def __init__(self, user_name):
|
||||
self.user_name = user_name
|
||||
self.categories = [_(u"General")]
|
||||
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.dialog = wx_ui.reportBugDialog(self.categories, self.reproducibilities, self.severities)
|
||||
widgetUtils.connect_event(self.dialog.ok, widgetUtils.BUTTON_PRESSED, self.send)
|
||||
self.dialog.get_response()
|
||||
|
||||
def send(self, *args, **kwargs):
|
||||
if self.dialog.get("summary") == "" or self.dialog.get("description") == "":
|
||||
self.dialog.no_filled()
|
||||
return
|
||||
if self.dialog.get("agree") == False:
|
||||
self.dialog.no_checkbox()
|
||||
return
|
||||
try:
|
||||
client = Client(application.report_bugs_url)
|
||||
issue = client.factory.create('IssueData')
|
||||
issue.project.name = application.name
|
||||
issue.project.id = 0
|
||||
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")
|
||||
# to do: Create getters for category, severity and reproducibility in wx_UI.
|
||||
issue.category = constants.categories[self.dialog.category.GetSelection()]
|
||||
issue.reproducibility.name = constants.reproducibilities[self.dialog.reproducibility.GetSelection()]
|
||||
issue.severity.name = constants.severities[self.dialog.severity.GetSelection()]
|
||||
issue.priority.name = "normal"
|
||||
issue.view_state.name = "public"
|
||||
issue.resolution.name = "open"
|
||||
issue.projection.name = "none"
|
||||
issue.eta.name = "eta"
|
||||
issue.status.name = "new"
|
||||
id = client.service.mc_issue_add(keys.keyring.get("bts_user"), keys.keyring.get("bts_password"), issue)
|
||||
self.dialog.success(id)
|
||||
except:
|
||||
self.dialog.error()
|
||||
def send(self, *args, **kwargs):
|
||||
if self.dialog.get("summary") == "" or self.dialog.get("description") == "":
|
||||
self.dialog.no_filled()
|
||||
return
|
||||
if self.dialog.get("agree") == False:
|
||||
self.dialog.no_checkbox()
|
||||
return
|
||||
try:
|
||||
client = Client(application.report_bugs_url)
|
||||
issue = client.factory.create('IssueData')
|
||||
issue.project.name = application.name
|
||||
issue.project.id = 0
|
||||
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")
|
||||
# to do: Create getters for category, severity and reproducibility in wx_UI.
|
||||
issue.category = constants.categories[self.dialog.category.GetSelection()]
|
||||
issue.reproducibility.name = constants.reproducibilities[self.dialog.reproducibility.GetSelection()]
|
||||
issue.severity.name = constants.severities[self.dialog.severity.GetSelection()]
|
||||
issue.priority.name = "normal"
|
||||
issue.view_state.name = "public"
|
||||
issue.resolution.name = "open"
|
||||
issue.projection.name = "none"
|
||||
issue.eta.name = "eta"
|
||||
issue.status.name = "new"
|
||||
id = client.service.mc_issue_add(keys.keyring.get("bts_user"), keys.keyring.get("bts_password"), issue)
|
||||
self.dialog.success(id)
|
||||
except:
|
||||
self.dialog.error()
|
||||
|
@ -21,75 +21,75 @@ import wx
|
||||
import widgetUtils
|
||||
import application
|
||||
class reportBugDialog(widgetUtils.BaseDialog):
|
||||
def __init__(self, categories, reproducibilities, severities):
|
||||
super(reportBugDialog, self).__init__(parent=None, id=wx.NewId())
|
||||
self.SetTitle(_(u"Report an error"))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
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.SetSelection(0)
|
||||
categoryB = wx.BoxSizer(wx.HORIZONTAL)
|
||||
categoryB.Add(categoryLabel, 0, wx.ALL, 5)
|
||||
categoryB.Add(self.category, 0, wx.ALL, 5)
|
||||
self.category.SetFocus()
|
||||
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)
|
||||
self.summary = wx.TextCtrl(panel, -1)
|
||||
dc = wx.WindowDC(self.summary)
|
||||
dc.SetFont(self.summary.GetFont())
|
||||
self.summary.SetSize(dc.GetTextExtent("a"*80))
|
||||
summaryB = wx.BoxSizer(wx.HORIZONTAL)
|
||||
summaryB.Add(summaryLabel, 0, wx.ALL, 5)
|
||||
summaryB.Add(self.summary, 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)
|
||||
self.description = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE)
|
||||
dc = wx.WindowDC(self.description)
|
||||
dc.SetFont(self.description.GetFont())
|
||||
(x, y, z) = dc.GetMultiLineTextExtent("0"*2000)
|
||||
self.description.SetSize((x, y))
|
||||
descBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
descBox.Add(descriptionLabel, 0, wx.ALL, 5)
|
||||
descBox.Add(self.description, 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)
|
||||
self.reproducibility = wx.ComboBox(panel, -1, choices=reproducibilities, style=wx.CB_READONLY)
|
||||
self.reproducibility.SetSelection(3)
|
||||
reprB = wx.BoxSizer(wx.HORIZONTAL)
|
||||
reprB.Add(reproducibilityLabel, 0, wx.ALL, 5)
|
||||
reprB.Add(self.reproducibility, 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"))
|
||||
self.severity = wx.ComboBox(panel, -1, choices=severities, style=wx.CB_READONLY)
|
||||
self.severity.SetSelection(3)
|
||||
severityB = wx.BoxSizer(wx.HORIZONTAL)
|
||||
severityB.Add(severityLabel, 0, wx.ALL, 5)
|
||||
severityB.Add(self.severity, 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.SetValue(False)
|
||||
sizer.Add(self.agree, 0, wx.ALL, 5)
|
||||
self.ok = wx.Button(panel, wx.ID_OK, _(u"Send report"))
|
||||
self.ok.SetDefault()
|
||||
cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Cancel"))
|
||||
btnBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
btnBox.Add(self.ok, 0, wx.ALL, 5)
|
||||
btnBox.Add(cancel, 0, wx.ALL, 5)
|
||||
sizer.Add(btnBox, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
self.SetClientSize(sizer.CalcMin())
|
||||
def __init__(self, categories, reproducibilities, severities):
|
||||
super(reportBugDialog, self).__init__(parent=None, id=wx.NewId())
|
||||
self.SetTitle(_(u"Report an error"))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
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.SetSelection(0)
|
||||
categoryB = wx.BoxSizer(wx.HORIZONTAL)
|
||||
categoryB.Add(categoryLabel, 0, wx.ALL, 5)
|
||||
categoryB.Add(self.category, 0, wx.ALL, 5)
|
||||
self.category.SetFocus()
|
||||
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)
|
||||
self.summary = wx.TextCtrl(panel, -1)
|
||||
dc = wx.WindowDC(self.summary)
|
||||
dc.SetFont(self.summary.GetFont())
|
||||
self.summary.SetSize(dc.GetTextExtent("a"*80))
|
||||
summaryB = wx.BoxSizer(wx.HORIZONTAL)
|
||||
summaryB.Add(summaryLabel, 0, wx.ALL, 5)
|
||||
summaryB.Add(self.summary, 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)
|
||||
self.description = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE)
|
||||
dc = wx.WindowDC(self.description)
|
||||
dc.SetFont(self.description.GetFont())
|
||||
(x, y, z) = dc.GetMultiLineTextExtent("0"*2000)
|
||||
self.description.SetSize((x, y))
|
||||
descBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
descBox.Add(descriptionLabel, 0, wx.ALL, 5)
|
||||
descBox.Add(self.description, 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)
|
||||
self.reproducibility = wx.ComboBox(panel, -1, choices=reproducibilities, style=wx.CB_READONLY)
|
||||
self.reproducibility.SetSelection(3)
|
||||
reprB = wx.BoxSizer(wx.HORIZONTAL)
|
||||
reprB.Add(reproducibilityLabel, 0, wx.ALL, 5)
|
||||
reprB.Add(self.reproducibility, 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"))
|
||||
self.severity = wx.ComboBox(panel, -1, choices=severities, style=wx.CB_READONLY)
|
||||
self.severity.SetSelection(3)
|
||||
severityB = wx.BoxSizer(wx.HORIZONTAL)
|
||||
severityB.Add(severityLabel, 0, wx.ALL, 5)
|
||||
severityB.Add(self.severity, 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.SetValue(False)
|
||||
sizer.Add(self.agree, 0, wx.ALL, 5)
|
||||
self.ok = wx.Button(panel, wx.ID_OK, _(u"Send report"))
|
||||
self.ok.SetDefault()
|
||||
cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Cancel"))
|
||||
btnBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
btnBox.Add(self.ok, 0, wx.ALL, 5)
|
||||
btnBox.Add(cancel, 0, wx.ALL, 5)
|
||||
sizer.Add(btnBox, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
self.SetClientSize(sizer.CalcMin())
|
||||
|
||||
def no_filled(self):
|
||||
wx.MessageDialog(self, _(u"You must fill out both fields"), _(u"Error"), wx.OK|wx.ICON_ERROR).ShowModal()
|
||||
def no_filled(self):
|
||||
wx.MessageDialog(self, _(u"You must fill out both fields"), _(u"Error"), wx.OK|wx.ICON_ERROR).ShowModal()
|
||||
|
||||
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()
|
||||
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()
|
||||
|
||||
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()
|
||||
self.EndModal(wx.ID_OK)
|
||||
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()
|
||||
self.EndModal(wx.ID_OK)
|
||||
|
||||
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()
|
||||
self.EndModal(wx.ID_CANCEL)
|
||||
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()
|
||||
self.EndModal(wx.ID_CANCEL)
|
||||
|
@ -1,8 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
import platform
|
||||
if platform.system() == 'Linux':
|
||||
from .linux import LinuxKeyboardHandler as GlobalKeyboardHandler
|
||||
from .linux import LinuxKeyboardHandler as GlobalKeyboardHandler
|
||||
else:
|
||||
from .wx_handler import WXKeyboardHandler as GlobalKeyboardHandler
|
||||
from .wx_handler import WXKeyboardHandler as GlobalKeyboardHandler
|
||||
#elif platform.system() == 'Darwin':
|
||||
#from osx import OSXKeyboardHandler as GlobalKeyboardHandler
|
||||
#from osx import OSXKeyboardHandler as GlobalKeyboardHandler
|
||||
|
@ -1,127 +1,127 @@
|
||||
keys = {
|
||||
'accept': 30,
|
||||
'add': 107,
|
||||
'apps': 93,
|
||||
'attn': 246,
|
||||
'back': 8,
|
||||
'browser_back': 166,
|
||||
'browser_forward': 167,
|
||||
'cancel': 3,
|
||||
'capital': 20,
|
||||
'clear': 12,
|
||||
'control': 17,
|
||||
'convert': 28,
|
||||
'crsel': 247,
|
||||
'decimal': 110,
|
||||
'delete': 46,
|
||||
'divide': 111,
|
||||
'down': 40,
|
||||
'end': 35,
|
||||
'ereof': 249,
|
||||
'escape': 27,
|
||||
'execute': 43,
|
||||
'exsel': 248,
|
||||
'f1': 112,
|
||||
'f10': 121,
|
||||
'f11': 122,
|
||||
'f12': 123,
|
||||
'f13': 124,
|
||||
'f14': 125,
|
||||
'f15': 126,
|
||||
'f16': 127,
|
||||
'f17': 128,
|
||||
'f18': 129,
|
||||
'f19': 130,
|
||||
'f2': 113,
|
||||
'f20': 131,
|
||||
'f21': 132,
|
||||
'f22': 133,
|
||||
'f23': 134,
|
||||
'f24': 135,
|
||||
'f3': 114,
|
||||
'f4': 115,
|
||||
'f5': 116,
|
||||
'f6': 117,
|
||||
'f7': 118,
|
||||
'f8': 119,
|
||||
'f9': 120,
|
||||
'final': 24,
|
||||
'hangeul': 21,
|
||||
'hangul': 21,
|
||||
'hanja': 25,
|
||||
'help': 47,
|
||||
'home': 36,
|
||||
'insert': 45,
|
||||
'junja': 23,
|
||||
'kana': 21,
|
||||
'kanji': 25,
|
||||
'lbutton': 1,
|
||||
'lcontrol': 162,
|
||||
'left': 37,
|
||||
'lmenu': 164,
|
||||
'lshift': 160,
|
||||
'lwin': 91,
|
||||
'mbutton': 4,
|
||||
'media_next_track': 176,
|
||||
'media_play_pause': 179,
|
||||
'media_prev_track': 177,
|
||||
'menu': 18,
|
||||
'modechange': 31,
|
||||
'multiply': 106,
|
||||
'next': 34,
|
||||
'noname': 252,
|
||||
'nonconvert': 29,
|
||||
'numlock': 144,
|
||||
'numpad0': 96,
|
||||
'numpad1': 97,
|
||||
'numpad2': 98,
|
||||
'numpad3': 99,
|
||||
'numpad4': 100,
|
||||
'numpad5': 101,
|
||||
'numpad6': 102,
|
||||
'numpad7': 103,
|
||||
'numpad8': 104,
|
||||
'numpad9': 105,
|
||||
'oem_clear': 254,
|
||||
'pa1': 253,
|
||||
'pagedown': 34,
|
||||
'pageup': 33,
|
||||
'pause': 19,
|
||||
'play': 250,
|
||||
'print': 42,
|
||||
'prior': 33,
|
||||
'processkey': 229,
|
||||
'rbutton': 2,
|
||||
'rcontrol': 163,
|
||||
'return': 13,
|
||||
'right': 39,
|
||||
'rmenu': 165,
|
||||
'rshift': 161,
|
||||
'rwin': 92,
|
||||
'scroll': 145,
|
||||
'select': 41,
|
||||
'separator': 108,
|
||||
'shift': 16,
|
||||
'snapshot': 44,
|
||||
'space': 32,
|
||||
'subtract': 109,
|
||||
'tab': 9,
|
||||
'up': 38,
|
||||
'volume_down': 174,
|
||||
'volume_mute': 173,
|
||||
'volume_up': 175,
|
||||
'xbutton1': 5,
|
||||
'xbutton2': 6,
|
||||
'zoom': 251,
|
||||
'/': 191,
|
||||
';': 218,
|
||||
'[': 219,
|
||||
'\\': 220,
|
||||
']': 221,
|
||||
'\'': 222,
|
||||
'=': 187,
|
||||
'-': 189,
|
||||
';': 186,
|
||||
'accept': 30,
|
||||
'add': 107,
|
||||
'apps': 93,
|
||||
'attn': 246,
|
||||
'back': 8,
|
||||
'browser_back': 166,
|
||||
'browser_forward': 167,
|
||||
'cancel': 3,
|
||||
'capital': 20,
|
||||
'clear': 12,
|
||||
'control': 17,
|
||||
'convert': 28,
|
||||
'crsel': 247,
|
||||
'decimal': 110,
|
||||
'delete': 46,
|
||||
'divide': 111,
|
||||
'down': 40,
|
||||
'end': 35,
|
||||
'ereof': 249,
|
||||
'escape': 27,
|
||||
'execute': 43,
|
||||
'exsel': 248,
|
||||
'f1': 112,
|
||||
'f10': 121,
|
||||
'f11': 122,
|
||||
'f12': 123,
|
||||
'f13': 124,
|
||||
'f14': 125,
|
||||
'f15': 126,
|
||||
'f16': 127,
|
||||
'f17': 128,
|
||||
'f18': 129,
|
||||
'f19': 130,
|
||||
'f2': 113,
|
||||
'f20': 131,
|
||||
'f21': 132,
|
||||
'f22': 133,
|
||||
'f23': 134,
|
||||
'f24': 135,
|
||||
'f3': 114,
|
||||
'f4': 115,
|
||||
'f5': 116,
|
||||
'f6': 117,
|
||||
'f7': 118,
|
||||
'f8': 119,
|
||||
'f9': 120,
|
||||
'final': 24,
|
||||
'hangeul': 21,
|
||||
'hangul': 21,
|
||||
'hanja': 25,
|
||||
'help': 47,
|
||||
'home': 36,
|
||||
'insert': 45,
|
||||
'junja': 23,
|
||||
'kana': 21,
|
||||
'kanji': 25,
|
||||
'lbutton': 1,
|
||||
'lcontrol': 162,
|
||||
'left': 37,
|
||||
'lmenu': 164,
|
||||
'lshift': 160,
|
||||
'lwin': 91,
|
||||
'mbutton': 4,
|
||||
'media_next_track': 176,
|
||||
'media_play_pause': 179,
|
||||
'media_prev_track': 177,
|
||||
'menu': 18,
|
||||
'modechange': 31,
|
||||
'multiply': 106,
|
||||
'next': 34,
|
||||
'noname': 252,
|
||||
'nonconvert': 29,
|
||||
'numlock': 144,
|
||||
'numpad0': 96,
|
||||
'numpad1': 97,
|
||||
'numpad2': 98,
|
||||
'numpad3': 99,
|
||||
'numpad4': 100,
|
||||
'numpad5': 101,
|
||||
'numpad6': 102,
|
||||
'numpad7': 103,
|
||||
'numpad8': 104,
|
||||
'numpad9': 105,
|
||||
'oem_clear': 254,
|
||||
'pa1': 253,
|
||||
'pagedown': 34,
|
||||
'pageup': 33,
|
||||
'pause': 19,
|
||||
'play': 250,
|
||||
'print': 42,
|
||||
'prior': 33,
|
||||
'processkey': 229,
|
||||
'rbutton': 2,
|
||||
'rcontrol': 163,
|
||||
'return': 13,
|
||||
'right': 39,
|
||||
'rmenu': 165,
|
||||
'rshift': 161,
|
||||
'rwin': 92,
|
||||
'scroll': 145,
|
||||
'select': 41,
|
||||
'separator': 108,
|
||||
'shift': 16,
|
||||
'snapshot': 44,
|
||||
'space': 32,
|
||||
'subtract': 109,
|
||||
'tab': 9,
|
||||
'up': 38,
|
||||
'volume_down': 174,
|
||||
'volume_mute': 173,
|
||||
'volume_up': 175,
|
||||
'xbutton1': 5,
|
||||
'xbutton2': 6,
|
||||
'zoom': 251,
|
||||
'/': 191,
|
||||
';': 218,
|
||||
'[': 219,
|
||||
'\\': 220,
|
||||
']': 221,
|
||||
'\'': 222,
|
||||
'=': 187,
|
||||
'-': 189,
|
||||
';': 186,
|
||||
}
|
||||
|
||||
modifiers = {'alt': 1, 'control': 2, 'shift': 4, 'win': 8}
|
||||
|
@ -3,56 +3,56 @@ import threading
|
||||
import thread
|
||||
import pyatspi
|
||||
def parse(s):
|
||||
"""parse a string like control+f into (modifier, key).
|
||||
Unknown modifiers will return ValueError."""
|
||||
m = 0
|
||||
lst = s.split('+')
|
||||
if not len(lst): return (0, s)
|
||||
"""parse a string like control+f into (modifier, key).
|
||||
Unknown modifiers will return ValueError."""
|
||||
m = 0
|
||||
lst = s.split('+')
|
||||
if not len(lst): return (0, s)
|
||||
#Are these right?
|
||||
d = {
|
||||
"shift": 1<<pyatspi.MODIFIER_SHIFT,
|
||||
"control": 1<<pyatspi.MODIFIER_CONTROL,
|
||||
"alt": 1<<pyatspi.MODIFIER_ALT,
|
||||
"win":1<<pyatspi.MODIFIER_META3,
|
||||
}
|
||||
for item in lst:
|
||||
if item in d:
|
||||
m|=d[item]
|
||||
lst.remove(item)
|
||||
d = {
|
||||
"shift": 1<<pyatspi.MODIFIER_SHIFT,
|
||||
"control": 1<<pyatspi.MODIFIER_CONTROL,
|
||||
"alt": 1<<pyatspi.MODIFIER_ALT,
|
||||
"win":1<<pyatspi.MODIFIER_META3,
|
||||
}
|
||||
for item in lst:
|
||||
if item in d:
|
||||
m|=d[item]
|
||||
lst.remove(item)
|
||||
#end if
|
||||
if len(lst) > 1: #more than one key, parse error
|
||||
raise ValueError, 'unknown modifier %s' % lst[0]
|
||||
return (m, lst[0].lower())
|
||||
if len(lst) > 1: #more than one key, parse error
|
||||
raise ValueError, 'unknown modifier %s' % lst[0]
|
||||
return (m, lst[0].lower())
|
||||
class AtspiThread(threading.Thread):
|
||||
def run(self):
|
||||
pyatspi.Registry.registerKeystrokeListener(handler, kind=(pyatspi.KEY_PRESSED_EVENT,),
|
||||
mask=pyatspi.allModifiers())
|
||||
pyatspi.Registry.start()
|
||||
def run(self):
|
||||
pyatspi.Registry.registerKeystrokeListener(handler, kind=(pyatspi.KEY_PRESSED_EVENT,),
|
||||
mask=pyatspi.allModifiers())
|
||||
pyatspi.Registry.start()
|
||||
#the keys we registered
|
||||
keys = {}
|
||||
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.
|
||||
if (not e.is_text) and e.id >= 97 <= 126:
|
||||
k = chr(e.id)
|
||||
if (m,k) not in keys: return False
|
||||
thread.start_new(keys[(m,k)], ())
|
||||
return True #don't pass it on
|
||||
if (not e.is_text) and e.id >= 97 <= 126:
|
||||
k = chr(e.id)
|
||||
if (m,k) not in keys: return False
|
||||
thread.start_new(keys[(m,k)], ())
|
||||
return True #don't pass it on
|
||||
class LinuxKeyboardHandler(KeyboardHandler):
|
||||
def __init__(self, *args, **kwargs):
|
||||
KeyboardHandler.__init__(self, *args, **kwargs)
|
||||
t = AtspiThread()
|
||||
t.start()
|
||||
def register_key(self, key, function):
|
||||
"""key will be a string, such as control+shift+f.
|
||||
We need to convert that, using parse_key,
|
||||
into modifier and key to put into our dictionary."""
|
||||
def __init__(self, *args, **kwargs):
|
||||
KeyboardHandler.__init__(self, *args, **kwargs)
|
||||
t = AtspiThread()
|
||||
t.start()
|
||||
def register_key(self, key, function):
|
||||
"""key will be a string, such as control+shift+f.
|
||||
We need to convert that, using parse_key,
|
||||
into modifier and key to put into our dictionary."""
|
||||
#register key so we know if we have it on event receive.
|
||||
t = parse(key)
|
||||
keys[t] = function
|
||||
t = parse(key)
|
||||
keys[t] = function
|
||||
#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):
|
||||
KeyboardHandler.unregister_key(self, key, function)
|
||||
del keys[parse(key)]
|
||||
def unregister_key (self, key, function):
|
||||
KeyboardHandler.unregister_key(self, key, function)
|
||||
del keys[parse(key)]
|
||||
|
@ -5,84 +5,84 @@ class KeyboardHandlerError (Exception): pass
|
||||
|
||||
class KeyboardHandler(object):
|
||||
|
||||
def __init__(self, repeat_rate=0.0, *args, **kwargs):
|
||||
self.repeat_rate = repeat_rate #How long between accepting the same keystroke?
|
||||
self._last_key = None
|
||||
self._last_keypress_time = 0
|
||||
super(KeyboardHandler, self).__init__(*args, **kwargs)
|
||||
self.active_keys = {}
|
||||
if not hasattr(self, 'replacement_mods'):
|
||||
self.replacement_mods = {}
|
||||
if not hasattr(self, 'replacement_keys'):
|
||||
self.replacement_keys = {}
|
||||
def __init__(self, repeat_rate=0.0, *args, **kwargs):
|
||||
self.repeat_rate = repeat_rate #How long between accepting the same keystroke?
|
||||
self._last_key = None
|
||||
self._last_keypress_time = 0
|
||||
super(KeyboardHandler, self).__init__(*args, **kwargs)
|
||||
self.active_keys = {}
|
||||
if not hasattr(self, 'replacement_mods'):
|
||||
self.replacement_mods = {}
|
||||
if not hasattr(self, 'replacement_keys'):
|
||||
self.replacement_keys = {}
|
||||
|
||||
def register_key (self, key, function):
|
||||
if key in self.active_keys:
|
||||
raise KeyboardHandlerError("Key %s is already registered to a function" % key)
|
||||
if not callable(function):
|
||||
raise TypeError("Must provide a callable to be invoked upon keypress")
|
||||
self.active_keys[key] = function
|
||||
def register_key (self, key, function):
|
||||
if key in self.active_keys:
|
||||
raise KeyboardHandlerError("Key %s is already registered to a function" % key)
|
||||
if not callable(function):
|
||||
raise TypeError("Must provide a callable to be invoked upon keypress")
|
||||
self.active_keys[key] = function
|
||||
|
||||
def unregister_key (self, key, function):
|
||||
try:
|
||||
if self.active_keys[key] != function:
|
||||
raise KeyboardHandlerError("key %s is not registered to that function" % key)
|
||||
except KeyError:
|
||||
raise KeyboardHandlerError("Key %s not currently registered" % key)
|
||||
del(self.active_keys[key])
|
||||
def unregister_key (self, key, function):
|
||||
try:
|
||||
if self.active_keys[key] != function:
|
||||
raise KeyboardHandlerError("key %s is not registered to that function" % key)
|
||||
except KeyError:
|
||||
raise KeyboardHandlerError("Key %s not currently registered" % key)
|
||||
del(self.active_keys[key])
|
||||
|
||||
def unregister_all_keys(self):
|
||||
for key in list(self.active_keys):
|
||||
self.unregister_key(key, self.active_keys[key])
|
||||
def unregister_all_keys(self):
|
||||
for key in list(self.active_keys):
|
||||
self.unregister_key(key, self.active_keys[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:
|
||||
return
|
||||
try:
|
||||
function = self.active_keys[key]
|
||||
except KeyError:
|
||||
return
|
||||
self._last_key = key
|
||||
self._last_keypress_time = time.time()
|
||||
return function()
|
||||
def handle_key (self, key):
|
||||
if self.repeat_rate and key == self._last_key and time.time() - self._last_keypress_time < self.repeat_rate:
|
||||
return
|
||||
try:
|
||||
function = self.active_keys[key]
|
||||
except KeyError:
|
||||
return
|
||||
self._last_key = key
|
||||
self._last_keypress_time = time.time()
|
||||
return function()
|
||||
|
||||
def register_keys(self, keys):
|
||||
"""Given a mapping of keystrokes to functions, registers all keystrokes"""
|
||||
for k in keys:
|
||||
self.register_key(k, keys[k])
|
||||
def register_keys(self, keys):
|
||||
"""Given a mapping of keystrokes to functions, registers all keystrokes"""
|
||||
for k in keys:
|
||||
self.register_key(k, keys[k])
|
||||
|
||||
def unregister_keys(self, keys):
|
||||
"""Given a mapping of keys to their functions, unregisters all provided keys."""
|
||||
for k in keys:
|
||||
self.unregister_key(k, keys[k])
|
||||
def unregister_keys(self, keys):
|
||||
"""Given a mapping of keys to their functions, unregisters all provided keys."""
|
||||
for k in keys:
|
||||
self.unregister_key(k, keys[k])
|
||||
|
||||
def standardize_key(self, key):
|
||||
"""Takes a keystroke and places it in a standard case and order in a list."""
|
||||
working = key.split('+')
|
||||
working = [i.lower() for i in working]
|
||||
answer = []
|
||||
if "control" in working:
|
||||
answer.append("control")
|
||||
if "win" in working:
|
||||
answer.append("win")
|
||||
if "alt" in working:
|
||||
answer.append("alt")
|
||||
if "shift" in working:
|
||||
answer.append("shift")
|
||||
if working[-1] not in answer:
|
||||
answer.append(working[-1])
|
||||
return answer
|
||||
def standardize_key(self, key):
|
||||
"""Takes a keystroke and places it in a standard case and order in a list."""
|
||||
working = key.split('+')
|
||||
working = [i.lower() for i in working]
|
||||
answer = []
|
||||
if "control" in working:
|
||||
answer.append("control")
|
||||
if "win" in working:
|
||||
answer.append("win")
|
||||
if "alt" in working:
|
||||
answer.append("alt")
|
||||
if "shift" in working:
|
||||
answer.append("shift")
|
||||
if working[-1] not in answer:
|
||||
answer.append(working[-1])
|
||||
return answer
|
||||
|
||||
def standardize_keymap(self, keymap):
|
||||
"""Given a keymap, returns the keymap standardized."""
|
||||
full = {}
|
||||
for i in keymap:
|
||||
answer = ""
|
||||
new = self.standardize_key(keymap[i])
|
||||
for (c, j) in enumerate(new):
|
||||
if c < len(new)-1:
|
||||
answer = "%s%s+" % (answer, j)
|
||||
else:
|
||||
answer = "%s%s" % (answer, j)
|
||||
full[i] = answer
|
||||
return full
|
||||
def standardize_keymap(self, keymap):
|
||||
"""Given a keymap, returns the keymap standardized."""
|
||||
full = {}
|
||||
for i in keymap:
|
||||
answer = ""
|
||||
new = self.standardize_key(keymap[i])
|
||||
for (c, j) in enumerate(new):
|
||||
if c < len(new)-1:
|
||||
answer = "%s%s+" % (answer, j)
|
||||
else:
|
||||
answer = "%s%s" % (answer, j)
|
||||
full[i] = answer
|
||||
return full
|
||||
|
@ -12,45 +12,45 @@ kEventHotKeyReleasedSubtype = 9
|
||||
|
||||
class OSXKeyboardHandler(KeyboardHandler):
|
||||
|
||||
def __init__(self):
|
||||
super(OSXKeyboardHandler, self).__init__()
|
||||
self.replacement_keys = dict()
|
||||
self.app = KeyboardCapturingNSApplication.alloc().init()
|
||||
self._event_thread = Thread(target=AppHelper.runEventLoop)
|
||||
self._event_thread.start()
|
||||
def __init__(self):
|
||||
super(OSXKeyboardHandler, self).__init__()
|
||||
self.replacement_keys = dict()
|
||||
self.app = KeyboardCapturingNSApplication.alloc().init()
|
||||
self._event_thread = Thread(target=AppHelper.runEventLoop)
|
||||
self._event_thread.start()
|
||||
|
||||
def register_key (self, key, function):
|
||||
super(OSXKeyboardHandler, self).register_key(key, function)
|
||||
k, m = self.parse_key(key)
|
||||
key_id = RegisterEventHotKey(k, m, (0, 0), GetApplicationEventTarget(), 0)
|
||||
self.key_ids[key] = key_id
|
||||
def register_key (self, key, function):
|
||||
super(OSXKeyboardHandler, self).register_key(key, function)
|
||||
k, m = self.parse_key(key)
|
||||
key_id = RegisterEventHotKey(k, m, (0, 0), GetApplicationEventTarget(), 0)
|
||||
self.key_ids[key] = key_id
|
||||
|
||||
def unregister_key (self, key, function):
|
||||
super(OSXKeyboardHandler, self).unregister_key(key, function)
|
||||
key_id = self.key_ids[key]
|
||||
raise NotImplementedError
|
||||
def unregister_key (self, key, function):
|
||||
super(OSXKeyboardHandler, self).unregister_key(key, function)
|
||||
key_id = self.key_ids[key]
|
||||
raise NotImplementedError
|
||||
|
||||
def parse_key (self, key):
|
||||
key=key.split("+")
|
||||
#replacements
|
||||
#Modifier keys:
|
||||
for index, item in enumerate(key[0:-1]):
|
||||
if self.replacement_mods.has_key(item):
|
||||
key[index] = self.replacement_mods[item]
|
||||
if self.replacement_keys.has_key(key[-1]):
|
||||
key[-1] = self.replacement_keys[key[-1]]
|
||||
elif len(key[-1])==1:
|
||||
key[-1] = ord(str(key[-1]))-36
|
||||
mods = 0
|
||||
for i in key[:-1]:
|
||||
mods = mods|i
|
||||
return [key[-1], mods]
|
||||
def parse_key (self, key):
|
||||
key=key.split("+")
|
||||
#replacements
|
||||
#Modifier keys:
|
||||
for index, item in enumerate(key[0:-1]):
|
||||
if self.replacement_mods.has_key(item):
|
||||
key[index] = self.replacement_mods[item]
|
||||
if self.replacement_keys.has_key(key[-1]):
|
||||
key[-1] = self.replacement_keys[key[-1]]
|
||||
elif len(key[-1])==1:
|
||||
key[-1] = ord(str(key[-1]))-36
|
||||
mods = 0
|
||||
for i in key[:-1]:
|
||||
mods = mods|i
|
||||
return [key[-1], mods]
|
||||
|
||||
class KeyboardCapturingNSApplication(NSApplication):
|
||||
|
||||
def sendEvent_(self, theEvent):
|
||||
if theEvent.type() == NSSystemDefined and theEvent.subtype() == kEventHotKeyPressedSubtype:
|
||||
self.activateIgnoringOtherApps_(True)
|
||||
NSRunAlertPanel(u'Hot Key Pressed', u'Hot Key Pressed', None, None, None)
|
||||
super(NSApplication, self).sendEvent_(theEvent)
|
||||
def sendEvent_(self, theEvent):
|
||||
if theEvent.type() == NSSystemDefined and theEvent.subtype() == kEventHotKeyPressedSubtype:
|
||||
self.activateIgnoringOtherApps_(True)
|
||||
NSRunAlertPanel(u'Hot Key Pressed', u'Hot Key Pressed', None, None, None)
|
||||
super(NSApplication, self).sendEvent_(theEvent)
|
||||
|
||||
|
@ -5,36 +5,36 @@ from main import KeyboardHandler
|
||||
|
||||
class WindowsKeyboardHandler(KeyboardHandler):
|
||||
|
||||
def __init__ (self, *args, **kwargs):
|
||||
super(WindowsKeyboardHandler, self).__init__(*args, **kwargs)
|
||||
#Setup the replacement dictionaries.
|
||||
for i in dir(win32con):
|
||||
if i.startswith("VK_"):
|
||||
key = i[3:].lower()
|
||||
self.replacement_keys[key] = getattr(win32con, i)
|
||||
elif i.startswith("MOD_"):
|
||||
key = i[4:].lower()
|
||||
self.replacement_mods[key] = getattr(win32con, i)
|
||||
self.replacement_keys .update(dict(pageup=win32con.VK_PRIOR, pagedown=win32con.VK_NEXT))
|
||||
def __init__ (self, *args, **kwargs):
|
||||
super(WindowsKeyboardHandler, self).__init__(*args, **kwargs)
|
||||
#Setup the replacement dictionaries.
|
||||
for i in dir(win32con):
|
||||
if i.startswith("VK_"):
|
||||
key = i[3:].lower()
|
||||
self.replacement_keys[key] = getattr(win32con, i)
|
||||
elif i.startswith("MOD_"):
|
||||
key = i[4:].lower()
|
||||
self.replacement_mods[key] = getattr(win32con, i)
|
||||
self.replacement_keys .update(dict(pageup=win32con.VK_PRIOR, pagedown=win32con.VK_NEXT))
|
||||
|
||||
def parse_key (self, keystroke, separator="+"):
|
||||
keystroke = str(keystroke) #We don't want unicode
|
||||
keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)]
|
||||
mods = 0
|
||||
for i in keystroke[:-1]:
|
||||
mods = mods | i #or everything together
|
||||
return (mods, keystroke[-1])
|
||||
def parse_key (self, keystroke, separator="+"):
|
||||
keystroke = str(keystroke) #We don't want unicode
|
||||
keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)]
|
||||
mods = 0
|
||||
for i in keystroke[:-1]:
|
||||
mods = mods | i #or everything together
|
||||
return (mods, keystroke[-1])
|
||||
|
||||
def keycode_from_key(self, key):
|
||||
if key in self.replacement_mods:
|
||||
return self.replacement_mods[key]
|
||||
if key in self.replacement_keys:
|
||||
return self.replacement_keys[key]
|
||||
if len(key) == 1:
|
||||
return win32api.VkKeyScanEx(key, win32api.GetKeyboardLayout())
|
||||
def keycode_from_key(self, key):
|
||||
if key in self.replacement_mods:
|
||||
return self.replacement_mods[key]
|
||||
if key in self.replacement_keys:
|
||||
return self.replacement_keys[key]
|
||||
if len(key) == 1:
|
||||
return win32api.VkKeyScanEx(key, win32api.GetKeyboardLayout())
|
||||
|
||||
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."""
|
||||
key = self.keycode_from_key(key)
|
||||
return win32api.GetAsyncKeyState(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."""
|
||||
key = self.keycode_from_key(key)
|
||||
return win32api.GetAsyncKeyState(key)
|
||||
|
||||
|
@ -10,121 +10,121 @@ from . import key_constants
|
||||
__all__ = ['WXKeyboardHandler', 'WXControlKeyboardHandler']
|
||||
|
||||
def call_after(func):
|
||||
def wrapper(*args, **kwargs):
|
||||
wx.CallAfter(func, *args, **kwargs)
|
||||
functools.update_wrapper(wrapper, func)
|
||||
return wrapper
|
||||
def wrapper(*args, **kwargs):
|
||||
wx.CallAfter(func, *args, **kwargs)
|
||||
functools.update_wrapper(wrapper, func)
|
||||
return wrapper
|
||||
|
||||
|
||||
class BaseWXKeyboardHandler(KeyboardHandler):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(BaseWXKeyboardHandler, self).__init__(*args, **kwargs)
|
||||
#Setup the replacement dictionaries.
|
||||
for i in dir(wx):
|
||||
if i.startswith('WXK_'):
|
||||
key = i[4:].lower()
|
||||
self.replacement_keys[key] = getattr(wx, i)
|
||||
elif i.startswith('MOD_'):
|
||||
key = i[4:].lower()
|
||||
self.replacement_mods[key] = getattr(wx, i)
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(BaseWXKeyboardHandler, self).__init__(*args, **kwargs)
|
||||
#Setup the replacement dictionaries.
|
||||
for i in dir(wx):
|
||||
if i.startswith('WXK_'):
|
||||
key = i[4:].lower()
|
||||
self.replacement_keys[key] = getattr(wx, i)
|
||||
elif i.startswith('MOD_'):
|
||||
key = i[4:].lower()
|
||||
self.replacement_mods[key] = getattr(wx, i)
|
||||
|
||||
def parse_key (self, keystroke, separator="+"):
|
||||
keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)]
|
||||
mods = 0
|
||||
for i in keystroke[:-1]:
|
||||
mods = mods | i #or everything together
|
||||
return (mods, keystroke[-1])
|
||||
def parse_key (self, keystroke, separator="+"):
|
||||
keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)]
|
||||
mods = 0
|
||||
for i in keystroke[:-1]:
|
||||
mods = mods | i #or everything together
|
||||
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):
|
||||
|
||||
def __init__ (self, parent, *args, **kwargs):
|
||||
super(WXKeyboardHandler, self).__init__(*args, **kwargs)
|
||||
self.parent = parent
|
||||
self.key_ids = {}
|
||||
self.replacement_keys = key_constants.keys
|
||||
self.replacement_mods = key_constants.modifiers
|
||||
def __init__ (self, parent, *args, **kwargs):
|
||||
super(WXKeyboardHandler, self).__init__(*args, **kwargs)
|
||||
self.parent = parent
|
||||
self.key_ids = {}
|
||||
self.replacement_keys = key_constants.keys
|
||||
self.replacement_mods = key_constants.modifiers
|
||||
|
||||
@call_after
|
||||
def register_key(self, key, function):
|
||||
super(WXKeyboardHandler, self).register_key(key, function)
|
||||
key_id = wx.NewId()
|
||||
parsed = self.parse_key(key)
|
||||
res = self.parent.RegisterHotKey(key_id, *parsed)
|
||||
if not res:
|
||||
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.key_ids[key] = key_id
|
||||
return res
|
||||
@call_after
|
||||
def register_key(self, key, function):
|
||||
super(WXKeyboardHandler, self).register_key(key, function)
|
||||
key_id = wx.NewId()
|
||||
parsed = self.parse_key(key)
|
||||
res = self.parent.RegisterHotKey(key_id, *parsed)
|
||||
if not res:
|
||||
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.key_ids[key] = key_id
|
||||
return res
|
||||
|
||||
def parse_key (self, keystroke, separator="+"):
|
||||
keystroke = str(keystroke) #We don't want unicode
|
||||
keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)]
|
||||
mods = 0
|
||||
for i in keystroke[:-1]:
|
||||
mods = mods | i #or everything together
|
||||
return (mods, keystroke[-1])
|
||||
def parse_key (self, keystroke, separator="+"):
|
||||
keystroke = str(keystroke) #We don't want unicode
|
||||
keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)]
|
||||
mods = 0
|
||||
for i in keystroke[:-1]:
|
||||
mods = mods | i #or everything together
|
||||
return (mods, keystroke[-1])
|
||||
|
||||
@call_after
|
||||
def unregister_key (self, key, function):
|
||||
super(WXKeyboardHandler, self).unregister_key(key, function)
|
||||
if key not in self.key_ids:
|
||||
return #there's nothing we can do.
|
||||
key_id = self.key_ids[key]
|
||||
self.parent.UnregisterHotKey(key_id)
|
||||
self.parent.Unbind( wx.EVT_HOTKEY, id=key_id)
|
||||
self.key_ids.pop(key)
|
||||
@call_after
|
||||
def unregister_key (self, key, function):
|
||||
super(WXKeyboardHandler, self).unregister_key(key, function)
|
||||
if key not in self.key_ids:
|
||||
return #there's nothing we can do.
|
||||
key_id = self.key_ids[key]
|
||||
self.parent.UnregisterHotKey(key_id)
|
||||
self.parent.Unbind( wx.EVT_HOTKEY, id=key_id)
|
||||
self.key_ids.pop(key)
|
||||
|
||||
def process_key (self, evt, id):
|
||||
evt.Skip()
|
||||
key_ids = self.key_ids.keys()
|
||||
for i in key_ids:
|
||||
if self.key_ids.get(i) == id:
|
||||
self.handle_key(i)
|
||||
def process_key (self, evt, id):
|
||||
evt.Skip()
|
||||
key_ids = self.key_ids.keys()
|
||||
for i in key_ids:
|
||||
if self.key_ids.get(i) == id:
|
||||
self.handle_key(i)
|
||||
|
||||
class WXControlKeyboardHandler(wx.StaticText, KeyboardHandler):
|
||||
|
||||
def __init__(self, parent=None, *a, **k):
|
||||
wx.StaticText.__init__(self, parent=parent)
|
||||
KeyboardHandler.__init__(self, *a, **k)
|
||||
self.wx_replacements = {}
|
||||
for i in [d for d in dir(wx) if d.startswith('WXK_')]:
|
||||
self.wx_replacements[getattr(wx, i)] = i[4:].lower()
|
||||
self.Bind(wx.EVT_KEY_DOWN, self.process_key, self)
|
||||
self.SetFocus()
|
||||
def __init__(self, parent=None, *a, **k):
|
||||
wx.StaticText.__init__(self, parent=parent)
|
||||
KeyboardHandler.__init__(self, *a, **k)
|
||||
self.wx_replacements = {}
|
||||
for i in [d for d in dir(wx) if d.startswith('WXK_')]:
|
||||
self.wx_replacements[getattr(wx, i)] = i[4:].lower()
|
||||
self.Bind(wx.EVT_KEY_DOWN, self.process_key, self)
|
||||
self.SetFocus()
|
||||
|
||||
def process_key(self, evt):
|
||||
keycode = evt.GetKeyCode()
|
||||
keyname = self.wx_replacements.get(keycode, None)
|
||||
modifiers = ""
|
||||
replacements = ( (evt.ControlDown(), 'control+'),
|
||||
(evt.AltDown(), 'alt+'),
|
||||
(evt.ShiftDown(), 'shift+'),
|
||||
(evt.MetaDown(), 'win+')
|
||||
)
|
||||
for mod, ch in (replacements):
|
||||
if mod:
|
||||
modifiers += ch
|
||||
if keyname is None:
|
||||
if 27 < keycode < 256:
|
||||
keyname = chr(keycode).lower()
|
||||
else:
|
||||
keyname = "(%s)unknown" % keycode
|
||||
key = modifiers + keyname
|
||||
self.handle_key(key)
|
||||
def process_key(self, evt):
|
||||
keycode = evt.GetKeyCode()
|
||||
keyname = self.wx_replacements.get(keycode, None)
|
||||
modifiers = ""
|
||||
replacements = ( (evt.ControlDown(), 'control+'),
|
||||
(evt.AltDown(), 'alt+'),
|
||||
(evt.ShiftDown(), 'shift+'),
|
||||
(evt.MetaDown(), 'win+')
|
||||
)
|
||||
for mod, ch in (replacements):
|
||||
if mod:
|
||||
modifiers += ch
|
||||
if keyname is None:
|
||||
if 27 < keycode < 256:
|
||||
keyname = chr(keycode).lower()
|
||||
else:
|
||||
keyname = "(%s)unknown" % keycode
|
||||
key = modifiers + keyname
|
||||
self.handle_key(key)
|
||||
|
@ -14,9 +14,9 @@ import paths
|
||||
# lib = load_library("snapshot_api_keys64", x64_path=paths.app_path("keys/lib"))
|
||||
#else:
|
||||
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:
|
||||
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
|
||||
# lib = linuxKeys
|
||||
@ -24,20 +24,20 @@ else:
|
||||
keyring = None
|
||||
|
||||
def setup():
|
||||
global keyring
|
||||
if keyring == None:
|
||||
keyring = Keyring()
|
||||
global keyring
|
||||
if keyring == None:
|
||||
keyring = Keyring()
|
||||
|
||||
class Keyring(object):
|
||||
def __init__(self):
|
||||
super(Keyring, self).__init__()
|
||||
def __init__(self):
|
||||
super(Keyring, self).__init__()
|
||||
|
||||
def _call_method(self, function):
|
||||
result = getattr(lib, function)
|
||||
result = c_char_p(result.__call__())
|
||||
return result.value
|
||||
def _call_method(self, function):
|
||||
result = getattr(lib, function)
|
||||
result = c_char_p(result.__call__())
|
||||
return result.value
|
||||
|
||||
def get(self, func):
|
||||
if hasattr(application,func+"_override"):
|
||||
return getattr(application,func+'_override')
|
||||
return getattr(self, "_call_method")("get_"+func)
|
||||
def get(self, func):
|
||||
if hasattr(application,func+"_override"):
|
||||
return getattr(application,func+'_override')
|
||||
return getattr(self, "_call_method")("get_"+func)
|
||||
|
@ -1,9 +1,9 @@
|
||||
from __future__ import unicode_literals
|
||||
def get_api_key():
|
||||
return "8pDLbyOW3saYnvSZ4uLFg\0"
|
||||
return "8pDLbyOW3saYnvSZ4uLFg\0"
|
||||
|
||||
def get_api_secret():
|
||||
return "YsgdrzY9B4yyYvYsyee78rKI3GshjHpenVS9LnFJXY\0";
|
||||
return "YsgdrzY9B4yyYvYsyee78rKI3GshjHpenVS9LnFJXY\0";
|
||||
|
||||
#char *get_dropbox_api_key(){
|
||||
#return "key\0";
|
||||
|
@ -1,60 +1,60 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
actions = {
|
||||
"up": _(u"Go up in the current buffer"),
|
||||
"down": _(u"Go down in the current buffer"),
|
||||
"left": _(u"Go to the previous buffer"),
|
||||
"right": _(u"Go to the next buffer"),
|
||||
"next_account": _(u"Focus the next session"),
|
||||
"previous_account": _(u"Focus the previous session"),
|
||||
"show_hide": _(u"Show or hide the GUI"),
|
||||
"post_tweet": _(u"New tweet"),
|
||||
"post_reply": _(u"Reply"),
|
||||
"post_retweet": _(u"Retweet"),
|
||||
"send_dm": _(u"Send direct message"),
|
||||
"add_to_favourites": _(u"Like a tweet"),
|
||||
"toggle_like": _(u"Like/unlike a tweet"),
|
||||
"remove_from_favourites": _(u"Unlike a tweet"),
|
||||
"follow": _(u"Open the user actions dialogue"),
|
||||
"user_details": _(u"See user details"),
|
||||
"view_item": _(u"Show tweet"),
|
||||
"exit": _(u"Quit"),
|
||||
"open_timeline": _(u"Open user timeline"),
|
||||
"remove_buffer": _(u"Destroy buffer"),
|
||||
"interact": _(u"Interact with the currently focused tweet."),
|
||||
"url": _(u"Open URL"),
|
||||
"open_in_browser": _(u"View in Twitter"),
|
||||
"volume_up": _(u"Increase volume by 5%"),
|
||||
"volume_down": _(u"Decrease volume by 5%"),
|
||||
"go_home": _(u"Jump to the first element of a 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_down": _(u"Jump 20 elements down in the current buffer"),
|
||||
"update_profile": _(u"Edit profile"),
|
||||
"delete": _(u"Delete a tweet or direct message"),
|
||||
"clear_buffer": _(u"Empty the current buffer"),
|
||||
"repeat_item": _(u"Repeat last item"),
|
||||
"copy_to_clipboard": _(u"Copy to clipboard"),
|
||||
"add_to_list": _(u"Add to list"),
|
||||
"remove_from_list": _(u"Remove from list"),
|
||||
"toggle_buffer_mute": _(u"Mute/unmute the active buffer"),
|
||||
"toggle_session_mute": _(u"Mute/unmute the current session"),
|
||||
"toggle_autoread": _(u"toggle the automatic reading of incoming tweets in the active buffer"),
|
||||
"search": _(u"Search on twitter"),
|
||||
"find": _(u"Find a string in the currently focused buffer"),
|
||||
"edit_keystrokes": _(u"Show the keystroke editor"),
|
||||
"view_user_lists": _(u"Show lists for a specified user"),
|
||||
"get_more_items": _(u"load previous items"),
|
||||
"reverse_geocode": _(u"Get geolocation"),
|
||||
"view_reverse_geocode": _(u"Display the tweet's geolocation in a dialog"),
|
||||
"get_trending_topics": _(u"Create a trending topics buffer"),
|
||||
"open_conversation": _(u"View conversation"),
|
||||
"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."),
|
||||
"configuration": _(u"Opens the global settings dialogue"),
|
||||
"list_manager": _(u"Opens the list manager"),
|
||||
"accountConfiguration": _(u"Opens the account settings dialogue"),
|
||||
"audio": _(u"Try to play an audio file"),
|
||||
"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."),
|
||||
"up": _(u"Go up in the current buffer"),
|
||||
"down": _(u"Go down in the current buffer"),
|
||||
"left": _(u"Go to the previous buffer"),
|
||||
"right": _(u"Go to the next buffer"),
|
||||
"next_account": _(u"Focus the next session"),
|
||||
"previous_account": _(u"Focus the previous session"),
|
||||
"show_hide": _(u"Show or hide the GUI"),
|
||||
"post_tweet": _(u"New tweet"),
|
||||
"post_reply": _(u"Reply"),
|
||||
"post_retweet": _(u"Retweet"),
|
||||
"send_dm": _(u"Send direct message"),
|
||||
"add_to_favourites": _(u"Like a tweet"),
|
||||
"toggle_like": _(u"Like/unlike a tweet"),
|
||||
"remove_from_favourites": _(u"Unlike a tweet"),
|
||||
"follow": _(u"Open the user actions dialogue"),
|
||||
"user_details": _(u"See user details"),
|
||||
"view_item": _(u"Show tweet"),
|
||||
"exit": _(u"Quit"),
|
||||
"open_timeline": _(u"Open user timeline"),
|
||||
"remove_buffer": _(u"Destroy buffer"),
|
||||
"interact": _(u"Interact with the currently focused tweet."),
|
||||
"url": _(u"Open URL"),
|
||||
"open_in_browser": _(u"View in Twitter"),
|
||||
"volume_up": _(u"Increase volume by 5%"),
|
||||
"volume_down": _(u"Decrease volume by 5%"),
|
||||
"go_home": _(u"Jump to the first element of a 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_down": _(u"Jump 20 elements down in the current buffer"),
|
||||
"update_profile": _(u"Edit profile"),
|
||||
"delete": _(u"Delete a tweet or direct message"),
|
||||
"clear_buffer": _(u"Empty the current buffer"),
|
||||
"repeat_item": _(u"Repeat last item"),
|
||||
"copy_to_clipboard": _(u"Copy to clipboard"),
|
||||
"add_to_list": _(u"Add to list"),
|
||||
"remove_from_list": _(u"Remove from list"),
|
||||
"toggle_buffer_mute": _(u"Mute/unmute the active buffer"),
|
||||
"toggle_session_mute": _(u"Mute/unmute the current session"),
|
||||
"toggle_autoread": _(u"toggle the automatic reading of incoming tweets in the active buffer"),
|
||||
"search": _(u"Search on twitter"),
|
||||
"find": _(u"Find a string in the currently focused buffer"),
|
||||
"edit_keystrokes": _(u"Show the keystroke editor"),
|
||||
"view_user_lists": _(u"Show lists for a specified user"),
|
||||
"get_more_items": _(u"load previous items"),
|
||||
"reverse_geocode": _(u"Get geolocation"),
|
||||
"view_reverse_geocode": _(u"Display the tweet's geolocation in a dialog"),
|
||||
"get_trending_topics": _(u"Create a trending topics buffer"),
|
||||
"open_conversation": _(u"View conversation"),
|
||||
"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."),
|
||||
"configuration": _(u"Opens the global settings dialogue"),
|
||||
"list_manager": _(u"Opens the list manager"),
|
||||
"accountConfiguration": _(u"Opens the account settings dialogue"),
|
||||
"audio": _(u"Try to play an audio file"),
|
||||
"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."),
|
||||
}
|
@ -9,53 +9,53 @@ from . import constants
|
||||
from pubsub import pub
|
||||
|
||||
class KeystrokeEditor(object):
|
||||
def __init__(self):
|
||||
super(KeystrokeEditor, self).__init__()
|
||||
self.changed = False # Change it if the keyboard shorcuts are reassigned.
|
||||
self.dialog = wx_ui.keystrokeEditorDialog()
|
||||
self.map = config.keymap["keymap"]
|
||||
# we need to copy the keymap before modify it, for unregistering the old keystrokes if is needed.
|
||||
self.hold_map = self.map.copy()
|
||||
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.execute, widgetUtils.BUTTON_PRESSED, self.execute_action)
|
||||
self.dialog.get_response()
|
||||
def __init__(self):
|
||||
super(KeystrokeEditor, self).__init__()
|
||||
self.changed = False # Change it if the keyboard shorcuts are reassigned.
|
||||
self.dialog = wx_ui.keystrokeEditorDialog()
|
||||
self.map = config.keymap["keymap"]
|
||||
# we need to copy the keymap before modify it, for unregistering the old keystrokes if is needed.
|
||||
self.hold_map = self.map.copy()
|
||||
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.execute, widgetUtils.BUTTON_PRESSED, self.execute_action)
|
||||
self.dialog.get_response()
|
||||
|
||||
def edit_keystroke(self, *args, **kwargs):
|
||||
action = self.dialog.actions[self.dialog.get_action()]
|
||||
edit_dialog = wx_ui.editKeystrokeDialog()
|
||||
self.set_keystroke(self.map[action], edit_dialog)
|
||||
answer = edit_dialog.get_response()
|
||||
if answer == widgetUtils.OK:
|
||||
new_keystroke = self.get_edited_keystroke(edit_dialog)
|
||||
if new_keystroke != self.map[action]:
|
||||
self.changed = True
|
||||
self.map[action] = new_keystroke
|
||||
self.dialog.put_keystrokes(constants.actions, self.map)
|
||||
def edit_keystroke(self, *args, **kwargs):
|
||||
action = self.dialog.actions[self.dialog.get_action()]
|
||||
edit_dialog = wx_ui.editKeystrokeDialog()
|
||||
self.set_keystroke(self.map[action], edit_dialog)
|
||||
answer = edit_dialog.get_response()
|
||||
if answer == widgetUtils.OK:
|
||||
new_keystroke = self.get_edited_keystroke(edit_dialog)
|
||||
if new_keystroke != self.map[action]:
|
||||
self.changed = True
|
||||
self.map[action] = new_keystroke
|
||||
self.dialog.put_keystrokes(constants.actions, self.map)
|
||||
|
||||
def set_keystroke(self, keystroke, dialog):
|
||||
for i in keystroke.split("+"):
|
||||
if hasattr(dialog, i):
|
||||
dialog.set(i, True)
|
||||
dialog.set("key", keystroke.split("+")[-1])
|
||||
def set_keystroke(self, keystroke, dialog):
|
||||
for i in keystroke.split("+"):
|
||||
if hasattr(dialog, i):
|
||||
dialog.set(i, True)
|
||||
dialog.set("key", keystroke.split("+")[-1])
|
||||
|
||||
def get_edited_keystroke(self, dialog):
|
||||
keys = []
|
||||
if dialog.get("control") == True:
|
||||
keys.append("control")
|
||||
if dialog.get("win") == True:
|
||||
keys.append("win")
|
||||
if dialog.get("alt") == True:
|
||||
keys.append("alt")
|
||||
if dialog.get("shift") == True:
|
||||
keys.append("shift")
|
||||
if dialog.get("key") != "":
|
||||
keys.append(dialog.get("key"))
|
||||
else:
|
||||
wx_ui.no_key()
|
||||
return
|
||||
return "+".join(keys)
|
||||
def get_edited_keystroke(self, dialog):
|
||||
keys = []
|
||||
if dialog.get("control") == True:
|
||||
keys.append("control")
|
||||
if dialog.get("win") == True:
|
||||
keys.append("win")
|
||||
if dialog.get("alt") == True:
|
||||
keys.append("alt")
|
||||
if dialog.get("shift") == True:
|
||||
keys.append("shift")
|
||||
if dialog.get("key") != "":
|
||||
keys.append(dialog.get("key"))
|
||||
else:
|
||||
wx_ui.no_key()
|
||||
return
|
||||
return "+".join(keys)
|
||||
|
||||
def execute_action(self, *args, **kwargs):
|
||||
action = self.dialog.actions[self.dialog.get_action()]
|
||||
pub.sendMessage("execute-action", action=action)
|
||||
def execute_action(self, *args, **kwargs):
|
||||
action = self.dialog.actions[self.dialog.get_action()]
|
||||
pub.sendMessage("execute-action", action=action)
|
||||
|
@ -5,78 +5,78 @@ from multiplatform_widgets import widgets
|
||||
from wxUI.dialogs import baseDialog
|
||||
|
||||
class keystrokeEditorDialog(baseDialog.BaseWXDialog):
|
||||
def __init__(self):
|
||||
super(keystrokeEditorDialog, self).__init__(parent=None, id=-1, title=_(u"Keystroke editor"))
|
||||
panel = wx.Panel(self)
|
||||
self.actions = []
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
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.list.SetFocus()
|
||||
firstSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
firstSizer.Add(keysText, 0, wx.ALL, 5)
|
||||
firstSizer.Add(self.keys.list, 0, wx.ALL, 5)
|
||||
self.edit = wx.Button(panel, -1, _(u"Edit"))
|
||||
self.edit.SetDefault()
|
||||
self.execute = wx.Button(panel, -1, _(u"Execute action"))
|
||||
close = wx.Button(panel, wx.ID_CANCEL, _(u"Close"))
|
||||
secondSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
secondSizer.Add(self.edit, 0, wx.ALL, 5)
|
||||
secondSizer.Add(self.execute, 0, wx.ALL, 5)
|
||||
secondSizer.Add(close, 0, wx.ALL, 5)
|
||||
sizer.Add(firstSizer, 0, wx.ALL, 5)
|
||||
sizer.Add(secondSizer, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
self.SetClientSize(sizer.CalcMin())
|
||||
def __init__(self):
|
||||
super(keystrokeEditorDialog, self).__init__(parent=None, id=-1, title=_(u"Keystroke editor"))
|
||||
panel = wx.Panel(self)
|
||||
self.actions = []
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
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.list.SetFocus()
|
||||
firstSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
firstSizer.Add(keysText, 0, wx.ALL, 5)
|
||||
firstSizer.Add(self.keys.list, 0, wx.ALL, 5)
|
||||
self.edit = wx.Button(panel, -1, _(u"Edit"))
|
||||
self.edit.SetDefault()
|
||||
self.execute = wx.Button(panel, -1, _(u"Execute action"))
|
||||
close = wx.Button(panel, wx.ID_CANCEL, _(u"Close"))
|
||||
secondSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
secondSizer.Add(self.edit, 0, wx.ALL, 5)
|
||||
secondSizer.Add(self.execute, 0, wx.ALL, 5)
|
||||
secondSizer.Add(close, 0, wx.ALL, 5)
|
||||
sizer.Add(firstSizer, 0, wx.ALL, 5)
|
||||
sizer.Add(secondSizer, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
self.SetClientSize(sizer.CalcMin())
|
||||
|
||||
def put_keystrokes(self, actions, keystrokes):
|
||||
selection = self.keys.get_selected()
|
||||
self.keys.clear()
|
||||
for i in keystrokes:
|
||||
if (i in actions) == False:
|
||||
continue
|
||||
action = actions[i]
|
||||
self.actions.append(i)
|
||||
keystroke = keystrokes[i]
|
||||
self.keys.insert_item(False, *[action, keystroke])
|
||||
self.keys.select_item(selection)
|
||||
def put_keystrokes(self, actions, keystrokes):
|
||||
selection = self.keys.get_selected()
|
||||
self.keys.clear()
|
||||
for i in keystrokes:
|
||||
if (i in actions) == False:
|
||||
continue
|
||||
action = actions[i]
|
||||
self.actions.append(i)
|
||||
keystroke = keystrokes[i]
|
||||
self.keys.insert_item(False, *[action, keystroke])
|
||||
self.keys.select_item(selection)
|
||||
|
||||
def get_action(self):
|
||||
return self.keys.get_selected()
|
||||
def get_action(self):
|
||||
return self.keys.get_selected()
|
||||
|
||||
class editKeystrokeDialog(baseDialog.BaseWXDialog):
|
||||
def __init__(self):
|
||||
super(editKeystrokeDialog, self).__init__(parent=None, id=-1, title=_(u"Editing keystroke"))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
self.control = wx.CheckBox(panel, -1, _(u"Control"))
|
||||
self.alt = wx.CheckBox(panel, -1, _(u"Alt"))
|
||||
self.shift = wx.CheckBox(panel, -1, _(u"Shift"))
|
||||
self.win = wx.CheckBox(panel, -1, _(u"Windows"))
|
||||
sizer1 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
sizer1.Add(self.control)
|
||||
sizer1.Add(self.alt)
|
||||
sizer1.Add(self.shift)
|
||||
sizer1.Add(self.win)
|
||||
charLabel = wx.StaticText(panel, -1, _(u"Key"))
|
||||
self.key = wx.TextCtrl(panel, -1)
|
||||
sizer2 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
sizer2.Add(charLabel)
|
||||
sizer2.Add(self.key)
|
||||
ok = wx.Button(panel, wx.ID_OK, _(u"OK"))
|
||||
ok.SetDefault()
|
||||
cancel = wx.Button(panel, wx.ID_CANCEL)
|
||||
sizer3 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
sizer3.Add(ok)
|
||||
sizer3.Add(cancel)
|
||||
sizer.Add(sizer1)
|
||||
sizer.Add(sizer2)
|
||||
sizer.Add(sizer3)
|
||||
panel.SetSizerAndFit(sizer)
|
||||
def __init__(self):
|
||||
super(editKeystrokeDialog, self).__init__(parent=None, id=-1, title=_(u"Editing keystroke"))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
self.control = wx.CheckBox(panel, -1, _(u"Control"))
|
||||
self.alt = wx.CheckBox(panel, -1, _(u"Alt"))
|
||||
self.shift = wx.CheckBox(panel, -1, _(u"Shift"))
|
||||
self.win = wx.CheckBox(panel, -1, _(u"Windows"))
|
||||
sizer1 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
sizer1.Add(self.control)
|
||||
sizer1.Add(self.alt)
|
||||
sizer1.Add(self.shift)
|
||||
sizer1.Add(self.win)
|
||||
charLabel = wx.StaticText(panel, -1, _(u"Key"))
|
||||
self.key = wx.TextCtrl(panel, -1)
|
||||
sizer2 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
sizer2.Add(charLabel)
|
||||
sizer2.Add(self.key)
|
||||
ok = wx.Button(panel, wx.ID_OK, _(u"OK"))
|
||||
ok.SetDefault()
|
||||
cancel = wx.Button(panel, wx.ID_CANCEL)
|
||||
sizer3 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
sizer3.Add(ok)
|
||||
sizer3.Add(cancel)
|
||||
sizer.Add(sizer1)
|
||||
sizer.Add(sizer2)
|
||||
sizer.Add(sizer3)
|
||||
panel.SetSizerAndFit(sizer)
|
||||
|
||||
|
||||
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():
|
||||
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()
|
||||
|
@ -20,195 +20,195 @@ LOCALE_SLANGDISPLAYNAME=0x6f
|
||||
curLang="en"
|
||||
|
||||
def localeNameToWindowsLCID(localeName):
|
||||
"""Retreave the Windows locale identifier (LCID) for the given locale name
|
||||
@param localeName: a string of 2letterLanguage_2letterCountry or or just 2letterLanguage
|
||||
@type localeName: string
|
||||
@returns: a Windows LCID
|
||||
@rtype: integer
|
||||
"""
|
||||
#Windows Vista is able to convert locale names to LCIDs
|
||||
func_LocaleNameToLCID=getattr(ctypes.windll.kernel32,'LocaleNameToLCID',None)
|
||||
if func_LocaleNameToLCID is not None:
|
||||
localeName=localeName.replace('_','-')
|
||||
LCID=func_LocaleNameToLCID(str(localeName),0)
|
||||
else: #Windows doesn't have this functionality, manually search Python's windows_locale dictionary for the LCID
|
||||
localeName=locale.normalize(localeName)
|
||||
if '.' in localeName:
|
||||
localeName=localeName.split('.')[0]
|
||||
LCList=[x[0] for x in locale.windows_locale.items() if x[1]==localeName]
|
||||
if len(LCList)>0:
|
||||
LCID=LCList[0]
|
||||
else:
|
||||
LCID=0
|
||||
return LCID
|
||||
"""Retreave the Windows locale identifier (LCID) for the given locale name
|
||||
@param localeName: a string of 2letterLanguage_2letterCountry or or just 2letterLanguage
|
||||
@type localeName: string
|
||||
@returns: a Windows LCID
|
||||
@rtype: integer
|
||||
"""
|
||||
#Windows Vista is able to convert locale names to LCIDs
|
||||
func_LocaleNameToLCID=getattr(ctypes.windll.kernel32,'LocaleNameToLCID',None)
|
||||
if func_LocaleNameToLCID is not None:
|
||||
localeName=localeName.replace('_','-')
|
||||
LCID=func_LocaleNameToLCID(str(localeName),0)
|
||||
else: #Windows doesn't have this functionality, manually search Python's windows_locale dictionary for the LCID
|
||||
localeName=locale.normalize(localeName)
|
||||
if '.' in localeName:
|
||||
localeName=localeName.split('.')[0]
|
||||
LCList=[x[0] for x in locale.windows_locale.items() if x[1]==localeName]
|
||||
if len(LCList)>0:
|
||||
LCID=LCList[0]
|
||||
else:
|
||||
LCID=0
|
||||
return LCID
|
||||
|
||||
def getLanguageDescription(language):
|
||||
"""Finds out the description (localized full name) of a given local name"""
|
||||
desc=None
|
||||
if platform.system() == "Windows":
|
||||
LCID=localeNameToWindowsLCID(language)
|
||||
if LCID!=0:
|
||||
buf=ctypes.create_unicode_buffer(1024)
|
||||
if '_' not in language:
|
||||
res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGDISPLAYNAME,buf,1024)
|
||||
else:
|
||||
res=0
|
||||
if res==0:
|
||||
res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGUAGE,buf,1024)
|
||||
desc=buf.value
|
||||
elif platform.system() == "Linux" or not desc:
|
||||
desc={
|
||||
"am":pgettext("languageName","Amharic"),
|
||||
"an":pgettext("languageName","Aragonese"),
|
||||
"es":pgettext("languageName","Spanish"),
|
||||
"pt":pgettext("languageName","Portuguese"),
|
||||
"ru":pgettext("languageName","Russian"),
|
||||
"it":pgettext("languageName","italian"),
|
||||
"tr":pgettext("languageName","Turkey"),
|
||||
"gl":pgettext("languageName","Galician"),
|
||||
"ca":pgettext("languageName","Catala"),
|
||||
"eu":pgettext("languageName","Vasque"),
|
||||
"pl":pgettext("languageName","polish"),
|
||||
"ar":pgettext("languageName","Arabic"),
|
||||
"ne":pgettext("languageName","Nepali"),
|
||||
"sr":pgettext("languageName","Serbian (Latin)"),
|
||||
"ja":pgettext("languageName","Japanese"),
|
||||
}.get(language,None)
|
||||
return desc
|
||||
"""Finds out the description (localized full name) of a given local name"""
|
||||
desc=None
|
||||
if platform.system() == "Windows":
|
||||
LCID=localeNameToWindowsLCID(language)
|
||||
if LCID!=0:
|
||||
buf=ctypes.create_unicode_buffer(1024)
|
||||
if '_' not in language:
|
||||
res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGDISPLAYNAME,buf,1024)
|
||||
else:
|
||||
res=0
|
||||
if res==0:
|
||||
res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGUAGE,buf,1024)
|
||||
desc=buf.value
|
||||
elif platform.system() == "Linux" or not desc:
|
||||
desc={
|
||||
"am":pgettext("languageName","Amharic"),
|
||||
"an":pgettext("languageName","Aragonese"),
|
||||
"es":pgettext("languageName","Spanish"),
|
||||
"pt":pgettext("languageName","Portuguese"),
|
||||
"ru":pgettext("languageName","Russian"),
|
||||
"it":pgettext("languageName","italian"),
|
||||
"tr":pgettext("languageName","Turkey"),
|
||||
"gl":pgettext("languageName","Galician"),
|
||||
"ca":pgettext("languageName","Catala"),
|
||||
"eu":pgettext("languageName","Vasque"),
|
||||
"pl":pgettext("languageName","polish"),
|
||||
"ar":pgettext("languageName","Arabic"),
|
||||
"ne":pgettext("languageName","Nepali"),
|
||||
"sr":pgettext("languageName","Serbian (Latin)"),
|
||||
"ja":pgettext("languageName","Japanese"),
|
||||
}.get(language,None)
|
||||
return desc
|
||||
|
||||
def getAvailableLanguages():
|
||||
"""generates a list of locale names, plus their full localized language and country names.
|
||||
@rtype: list of tuples
|
||||
"""
|
||||
#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 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
|
||||
if 'en' not in l:
|
||||
l.append('en')
|
||||
l.sort()
|
||||
#For each locale, ask Windows for its human readable display name
|
||||
d=[]
|
||||
for i in l:
|
||||
desc=getLanguageDescription(i)
|
||||
label="%s, %s"%(desc,i) if desc else i
|
||||
d.append(label)
|
||||
#include a 'user default, windows' language, which just represents the default language for this user account
|
||||
l.append("system")
|
||||
# Translators: the label for the Windows default NVDA interface language.
|
||||
d.append(_("User default"))
|
||||
#return a zipped up version of both the lists (a list with tuples of locale,label)
|
||||
return list(zip(l,d))
|
||||
"""generates a list of locale names, plus their full localized language and country names.
|
||||
@rtype: list of tuples
|
||||
"""
|
||||
#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 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
|
||||
if 'en' not in l:
|
||||
l.append('en')
|
||||
l.sort()
|
||||
#For each locale, ask Windows for its human readable display name
|
||||
d=[]
|
||||
for i in l:
|
||||
desc=getLanguageDescription(i)
|
||||
label="%s, %s"%(desc,i) if desc else i
|
||||
d.append(label)
|
||||
#include a 'user default, windows' language, which just represents the default language for this user account
|
||||
l.append("system")
|
||||
# Translators: the label for the Windows default NVDA interface language.
|
||||
d.append(_("User default"))
|
||||
#return a zipped up version of both the lists (a list with tuples of locale,label)
|
||||
return list(zip(l,d))
|
||||
|
||||
def makePgettext(translations):
|
||||
"""Obtaina pgettext function for use with a gettext translations instance.
|
||||
pgettext is used to support message contexts,
|
||||
but Python 2.7's gettext module doesn't support this,
|
||||
so NVDA must provide its own implementation.
|
||||
"""
|
||||
if isinstance(translations, gettext.GNUTranslations):
|
||||
def pgettext(context, message):
|
||||
message = str(message)
|
||||
try:
|
||||
# Look up the message with its context.
|
||||
return translations._catalog["%s\x04%s" % (context, message)]
|
||||
except KeyError:
|
||||
return message
|
||||
else:
|
||||
def pgettext(context, message):
|
||||
return str(message)
|
||||
return pgettext
|
||||
"""Obtaina pgettext function for use with a gettext translations instance.
|
||||
pgettext is used to support message contexts,
|
||||
but Python 2.7's gettext module doesn't support this,
|
||||
so NVDA must provide its own implementation.
|
||||
"""
|
||||
if isinstance(translations, gettext.GNUTranslations):
|
||||
def pgettext(context, message):
|
||||
message = str(message)
|
||||
try:
|
||||
# Look up the message with its context.
|
||||
return translations._catalog["%s\x04%s" % (context, message)]
|
||||
except KeyError:
|
||||
return message
|
||||
else:
|
||||
def pgettext(context, message):
|
||||
return str(message)
|
||||
return pgettext
|
||||
|
||||
def setLanguage(lang):
|
||||
system = platform.system()
|
||||
global curLang
|
||||
try:
|
||||
if lang=="system":
|
||||
if system == "Windows":
|
||||
windowsLCID=ctypes.windll.kernel32.GetUserDefaultUILanguage()
|
||||
localeName=locale.windows_locale[windowsLCID]
|
||||
elif system == "Darwin":
|
||||
import Foundation
|
||||
localeName = Foundation.NSLocale.currentLocale().identifier()
|
||||
elif system == "Linux":
|
||||
localeName = locale.getdefaultlocale()[0]
|
||||
trans=gettext.translation(application.short_name, localedir=paths.locale_path(), languages=[localeName])
|
||||
curLang=localeName
|
||||
system = platform.system()
|
||||
global curLang
|
||||
try:
|
||||
if lang=="system":
|
||||
if system == "Windows":
|
||||
windowsLCID=ctypes.windll.kernel32.GetUserDefaultUILanguage()
|
||||
localeName=locale.windows_locale[windowsLCID]
|
||||
elif system == "Darwin":
|
||||
import Foundation
|
||||
localeName = Foundation.NSLocale.currentLocale().identifier()
|
||||
elif system == "Linux":
|
||||
localeName = locale.getdefaultlocale()[0]
|
||||
trans=gettext.translation(application.short_name, localedir=paths.locale_path(), languages=[localeName])
|
||||
curLang=localeName
|
||||
# else:
|
||||
# localeName=locale.getdefaultlocale()[0]
|
||||
# trans=gettext.translation('twblue', localedir=paths.locale_path(), languages=[localeName])
|
||||
# curLang=localeName
|
||||
|
||||
else:
|
||||
trans=gettext.translation(application.short_name, localedir=paths.locale_path(), languages=[lang])
|
||||
curLang=lang
|
||||
localeChanged=False
|
||||
#Try setting Python's locale to lang
|
||||
else:
|
||||
trans=gettext.translation(application.short_name, localedir=paths.locale_path(), languages=[lang])
|
||||
curLang=lang
|
||||
localeChanged=False
|
||||
#Try setting Python's locale to lang
|
||||
# try:
|
||||
if system == "Windows":
|
||||
locale.setlocale(locale.LC_ALL, langToWindowsLocale(lang))
|
||||
localeChanged=True
|
||||
else:
|
||||
locale.setlocale(locale.LC_ALL, lang)
|
||||
localeChanged=True
|
||||
if system == "Windows":
|
||||
locale.setlocale(locale.LC_ALL, langToWindowsLocale(lang))
|
||||
localeChanged=True
|
||||
else:
|
||||
locale.setlocale(locale.LC_ALL, lang)
|
||||
localeChanged=True
|
||||
# except:
|
||||
# pass
|
||||
if not localeChanged and '_' in lang:
|
||||
#Python couldn'tsupport the language_country locale, just try language.
|
||||
try:
|
||||
locale.setlocale(locale.LC_ALL, lang.split('_')[0])
|
||||
except:
|
||||
pass
|
||||
#Set the windows locale for this thread (NVDA core) to this locale.
|
||||
if system == "Windows":
|
||||
LCID=localeNameToWindowsLCID(lang)
|
||||
ctypes.windll.kernel32.SetThreadLocale(LCID)
|
||||
except IOError:
|
||||
trans=gettext.translation(application.short_name, fallback=True)
|
||||
curLang="en"
|
||||
if sys.version[0] == "3":
|
||||
trans.install()
|
||||
else:
|
||||
trans.install(unicode=True)
|
||||
# Install our pgettext function.
|
||||
if not localeChanged and '_' in lang:
|
||||
#Python couldn'tsupport the language_country locale, just try language.
|
||||
try:
|
||||
locale.setlocale(locale.LC_ALL, lang.split('_')[0])
|
||||
except:
|
||||
pass
|
||||
#Set the windows locale for this thread (NVDA core) to this locale.
|
||||
if system == "Windows":
|
||||
LCID=localeNameToWindowsLCID(lang)
|
||||
ctypes.windll.kernel32.SetThreadLocale(LCID)
|
||||
except IOError:
|
||||
trans=gettext.translation(application.short_name, fallback=True)
|
||||
curLang="en"
|
||||
if sys.version[0] == "3":
|
||||
trans.install()
|
||||
else:
|
||||
trans.install(unicode=True)
|
||||
# Install our pgettext function.
|
||||
# __builtin__.__dict__["pgettext"] = makePgettext(trans)
|
||||
|
||||
def getLanguage():
|
||||
return curLang
|
||||
return curLang
|
||||
|
||||
def normalizeLanguage(lang):
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
lang=lang.replace('-','_')
|
||||
ld=lang.split('_')
|
||||
ld[0]=ld[0].lower()
|
||||
#Filter out meta languages such as x-western
|
||||
if ld[0]=='x':
|
||||
return None
|
||||
if len(ld)>=2:
|
||||
ld[1]=ld[1].upper()
|
||||
return "_".join(ld)
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
lang=lang.replace('-','_')
|
||||
ld=lang.split('_')
|
||||
ld[0]=ld[0].lower()
|
||||
#Filter out meta languages such as x-western
|
||||
if ld[0]=='x':
|
||||
return None
|
||||
if len(ld)>=2:
|
||||
ld[1]=ld[1].upper()
|
||||
return "_".join(ld)
|
||||
|
||||
def langToWindowsLocale(lang):
|
||||
languages = {"en": "eng",
|
||||
"ar": "ara",
|
||||
"ca": "cat",
|
||||
"de": "deu",
|
||||
"es": "esp",
|
||||
"fi": "fin",
|
||||
"fr": "fre_FRA",
|
||||
"gl": "glc",
|
||||
"eu": "euq",
|
||||
"hu": "hun",
|
||||
"hr": "hrv",
|
||||
"it": "ita",
|
||||
"ja": "jpn",
|
||||
"pl": "plk",
|
||||
"pt": "ptb",
|
||||
"ru": "rus",
|
||||
"tr": "trk",
|
||||
"sr": "eng",
|
||||
}
|
||||
return languages[lang]
|
||||
languages = {"en": "eng",
|
||||
"ar": "ara",
|
||||
"ca": "cat",
|
||||
"de": "deu",
|
||||
"es": "esp",
|
||||
"fi": "fin",
|
||||
"fr": "fre_FRA",
|
||||
"gl": "glc",
|
||||
"eu": "euq",
|
||||
"hu": "hun",
|
||||
"hr": "hrv",
|
||||
"it": "ita",
|
||||
"ja": "jpn",
|
||||
"pl": "plk",
|
||||
"pt": "ptb",
|
||||
"ru": "rus",
|
||||
"tr": "trk",
|
||||
"sr": "eng",
|
||||
}
|
||||
return languages[lang]
|
||||
|
@ -37,9 +37,9 @@ error_handler.setLevel(logging.ERROR)
|
||||
logger.addHandler(error_handler)
|
||||
|
||||
def handle_exception(exc_type, exc_value, exc_traceback):
|
||||
if issubclass(exc_type, KeyboardInterrupt):
|
||||
sys.__excepthook__(exc_type, exc_value, exc_traceback)
|
||||
return
|
||||
logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
|
||||
if issubclass(exc_type, KeyboardInterrupt):
|
||||
sys.__excepthook__(exc_type, exc_value, exc_traceback)
|
||||
return
|
||||
logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
|
||||
|
||||
sys.excepthook = handle_exception
|
||||
|
204
src/main.py
204
src/main.py
@ -7,19 +7,19 @@ from win32com.client import GetObject
|
||||
|
||||
system = platform.system()
|
||||
if system == "Windows":
|
||||
import sys
|
||||
import os
|
||||
#redirect the original stdout and stderr
|
||||
stdout=sys.stdout
|
||||
stderr=sys.stderr
|
||||
sys.stdout = open(os.path.join(os.getenv("temp"), "stdout.log"), "w")
|
||||
sys.stderr = open(os.path.join(os.getenv("temp"), "stderr.log"), "w")
|
||||
import sys
|
||||
import os
|
||||
#redirect the original stdout and stderr
|
||||
stdout=sys.stdout
|
||||
stderr=sys.stderr
|
||||
sys.stdout = open(os.path.join(os.getenv("temp"), "stdout.log"), "w")
|
||||
sys.stderr = open(os.path.join(os.getenv("temp"), "stderr.log"), "w")
|
||||
import languageHandler
|
||||
import paths
|
||||
#check if TWBlue is installed (Windows only)
|
||||
# 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")):
|
||||
paths.mode="installed"
|
||||
paths.mode="installed"
|
||||
import commandline
|
||||
import config
|
||||
import output
|
||||
@ -32,114 +32,114 @@ import widgetUtils
|
||||
import webbrowser
|
||||
from wxUI import commonMessageDialogs
|
||||
if system == "Windows":
|
||||
from logger import logger
|
||||
from update import updater
|
||||
stdout_temp=sys.stdout
|
||||
stderr_temp=sys.stderr
|
||||
from logger import logger
|
||||
from update import updater
|
||||
stdout_temp=sys.stdout
|
||||
stderr_temp=sys.stderr
|
||||
#if it's a binary version
|
||||
if hasattr(sys, 'frozen'):
|
||||
sys.stderr = open(os.path.join(paths.logs_path(), "stderr.log"), 'w')
|
||||
sys.stdout = open(os.path.join(paths.logs_path(), "stdout.log"), 'w')
|
||||
else:
|
||||
sys.stdout=stdout
|
||||
sys.stderr=stderr
|
||||
# We are running from source, let's prepare vlc module for that situation
|
||||
if system=="Windows":
|
||||
arch="x86"
|
||||
if platform.architecture()[0][:2] == "64":
|
||||
arch="x64"
|
||||
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"))
|
||||
#the final log files have been opened succesfully, let's close the temporary files
|
||||
stdout_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
|
||||
os.remove(stdout_temp.name)
|
||||
os.remove(stderr_temp.name)
|
||||
if hasattr(sys, 'frozen'):
|
||||
sys.stderr = open(os.path.join(paths.logs_path(), "stderr.log"), 'w')
|
||||
sys.stdout = open(os.path.join(paths.logs_path(), "stdout.log"), 'w')
|
||||
else:
|
||||
sys.stdout=stdout
|
||||
sys.stderr=stderr
|
||||
# We are running from source, let's prepare vlc module for that situation
|
||||
if system=="Windows":
|
||||
arch="x86"
|
||||
if platform.architecture()[0][:2] == "64":
|
||||
arch="x64"
|
||||
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"))
|
||||
#the final log files have been opened succesfully, let's close the temporary files
|
||||
stdout_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
|
||||
os.remove(stdout_temp.name)
|
||||
os.remove(stderr_temp.name)
|
||||
import sound
|
||||
if system == "Linux":
|
||||
from gi.repository import Gdk, GObject, GLib
|
||||
from gi.repository import Gdk, GObject, GLib
|
||||
|
||||
log = logging.getLogger("main")
|
||||
|
||||
def setup():
|
||||
log.debug("Starting " + application.name + " %s" % (application.version,))
|
||||
config.setup()
|
||||
proxy_setup()
|
||||
log.debug("Using %s %s" % (platform.system(), platform.architecture()[0]))
|
||||
log.debug("Application path is %s" % (paths.app_path(),))
|
||||
log.debug("config path is %s" % (paths.config_path(),))
|
||||
sound.setup()
|
||||
languageHandler.setLanguage(config.app["app-settings"]["language"])
|
||||
fixes.setup()
|
||||
output.setup()
|
||||
keys.setup()
|
||||
from controller import settings
|
||||
from controller import mainController
|
||||
from sessionmanager import sessionManager
|
||||
app = widgetUtils.mainLoopObject()
|
||||
check_pid()
|
||||
if system == "Windows":
|
||||
if config.app["app-settings"]["donation_dialog_displayed"] == False:
|
||||
donation()
|
||||
if config.app['app-settings']['check_for_updates']:
|
||||
updater.do_update()
|
||||
sm = sessionManager.sessionManagerController()
|
||||
sm.fill_list()
|
||||
if len(sm.sessions) == 0: sm.show()
|
||||
else:
|
||||
sm.do_ok()
|
||||
if hasattr(sm.view, "destroy"):
|
||||
sm.view.destroy()
|
||||
del sm
|
||||
r = mainController.Controller()
|
||||
r.view.show()
|
||||
r.do_work()
|
||||
r.check_invisible_at_startup()
|
||||
if system == "Windows":
|
||||
call_threaded(r.start)
|
||||
elif system == "Linux":
|
||||
GLib.idle_add(r.start)
|
||||
app.run()
|
||||
log.debug("Starting " + application.name + " %s" % (application.version,))
|
||||
config.setup()
|
||||
proxy_setup()
|
||||
log.debug("Using %s %s" % (platform.system(), platform.architecture()[0]))
|
||||
log.debug("Application path is %s" % (paths.app_path(),))
|
||||
log.debug("config path is %s" % (paths.config_path(),))
|
||||
sound.setup()
|
||||
languageHandler.setLanguage(config.app["app-settings"]["language"])
|
||||
fixes.setup()
|
||||
output.setup()
|
||||
keys.setup()
|
||||
from controller import settings
|
||||
from controller import mainController
|
||||
from sessionmanager import sessionManager
|
||||
app = widgetUtils.mainLoopObject()
|
||||
check_pid()
|
||||
if system == "Windows":
|
||||
if config.app["app-settings"]["donation_dialog_displayed"] == False:
|
||||
donation()
|
||||
if config.app['app-settings']['check_for_updates']:
|
||||
updater.do_update()
|
||||
sm = sessionManager.sessionManagerController()
|
||||
sm.fill_list()
|
||||
if len(sm.sessions) == 0: sm.show()
|
||||
else:
|
||||
sm.do_ok()
|
||||
if hasattr(sm.view, "destroy"):
|
||||
sm.view.destroy()
|
||||
del sm
|
||||
r = mainController.Controller()
|
||||
r.view.show()
|
||||
r.do_work()
|
||||
r.check_invisible_at_startup()
|
||||
if system == "Windows":
|
||||
call_threaded(r.start)
|
||||
elif system == "Linux":
|
||||
GLib.idle_add(r.start)
|
||||
app.run()
|
||||
|
||||
def proxy_setup():
|
||||
if config.app["proxy"]["server"] != "" and config.app["proxy"]["type"] > 0:
|
||||
log.debug("Loading proxy settings")
|
||||
proxy_url = config.app["proxy"]["server"] + ":" + str(config.app["proxy"]["port"])
|
||||
if config.app["proxy"]["user"] != "" and config.app["proxy"]["password"] != "":
|
||||
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"]:
|
||||
proxy_url = config.app["proxy"]["user"] + "@" + proxy_url
|
||||
proxy_url = config.proxyTypes[config.app["proxy"]["type"]] + "://" + proxy_url
|
||||
os.environ["HTTP_PROXY"] = proxy_url
|
||||
os.environ["HTTPS_PROXY"] = proxy_url
|
||||
if config.app["proxy"]["server"] != "" and config.app["proxy"]["type"] > 0:
|
||||
log.debug("Loading proxy settings")
|
||||
proxy_url = config.app["proxy"]["server"] + ":" + str(config.app["proxy"]["port"])
|
||||
if config.app["proxy"]["user"] != "" and config.app["proxy"]["password"] != "":
|
||||
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"]:
|
||||
proxy_url = config.app["proxy"]["user"] + "@" + proxy_url
|
||||
proxy_url = config.proxyTypes[config.app["proxy"]["type"]] + "://" + proxy_url
|
||||
os.environ["HTTP_PROXY"] = proxy_url
|
||||
os.environ["HTTPS_PROXY"] = proxy_url
|
||||
|
||||
def donation():
|
||||
dlg = commonMessageDialogs.donation()
|
||||
if dlg == widgetUtils.YES:
|
||||
webbrowser.open_new_tab(_("https://twblue.es/donate"))
|
||||
config.app["app-settings"]["donation_dialog_displayed"] = True
|
||||
dlg = commonMessageDialogs.donation()
|
||||
if dlg == widgetUtils.YES:
|
||||
webbrowser.open_new_tab(_("https://twblue.es/donate"))
|
||||
config.app["app-settings"]["donation_dialog_displayed"] = True
|
||||
|
||||
def is_running(pid):
|
||||
"Check if the process with ID pid is running. Adapted from https://stackoverflow.com/a/568589"
|
||||
WMI = GetObject('winmgmts:')
|
||||
processes = WMI.InstancesOf('Win32_Process')
|
||||
return [process.Properties_('ProcessID').Value for process in processes if process.Properties_('ProcessID').Value == pid]
|
||||
"Check if the process with ID pid is running. Adapted from https://stackoverflow.com/a/568589"
|
||||
WMI = GetObject('winmgmts:')
|
||||
processes = WMI.InstancesOf('Win32_Process')
|
||||
return [process.Properties_('ProcessID').Value for process in processes if process.Properties_('ProcessID').Value == pid]
|
||||
|
||||
def check_pid():
|
||||
"Insures that only one copy of the application is running at a time."
|
||||
pidpath = os.path.join(os.getenv("temp"), "{}.pid".format(application.name))
|
||||
if os.path.exists(pidpath):
|
||||
with open(pidpath) as fin:
|
||||
pid = int(fin.read())
|
||||
if is_running(pid):
|
||||
# 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))
|
||||
sys.exit(1)
|
||||
else:
|
||||
commonMessageDialogs.dead_pid()
|
||||
# Write the new PID
|
||||
with open(pidpath,"w") as cam:
|
||||
cam.write(str(os.getpid()))
|
||||
"Insures that only one copy of the application is running at a time."
|
||||
pidpath = os.path.join(os.getenv("temp"), "{}.pid".format(application.name))
|
||||
if os.path.exists(pidpath):
|
||||
with open(pidpath) as fin:
|
||||
pid = int(fin.read())
|
||||
if is_running(pid):
|
||||
# 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))
|
||||
sys.exit(1)
|
||||
else:
|
||||
commonMessageDialogs.dead_pid()
|
||||
# Write the new PID
|
||||
with open(pidpath,"w") as cam:
|
||||
cam.write(str(os.getpid()))
|
||||
|
||||
setup()
|
||||
|
@ -8,85 +8,85 @@ import logging
|
||||
log = logging.getLogger("multiplatform_widgets.widgets")
|
||||
|
||||
class list(object):
|
||||
def __init__(self, parent, *columns, **listArguments):
|
||||
self.system = platform.system()
|
||||
self.columns = columns
|
||||
self.listArguments = listArguments
|
||||
log.debug("Creating list: Columns: %s, arguments: %s" % (self.columns, self.listArguments))
|
||||
self.create_list(parent)
|
||||
def __init__(self, parent, *columns, **listArguments):
|
||||
self.system = platform.system()
|
||||
self.columns = columns
|
||||
self.listArguments = listArguments
|
||||
log.debug("Creating list: Columns: %s, arguments: %s" % (self.columns, self.listArguments))
|
||||
self.create_list(parent)
|
||||
# self.set_size()
|
||||
|
||||
def set_windows_size(self, column, characters_max):
|
||||
# it = wx.ListItem()
|
||||
# dc = wx.WindowDC(self.list)
|
||||
# dc.SetFont(it.GetFont())
|
||||
# (x, y) = dc.GetTextExtent("r"*characters_max)
|
||||
self.list.SetColumnWidth(column, characters_max*2)
|
||||
def set_windows_size(self, column, characters_max):
|
||||
# it = wx.ListItem()
|
||||
# dc = wx.WindowDC(self.list)
|
||||
# dc.SetFont(it.GetFont())
|
||||
# (x, y) = dc.GetTextExtent("r"*characters_max)
|
||||
self.list.SetColumnWidth(column, characters_max*2)
|
||||
|
||||
def set_size(self):
|
||||
self.list.SetSize((self.list.GetBestSize()[0], 728))
|
||||
def set_size(self):
|
||||
self.list.SetSize((self.list.GetBestSize()[0], 728))
|
||||
# self.list.SetSize((1439, 1000))
|
||||
|
||||
def create_list(self, parent):
|
||||
if self.system == "Windows":
|
||||
self.list = wx.ListCtrl(parent, -1, **self.listArguments)
|
||||
for i in range(0, len(self.columns)):
|
||||
self.list.InsertColumn(i, u"%s" % (self.columns[i]))
|
||||
else:
|
||||
self.list = wx.ListBox(parent, -1, choices=[])
|
||||
def create_list(self, parent):
|
||||
if self.system == "Windows":
|
||||
self.list = wx.ListCtrl(parent, -1, **self.listArguments)
|
||||
for i in range(0, len(self.columns)):
|
||||
self.list.InsertColumn(i, u"%s" % (self.columns[i]))
|
||||
else:
|
||||
self.list = wx.ListBox(parent, -1, choices=[])
|
||||
|
||||
def insert_item(self, reversed, *item):
|
||||
""" Inserts an item on the list, depending on the OS."""
|
||||
if self.system == "Windows":
|
||||
if reversed == False: items = self.list.GetItemCount()
|
||||
else: items = 0
|
||||
self.list.InsertItem(items, item[0])
|
||||
for i in range(1, len(self.columns)):
|
||||
self.list.SetItem(items, i, item[i])
|
||||
else:
|
||||
self.list.Append(" ".join(item))
|
||||
def insert_item(self, reversed, *item):
|
||||
""" Inserts an item on the list, depending on the OS."""
|
||||
if self.system == "Windows":
|
||||
if reversed == False: items = self.list.GetItemCount()
|
||||
else: items = 0
|
||||
self.list.InsertItem(items, item[0])
|
||||
for i in range(1, len(self.columns)):
|
||||
self.list.SetItem(items, i, item[i])
|
||||
else:
|
||||
self.list.Append(" ".join(item))
|
||||
|
||||
def remove_item(self, pos):
|
||||
""" Deletes an item from the list."""
|
||||
if self.system == "Windows":
|
||||
if pos > 0: self.list.Focus(pos-1)
|
||||
self.list.DeleteItem(pos)
|
||||
else:
|
||||
if pos > 0: self.list.SetSelection(pos-1)
|
||||
self.list.Delete(pos)
|
||||
def remove_item(self, pos):
|
||||
""" Deletes an item from the list."""
|
||||
if self.system == "Windows":
|
||||
if pos > 0: self.list.Focus(pos-1)
|
||||
self.list.DeleteItem(pos)
|
||||
else:
|
||||
if pos > 0: self.list.SetSelection(pos-1)
|
||||
self.list.Delete(pos)
|
||||
|
||||
def clear(self):
|
||||
if self.system == "Windows":
|
||||
self.list.DeleteAllItems()
|
||||
else:
|
||||
self.list.Clear()
|
||||
def clear(self):
|
||||
if self.system == "Windows":
|
||||
self.list.DeleteAllItems()
|
||||
else:
|
||||
self.list.Clear()
|
||||
|
||||
def get_selected(self):
|
||||
if self.system == "Windows":
|
||||
return self.list.GetFocusedItem()
|
||||
else:
|
||||
return self.list.GetSelection()
|
||||
def get_selected(self):
|
||||
if self.system == "Windows":
|
||||
return self.list.GetFocusedItem()
|
||||
else:
|
||||
return self.list.GetSelection()
|
||||
|
||||
def select_item(self, pos):
|
||||
if self.system == "Windows":
|
||||
self.list.Focus(pos)
|
||||
else:
|
||||
self.list.SetSelection(pos)
|
||||
def select_item(self, pos):
|
||||
if self.system == "Windows":
|
||||
self.list.Focus(pos)
|
||||
else:
|
||||
self.list.SetSelection(pos)
|
||||
|
||||
def get_count(self):
|
||||
if self.system == "Windows":
|
||||
selected = self.list.GetItemCount()
|
||||
else:
|
||||
selected = self.list.GetCount()
|
||||
if selected == -1:
|
||||
return 0
|
||||
else:
|
||||
return selected
|
||||
def get_count(self):
|
||||
if self.system == "Windows":
|
||||
selected = self.list.GetItemCount()
|
||||
else:
|
||||
selected = self.list.GetCount()
|
||||
if selected == -1:
|
||||
return 0
|
||||
else:
|
||||
return selected
|
||||
|
||||
def get_text_column(self, indexId, column):
|
||||
item = self.list.GetItem(indexId, column)
|
||||
return item.GetText()
|
||||
def get_text_column(self, indexId, column):
|
||||
item = self.list.GetItem(indexId, column)
|
||||
return item.GetText()
|
||||
|
||||
def set_text_column(self, indexId, column, text):
|
||||
item = self.list.SetStringItem(indexId, column, text)
|
||||
return item
|
||||
def set_text_column(self, indexId, column, text):
|
||||
item = self.list.SetStringItem(indexId, column, text)
|
||||
return item
|
||||
|
@ -10,35 +10,35 @@ from platform_utils import paths
|
||||
RUN_REGKEY = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
|
||||
|
||||
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:
|
||||
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s" % app_subkey)
|
||||
inst_dir = winreg.QueryValueEx(key,"InstallLocation")[0]
|
||||
except WindowsError:
|
||||
return False
|
||||
winreg.CloseKey(key)
|
||||
try:
|
||||
return os.stat(inst_dir) == os.stat(paths.app_path())
|
||||
except WindowsError:
|
||||
return False
|
||||
try:
|
||||
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s" % app_subkey)
|
||||
inst_dir = winreg.QueryValueEx(key,"InstallLocation")[0]
|
||||
except WindowsError:
|
||||
return False
|
||||
winreg.CloseKey(key)
|
||||
try:
|
||||
return os.stat(inst_dir) == os.stat(paths.app_path())
|
||||
except WindowsError:
|
||||
return False
|
||||
|
||||
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:
|
||||
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, RUN_REGKEY)
|
||||
val = winreg.QueryValueEx(key, str(app_name))[0]
|
||||
return os.stat(val) == os.stat(sys.argv[0])
|
||||
except (WindowsError, OSError):
|
||||
return False
|
||||
try:
|
||||
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, RUN_REGKEY)
|
||||
val = winreg.QueryValueEx(key, str(app_name))[0]
|
||||
return os.stat(val) == os.stat(sys.argv[0])
|
||||
except (WindowsError, OSError):
|
||||
return False
|
||||
|
||||
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."""
|
||||
if getAutoStart(app_name) == enable:
|
||||
return
|
||||
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, RUN_REGKEY, 0, winreg.KEY_WRITE)
|
||||
if enable:
|
||||
winreg.SetValueEx(key, str(app_name), None, winreg.REG_SZ, paths.get_executable())
|
||||
else:
|
||||
winreg.DeleteValue(key, str(app_name))
|
||||
"""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:
|
||||
return
|
||||
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, RUN_REGKEY, 0, winreg.KEY_WRITE)
|
||||
if enable:
|
||||
winreg.SetValueEx(key, str(app_name), None, winreg.REG_SZ, paths.get_executable())
|
||||
else:
|
||||
winreg.DeleteValue(key, str(app_name))
|
||||
|
@ -5,14 +5,14 @@ import logging
|
||||
log = logging.getLogger("mysc.localization")
|
||||
|
||||
def get(rootFolder):
|
||||
log.debug("Getting documentation folder. RootFolder: %s" % (rootFolder,))
|
||||
defaultLocale = languageHandler.curLang
|
||||
if len(defaultLocale) > 2:
|
||||
defaultLocale = defaultLocale[:2]
|
||||
log.debug("Locale: %s" % (defaultLocale,))
|
||||
if os.path.exists(rootFolder+"/"+defaultLocale):
|
||||
return defaultLocale
|
||||
else:
|
||||
log.debug("The folder does not exist, using the English folder...")
|
||||
return "en"
|
||||
log.debug("Getting documentation folder. RootFolder: %s" % (rootFolder,))
|
||||
defaultLocale = languageHandler.curLang
|
||||
if len(defaultLocale) > 2:
|
||||
defaultLocale = defaultLocale[:2]
|
||||
log.debug("Locale: %s" % (defaultLocale,))
|
||||
if os.path.exists(rootFolder+"/"+defaultLocale):
|
||||
return defaultLocale
|
||||
else:
|
||||
log.debug("The folder does not exist, using the English folder...")
|
||||
return "en"
|
||||
|
||||
|
@ -4,34 +4,34 @@ import logging
|
||||
log = logging.getLogger("mysc.repeating_timer")
|
||||
|
||||
class RepeatingTimer(threading.Thread):
|
||||
"""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
|
||||
"""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
|
||||
|
||||
t = RepeatingTimer(30.0, f, args=[], kwargs={})
|
||||
t.start()
|
||||
t.cancel() # stop the timer's actions
|
||||
"""
|
||||
t = RepeatingTimer(30.0, f, args=[], kwargs={})
|
||||
t.start()
|
||||
t.cancel() # stop the timer's actions
|
||||
"""
|
||||
|
||||
def __init__(self, interval, function, daemon=True, *args, **kwargs):
|
||||
threading.Thread.__init__(self)
|
||||
self.daemon = daemon
|
||||
self.interval = float(interval)
|
||||
self.function = function
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
self.finished = threading.Event()
|
||||
def __init__(self, interval, function, daemon=True, *args, **kwargs):
|
||||
threading.Thread.__init__(self)
|
||||
self.daemon = daemon
|
||||
self.interval = float(interval)
|
||||
self.function = function
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
self.finished = threading.Event()
|
||||
|
||||
def cancel(self):
|
||||
"""Stop the timer if it hasn't finished yet"""
|
||||
log.debug("Stopping repeater for %s" % (self.function,))
|
||||
self.finished.set()
|
||||
stop = cancel
|
||||
def cancel(self):
|
||||
"""Stop the timer if it hasn't finished yet"""
|
||||
log.debug("Stopping repeater for %s" % (self.function,))
|
||||
self.finished.set()
|
||||
stop = cancel
|
||||
|
||||
def run(self):
|
||||
while not self.finished.is_set():
|
||||
self.finished.wait(self.interval)
|
||||
if not self.finished.is_set(): #In case someone has canceled while waiting
|
||||
try:
|
||||
self.function(*self.args, **self.kwargs)
|
||||
except:
|
||||
log.exception("Execution failed. Function: %r args: %r and kwargs: %r" % (self.function, self.args, self.kwargs))
|
||||
def run(self):
|
||||
while not self.finished.is_set():
|
||||
self.finished.wait(self.interval)
|
||||
if not self.finished.is_set(): #In case someone has canceled while waiting
|
||||
try:
|
||||
self.function(*self.args, **self.kwargs)
|
||||
except:
|
||||
log.exception("Execution failed. Function: %r args: %r and kwargs: %r" % (self.function, self.args, self.kwargs))
|
||||
|
@ -4,13 +4,13 @@ import sys, os
|
||||
import application
|
||||
|
||||
def restart_program():
|
||||
""" Function that restarts the application if is executed."""
|
||||
args = sys.argv[:]
|
||||
if not hasattr(sys, "frozen"):
|
||||
args.insert(0, sys.executable)
|
||||
if sys.platform == 'win32':
|
||||
args = ['"%s"' % arg for arg in args]
|
||||
pidpath = os.path.join(os.getenv("temp"), "{}.pid".format(application.name))
|
||||
if os.path.exists(pidpath):
|
||||
os.remove(pidpath)
|
||||
os.execv(sys.executable, args)
|
||||
""" Function that restarts the application if is executed."""
|
||||
args = sys.argv[:]
|
||||
if not hasattr(sys, "frozen"):
|
||||
args.insert(0, sys.executable)
|
||||
if sys.platform == 'win32':
|
||||
args = ['"%s"' % arg for arg in args]
|
||||
pidpath = os.path.join(os.getenv("temp"), "{}.pid".format(application.name))
|
||||
if os.path.exists(pidpath):
|
||||
os.remove(pidpath)
|
||||
os.execv(sys.executable, args)
|
||||
|
@ -6,14 +6,14 @@ import wx
|
||||
from pubsub import pub
|
||||
|
||||
def call_threaded(func, *args, **kwargs):
|
||||
#Call the given function in a daemonized thread and return the thread.
|
||||
def new_func(*a, **k):
|
||||
try:
|
||||
func(*a, **k)
|
||||
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))
|
||||
#Call the given function in a daemonized thread and return the thread.
|
||||
def new_func(*a, **k):
|
||||
try:
|
||||
func(*a, **k)
|
||||
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))
|
||||
# pass
|
||||
thread = threading.Thread(target=new_func, args=args, kwargs=kwargs)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
return thread
|
||||
thread = threading.Thread(target=new_func, args=args, kwargs=kwargs)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
return thread
|
||||
|
@ -8,16 +8,16 @@ import platform
|
||||
notify = None
|
||||
|
||||
def setup():
|
||||
global notify
|
||||
if platform.system() == "Windows":
|
||||
from . import windows
|
||||
notify = windows.notification()
|
||||
elif platform.system() == "Linux":
|
||||
from . import linux
|
||||
notify = linux.notification()
|
||||
global notify
|
||||
if platform.system() == "Windows":
|
||||
from . import windows
|
||||
notify = windows.notification()
|
||||
elif platform.system() == "Linux":
|
||||
from . import linux
|
||||
notify = linux.notification()
|
||||
|
||||
def send(title, text):
|
||||
global notify
|
||||
if not notify or notify is None:
|
||||
setup()
|
||||
notify.notify(title, text)
|
||||
global notify
|
||||
if not notify or notify is None:
|
||||
setup()
|
||||
notify.notify(title, text)
|
||||
|
@ -5,23 +5,23 @@ import dbus
|
||||
import application
|
||||
|
||||
class notifications(object):
|
||||
"""Supports notifications on Linux.
|
||||
"""
|
||||
"""Supports notifications on Linux.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(notifications, self).__init__()
|
||||
self.item = "org.freedesktop.Notifications"
|
||||
self.path = "/org/freedesktop/Notifications"
|
||||
self.interface = "org.freedesktop.Notifications"
|
||||
self.app_name = application.name
|
||||
self.id_num_to_replace = 0
|
||||
self.icon = "/usr/share/icons/Tango/32x32/status/sunny.png"
|
||||
def __init__(self):
|
||||
super(notifications, self).__init__()
|
||||
self.item = "org.freedesktop.Notifications"
|
||||
self.path = "/org/freedesktop/Notifications"
|
||||
self.interface = "org.freedesktop.Notifications"
|
||||
self.app_name = application.name
|
||||
self.id_num_to_replace = 0
|
||||
self.icon = "/usr/share/icons/Tango/32x32/status/sunny.png"
|
||||
|
||||
def notify(self, title="", text=""):
|
||||
actions_list = ''
|
||||
hint = ''
|
||||
time = 5000 # Use seconds x 1000
|
||||
bus = dbus.SessionBus()
|
||||
notif = bus.get_object(self.item, self.path)
|
||||
notify = dbus.Interface(notif, self.interface)
|
||||
notify.Notify(self.app_name, self.id_num_to_replace, self.icon, title, text, actions_list, hint, time)
|
||||
def notify(self, title="", text=""):
|
||||
actions_list = ''
|
||||
hint = ''
|
||||
time = 5000 # Use seconds x 1000
|
||||
bus = dbus.SessionBus()
|
||||
notif = bus.get_object(self.item, self.path)
|
||||
notify = dbus.Interface(notif, self.interface)
|
||||
notify.Notify(self.app_name, self.id_num_to_replace, self.icon, title, text, actions_list, hint, time)
|
||||
|
@ -5,5 +5,5 @@ import wx
|
||||
|
||||
class notification(object):
|
||||
|
||||
def notify(self, title, text):
|
||||
wx.NotificationMessage(title, text).Show()
|
||||
def notify(self, title, text):
|
||||
wx.NotificationMessage(title, text).Show()
|
||||
|
@ -8,28 +8,28 @@ import sys
|
||||
speaker = None
|
||||
|
||||
def speak(text, interrupt=0, speech=True, braille=True):
|
||||
global speaker
|
||||
if not speaker:
|
||||
setup()
|
||||
if speech:
|
||||
speaker.speak(text, interrupt)
|
||||
if braille:
|
||||
speaker.braille(text)
|
||||
global speaker
|
||||
if not speaker:
|
||||
setup()
|
||||
if speech:
|
||||
speaker.speak(text, interrupt)
|
||||
if braille:
|
||||
speaker.braille(text)
|
||||
|
||||
def setup ():
|
||||
global speaker
|
||||
logging.debug("Initializing output subsystem.")
|
||||
try:
|
||||
# speaker = speech.Speaker(speech.outputs.Sapi5())
|
||||
# else:
|
||||
speaker = outputs.auto.Auto()
|
||||
except:
|
||||
return logging.exception("Output: Error during initialization.")
|
||||
global speaker
|
||||
logging.debug("Initializing output subsystem.")
|
||||
try:
|
||||
# speaker = speech.Speaker(speech.outputs.Sapi5())
|
||||
# else:
|
||||
speaker = outputs.auto.Auto()
|
||||
except:
|
||||
return logging.exception("Output: Error during initialization.")
|
||||
|
||||
def copy(text):
|
||||
import win32clipboard
|
||||
#Copies text to the clipboard.
|
||||
win32clipboard.OpenClipboard()
|
||||
win32clipboard.EmptyClipboard()
|
||||
win32clipboard.SetClipboardText(text, win32clipboard.CF_UNICODETEXT)
|
||||
win32clipboard.CloseClipboard()
|
||||
import win32clipboard
|
||||
#Copies text to the clipboard.
|
||||
win32clipboard.OpenClipboard()
|
||||
win32clipboard.EmptyClipboard()
|
||||
win32clipboard.SetClipboardText(text, win32clipboard.CF_UNICODETEXT)
|
||||
win32clipboard.CloseClipboard()
|
||||
|
82
src/paths.py
82
src/paths.py
@ -10,58 +10,58 @@ directory = None
|
||||
fsencoding = sys.getfilesystemencoding()
|
||||
|
||||
if len(glob.glob("Uninstall.exe")) > 0: # installed copy
|
||||
mode= "installed"
|
||||
mode= "installed"
|
||||
|
||||
def app_path():
|
||||
return paths_.app_path()
|
||||
return paths_.app_path()
|
||||
|
||||
def config_path():
|
||||
global mode, directory
|
||||
if mode == "portable":
|
||||
if directory != None: path = os.path.join(directory, "config")
|
||||
elif directory == None: path = os.path.join(app_path(), "config")
|
||||
elif mode == "installed":
|
||||
path = os.path.join(data_path(), "config")
|
||||
if not os.path.exists(path):
|
||||
# log.debug("%s path does not exist, creating..." % (path,))
|
||||
os.mkdir(path)
|
||||
return path
|
||||
global mode, directory
|
||||
if mode == "portable":
|
||||
if directory != None: path = os.path.join(directory, "config")
|
||||
elif directory == None: path = os.path.join(app_path(), "config")
|
||||
elif mode == "installed":
|
||||
path = os.path.join(data_path(), "config")
|
||||
if not os.path.exists(path):
|
||||
# log.debug("%s path does not exist, creating..." % (path,))
|
||||
os.mkdir(path)
|
||||
return path
|
||||
|
||||
def logs_path():
|
||||
global mode, directory
|
||||
if mode == "portable":
|
||||
if directory != None: path = os.path.join(directory, "logs")
|
||||
elif directory == None: path = os.path.join(app_path(), "logs")
|
||||
elif mode == "installed":
|
||||
path = os.path.join(data_path(), "logs")
|
||||
if not os.path.exists(path):
|
||||
# log.debug("%s path does not exist, creating..." % (path,))
|
||||
os.mkdir(path)
|
||||
return path
|
||||
global mode, directory
|
||||
if mode == "portable":
|
||||
if directory != None: path = os.path.join(directory, "logs")
|
||||
elif directory == None: path = os.path.join(app_path(), "logs")
|
||||
elif mode == "installed":
|
||||
path = os.path.join(data_path(), "logs")
|
||||
if not os.path.exists(path):
|
||||
# log.debug("%s path does not exist, creating..." % (path,))
|
||||
os.mkdir(path)
|
||||
return path
|
||||
|
||||
def data_path(app_name='socializer'):
|
||||
if platform.system() == "Windows":
|
||||
data_path = os.path.join(os.getenv("AppData"), app_name)
|
||||
else:
|
||||
data_path = os.path.join(os.environ['HOME'], ".%s" % app_name)
|
||||
if not os.path.exists(data_path):
|
||||
os.mkdir(data_path)
|
||||
return data_path
|
||||
if platform.system() == "Windows":
|
||||
data_path = os.path.join(os.getenv("AppData"), app_name)
|
||||
else:
|
||||
data_path = os.path.join(os.environ['HOME'], ".%s" % app_name)
|
||||
if not os.path.exists(data_path):
|
||||
os.mkdir(data_path)
|
||||
return data_path
|
||||
|
||||
def locale_path():
|
||||
return os.path.join(app_path(), "locales")
|
||||
return os.path.join(app_path(), "locales")
|
||||
|
||||
def sound_path():
|
||||
return os.path.join(app_path(), "sounds")
|
||||
return os.path.join(app_path(), "sounds")
|
||||
|
||||
def com_path():
|
||||
global mode, directory
|
||||
if mode == "portable":
|
||||
if directory != None: path = os.path.join(directory, "com_cache")
|
||||
elif directory == None: path = os.path.join(app_path(), "com_cache")
|
||||
elif mode == "installed":
|
||||
path = os.path.join(data_path(), "com_cache")
|
||||
if not os.path.exists(path):
|
||||
# log.debug("%s path does not exist, creating..." % (path,))
|
||||
os.mkdir(path)
|
||||
return path
|
||||
global mode, directory
|
||||
if mode == "portable":
|
||||
if directory != None: path = os.path.join(directory, "com_cache")
|
||||
elif directory == None: path = os.path.join(app_path(), "com_cache")
|
||||
elif mode == "installed":
|
||||
path = os.path.join(data_path(), "com_cache")
|
||||
if not os.path.exists(path):
|
||||
# log.debug("%s path does not exist, creating..." % (path,))
|
||||
os.mkdir(path)
|
||||
return path
|
||||
|
@ -3,55 +3,55 @@ from gi.repository import Gtk
|
||||
import widgetUtils
|
||||
|
||||
class sessionManagerWindow(widgetUtils.baseDialog):
|
||||
def __init__(self):
|
||||
super(sessionManagerWindow, self).__init__("Session Manager", None, 0, (Gtk.STOCK_OK, widgetUtils.OK, Gtk.STOCK_CANCEL, widgetUtils.CANCEL))
|
||||
self.list = widgetUtils.list("Session")
|
||||
self.box.add(self.list.list)
|
||||
btnBox = Gtk.Box(spacing=6)
|
||||
self.new = Gtk.Button("New account")
|
||||
self.remove = Gtk.Button("Remove account")
|
||||
self.configuration = Gtk.Button("Configuration")
|
||||
btnBox.add(self.new)
|
||||
btnBox.add(self.remove)
|
||||
btnBox.add(self.configuration)
|
||||
self.box.add(btnBox)
|
||||
self.show_all()
|
||||
def __init__(self):
|
||||
super(sessionManagerWindow, self).__init__("Session Manager", None, 0, (Gtk.STOCK_OK, widgetUtils.OK, Gtk.STOCK_CANCEL, widgetUtils.CANCEL))
|
||||
self.list = widgetUtils.list("Session")
|
||||
self.box.add(self.list.list)
|
||||
btnBox = Gtk.Box(spacing=6)
|
||||
self.new = Gtk.Button("New account")
|
||||
self.remove = Gtk.Button("Remove account")
|
||||
self.configuration = Gtk.Button("Configuration")
|
||||
btnBox.add(self.new)
|
||||
btnBox.add(self.remove)
|
||||
btnBox.add(self.configuration)
|
||||
self.box.add(btnBox)
|
||||
self.show_all()
|
||||
|
||||
def fill_list(self, sessionsList):
|
||||
for i in sessionsList:
|
||||
self.list.insert_item(False, i)
|
||||
if self.list.get_count() > 0:
|
||||
self.list.select_item(0)
|
||||
def fill_list(self, sessionsList):
|
||||
for i in sessionsList:
|
||||
self.list.insert_item(False, i)
|
||||
if self.list.get_count() > 0:
|
||||
self.list.select_item(0)
|
||||
|
||||
def new_account_dialog(self):
|
||||
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?")
|
||||
answer = dialog.run()
|
||||
dialog.destroy()
|
||||
return answer
|
||||
def new_account_dialog(self):
|
||||
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?")
|
||||
answer = dialog.run()
|
||||
dialog.destroy()
|
||||
return answer
|
||||
|
||||
def add_new_session_to_list(self):
|
||||
total = self.list.get_count()
|
||||
name = "Authorized account %d" % (total+1)
|
||||
self.list.insert_item(name)
|
||||
if self.list.get_count() == 1:
|
||||
self.list.select_item(0)
|
||||
def add_new_session_to_list(self):
|
||||
total = self.list.get_count()
|
||||
name = "Authorized account %d" % (total+1)
|
||||
self.list.insert_item(name)
|
||||
if self.list.get_count() == 1:
|
||||
self.list.select_item(0)
|
||||
|
||||
def show_unauthorised_error(self):
|
||||
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.")
|
||||
answer = dialog.run()
|
||||
return answer
|
||||
def show_unauthorised_error(self):
|
||||
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.")
|
||||
answer = dialog.run()
|
||||
return answer
|
||||
|
||||
def remove_account_dialog(self):
|
||||
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?")
|
||||
answer = dialog.run()
|
||||
return answer
|
||||
def remove_account_dialog(self):
|
||||
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?")
|
||||
answer = dialog.run()
|
||||
return answer
|
||||
|
||||
def get_selected(self):
|
||||
return self.list.get_selected()
|
||||
def get_selected(self):
|
||||
return self.list.get_selected()
|
||||
|
||||
def remove_session(self, sessionID):
|
||||
self.list.remove_item(sessionID)
|
||||
def remove_session(self, sessionID):
|
||||
self.list.remove_item(sessionID)
|
||||
|
||||
|
@ -11,41 +11,41 @@ from sessions import session_exceptions
|
||||
|
||||
manager = None
|
||||
def setup():
|
||||
global manager
|
||||
if not manager:
|
||||
manager = sessionManager()
|
||||
global manager
|
||||
if not manager:
|
||||
manager = sessionManager()
|
||||
|
||||
class sessionManager(object):
|
||||
# def __init__(self):
|
||||
# FILE = "sessions.conf"
|
||||
# SPEC = "app-configuration.defaults"
|
||||
# try:
|
||||
# self.main = Configuration(paths.config_path(FILE), paths.app_path(SPEC))
|
||||
# except ConfigurationResetException:
|
||||
# pass
|
||||
# def __init__(self):
|
||||
# FILE = "sessions.conf"
|
||||
# SPEC = "app-configuration.defaults"
|
||||
# try:
|
||||
# self.main = Configuration(paths.config_path(FILE), paths.app_path(SPEC))
|
||||
# except ConfigurationResetException:
|
||||
# pass
|
||||
|
||||
def get_current_session(self):
|
||||
if self.is_valid(config.app["sessions"]["current_session"]):
|
||||
return config.app["sessions"]["current_session"]
|
||||
else:
|
||||
return False
|
||||
def get_current_session(self):
|
||||
if self.is_valid(config.app["sessions"]["current_session"]):
|
||||
return config.app["sessions"]["current_session"]
|
||||
else:
|
||||
return False
|
||||
|
||||
def add_session(self, id):
|
||||
log.debug("Adding a new session: %s" % (id,))
|
||||
path = os.path.join(paths.config_path(), id)
|
||||
if not os.path.exists(path):
|
||||
log.debug("Creating %s path" % (os.path.join(paths.config_path(), path),))
|
||||
os.mkdir(path)
|
||||
config.app["sessions"]["sessions"].append(id)
|
||||
def add_session(self, id):
|
||||
log.debug("Adding a new session: %s" % (id,))
|
||||
path = os.path.join(paths.config_path(), id)
|
||||
if not os.path.exists(path):
|
||||
log.debug("Creating %s path" % (os.path.join(paths.config_path(), path),))
|
||||
os.mkdir(path)
|
||||
config.app["sessions"]["sessions"].append(id)
|
||||
|
||||
def set_current_session(self, sessionID):
|
||||
config.app["sessions"]["current_session"] = sessionID
|
||||
config.app.write()
|
||||
def set_current_session(self, sessionID):
|
||||
config.app["sessions"]["current_session"] = sessionID
|
||||
config.app.write()
|
||||
|
||||
def is_valid(self, id):
|
||||
if not os.path.exists(os.path.join(paths.config_path(), id)):
|
||||
raise session_exceptions.NonExistentSessionError("That session does not exist.")
|
||||
config.app["sessions"]["current_session"] = ""
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
def is_valid(self, id):
|
||||
if not os.path.exists(os.path.join(paths.config_path(), id)):
|
||||
raise session_exceptions.NonExistentSessionError("That session does not exist.")
|
||||
config.app["sessions"]["current_session"] = ""
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
@ -4,10 +4,10 @@ import widgetUtils
|
||||
import platform
|
||||
import output
|
||||
if platform.system() == "Windows":
|
||||
from . import wxUI as view
|
||||
from controller import settings
|
||||
from . import wxUI as view
|
||||
from controller import settings
|
||||
elif platform.system() == "Linux":
|
||||
from . import gtkUI as view
|
||||
from . import gtkUI as view
|
||||
import paths
|
||||
import time
|
||||
import os
|
||||
@ -21,106 +21,106 @@ from tweepy.error import TweepError
|
||||
log = logging.getLogger("sessionmanager.sessionManager")
|
||||
|
||||
class sessionManagerController(object):
|
||||
def __init__(self, started=False):
|
||||
super(sessionManagerController, self).__init__()
|
||||
log.debug("Setting up the session manager.")
|
||||
self.started = started
|
||||
manager.setup()
|
||||
self.view = view.sessionManagerWindow()
|
||||
widgetUtils.connect_event(self.view.new, widgetUtils.BUTTON_PRESSED, self.manage_new_account)
|
||||
widgetUtils.connect_event(self.view.remove, widgetUtils.BUTTON_PRESSED, self.remove)
|
||||
if self.started == False:
|
||||
widgetUtils.connect_event(self.view.configuration, widgetUtils.BUTTON_PRESSED, self.configuration)
|
||||
else:
|
||||
self.view.hide_configuration()
|
||||
self.new_sessions = {}
|
||||
self.removed_sessions = []
|
||||
def __init__(self, started=False):
|
||||
super(sessionManagerController, self).__init__()
|
||||
log.debug("Setting up the session manager.")
|
||||
self.started = started
|
||||
manager.setup()
|
||||
self.view = view.sessionManagerWindow()
|
||||
widgetUtils.connect_event(self.view.new, widgetUtils.BUTTON_PRESSED, self.manage_new_account)
|
||||
widgetUtils.connect_event(self.view.remove, widgetUtils.BUTTON_PRESSED, self.remove)
|
||||
if self.started == False:
|
||||
widgetUtils.connect_event(self.view.configuration, widgetUtils.BUTTON_PRESSED, self.configuration)
|
||||
else:
|
||||
self.view.hide_configuration()
|
||||
self.new_sessions = {}
|
||||
self.removed_sessions = []
|
||||
|
||||
def fill_list(self):
|
||||
sessionsList = []
|
||||
reserved_dirs = ["dicts"]
|
||||
log.debug("Filling the sessions list.")
|
||||
self.sessions = []
|
||||
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:
|
||||
log.debug("Adding session %s" % (i,))
|
||||
strconfig = "%s/session.conf" % (os.path.join(paths.config_path(), i))
|
||||
config_test = config_utils.load_config(strconfig)
|
||||
if len(config_test) == 0:
|
||||
try:
|
||||
log.debug("Deleting session %s" % (i,))
|
||||
shutil.rmtree(os.path.join(paths.config_path(), i))
|
||||
continue
|
||||
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)
|
||||
os.exception("Exception thrown while removing malformed session")
|
||||
continue
|
||||
name = config_test["twitter"]["user_name"]
|
||||
if config_test["twitter"]["user_key"] != "" and config_test["twitter"]["user_secret"] != "":
|
||||
sessionsList.append(name)
|
||||
self.sessions.append(i)
|
||||
else:
|
||||
try:
|
||||
log.debug("Deleting session %s" % (i,))
|
||||
shutil.rmtree(os.path.join(paths.config_path(), i))
|
||||
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)
|
||||
os.exception("Exception thrown while removing malformed session")
|
||||
self.view.fill_list(sessionsList)
|
||||
def fill_list(self):
|
||||
sessionsList = []
|
||||
reserved_dirs = ["dicts"]
|
||||
log.debug("Filling the sessions list.")
|
||||
self.sessions = []
|
||||
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:
|
||||
log.debug("Adding session %s" % (i,))
|
||||
strconfig = "%s/session.conf" % (os.path.join(paths.config_path(), i))
|
||||
config_test = config_utils.load_config(strconfig)
|
||||
if len(config_test) == 0:
|
||||
try:
|
||||
log.debug("Deleting session %s" % (i,))
|
||||
shutil.rmtree(os.path.join(paths.config_path(), i))
|
||||
continue
|
||||
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)
|
||||
os.exception("Exception thrown while removing malformed session")
|
||||
continue
|
||||
name = config_test["twitter"]["user_name"]
|
||||
if config_test["twitter"]["user_key"] != "" and config_test["twitter"]["user_secret"] != "":
|
||||
sessionsList.append(name)
|
||||
self.sessions.append(i)
|
||||
else:
|
||||
try:
|
||||
log.debug("Deleting session %s" % (i,))
|
||||
shutil.rmtree(os.path.join(paths.config_path(), i))
|
||||
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)
|
||||
os.exception("Exception thrown while removing malformed session")
|
||||
self.view.fill_list(sessionsList)
|
||||
|
||||
def show(self):
|
||||
if self.view.get_response() == widgetUtils.OK:
|
||||
self.do_ok()
|
||||
def show(self):
|
||||
if self.view.get_response() == widgetUtils.OK:
|
||||
self.do_ok()
|
||||
# else:
|
||||
self.view.destroy()
|
||||
self.view.destroy()
|
||||
|
||||
def do_ok(self):
|
||||
log.debug("Starting sessions...")
|
||||
for i in self.sessions:
|
||||
if (i in sessions.sessions) == True: continue
|
||||
s = session.Session(i)
|
||||
s.get_configuration()
|
||||
if i not in config.app["sessions"]["ignored_sessions"]:
|
||||
try:
|
||||
s.login()
|
||||
except TweepError:
|
||||
self.show_auth_error(s.settings["twitter"]["user_name"])
|
||||
continue
|
||||
sessions.sessions[i] = s
|
||||
self.new_sessions[i] = s
|
||||
def do_ok(self):
|
||||
log.debug("Starting sessions...")
|
||||
for i in self.sessions:
|
||||
if (i in sessions.sessions) == True: continue
|
||||
s = session.Session(i)
|
||||
s.get_configuration()
|
||||
if i not in config.app["sessions"]["ignored_sessions"]:
|
||||
try:
|
||||
s.login()
|
||||
except TweepError:
|
||||
self.show_auth_error(s.settings["twitter"]["user_name"])
|
||||
continue
|
||||
sessions.sessions[i] = s
|
||||
self.new_sessions[i] = s
|
||||
# self.view.destroy()
|
||||
|
||||
def show_auth_error(self, user_name):
|
||||
error = view.auth_error(user_name)
|
||||
def show_auth_error(self, user_name):
|
||||
error = view.auth_error(user_name)
|
||||
|
||||
def manage_new_account(self, *args, **kwargs):
|
||||
if self.view.new_account_dialog() == widgetUtils.YES:
|
||||
location = (str(time.time())[-6:])
|
||||
log.debug("Creating session in the %s path" % (location,))
|
||||
s = session.Session(location)
|
||||
manager.manager.add_session(location)
|
||||
s.get_configuration()
|
||||
def manage_new_account(self, *args, **kwargs):
|
||||
if self.view.new_account_dialog() == widgetUtils.YES:
|
||||
location = (str(time.time())[-6:])
|
||||
log.debug("Creating session in the %s path" % (location,))
|
||||
s = session.Session(location)
|
||||
manager.manager.add_session(location)
|
||||
s.get_configuration()
|
||||
# try:
|
||||
s.authorise()
|
||||
self.sessions.append(location)
|
||||
self.view.add_new_session_to_list()
|
||||
s.settings.write()
|
||||
s.authorise()
|
||||
self.sessions.append(location)
|
||||
self.view.add_new_session_to_list()
|
||||
s.settings.write()
|
||||
# except:
|
||||
# log.exception("Error authorising the session")
|
||||
# self.view.show_unauthorised_error()
|
||||
# return
|
||||
|
||||
def remove(self, *args, **kwargs):
|
||||
if self.view.remove_account_dialog() == widgetUtils.YES:
|
||||
selected_account = self.sessions[self.view.get_selected()]
|
||||
self.view.remove_session(self.view.get_selected())
|
||||
self.removed_sessions.append(selected_account)
|
||||
self.sessions.remove(selected_account)
|
||||
shutil.rmtree(path=os.path.join(paths.config_path(), selected_account), ignore_errors=True)
|
||||
def remove(self, *args, **kwargs):
|
||||
if self.view.remove_account_dialog() == widgetUtils.YES:
|
||||
selected_account = self.sessions[self.view.get_selected()]
|
||||
self.view.remove_session(self.view.get_selected())
|
||||
self.removed_sessions.append(selected_account)
|
||||
self.sessions.remove(selected_account)
|
||||
shutil.rmtree(path=os.path.join(paths.config_path(), selected_account), ignore_errors=True)
|
||||
|
||||
|
||||
def configuration(self, *args, **kwargs):
|
||||
""" Opens the global settings dialogue."""
|
||||
d = settings.globalSettingsController()
|
||||
if d.response == widgetUtils.OK:
|
||||
d.save_configuration()
|
||||
def configuration(self, *args, **kwargs):
|
||||
""" Opens the global settings dialogue."""
|
||||
d = settings.globalSettingsController()
|
||||
if d.response == widgetUtils.OK:
|
||||
d.save_configuration()
|
||||
|
@ -5,77 +5,77 @@ from multiplatform_widgets import widgets
|
||||
import application
|
||||
|
||||
class sessionManagerWindow(wx.Dialog):
|
||||
def __init__(self):
|
||||
super(sessionManagerWindow, self).__init__(parent=None, title=_(u"Session manager"), size=wx.DefaultSize)
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
label = wx.StaticText(panel, -1, _(u"Accounts list"), size=wx.DefaultSize)
|
||||
listSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
self.list = widgets.list(panel, _(u"Account"), style=wx.LC_SINGLE_SEL|wx.LC_REPORT)
|
||||
listSizer.Add(label, 0, wx.ALL, 5)
|
||||
listSizer.Add(self.list.list, 0, wx.ALL, 5)
|
||||
sizer.Add(listSizer, 0, wx.ALL, 5)
|
||||
self.new = wx.Button(panel, -1, _(u"New account"), size=wx.DefaultSize)
|
||||
self.remove = wx.Button(panel, -1, _(u"Remove account"))
|
||||
self.configuration = wx.Button(panel, -1, _(u"Global Settings"))
|
||||
ok = wx.Button(panel, wx.ID_OK, size=wx.DefaultSize)
|
||||
ok.SetDefault()
|
||||
cancel = wx.Button(panel, wx.ID_CANCEL, size=wx.DefaultSize)
|
||||
buttons = wx.BoxSizer(wx.HORIZONTAL)
|
||||
buttons.Add(self.new, 0, wx.ALL, 5)
|
||||
buttons.Add(self.configuration, 0, wx.ALL, 5)
|
||||
buttons.Add(ok, 0, wx.ALL, 5)
|
||||
buttons.Add(cancel, 0, wx.ALL, 5)
|
||||
sizer.Add(buttons, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
min = sizer.CalcMin()
|
||||
self.SetClientSize(min)
|
||||
def __init__(self):
|
||||
super(sessionManagerWindow, self).__init__(parent=None, title=_(u"Session manager"), size=wx.DefaultSize)
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
label = wx.StaticText(panel, -1, _(u"Accounts list"), size=wx.DefaultSize)
|
||||
listSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
self.list = widgets.list(panel, _(u"Account"), style=wx.LC_SINGLE_SEL|wx.LC_REPORT)
|
||||
listSizer.Add(label, 0, wx.ALL, 5)
|
||||
listSizer.Add(self.list.list, 0, wx.ALL, 5)
|
||||
sizer.Add(listSizer, 0, wx.ALL, 5)
|
||||
self.new = wx.Button(panel, -1, _(u"New account"), size=wx.DefaultSize)
|
||||
self.remove = wx.Button(panel, -1, _(u"Remove account"))
|
||||
self.configuration = wx.Button(panel, -1, _(u"Global Settings"))
|
||||
ok = wx.Button(panel, wx.ID_OK, size=wx.DefaultSize)
|
||||
ok.SetDefault()
|
||||
cancel = wx.Button(panel, wx.ID_CANCEL, size=wx.DefaultSize)
|
||||
buttons = wx.BoxSizer(wx.HORIZONTAL)
|
||||
buttons.Add(self.new, 0, wx.ALL, 5)
|
||||
buttons.Add(self.configuration, 0, wx.ALL, 5)
|
||||
buttons.Add(ok, 0, wx.ALL, 5)
|
||||
buttons.Add(cancel, 0, wx.ALL, 5)
|
||||
sizer.Add(buttons, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
min = sizer.CalcMin()
|
||||
self.SetClientSize(min)
|
||||
|
||||
def fill_list(self, sessionsList):
|
||||
for i in sessionsList:
|
||||
self.list.insert_item(False, i)
|
||||
if self.list.get_count() > 0:
|
||||
self.list.select_item(0)
|
||||
self.list.list.SetSize(self.list.list.GetBestSize())
|
||||
def fill_list(self, sessionsList):
|
||||
for i in sessionsList:
|
||||
self.list.insert_item(False, i)
|
||||
if self.list.get_count() > 0:
|
||||
self.list.select_item(0)
|
||||
self.list.list.SetSize(self.list.list.GetBestSize())
|
||||
|
||||
def ok(self, ev):
|
||||
if self.list.get_count() == 0:
|
||||
wx.MessageDialog(None, _(u"You need to configure an account."), _(u"Account Error"), wx.ICON_ERROR).ShowModal()
|
||||
return
|
||||
self.controller.do_ok()
|
||||
self.EndModal(wx.ID_OK)
|
||||
def ok(self, ev):
|
||||
if self.list.get_count() == 0:
|
||||
wx.MessageDialog(None, _(u"You need to configure an account."), _(u"Account Error"), wx.ICON_ERROR).ShowModal()
|
||||
return
|
||||
self.controller.do_ok()
|
||||
self.EndModal(wx.ID_OK)
|
||||
|
||||
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()
|
||||
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()
|
||||
|
||||
def add_new_session_to_list(self):
|
||||
total = self.list.get_count()
|
||||
name = _(u"Authorized account %d") % (total+1)
|
||||
self.list.insert_item(False, name)
|
||||
if self.list.get_count() == 1:
|
||||
self.list.select_item(0)
|
||||
def add_new_session_to_list(self):
|
||||
total = self.list.get_count()
|
||||
name = _(u"Authorized account %d") % (total+1)
|
||||
self.list.insert_item(False, name)
|
||||
if self.list.get_count() == 1:
|
||||
self.list.select_item(0)
|
||||
|
||||
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()
|
||||
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()
|
||||
|
||||
def get_response(self):
|
||||
return self.ShowModal()
|
||||
def get_response(self):
|
||||
return self.ShowModal()
|
||||
|
||||
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()
|
||||
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()
|
||||
|
||||
def get_selected(self):
|
||||
return self.list.get_selected()
|
||||
def get_selected(self):
|
||||
return self.list.get_selected()
|
||||
|
||||
def remove_session(self, sessionID):
|
||||
self.list.remove_item(sessionID)
|
||||
def remove_session(self, sessionID):
|
||||
self.list.remove_item(sessionID)
|
||||
|
||||
|
||||
def hide_configuration(self):
|
||||
self.configuration.Hide()
|
||||
def hide_configuration(self):
|
||||
self.configuration.Hide()
|
||||
|
||||
def destroy(self):
|
||||
self.Destroy()
|
||||
def destroy(self):
|
||||
self.Destroy()
|
||||
|
||||
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()
|
||||
|
@ -18,103 +18,103 @@ from . import session_exceptions as Exceptions
|
||||
log = logging.getLogger("sessionmanager.session")
|
||||
|
||||
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):
|
||||
""" Decorator for checking if the user is logged in.
|
||||
Some functions may need this to avoid making unneeded calls."""
|
||||
def f(self, *args, **kwargs):
|
||||
if self.logged == True:
|
||||
fn(self, *args, **kwargs)
|
||||
else:
|
||||
raise Exceptions.NotLoggedSessionError("You are not logged in yet.")
|
||||
return f
|
||||
def _require_login(fn):
|
||||
""" Decorator for checking if the user is logged in.
|
||||
Some functions may need this to avoid making unneeded calls."""
|
||||
def f(self, *args, **kwargs):
|
||||
if self.logged == True:
|
||||
fn(self, *args, **kwargs)
|
||||
else:
|
||||
raise Exceptions.NotLoggedSessionError("You are not logged in yet.")
|
||||
return f
|
||||
|
||||
def _require_configuration(fn):
|
||||
""" Check if the user has a configured session."""
|
||||
def f(self, *args, **kwargs):
|
||||
if self.settings != None:
|
||||
fn(self, *args, **kwargs)
|
||||
else:
|
||||
raise Exceptions.NotConfiguredSessionError("Not configured.")
|
||||
return f
|
||||
def _require_configuration(fn):
|
||||
""" Check if the user has a configured session."""
|
||||
def f(self, *args, **kwargs):
|
||||
if self.settings != None:
|
||||
fn(self, *args, **kwargs)
|
||||
else:
|
||||
raise Exceptions.NotConfiguredSessionError("Not configured.")
|
||||
return f
|
||||
|
||||
def __init__(self, session_id):
|
||||
""" session_id (str): The name of the folder inside the config directory where the session is located."""
|
||||
super(baseSession, self).__init__()
|
||||
self.session_id = session_id
|
||||
self.logged = False
|
||||
self.settings = None
|
||||
self.db={}
|
||||
def __init__(self, session_id):
|
||||
""" session_id (str): The name of the folder inside the config directory where the session is located."""
|
||||
super(baseSession, self).__init__()
|
||||
self.session_id = session_id
|
||||
self.logged = False
|
||||
self.settings = None
|
||||
self.db={}
|
||||
|
||||
@property
|
||||
def is_logged(self):
|
||||
return self.logged
|
||||
@property
|
||||
def is_logged(self):
|
||||
return self.logged
|
||||
|
||||
def get_configuration(self):
|
||||
""" Get settings for a session."""
|
||||
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()
|
||||
def get_configuration(self):
|
||||
""" Get settings for a session."""
|
||||
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()
|
||||
|
||||
def init_sound(self):
|
||||
try: self.sound = sound.soundSystem(self.settings["sound"])
|
||||
except: pass
|
||||
def init_sound(self):
|
||||
try: self.sound = sound.soundSystem(self.settings["sound"])
|
||||
except: pass
|
||||
|
||||
@_require_configuration
|
||||
def login(self, verify_credentials=True):
|
||||
pass
|
||||
@_require_configuration
|
||||
def login(self, verify_credentials=True):
|
||||
pass
|
||||
|
||||
@_require_configuration
|
||||
def authorise(self):
|
||||
pass
|
||||
@_require_configuration
|
||||
def authorise(self):
|
||||
pass
|
||||
|
||||
def shelve(self):
|
||||
"""Shelve the database to allow for persistance."""
|
||||
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:
|
||||
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 shelve(self):
|
||||
"""Shelve the database to allow for persistance."""
|
||||
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:
|
||||
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):
|
||||
"""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
|
||||
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
|
||||
|
||||
|
@ -1,11 +1,4 @@
|
||||
# -*- 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
|
||||
system = platform.system()
|
||||
from . import utils
|
||||
@ -21,151 +14,151 @@ from .long_tweets import twishort, tweets
|
||||
log = logging.getLogger("compose")
|
||||
|
||||
def StripChars(s):
|
||||
"""Converts any html entities in s to their unicode-decoded equivalents and returns a string."""
|
||||
entity_re = re.compile(r"&(#\d+|\w+);")
|
||||
def matchFunc(match):
|
||||
"""Nested function to handle a match object.
|
||||
If we match &blah; and it's not found, &blah; will be returned.
|
||||
if we match #\d+, unichr(digits) will be returned.
|
||||
Else, a unicode string will be returned."""
|
||||
if match.group(1).startswith('#'): return chr(int(match.group(1)[1:]))
|
||||
replacement = html.entities.entitydefs.get(match.group(1), "&%s;" % match.group(1))
|
||||
return replacement
|
||||
return str(entity_re.sub(matchFunc, s))
|
||||
"""Converts any html entities in s to their unicode-decoded equivalents and returns a string."""
|
||||
entity_re = re.compile(r"&(#\d+|\w+);")
|
||||
def matchFunc(match):
|
||||
"""Nested function to handle a match object.
|
||||
If we match &blah; and it's not found, &blah; will be returned.
|
||||
if we match #\d+, unichr(digits) will be returned.
|
||||
Else, a unicode string will be returned."""
|
||||
if match.group(1).startswith('#'): return chr(int(match.group(1)[1:]))
|
||||
replacement = html.entities.entitydefs.get(match.group(1), "&%s;" % match.group(1))
|
||||
return replacement
|
||||
return str(entity_re.sub(matchFunc, s))
|
||||
|
||||
chars = "abcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
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."""
|
||||
if system == "Windows":
|
||||
original_date = arrow.get(tweet.created_at, locale="en")
|
||||
if relative_times == True:
|
||||
ts = original_date.humanize(locale=languageHandler.curLang[:2])
|
||||
else:
|
||||
ts = original_date.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2])
|
||||
else:
|
||||
ts = tweet.created_at
|
||||
if hasattr(tweet, "message"):
|
||||
value = "message"
|
||||
elif hasattr(tweet, "full_text"):
|
||||
value = "full_text"
|
||||
else:
|
||||
value = "text"
|
||||
if hasattr(tweet, "retweeted_status") and value != "message":
|
||||
text = StripChars(getattr(tweet.retweeted_status, value))
|
||||
else:
|
||||
text = StripChars(getattr(tweet, value))
|
||||
if show_screen_names:
|
||||
user = tweet.user.screen_name
|
||||
else:
|
||||
user = tweet.user.name
|
||||
source = re.sub(r"(?s)<.*?>", "", tweet.source)
|
||||
if hasattr(tweet, "retweeted_status"):
|
||||
if (hasattr(tweet, "message")) == False and tweet.retweeted_status.is_quote_status == False:
|
||||
text = "RT @%s: %s" % (tweet.retweeted_status.user.screen_name, text)
|
||||
elif tweet.retweeted_status.is_quote_status:
|
||||
text = "%s" % (text)
|
||||
else:
|
||||
text = "RT @%s: %s" % (tweet.retweeted_status.user.screen_name, text)
|
||||
if not hasattr(tweet, "message"):
|
||||
""" 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":
|
||||
original_date = arrow.get(tweet.created_at, locale="en")
|
||||
if relative_times == True:
|
||||
ts = original_date.humanize(locale=languageHandler.curLang[:2])
|
||||
else:
|
||||
ts = original_date.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2])
|
||||
else:
|
||||
ts = tweet.created_at
|
||||
if hasattr(tweet, "message"):
|
||||
value = "message"
|
||||
elif hasattr(tweet, "full_text"):
|
||||
value = "full_text"
|
||||
else:
|
||||
value = "text"
|
||||
if hasattr(tweet, "retweeted_status") and value != "message":
|
||||
text = StripChars(getattr(tweet.retweeted_status, value))
|
||||
else:
|
||||
text = StripChars(getattr(tweet, value))
|
||||
if show_screen_names:
|
||||
user = tweet.user.screen_name
|
||||
else:
|
||||
user = tweet.user.name
|
||||
source = re.sub(r"(?s)<.*?>", "", tweet.source)
|
||||
if hasattr(tweet, "retweeted_status"):
|
||||
if (hasattr(tweet, "message")) == False and tweet.retweeted_status.is_quote_status == False:
|
||||
text = "RT @%s: %s" % (tweet.retweeted_status.user.screen_name, text)
|
||||
elif tweet.retweeted_status.is_quote_status:
|
||||
text = "%s" % (text)
|
||||
else:
|
||||
text = "RT @%s: %s" % (tweet.retweeted_status.user.screen_name, text)
|
||||
if not hasattr(tweet, "message"):
|
||||
|
||||
if hasattr(tweet, "retweeted_status"):
|
||||
text = utils.expand_urls(text, tweet.retweeted_status.entities)
|
||||
else:
|
||||
text = utils.expand_urls(text, tweet.entities)
|
||||
if config.app['app-settings']['handle_longtweets']: pass
|
||||
return [user+", ", text, ts+", ", source]
|
||||
if hasattr(tweet, "retweeted_status"):
|
||||
text = utils.expand_urls(text, tweet.retweeted_status.entities)
|
||||
else:
|
||||
text = utils.expand_urls(text, tweet.entities)
|
||||
if config.app['app-settings']['handle_longtweets']: pass
|
||||
return [user+", ", text, ts+", ", source]
|
||||
|
||||
def compose_direct_message(item, db, relative_times, show_screen_names=False, session=None):
|
||||
if system == "Windows":
|
||||
# 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.
|
||||
original_date = arrow.get(int(item.created_timestamp))
|
||||
if relative_times == True:
|
||||
ts = original_date.humanize(locale=languageHandler.curLang[:2])
|
||||
else:
|
||||
ts = original_date.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2])
|
||||
else:
|
||||
ts = item.created_timestamp
|
||||
text = StripChars(item.message_create["message_data"]["text"])
|
||||
source = "DM"
|
||||
sender = session.get_user(item.message_create["sender_id"])
|
||||
if db["user_name"] == sender.screen_name:
|
||||
if show_screen_names:
|
||||
user = _(u"Dm to %s ") % (session.get_user(item.message_create["target"]["recipient_id"]).screen_name)
|
||||
else:
|
||||
user = _(u"Dm to %s ") % (session.get_user(item.message_create["target"]["recipient_id"]).name)
|
||||
else:
|
||||
if show_screen_names:
|
||||
user = sender.screen_name
|
||||
else:
|
||||
user = sender.name
|
||||
if text[-1] in chars: text=text+"."
|
||||
text = utils.expand_urls(text, item.message_create["message_data"]["entities"])
|
||||
return [user+", ", text, ts+", ", source]
|
||||
if system == "Windows":
|
||||
# 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.
|
||||
original_date = arrow.get(int(item.created_timestamp))
|
||||
if relative_times == True:
|
||||
ts = original_date.humanize(locale=languageHandler.curLang[:2])
|
||||
else:
|
||||
ts = original_date.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2])
|
||||
else:
|
||||
ts = item.created_timestamp
|
||||
text = StripChars(item.message_create["message_data"]["text"])
|
||||
source = "DM"
|
||||
sender = session.get_user(item.message_create["sender_id"])
|
||||
if db["user_name"] == sender.screen_name:
|
||||
if show_screen_names:
|
||||
user = _(u"Dm to %s ") % (session.get_user(item.message_create["target"]["recipient_id"]).screen_name)
|
||||
else:
|
||||
user = _(u"Dm to %s ") % (session.get_user(item.message_create["target"]["recipient_id"]).name)
|
||||
else:
|
||||
if show_screen_names:
|
||||
user = sender.screen_name
|
||||
else:
|
||||
user = sender.name
|
||||
if text[-1] in chars: text=text+"."
|
||||
text = utils.expand_urls(text, item.message_create["message_data"]["entities"])
|
||||
return [user+", ", text, ts+", ", source]
|
||||
|
||||
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."""
|
||||
if hasattr(quoted_tweet, "retweeted_status"):
|
||||
if hasattr(quoted_tweet.retweeted_status, "full_text"):
|
||||
value = "full_text"
|
||||
else:
|
||||
value = "text"
|
||||
text = StripChars(getattr(quoted_tweet.retweeted_status, value))
|
||||
else:
|
||||
if hasattr(quoted_tweet, "full_text"):
|
||||
value = "full_text"
|
||||
else:
|
||||
value = "text"
|
||||
text = StripChars(getattr(quoted_tweet, value))
|
||||
if show_screen_names:
|
||||
quoting_user = quoted_tweet.user.screen_name
|
||||
else:
|
||||
quoting_user = quoted_tweet.user.name
|
||||
source = quoted_tweet.source
|
||||
if hasattr(quoted_tweet, "retweeted_status"):
|
||||
text = "rt @%s: %s" % (quoted_tweet.retweeted_status.user.screen_name, text)
|
||||
if text[-1] in chars: text=text+"."
|
||||
original_user = original_tweet.user.screen_name
|
||||
if hasattr(original_tweet, "message"):
|
||||
original_text = original_tweet.message
|
||||
elif hasattr(original_tweet, "full_text"):
|
||||
original_text = StripChars(original_tweet.full_text)
|
||||
else:
|
||||
original_text = StripChars(original_tweet.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.entities["urls"].extend(original_tweet.entities["urls"])
|
||||
return quoted_tweet
|
||||
""" 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, "full_text"):
|
||||
value = "full_text"
|
||||
else:
|
||||
value = "text"
|
||||
text = StripChars(getattr(quoted_tweet.retweeted_status, value))
|
||||
else:
|
||||
if hasattr(quoted_tweet, "full_text"):
|
||||
value = "full_text"
|
||||
else:
|
||||
value = "text"
|
||||
text = StripChars(getattr(quoted_tweet, value))
|
||||
if show_screen_names:
|
||||
quoting_user = quoted_tweet.user.screen_name
|
||||
else:
|
||||
quoting_user = quoted_tweet.user.name
|
||||
source = quoted_tweet.source
|
||||
if hasattr(quoted_tweet, "retweeted_status"):
|
||||
text = "rt @%s: %s" % (quoted_tweet.retweeted_status.user.screen_name, text)
|
||||
if text[-1] in chars: text=text+"."
|
||||
original_user = original_tweet.user.screen_name
|
||||
if hasattr(original_tweet, "message"):
|
||||
original_text = original_tweet.message
|
||||
elif hasattr(original_tweet, "full_text"):
|
||||
original_text = StripChars(original_tweet.full_text)
|
||||
else:
|
||||
original_text = StripChars(original_tweet.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.entities["urls"].extend(original_tweet.entities["urls"])
|
||||
return quoted_tweet
|
||||
|
||||
def compose_followers_list(tweet, db, relative_times=True, show_screen_names=False, session=None):
|
||||
if system == "Windows":
|
||||
original_date = arrow.get(tweet.created_at, locale="en")
|
||||
if relative_times == True:
|
||||
ts = original_date.humanize(locale=languageHandler.curLang[:2])
|
||||
else:
|
||||
ts = original_date.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2])
|
||||
else:
|
||||
ts = tweet.created_at
|
||||
if hasattr(tweet, "status"):
|
||||
if system == "Windows":
|
||||
original_date2 = arrow.get(tweet.status.created_at, locale="en")
|
||||
if relative_times:
|
||||
ts2 = original_date2.humanize(locale=languageHandler.curLang[:2])
|
||||
else:
|
||||
ts2 = original_date2.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2])
|
||||
else:
|
||||
ts2 = _("Unavailable")
|
||||
else:
|
||||
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)]
|
||||
if system == "Windows":
|
||||
original_date = arrow.get(tweet.created_at, locale="en")
|
||||
if relative_times == True:
|
||||
ts = original_date.humanize(locale=languageHandler.curLang[:2])
|
||||
else:
|
||||
ts = original_date.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2])
|
||||
else:
|
||||
ts = tweet.created_at
|
||||
if hasattr(tweet, "status"):
|
||||
if system == "Windows":
|
||||
original_date2 = arrow.get(tweet.status.created_at, locale="en")
|
||||
if relative_times:
|
||||
ts2 = original_date2.humanize(locale=languageHandler.curLang[:2])
|
||||
else:
|
||||
ts2 = original_date2.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2])
|
||||
else:
|
||||
ts2 = _("Unavailable")
|
||||
else:
|
||||
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)]
|
||||
|
||||
def compose_list(list):
|
||||
name = list.name
|
||||
if list.description == None: description = _(u"No description available")
|
||||
else: description = list.description
|
||||
user = list.user.name
|
||||
members = str(list.member_count)
|
||||
if list.mode == "private": status = _(u"private")
|
||||
else: status = _(u"public")
|
||||
return [name, description, user, members, status]
|
||||
name = list.name
|
||||
if list.description == None: description = _(u"No description available")
|
||||
else: description = list.description
|
||||
user = list.user.name
|
||||
members = str(list.member_count)
|
||||
if list.mode == "private": status = _(u"private")
|
||||
else: status = _(u"public")
|
||||
return [name, description, user, members, status]
|
||||
|
@ -20,33 +20,33 @@ from __future__ import unicode_literals
|
||||
from sessions.twitter import utils
|
||||
|
||||
def is_long(tweet):
|
||||
""" Check if the passed tweet contains a quote in its metadata.
|
||||
tweet dict: a tweet dictionary.
|
||||
returns True if a quote is detected, False otherwise."""
|
||||
if hasattr(tweet, "quoted_status_id") and hasattr(tweet, "quoted_status"):
|
||||
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"):
|
||||
return tweet.retweeted_status.quoted_status_id
|
||||
return False
|
||||
""" Check if the passed tweet contains a quote in its metadata.
|
||||
tweet dict: a tweet dictionary.
|
||||
returns True if a quote is detected, False otherwise."""
|
||||
if hasattr(tweet, "quoted_status_id") and hasattr(tweet, "quoted_status"):
|
||||
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"):
|
||||
return tweet.retweeted_status.quoted_status_id
|
||||
return False
|
||||
|
||||
def clear_url(tweet):
|
||||
""" Reads data from a quoted tweet and removes the link to the Status from the tweet's text.
|
||||
tweet dict: a tweet dictionary.
|
||||
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, "full_text"):
|
||||
value = "full_text"
|
||||
else:
|
||||
value = "text"
|
||||
urls = utils.find_urls_in_text(getattr(tweet.retweeted_status, value))
|
||||
try: tweet.message = tweet.message.replace(urls[-1], "")
|
||||
except IndexError: pass
|
||||
else:
|
||||
if hasattr(tweet, "full_text"):
|
||||
value = "full_text"
|
||||
else:
|
||||
value = "text"
|
||||
urls = utils.find_urls_in_text(getattr(tweet, value))
|
||||
try: tweet.message = tweet.message.replace(urls[-1], "")
|
||||
except IndexError: pass
|
||||
return tweet
|
||||
""" Reads data from a quoted tweet and removes the link to the Status from the tweet's text.
|
||||
tweet dict: a tweet dictionary.
|
||||
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, "full_text"):
|
||||
value = "full_text"
|
||||
else:
|
||||
value = "text"
|
||||
urls = utils.find_urls_in_text(getattr(tweet.retweeted_status, value))
|
||||
try: tweet.message = tweet.message.replace(urls[-1], "")
|
||||
except IndexError: pass
|
||||
else:
|
||||
if hasattr(tweet, "full_text"):
|
||||
value = "full_text"
|
||||
else:
|
||||
value = "text"
|
||||
urls = utils.find_urls_in_text(getattr(tweet, value))
|
||||
try: tweet.message = tweet.message.replace(urls[-1], "")
|
||||
except IndexError: pass
|
||||
return tweet
|
||||
|
@ -28,77 +28,77 @@ from sessions.twitter import utils
|
||||
log = logging.getLogger("long_tweets.twishort")
|
||||
|
||||
def get_twishort_uri(url):
|
||||
""" Takes A twishort URl and returns the twishort ID.
|
||||
url str: an url like http://twishort.com/id.
|
||||
returns a twishort ID if the URL is valid, False otherwise."""
|
||||
try:
|
||||
return url.split("twishort.com/")[1]
|
||||
except ValueError:
|
||||
return False
|
||||
""" Takes A twishort URl and returns the twishort ID.
|
||||
url str: an url like http://twishort.com/id.
|
||||
returns a twishort ID if the URL is valid, False otherwise."""
|
||||
try:
|
||||
return url.split("twishort.com/")[1]
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
def is_long(tweet):
|
||||
""" Check if the passed tweet is made with Twishort.
|
||||
returns True if is a long tweet, False otherwise."""
|
||||
long = False
|
||||
for url in range(0, len(tweet.entities["urls"])):
|
||||
try:
|
||||
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"])
|
||||
except IndexError:
|
||||
pass
|
||||
# sometimes Twitter returns URL's with None objects, so let's take it.
|
||||
# see https://github.com/manuelcortez/TWBlue/issues/103
|
||||
except TypeError:
|
||||
pass
|
||||
if long == False and hasattr(tweet, "retweeted_status"):
|
||||
for url in range(0, len(tweet.retweeted_status.entities["urls"])):
|
||||
try:
|
||||
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"])
|
||||
except IndexError:
|
||||
pass
|
||||
except TypeError:
|
||||
pass
|
||||
return long
|
||||
""" Check if the passed tweet is made with Twishort.
|
||||
returns True if is a long tweet, False otherwise."""
|
||||
long = False
|
||||
for url in range(0, len(tweet.entities["urls"])):
|
||||
try:
|
||||
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"])
|
||||
except IndexError:
|
||||
pass
|
||||
# sometimes Twitter returns URL's with None objects, so let's take it.
|
||||
# see https://github.com/manuelcortez/TWBlue/issues/103
|
||||
except TypeError:
|
||||
pass
|
||||
if long == False and hasattr(tweet, "retweeted_status"):
|
||||
for url in range(0, len(tweet.retweeted_status.entities["urls"])):
|
||||
try:
|
||||
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"])
|
||||
except IndexError:
|
||||
pass
|
||||
except TypeError:
|
||||
pass
|
||||
return long
|
||||
|
||||
def get_full_text(uri):
|
||||
""" Get Twishort's full text.
|
||||
uri str: Twishort's identifier.
|
||||
returns the contents of the tweet."""
|
||||
try:
|
||||
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"]
|
||||
# Try to parse possible HTML entities.
|
||||
from sessions.twitter.compose import StripChars
|
||||
msg = StripChars(msg)
|
||||
return msg
|
||||
except:
|
||||
return False
|
||||
""" Get Twishort's full text.
|
||||
uri str: Twishort's identifier.
|
||||
returns the contents of the tweet."""
|
||||
try:
|
||||
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"]
|
||||
# Try to parse possible HTML entities.
|
||||
from sessions.twitter.compose import StripChars
|
||||
msg = StripChars(msg)
|
||||
return msg
|
||||
except:
|
||||
return False
|
||||
|
||||
def create_tweet(user_token, user_secret, text, media=0):
|
||||
""" 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.
|
||||
text str: Tweet text, max 10000 characters.
|
||||
media int: Not used currently.
|
||||
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)
|
||||
twishort_key=keys.keyring.get("twishort_api_key")
|
||||
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_update_ids_url = "http://api.twishort.com/1.1/update_ids.json"
|
||||
r=requests.Request('GET', x_auth_service_provider)
|
||||
prep=twitter.prepare_request(r)
|
||||
resp=twitter.send(prep)
|
||||
twitter.headers={
|
||||
'X-Auth-Service-Provider':x_auth_service_provider,
|
||||
'X-Verify-Credentials-Authorization':prep.headers['Authorization'],
|
||||
}
|
||||
data = {'api_key':twishort_key,
|
||||
"text": text.encode("utf-8"),
|
||||
"media": media}
|
||||
response = twitter.post(twishort_post_url, data=data)
|
||||
try:
|
||||
return response.json()["text_to_tweet"]
|
||||
except:
|
||||
print("There was a problem creating a long tweet")
|
||||
return 0
|
||||
""" 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.
|
||||
text str: Tweet text, max 10000 characters.
|
||||
media int: Not used currently.
|
||||
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)
|
||||
twishort_key=keys.keyring.get("twishort_api_key")
|
||||
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_update_ids_url = "http://api.twishort.com/1.1/update_ids.json"
|
||||
r=requests.Request('GET', x_auth_service_provider)
|
||||
prep=twitter.prepare_request(r)
|
||||
resp=twitter.send(prep)
|
||||
twitter.headers={
|
||||
'X-Auth-Service-Provider':x_auth_service_provider,
|
||||
'X-Verify-Credentials-Authorization':prep.headers['Authorization'],
|
||||
}
|
||||
data = {'api_key':twishort_key,
|
||||
"text": text.encode("utf-8"),
|
||||
"media": media}
|
||||
response = twitter.post(twishort_post_url, data=data)
|
||||
try:
|
||||
return response.json()["text_to_tweet"]
|
||||
except:
|
||||
print("There was a problem creating a long tweet")
|
||||
return 0
|
||||
|
@ -22,432 +22,432 @@ from .wxUI import authorisationDialog
|
||||
log = logging.getLogger("sessions.twitterSession")
|
||||
|
||||
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):
|
||||
""" Put new items in the local database.
|
||||
name str: The name for the buffer stored in the dictionary.
|
||||
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.
|
||||
returns the number of items that have been added in this execution"""
|
||||
if name == "direct_messages":
|
||||
return self.order_direct_messages(data)
|
||||
num = 0
|
||||
last_id = None
|
||||
if (name in self.db) == False:
|
||||
self.db[name] = []
|
||||
if ("users" in self.db) == False:
|
||||
self.db["users"] = {}
|
||||
if ignore_older and len(self.db[name]) > 0:
|
||||
if self.settings["general"]["reverse_timelines"] == False:
|
||||
last_id = self.db[name][0].id
|
||||
else:
|
||||
last_id = self.db[name][-1].id
|
||||
for i in data:
|
||||
if ignore_older and last_id != None:
|
||||
if i.id < last_id:
|
||||
log.error("Ignoring an older tweet... Last id: {0}, tweet id: {1}".format(last_id, i.id))
|
||||
continue
|
||||
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_long_tweet(i)
|
||||
if i == False: continue
|
||||
if self.settings["general"]["reverse_timelines"] == False: self.db[name].append(i)
|
||||
else: self.db[name].insert(0, i)
|
||||
num = num+1
|
||||
if hasattr(i, "user"):
|
||||
if (i.user.id in self.db["users"]) == False:
|
||||
self.db["users"][i.user.id] = i.user
|
||||
return num
|
||||
def order_buffer(self, name, data, ignore_older=True):
|
||||
""" Put new items in the local database.
|
||||
name str: The name for the buffer stored in the dictionary.
|
||||
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.
|
||||
returns the number of items that have been added in this execution"""
|
||||
if name == "direct_messages":
|
||||
return self.order_direct_messages(data)
|
||||
num = 0
|
||||
last_id = None
|
||||
if (name in self.db) == False:
|
||||
self.db[name] = []
|
||||
if ("users" in self.db) == False:
|
||||
self.db["users"] = {}
|
||||
if ignore_older and len(self.db[name]) > 0:
|
||||
if self.settings["general"]["reverse_timelines"] == False:
|
||||
last_id = self.db[name][0].id
|
||||
else:
|
||||
last_id = self.db[name][-1].id
|
||||
for i in data:
|
||||
if ignore_older and last_id != None:
|
||||
if i.id < last_id:
|
||||
log.error("Ignoring an older tweet... Last id: {0}, tweet id: {1}".format(last_id, i.id))
|
||||
continue
|
||||
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_long_tweet(i)
|
||||
if i == False: continue
|
||||
if self.settings["general"]["reverse_timelines"] == False: self.db[name].append(i)
|
||||
else: self.db[name].insert(0, i)
|
||||
num = num+1
|
||||
if hasattr(i, "user"):
|
||||
if (i.user.id in self.db["users"]) == False:
|
||||
self.db["users"][i.user.id] = i.user
|
||||
return num
|
||||
|
||||
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)
|
||||
name str: The name for the buffer stored in the dictionary.
|
||||
data list: A list with items and some information about cursors.
|
||||
returns the number of items that have been added in this execution"""
|
||||
num = 0
|
||||
if (name in self.db) == False:
|
||||
self.db[name] = []
|
||||
for i in data:
|
||||
if utils.find_item(i.id, self.db[name]) == None:
|
||||
if self.settings["general"]["reverse_timelines"] == False: self.db[name].append(i)
|
||||
else: self.db[name].insert(0, i)
|
||||
num = num+1
|
||||
return num
|
||||
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)
|
||||
name str: The name for the buffer stored in the dictionary.
|
||||
data list: A list with items and some information about cursors.
|
||||
returns the number of items that have been added in this execution"""
|
||||
num = 0
|
||||
if (name in self.db) == False:
|
||||
self.db[name] = []
|
||||
for i in data:
|
||||
if utils.find_item(i.id, self.db[name]) == None:
|
||||
if self.settings["general"]["reverse_timelines"] == False: self.db[name].append(i)
|
||||
else: self.db[name].insert(0, i)
|
||||
num = num+1
|
||||
return num
|
||||
|
||||
def order_direct_messages(self, data):
|
||||
""" Add incoming and sent direct messages to their corresponding database items.
|
||||
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."""
|
||||
incoming = 0
|
||||
sent = 0
|
||||
if ("direct_messages" in self.db) == False:
|
||||
self.db["direct_messages"] = []
|
||||
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.
|
||||
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 self.settings["general"]["reverse_timelines"] == False: self.db["sent_direct_messages"].append(i)
|
||||
else: self.db["sent_direct_messages"].insert(0, i)
|
||||
sent = sent+1
|
||||
else:
|
||||
if utils.find_item(i.id, self.db["direct_messages"]) == None:
|
||||
if self.settings["general"]["reverse_timelines"] == False: self.db["direct_messages"].append(i)
|
||||
else: self.db["direct_messages"].insert(0, i)
|
||||
incoming = incoming+1
|
||||
pub.sendMessage("sent-dms-updated", total=sent, account=self.db["user_name"])
|
||||
return incoming
|
||||
def order_direct_messages(self, data):
|
||||
""" Add incoming and sent direct messages to their corresponding database items.
|
||||
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."""
|
||||
incoming = 0
|
||||
sent = 0
|
||||
if ("direct_messages" in self.db) == False:
|
||||
self.db["direct_messages"] = []
|
||||
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.
|
||||
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 self.settings["general"]["reverse_timelines"] == False: self.db["sent_direct_messages"].append(i)
|
||||
else: self.db["sent_direct_messages"].insert(0, i)
|
||||
sent = sent+1
|
||||
else:
|
||||
if utils.find_item(i.id, self.db["direct_messages"]) == None:
|
||||
if self.settings["general"]["reverse_timelines"] == False: self.db["direct_messages"].append(i)
|
||||
else: self.db["direct_messages"].insert(0, i)
|
||||
incoming = incoming+1
|
||||
pub.sendMessage("sent-dms-updated", total=sent, account=self.db["user_name"])
|
||||
return incoming
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Session, self).__init__(*args, **kwargs)
|
||||
# Adds here the optional cursors objects.
|
||||
cursors = dict(direct_messages=-1)
|
||||
self.db["cursors"] = cursors
|
||||
self.reconnection_function_active = False
|
||||
self.counter = 0
|
||||
self.lists = []
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Session, self).__init__(*args, **kwargs)
|
||||
# Adds here the optional cursors objects.
|
||||
cursors = dict(direct_messages=-1)
|
||||
self.db["cursors"] = cursors
|
||||
self.reconnection_function_active = False
|
||||
self.counter = 0
|
||||
self.lists = []
|
||||
|
||||
# @_require_configuration
|
||||
def login(self, verify_credentials=True):
|
||||
""" Log into twitter using credentials from settings.
|
||||
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:
|
||||
try:
|
||||
log.debug("Logging in to twitter...")
|
||||
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.twitter = tweepy.API(self.auth)
|
||||
if verify_credentials == True:
|
||||
self.credentials = self.twitter.verify_credentials()
|
||||
self.logged = True
|
||||
log.debug("Logged.")
|
||||
self.counter = 0
|
||||
except IOError:
|
||||
log.error("The login attempt failed.")
|
||||
self.logged = False
|
||||
else:
|
||||
self.logged = False
|
||||
raise Exceptions.RequireCredentialsSessionError
|
||||
def login(self, verify_credentials=True):
|
||||
""" Log into twitter using credentials from settings.
|
||||
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:
|
||||
try:
|
||||
log.debug("Logging in to twitter...")
|
||||
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.twitter = tweepy.API(self.auth)
|
||||
if verify_credentials == True:
|
||||
self.credentials = self.twitter.verify_credentials()
|
||||
self.logged = True
|
||||
log.debug("Logged.")
|
||||
self.counter = 0
|
||||
except IOError:
|
||||
log.error("The login attempt failed.")
|
||||
self.logged = False
|
||||
else:
|
||||
self.logged = False
|
||||
raise Exceptions.RequireCredentialsSessionError
|
||||
|
||||
# @_require_configuration
|
||||
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()"""
|
||||
if self.logged == True:
|
||||
raise Exceptions.AlreadyAuthorisedError("The authorisation process is not needed at this time.")
|
||||
else:
|
||||
self.auth = tweepy.OAuthHandler(keyring.get("api_key"), keyring.get("api_secret"))
|
||||
redirect_url = self.auth.get_authorization_url()
|
||||
webbrowser.open_new_tab(redirect_url)
|
||||
self.authorisation_dialog = authorisationDialog()
|
||||
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.ShowModal()
|
||||
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()"""
|
||||
if self.logged == True:
|
||||
raise Exceptions.AlreadyAuthorisedError("The authorisation process is not needed at this time.")
|
||||
else:
|
||||
self.auth = tweepy.OAuthHandler(keyring.get("api_key"), keyring.get("api_secret"))
|
||||
redirect_url = self.auth.get_authorization_url()
|
||||
webbrowser.open_new_tab(redirect_url)
|
||||
self.authorisation_dialog = authorisationDialog()
|
||||
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.ShowModal()
|
||||
|
||||
def verify_authorisation(self, pincode):
|
||||
self.auth.get_access_token(pincode)
|
||||
self.settings["twitter"]["user_key"] = self.auth.access_token
|
||||
self.settings["twitter"]["user_secret"] = self.auth.access_token_secret
|
||||
self.settings.write()
|
||||
del self.auth
|
||||
def verify_authorisation(self, pincode):
|
||||
self.auth.get_access_token(pincode)
|
||||
self.settings["twitter"]["user_key"] = self.auth.access_token
|
||||
self.settings["twitter"]["user_secret"] = self.auth.access_token_secret
|
||||
self.settings.write()
|
||||
del self.auth
|
||||
|
||||
def authorisation_cancelled(self, *args, **kwargs):
|
||||
""" Destroy the authorization dialog. """
|
||||
self.authorisation_dialog.Destroy()
|
||||
del self.authorisation_dialog
|
||||
def authorisation_cancelled(self, *args, **kwargs):
|
||||
""" Destroy the authorization dialog. """
|
||||
self.authorisation_dialog.Destroy()
|
||||
del self.authorisation_dialog
|
||||
|
||||
def authorisation_accepted(self, *args, **kwargs):
|
||||
""" Gets the PIN code entered by user and validate it through Twitter."""
|
||||
pincode = self.authorisation_dialog.text.GetValue()
|
||||
self.verify_authorisation(pincode)
|
||||
self.authorisation_dialog.Destroy()
|
||||
def authorisation_accepted(self, *args, **kwargs):
|
||||
""" Gets the PIN code entered by user and validate it through Twitter."""
|
||||
pincode = self.authorisation_dialog.text.GetValue()
|
||||
self.verify_authorisation(pincode)
|
||||
self.authorisation_dialog.Destroy()
|
||||
|
||||
def get_more_items(self, update_function, users=False, dm=False, name=None, *args, **kwargs):
|
||||
""" Get more items for twitter objects.
|
||||
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).
|
||||
name str: name of the database item to put new element in."""
|
||||
results = []
|
||||
if "cursor" in kwargs and kwargs["cursor"] == 0:
|
||||
output.speak(_(u"There are no more items to retrieve in this buffer."))
|
||||
return
|
||||
data = getattr(self.twitter, update_function)(*args, **kwargs)
|
||||
if users == True:
|
||||
if type(data) == dict and "next_cursor" in data:
|
||||
if "next_cursor" in data: # There are more objects to retrieve.
|
||||
self.db[name]["cursor"] = data["next_cursor"]
|
||||
else: # Set cursor to 0, wich means no more items available.
|
||||
self.db[name]["cursor"] = 0
|
||||
for i in data["users"]: results.append(i)
|
||||
elif type(data) == list:
|
||||
results.extend(data[1:])
|
||||
elif dm == True:
|
||||
if "next_cursor" in data: # There are more objects to retrieve.
|
||||
self.db[name]["cursor"] = data["next_cursor"]
|
||||
else: # Set cursor to 0, wich means no more items available.
|
||||
self.db[name]["cursor"] = 0
|
||||
for i in data["events"]: results.append(i)
|
||||
else:
|
||||
results.extend(data[1:])
|
||||
return results
|
||||
def get_more_items(self, update_function, users=False, dm=False, name=None, *args, **kwargs):
|
||||
""" Get more items for twitter objects.
|
||||
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).
|
||||
name str: name of the database item to put new element in."""
|
||||
results = []
|
||||
if "cursor" in kwargs and kwargs["cursor"] == 0:
|
||||
output.speak(_(u"There are no more items to retrieve in this buffer."))
|
||||
return
|
||||
data = getattr(self.twitter, update_function)(*args, **kwargs)
|
||||
if users == True:
|
||||
if type(data) == dict and "next_cursor" in data:
|
||||
if "next_cursor" in data: # There are more objects to retrieve.
|
||||
self.db[name]["cursor"] = data["next_cursor"]
|
||||
else: # Set cursor to 0, wich means no more items available.
|
||||
self.db[name]["cursor"] = 0
|
||||
for i in data["users"]: results.append(i)
|
||||
elif type(data) == list:
|
||||
results.extend(data[1:])
|
||||
elif dm == True:
|
||||
if "next_cursor" in data: # There are more objects to retrieve.
|
||||
self.db[name]["cursor"] = data["next_cursor"]
|
||||
else: # Set cursor to 0, wich means no more items available.
|
||||
self.db[name]["cursor"] = 0
|
||||
for i in data["events"]: results.append(i)
|
||||
else:
|
||||
results.extend(data[1:])
|
||||
return results
|
||||
|
||||
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.
|
||||
If twitter returns an error, it will not call the method anymore.
|
||||
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.
|
||||
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.
|
||||
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"."""
|
||||
finished = False
|
||||
tries = 0
|
||||
if preexec_message:
|
||||
output.speak(preexec_message, True)
|
||||
while finished==False and tries < 25:
|
||||
try:
|
||||
val = getattr(self.twitter, call_name)(*args, **kwargs)
|
||||
finished = True
|
||||
except TweepError as e:
|
||||
output.speak(e.reason)
|
||||
val = None
|
||||
if e.error_code != 403 and e.error_code != 404:
|
||||
tries = tries+1
|
||||
time.sleep(5)
|
||||
elif report_failure and hasattr(e, 'reason'):
|
||||
output.speak(_("%s failed. Reason: %s") % (action, e.reason))
|
||||
finished = True
|
||||
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.
|
||||
If twitter returns an error, it will not call the method anymore.
|
||||
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.
|
||||
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.
|
||||
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"."""
|
||||
finished = False
|
||||
tries = 0
|
||||
if preexec_message:
|
||||
output.speak(preexec_message, True)
|
||||
while finished==False and tries < 25:
|
||||
try:
|
||||
val = getattr(self.twitter, call_name)(*args, **kwargs)
|
||||
finished = True
|
||||
except TweepError as e:
|
||||
output.speak(e.reason)
|
||||
val = None
|
||||
if e.error_code != 403 and e.error_code != 404:
|
||||
tries = tries+1
|
||||
time.sleep(5)
|
||||
elif report_failure and hasattr(e, 'reason'):
|
||||
output.speak(_("%s failed. Reason: %s") % (action, e.reason))
|
||||
finished = True
|
||||
# except:
|
||||
# tries = tries + 1
|
||||
# time.sleep(5)
|
||||
if report_success:
|
||||
output.speak(_("%s succeeded.") % action)
|
||||
if _sound != None: self.sound.play(_sound)
|
||||
return val
|
||||
if report_success:
|
||||
output.speak(_("%s succeeded.") % action)
|
||||
if _sound != None: self.sound.play(_sound)
|
||||
return val
|
||||
|
||||
def search(self, name, *args, **kwargs):
|
||||
""" Search in twitter, passing args and kwargs as arguments to the Twython function."""
|
||||
tl = self.twitter.search(*args, **kwargs)
|
||||
tl.reverse()
|
||||
return tl
|
||||
def search(self, name, *args, **kwargs):
|
||||
""" Search in twitter, passing args and kwargs as arguments to the Twython function."""
|
||||
tl = self.twitter.search(*args, **kwargs)
|
||||
tl.reverse()
|
||||
return tl
|
||||
|
||||
# @_require_login
|
||||
def get_favourites_timeline(self, name, *args, **kwargs):
|
||||
""" Gets favourites for the authenticated user or a friend or follower.
|
||||
name str: Name for storage in the database.
|
||||
args and kwargs are passed directly to the Twython function."""
|
||||
tl = self.call_paged("favorites", *args, **kwargs)
|
||||
return self.order_buffer(name, tl)
|
||||
def get_favourites_timeline(self, name, *args, **kwargs):
|
||||
""" Gets favourites for the authenticated user or a friend or follower.
|
||||
name str: Name for storage in the database.
|
||||
args and kwargs are passed directly to the Twython function."""
|
||||
tl = self.call_paged("favorites", *args, **kwargs)
|
||||
return self.order_buffer(name, tl)
|
||||
|
||||
def call_paged(self, update_function, *args, **kwargs):
|
||||
""" Makes a call to the Twitter API methods several times. Useful for get methods.
|
||||
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
|
||||
args and kwargs are passed to update_function.
|
||||
returns a list with all items retrieved."""
|
||||
max = 0
|
||||
results = []
|
||||
data = getattr(self.twitter, update_function)(count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs)
|
||||
results.extend(data)
|
||||
for i in range(0, max):
|
||||
if i == 0: max_id = results[-1].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)
|
||||
results.extend(data)
|
||||
results.reverse()
|
||||
return results
|
||||
def call_paged(self, update_function, *args, **kwargs):
|
||||
""" Makes a call to the Twitter API methods several times. Useful for get methods.
|
||||
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
|
||||
args and kwargs are passed to update_function.
|
||||
returns a list with all items retrieved."""
|
||||
max = 0
|
||||
results = []
|
||||
data = getattr(self.twitter, update_function)(count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs)
|
||||
results.extend(data)
|
||||
for i in range(0, max):
|
||||
if i == 0: max_id = results[-1].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)
|
||||
results.extend(data)
|
||||
results.reverse()
|
||||
return results
|
||||
|
||||
# @_require_login
|
||||
def get_user_info(self):
|
||||
""" Retrieves some information required by TWBlue for setup."""
|
||||
f = self.twitter.get_settings()
|
||||
sn = f["screen_name"]
|
||||
self.settings["twitter"]["user_name"] = sn
|
||||
self.db["user_name"] = sn
|
||||
self.db["user_id"] = self.twitter.get_user(screen_name=sn).id
|
||||
try:
|
||||
self.db["utc_offset"] = f["time_zone"]["utc_offset"]
|
||||
except KeyError:
|
||||
self.db["utc_offset"] = -time.timezone
|
||||
# Get twitter's supported languages and save them in a global variable
|
||||
#so we won't call to this method once per session.
|
||||
if len(application.supported_languages) == 0:
|
||||
application.supported_languages = self.twitter.supported_languages()
|
||||
self.get_lists()
|
||||
self.get_muted_users()
|
||||
self.settings.write()
|
||||
def get_user_info(self):
|
||||
""" Retrieves some information required by TWBlue for setup."""
|
||||
f = self.twitter.get_settings()
|
||||
sn = f["screen_name"]
|
||||
self.settings["twitter"]["user_name"] = sn
|
||||
self.db["user_name"] = sn
|
||||
self.db["user_id"] = self.twitter.get_user(screen_name=sn).id
|
||||
try:
|
||||
self.db["utc_offset"] = f["time_zone"]["utc_offset"]
|
||||
except KeyError:
|
||||
self.db["utc_offset"] = -time.timezone
|
||||
# Get twitter's supported languages and save them in a global variable
|
||||
#so we won't call to this method once per session.
|
||||
if len(application.supported_languages) == 0:
|
||||
application.supported_languages = self.twitter.supported_languages()
|
||||
self.get_lists()
|
||||
self.get_muted_users()
|
||||
self.settings.write()
|
||||
|
||||
# @_require_login
|
||||
def get_lists(self):
|
||||
""" 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)
|
||||
def get_lists(self):
|
||||
""" 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)
|
||||
|
||||
# @_require_login
|
||||
def get_muted_users(self):
|
||||
""" Gets muted users (oh really?)."""
|
||||
self.db["muted_users"] = self.twitter.mutes_ids()
|
||||
def get_muted_users(self):
|
||||
""" Gets muted users (oh really?)."""
|
||||
self.db["muted_users"] = self.twitter.mutes_ids()
|
||||
|
||||
# @_require_login
|
||||
def get_stream(self, name, function, *args, **kwargs):
|
||||
""" Retrieves the items for a regular stream.
|
||||
name str: Name to save items to the database.
|
||||
function str: A function to get the items."""
|
||||
last_id = -1
|
||||
if name in self.db:
|
||||
try:
|
||||
if self.db[name][0]["id"] > self.db[name][-1]["id"]:
|
||||
last_id = self.db[name][0]["id"]
|
||||
else:
|
||||
last_id = self.db[name][-1]["id"]
|
||||
except IndexError:
|
||||
pass
|
||||
tl = self.call_paged(function, sinze_id=last_id, *args, **kwargs)
|
||||
self.order_buffer(name, tl)
|
||||
def get_stream(self, name, function, *args, **kwargs):
|
||||
""" Retrieves the items for a regular stream.
|
||||
name str: Name to save items to the database.
|
||||
function str: A function to get the items."""
|
||||
last_id = -1
|
||||
if name in self.db:
|
||||
try:
|
||||
if self.db[name][0]["id"] > self.db[name][-1]["id"]:
|
||||
last_id = self.db[name][0]["id"]
|
||||
else:
|
||||
last_id = self.db[name][-1]["id"]
|
||||
except IndexError:
|
||||
pass
|
||||
tl = self.call_paged(function, sinze_id=last_id, *args, **kwargs)
|
||||
self.order_buffer(name, tl)
|
||||
|
||||
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.
|
||||
name str: Name to save it in the database.
|
||||
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".
|
||||
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."""
|
||||
items_ = []
|
||||
try:
|
||||
if "cursor" in self.db[name] and get_previous:
|
||||
cursor = self.db[name]["cursor"]
|
||||
else:
|
||||
cursor = -1
|
||||
except KeyError:
|
||||
cursor = -1
|
||||
if cursor != -1:
|
||||
tl = getattr(self.twitter, function)(cursor=cursor, count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs)
|
||||
else:
|
||||
tl = getattr(self.twitter, function)(count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs)
|
||||
tl[items].reverse()
|
||||
num = self.order_cursored_buffer(name, tl[items])
|
||||
# Recently, Twitter's new endpoints have cursor if there are more results.
|
||||
if "next_cursor" in tl:
|
||||
self.db[name]["cursor"] = tl["next_cursor"]
|
||||
else:
|
||||
self.db[name]["cursor"] = 0
|
||||
return num
|
||||
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.
|
||||
name str: Name to save it in the database.
|
||||
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".
|
||||
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."""
|
||||
items_ = []
|
||||
try:
|
||||
if "cursor" in self.db[name] and get_previous:
|
||||
cursor = self.db[name]["cursor"]
|
||||
else:
|
||||
cursor = -1
|
||||
except KeyError:
|
||||
cursor = -1
|
||||
if cursor != -1:
|
||||
tl = getattr(self.twitter, function)(cursor=cursor, count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs)
|
||||
else:
|
||||
tl = getattr(self.twitter, function)(count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs)
|
||||
tl[items].reverse()
|
||||
num = self.order_cursored_buffer(name, tl[items])
|
||||
# Recently, Twitter's new endpoints have cursor if there are more results.
|
||||
if "next_cursor" in tl:
|
||||
self.db[name]["cursor"] = tl["next_cursor"]
|
||||
else:
|
||||
self.db[name]["cursor"] = 0
|
||||
return num
|
||||
|
||||
def check_connection(self):
|
||||
""" Restart the Twitter object every 5 executions. It is useful for dealing with requests timeout and other oddities."""
|
||||
log.debug("Executing check connection...")
|
||||
self.counter += 1
|
||||
if self.counter >= 4:
|
||||
log.debug("Restarting connection after 5 minutes.")
|
||||
del self.twitter
|
||||
self.logged = False
|
||||
self.login(False)
|
||||
self.counter = 0
|
||||
def check_connection(self):
|
||||
""" Restart the Twitter object every 5 executions. It is useful for dealing with requests timeout and other oddities."""
|
||||
log.debug("Executing check connection...")
|
||||
self.counter += 1
|
||||
if self.counter >= 4:
|
||||
log.debug("Restarting connection after 5 minutes.")
|
||||
del self.twitter
|
||||
self.logged = False
|
||||
self.login(False)
|
||||
self.counter = 0
|
||||
|
||||
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.
|
||||
tweet dict: A tweet dictionary.
|
||||
Returns a quoted tweet or the original tweet if is not a quote"""
|
||||
status = tweets.is_long(tweet)
|
||||
if status != False and config.app["app-settings"]["handle_longtweets"]:
|
||||
quoted_tweet = self.get_quoted_tweet(tweet)
|
||||
return quoted_tweet
|
||||
return 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.
|
||||
tweet dict: A tweet dictionary.
|
||||
Returns a quoted tweet or the original tweet if is not a quote"""
|
||||
status = tweets.is_long(tweet)
|
||||
if status != False and config.app["app-settings"]["handle_longtweets"]:
|
||||
quoted_tweet = self.get_quoted_tweet(tweet)
|
||||
return quoted_tweet
|
||||
return tweet
|
||||
|
||||
def get_quoted_tweet(self, tweet):
|
||||
""" Process a tweet and extract all information related to the quote. """
|
||||
quoted_tweet = tweet
|
||||
if hasattr(tweet, "full_text"):
|
||||
value = "full_text"
|
||||
else:
|
||||
value = "text"
|
||||
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"):
|
||||
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"):
|
||||
original_tweet = quoted_tweet.retweeted_status.quoted_status
|
||||
else:
|
||||
return quoted_tweet
|
||||
original_tweet = self.check_long_tweet(original_tweet)
|
||||
if hasattr(original_tweet, "full_text"):
|
||||
value = "full_text"
|
||||
elif hasattr(original_tweet, "message"):
|
||||
value = "message"
|
||||
else:
|
||||
value = "text"
|
||||
setattr(original_tweet, value, utils.expand_urls(getattr(original_tweet, value), original_tweet.entities))
|
||||
return compose.compose_quoted_tweet(quoted_tweet, original_tweet)
|
||||
def get_quoted_tweet(self, tweet):
|
||||
""" Process a tweet and extract all information related to the quote. """
|
||||
quoted_tweet = tweet
|
||||
if hasattr(tweet, "full_text"):
|
||||
value = "full_text"
|
||||
else:
|
||||
value = "text"
|
||||
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"):
|
||||
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"):
|
||||
original_tweet = quoted_tweet.retweeted_status.quoted_status
|
||||
else:
|
||||
return quoted_tweet
|
||||
original_tweet = self.check_long_tweet(original_tweet)
|
||||
if hasattr(original_tweet, "full_text"):
|
||||
value = "full_text"
|
||||
elif hasattr(original_tweet, "message"):
|
||||
value = "message"
|
||||
else:
|
||||
value = "text"
|
||||
setattr(original_tweet, value, utils.expand_urls(getattr(original_tweet, value), original_tweet.entities))
|
||||
return compose.compose_quoted_tweet(quoted_tweet, original_tweet)
|
||||
|
||||
def check_long_tweet(self, tweet):
|
||||
""" Process a tweet and add extra info if it's a long tweet made with Twyshort.
|
||||
tweet dict: a tweet object.
|
||||
returns a tweet with a new argument message, or original tweet if it's not a long tweet."""
|
||||
long = twishort.is_long(tweet)
|
||||
if long != False and config.app["app-settings"]["handle_longtweets"]:
|
||||
message = twishort.get_full_text(long)
|
||||
if hasattr(tweet, "quoted_status"):
|
||||
tweet.quoted_status.message = message
|
||||
if tweet.quoted_status.message == False: return False
|
||||
tweet.quoted_status.twishort = True
|
||||
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 hasattr(tweet.quoted_status, "retweeted_status") and tweet.retweeted_status.user.screen_name == i["screen_name"]:
|
||||
continue
|
||||
tweet.quoted_status.message = u"@%s %s" % (i["screen_name"], tweet.message)
|
||||
else:
|
||||
tweet.message = message
|
||||
if tweet.message == False: return False
|
||||
tweet.twishort = True
|
||||
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 hasattr(tweet, "retweeted_status") and tweet.retweeted_status.user.screen_name == i["screen_name"]:
|
||||
continue
|
||||
return tweet
|
||||
def check_long_tweet(self, tweet):
|
||||
""" Process a tweet and add extra info if it's a long tweet made with Twyshort.
|
||||
tweet dict: a tweet object.
|
||||
returns a tweet with a new argument message, or original tweet if it's not a long tweet."""
|
||||
long = twishort.is_long(tweet)
|
||||
if long != False and config.app["app-settings"]["handle_longtweets"]:
|
||||
message = twishort.get_full_text(long)
|
||||
if hasattr(tweet, "quoted_status"):
|
||||
tweet.quoted_status.message = message
|
||||
if tweet.quoted_status.message == False: return False
|
||||
tweet.quoted_status.twishort = True
|
||||
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 hasattr(tweet.quoted_status, "retweeted_status") and tweet.retweeted_status.user.screen_name == i["screen_name"]:
|
||||
continue
|
||||
tweet.quoted_status.message = u"@%s %s" % (i["screen_name"], tweet.message)
|
||||
else:
|
||||
tweet.message = message
|
||||
if tweet.message == False: return False
|
||||
tweet.twishort = True
|
||||
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 hasattr(tweet, "retweeted_status") and tweet.retweeted_status.user.screen_name == i["screen_name"]:
|
||||
continue
|
||||
return tweet
|
||||
|
||||
def get_user(self, id):
|
||||
""" Returns an user object associated with an ID.
|
||||
id str: User identifier, provided by Twitter.
|
||||
returns a tweepy user object."""
|
||||
if ("users" in self.db) == False or (id in self.db["users"]) == False:
|
||||
try:
|
||||
user = self.twitter.get_user(id=id)
|
||||
except TweepError as err:
|
||||
user = UserModel(None)
|
||||
user.screen_name = "deleted_user"
|
||||
user.id = id
|
||||
user.name = _("Deleted account")
|
||||
user.id_str = id
|
||||
self.db["users"][user.id_str] = user
|
||||
return user
|
||||
else:
|
||||
return self.db["users"][id]
|
||||
def get_user(self, id):
|
||||
""" Returns an user object associated with an ID.
|
||||
id str: User identifier, provided by Twitter.
|
||||
returns a tweepy user object."""
|
||||
if ("users" in self.db) == False or (id in self.db["users"]) == False:
|
||||
try:
|
||||
user = self.twitter.get_user(id=id)
|
||||
except TweepError as err:
|
||||
user = UserModel(None)
|
||||
user.screen_name = "deleted_user"
|
||||
user.id = id
|
||||
user.name = _("Deleted account")
|
||||
user.id_str = id
|
||||
self.db["users"][user.id_str] = user
|
||||
return user
|
||||
else:
|
||||
return self.db["users"][id]
|
||||
|
||||
def get_user_by_screen_name(self, screen_name):
|
||||
""" Returns an user identifier associated with a screen_name.
|
||||
screen_name str: User name, such as tw_blue2, provided by Twitter.
|
||||
returns an user ID."""
|
||||
if ("users" in self.db) == False:
|
||||
user = utils.if_user_exists(self.twitter, screen_name)
|
||||
self.db["users"][user["id_str"]] = user
|
||||
return user["id_str"]
|
||||
else:
|
||||
for i in list(self.db["users"].keys()):
|
||||
if self.db["users"][i].screen_name == screen_name:
|
||||
return self.db["users"][i].id_str
|
||||
user = utils.if_user_exists(self.twitter, screen_name)
|
||||
self.db["users"][user.id_str] = user
|
||||
return user.id_str
|
||||
def get_user_by_screen_name(self, screen_name):
|
||||
""" Returns an user identifier associated with a screen_name.
|
||||
screen_name str: User name, such as tw_blue2, provided by Twitter.
|
||||
returns an user ID."""
|
||||
if ("users" in self.db) == False:
|
||||
user = utils.if_user_exists(self.twitter, screen_name)
|
||||
self.db["users"][user["id_str"]] = user
|
||||
return user["id_str"]
|
||||
else:
|
||||
for i in list(self.db["users"].keys()):
|
||||
if self.db["users"][i].screen_name == screen_name:
|
||||
return self.db["users"][i].id_str
|
||||
user = utils.if_user_exists(self.twitter, screen_name)
|
||||
self.db["users"][user.id_str] = user
|
||||
return user.id_str
|
||||
|
||||
def save_users(self, user_ids):
|
||||
""" Adds all new users to the users database. """
|
||||
if len(user_ids) == 0:
|
||||
return
|
||||
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"]]
|
||||
# Remove duplicates
|
||||
users_to_retrieve = list(dict.fromkeys(users_to_retrieve))
|
||||
if len(users_to_retrieve) == 0:
|
||||
return
|
||||
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")
|
||||
for user in users:
|
||||
self.db["users"][user.id_str] = user
|
||||
log.debug("Added %d new users" % (len(users)))
|
||||
def save_users(self, user_ids):
|
||||
""" Adds all new users to the users database. """
|
||||
if len(user_ids) == 0:
|
||||
return
|
||||
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"]]
|
||||
# Remove duplicates
|
||||
users_to_retrieve = list(dict.fromkeys(users_to_retrieve))
|
||||
if len(users_to_retrieve) == 0:
|
||||
return
|
||||
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")
|
||||
for user in users:
|
||||
self.db["users"][user.id_str] = user
|
||||
log.debug("Added %d new users" % (len(users)))
|
||||
|
@ -19,198 +19,198 @@ url_re2 = re.compile("(?:\w+://|www\.)[^ ,.?!#%=+][^ \\n\\t]*")
|
||||
bad_chars = '\'\\\n.,[](){}:;"'
|
||||
|
||||
def find_urls_in_text(text):
|
||||
return url_re2.findall(text)
|
||||
return url_re2.findall(text)
|
||||
|
||||
def find_urls (tweet):
|
||||
urls = []
|
||||
# Let's add URLS from tweet entities.
|
||||
if hasattr(tweet, "message_create"):
|
||||
entities = tweet.message_create["message_data"]["entities"]
|
||||
else:
|
||||
entities = tweet.entities
|
||||
for i in entities["urls"]:
|
||||
if i["expanded_url"] not in urls:
|
||||
urls.append(i["expanded_url"])
|
||||
if hasattr(tweet, "quoted_status"):
|
||||
for i in tweet.quoted_status.entities["urls"]:
|
||||
if i["expanded_url"] not in urls:
|
||||
urls.append(i["expanded_url"])
|
||||
if hasattr(tweet, "retweeted_status"):
|
||||
for i in tweet.retweeted_status.entities["urls"]:
|
||||
if i["expanded_url"] not in urls:
|
||||
urls.append(i["expanded_url"])
|
||||
if hasattr(tweet["retweeted_status"], "quoted_status"):
|
||||
for i in tweet.retweeted_status.quoted_status.entities["urls"]:
|
||||
if i["expanded_url"] not in urls:
|
||||
urls.append(i["expanded_url"])
|
||||
if hasattr(tweet, "message"):
|
||||
i = "message"
|
||||
elif hasattr(tweet, "full_text"):
|
||||
i = "full_text"
|
||||
else:
|
||||
i = "text"
|
||||
if hasattr(tweet, "message_create"):
|
||||
extracted_urls = find_urls_in_text(tweet.message_create["message_data"]["text"])
|
||||
else:
|
||||
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).
|
||||
for i in extracted_urls:
|
||||
if i not in urls and "https://t.co" not in i:
|
||||
urls.append(i)
|
||||
return urls
|
||||
urls = []
|
||||
# Let's add URLS from tweet entities.
|
||||
if hasattr(tweet, "message_create"):
|
||||
entities = tweet.message_create["message_data"]["entities"]
|
||||
else:
|
||||
entities = tweet.entities
|
||||
for i in entities["urls"]:
|
||||
if i["expanded_url"] not in urls:
|
||||
urls.append(i["expanded_url"])
|
||||
if hasattr(tweet, "quoted_status"):
|
||||
for i in tweet.quoted_status.entities["urls"]:
|
||||
if i["expanded_url"] not in urls:
|
||||
urls.append(i["expanded_url"])
|
||||
if hasattr(tweet, "retweeted_status"):
|
||||
for i in tweet.retweeted_status.entities["urls"]:
|
||||
if i["expanded_url"] not in urls:
|
||||
urls.append(i["expanded_url"])
|
||||
if hasattr(tweet["retweeted_status"], "quoted_status"):
|
||||
for i in tweet.retweeted_status.quoted_status.entities["urls"]:
|
||||
if i["expanded_url"] not in urls:
|
||||
urls.append(i["expanded_url"])
|
||||
if hasattr(tweet, "message"):
|
||||
i = "message"
|
||||
elif hasattr(tweet, "full_text"):
|
||||
i = "full_text"
|
||||
else:
|
||||
i = "text"
|
||||
if hasattr(tweet, "message_create"):
|
||||
extracted_urls = find_urls_in_text(tweet.message_create["message_data"]["text"])
|
||||
else:
|
||||
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).
|
||||
for i in extracted_urls:
|
||||
if i not in urls and "https://t.co" not in i:
|
||||
urls.append(i)
|
||||
return urls
|
||||
|
||||
def find_item(id, listItem):
|
||||
for i in range(0, len(listItem)):
|
||||
if listItem[i].id == id: return i
|
||||
return None
|
||||
for i in range(0, len(listItem)):
|
||||
if listItem[i].id == id: return i
|
||||
return None
|
||||
|
||||
def find_list(name, lists):
|
||||
for i in range(0, len(lists)):
|
||||
if lists[i].name == name: return lists[i].id
|
||||
for i in range(0, len(lists)):
|
||||
if lists[i].name == name: return lists[i].id
|
||||
|
||||
def is_audio(tweet):
|
||||
try:
|
||||
if len(find_urls(tweet)) < 1:
|
||||
return False
|
||||
if hasattr(tweet, "message_create"):
|
||||
entities = tweet.message_create["message_data"]["entities"]
|
||||
else:
|
||||
entities = tweet.entities
|
||||
if len(entities["hashtags"]) > 0:
|
||||
for i in entities["hashtags"]:
|
||||
if i["text"] == "audio":
|
||||
return True
|
||||
except IndexError:
|
||||
print(tweet.entities["hashtags"])
|
||||
log.exception("Exception while executing is_audio hashtag algorithm")
|
||||
try:
|
||||
if len(find_urls(tweet)) < 1:
|
||||
return False
|
||||
if hasattr(tweet, "message_create"):
|
||||
entities = tweet.message_create["message_data"]["entities"]
|
||||
else:
|
||||
entities = tweet.entities
|
||||
if len(entities["hashtags"]) > 0:
|
||||
for i in entities["hashtags"]:
|
||||
if i["text"] == "audio":
|
||||
return True
|
||||
except IndexError:
|
||||
print(tweet.entities["hashtags"])
|
||||
log.exception("Exception while executing is_audio hashtag algorithm")
|
||||
|
||||
def is_geocoded(tweet):
|
||||
if hasattr(tweet, "coordinates") and tweet.coordinates != None:
|
||||
return True
|
||||
if hasattr(tweet, "coordinates") and tweet.coordinates != None:
|
||||
return True
|
||||
|
||||
def is_media(tweet):
|
||||
if hasattr(tweet, "message_create"):
|
||||
entities = tweet.message_create["message_data"]["entities"]
|
||||
else:
|
||||
entities = tweet.entities
|
||||
if entities.get("media") == None:
|
||||
return False
|
||||
for i in entities["media"]:
|
||||
if i.get("type") != None and i.get("type") == "photo":
|
||||
return True
|
||||
return False
|
||||
if hasattr(tweet, "message_create"):
|
||||
entities = tweet.message_create["message_data"]["entities"]
|
||||
else:
|
||||
entities = tweet.entities
|
||||
if entities.get("media") == None:
|
||||
return False
|
||||
for i in entities["media"]:
|
||||
if i.get("type") != None and i.get("type") == "photo":
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_all_mentioned(tweet, conf, field="screen_name"):
|
||||
""" Gets all users that have been mentioned."""
|
||||
results = []
|
||||
for i in tweet.entities["user_mentions"]:
|
||||
if i["screen_name"] != conf["user_name"] and i["screen_name"] != tweet.user.screen_name:
|
||||
if i.get(field) not in results:
|
||||
results.append(i.get(field))
|
||||
return results
|
||||
""" Gets all users that have been mentioned."""
|
||||
results = []
|
||||
for i in tweet.entities["user_mentions"]:
|
||||
if i["screen_name"] != conf["user_name"] and i["screen_name"] != tweet.user.screen_name:
|
||||
if i.get(field) not in results:
|
||||
results.append(i.get(field))
|
||||
return results
|
||||
|
||||
def get_all_users(tweet, conf):
|
||||
string = []
|
||||
if hasattr(tweet, "retweeted_status"):
|
||||
string.append(tweet.user.screen_name)
|
||||
tweet = tweet.retweeted_status
|
||||
if hasattr(tweet, "sender"):
|
||||
string.append(tweet.sender.screen_name)
|
||||
else:
|
||||
if tweet.user.screen_name != conf["user_name"]:
|
||||
string.append(tweet.user.screen_name)
|
||||
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"] not in string:
|
||||
string.append(i["screen_name"])
|
||||
if len(string) == 0:
|
||||
string.append(tweet.user.screen_name)
|
||||
return string
|
||||
string = []
|
||||
if hasattr(tweet, "retweeted_status"):
|
||||
string.append(tweet.user.screen_name)
|
||||
tweet = tweet.retweeted_status
|
||||
if hasattr(tweet, "sender"):
|
||||
string.append(tweet.sender.screen_name)
|
||||
else:
|
||||
if tweet.user.screen_name != conf["user_name"]:
|
||||
string.append(tweet.user.screen_name)
|
||||
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"] not in string:
|
||||
string.append(i["screen_name"])
|
||||
if len(string) == 0:
|
||||
string.append(tweet.user.screen_name)
|
||||
return string
|
||||
|
||||
def if_user_exists(twitter, user):
|
||||
try:
|
||||
data = twitter.get_user(screen_name=user)
|
||||
return data
|
||||
except TweepError as err:
|
||||
if err.api_code == 50:
|
||||
return None
|
||||
else:
|
||||
return user
|
||||
try:
|
||||
data = twitter.get_user(screen_name=user)
|
||||
return data
|
||||
except TweepError as err:
|
||||
if err.api_code == 50:
|
||||
return None
|
||||
else:
|
||||
return user
|
||||
|
||||
def is_allowed(tweet, settings, buffer_name):
|
||||
clients = settings["twitter"]["ignored_clients"]
|
||||
if hasattr(tweet, "sender"): return True
|
||||
allowed = True
|
||||
tweet_data = {}
|
||||
if hasattr(tweet, "retweeted_status"):
|
||||
tweet_data["retweet"] = True
|
||||
if tweet.in_reply_to_status_id_str != None:
|
||||
tweet_data["reply"] = True
|
||||
if hasattr(tweet, "quoted_status"):
|
||||
tweet_data["quote"] = True
|
||||
if hasattr(tweet, "retweeted_status"):
|
||||
tweet = tweet.retweeted_status
|
||||
source = tweet.source
|
||||
for i in clients:
|
||||
if i.lower() == source.lower():
|
||||
return False
|
||||
return filter_tweet(tweet, tweet_data, settings, buffer_name)
|
||||
clients = settings["twitter"]["ignored_clients"]
|
||||
if hasattr(tweet, "sender"): return True
|
||||
allowed = True
|
||||
tweet_data = {}
|
||||
if hasattr(tweet, "retweeted_status"):
|
||||
tweet_data["retweet"] = True
|
||||
if tweet.in_reply_to_status_id_str != None:
|
||||
tweet_data["reply"] = True
|
||||
if hasattr(tweet, "quoted_status"):
|
||||
tweet_data["quote"] = True
|
||||
if hasattr(tweet, "retweeted_status"):
|
||||
tweet = tweet.retweeted_status
|
||||
source = tweet.source
|
||||
for i in clients:
|
||||
if i.lower() == source.lower():
|
||||
return False
|
||||
return filter_tweet(tweet, tweet_data, settings, buffer_name)
|
||||
|
||||
def filter_tweet(tweet, tweet_data, settings, buffer_name):
|
||||
if hasattr(tweet, "full_text"):
|
||||
value = "full_text"
|
||||
else:
|
||||
value = "text"
|
||||
for i in settings["filters"]:
|
||||
if settings["filters"][i]["in_buffer"] == buffer_name:
|
||||
regexp = settings["filters"][i]["regexp"]
|
||||
word = settings["filters"][i]["word"]
|
||||
# Added if/else for compatibility reasons.
|
||||
if "allow_rts" in settings["filters"][i]:
|
||||
allow_rts = settings["filters"][i]["allow_rts"]
|
||||
else:
|
||||
allow_rts = "True"
|
||||
if "allow_quotes" in settings["filters"][i]:
|
||||
allow_quotes = settings["filters"][i]["allow_quotes"]
|
||||
else:
|
||||
allow_quotes = "True"
|
||||
if "allow_replies" in settings["filters"][i]:
|
||||
allow_replies = settings["filters"][i]["allow_replies"]
|
||||
else:
|
||||
allow_replies = "True"
|
||||
if allow_rts == "False" and "retweet" in tweet_data:
|
||||
return False
|
||||
if allow_quotes == "False" and "quote" in tweet_data:
|
||||
return False
|
||||
if allow_replies == "False" and "reply" in tweet_data:
|
||||
return False
|
||||
if word != "" and settings["filters"][i]["if_word_exists"]:
|
||||
if word in getattr(tweet, value):
|
||||
return False
|
||||
elif word != "" and settings["filters"][i]["if_word_exists"] == False:
|
||||
if word not in getattr(tweet, value):
|
||||
return False
|
||||
if settings["filters"][i]["in_lang"] == "True":
|
||||
if getattr(tweet, lang) not in settings["filters"][i]["languages"]:
|
||||
return False
|
||||
elif settings["filters"][i]["in_lang"] == "False":
|
||||
if tweet.lang in settings["filters"][i]["languages"]:
|
||||
return False
|
||||
return True
|
||||
if hasattr(tweet, "full_text"):
|
||||
value = "full_text"
|
||||
else:
|
||||
value = "text"
|
||||
for i in settings["filters"]:
|
||||
if settings["filters"][i]["in_buffer"] == buffer_name:
|
||||
regexp = settings["filters"][i]["regexp"]
|
||||
word = settings["filters"][i]["word"]
|
||||
# Added if/else for compatibility reasons.
|
||||
if "allow_rts" in settings["filters"][i]:
|
||||
allow_rts = settings["filters"][i]["allow_rts"]
|
||||
else:
|
||||
allow_rts = "True"
|
||||
if "allow_quotes" in settings["filters"][i]:
|
||||
allow_quotes = settings["filters"][i]["allow_quotes"]
|
||||
else:
|
||||
allow_quotes = "True"
|
||||
if "allow_replies" in settings["filters"][i]:
|
||||
allow_replies = settings["filters"][i]["allow_replies"]
|
||||
else:
|
||||
allow_replies = "True"
|
||||
if allow_rts == "False" and "retweet" in tweet_data:
|
||||
return False
|
||||
if allow_quotes == "False" and "quote" in tweet_data:
|
||||
return False
|
||||
if allow_replies == "False" and "reply" in tweet_data:
|
||||
return False
|
||||
if word != "" and settings["filters"][i]["if_word_exists"]:
|
||||
if word in getattr(tweet, value):
|
||||
return False
|
||||
elif word != "" and settings["filters"][i]["if_word_exists"] == False:
|
||||
if word not in getattr(tweet, value):
|
||||
return False
|
||||
if settings["filters"][i]["in_lang"] == "True":
|
||||
if getattr(tweet, lang) not in settings["filters"][i]["languages"]:
|
||||
return False
|
||||
elif settings["filters"][i]["in_lang"] == "False":
|
||||
if tweet.lang in settings["filters"][i]["languages"]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def twitter_error(error):
|
||||
if error.api_code == 179:
|
||||
msg = _(u"Sorry, you are not authorised to see this status.")
|
||||
elif error.api_code == 144:
|
||||
msg = _(u"No status found with that ID")
|
||||
else:
|
||||
msg = _(u"Error code {0}").format(error.api_code,)
|
||||
output.speak(msg)
|
||||
if error.api_code == 179:
|
||||
msg = _(u"Sorry, you are not authorised to see this status.")
|
||||
elif error.api_code == 144:
|
||||
msg = _(u"No status found with that ID")
|
||||
else:
|
||||
msg = _(u"Error code {0}").format(error.api_code,)
|
||||
output.speak(msg)
|
||||
|
||||
def expand_urls(text, entities):
|
||||
""" Expand all URLS present in text with information found in entities"""
|
||||
urls = find_urls_in_text(text)
|
||||
for url in entities["urls"]:
|
||||
if url["url"] in text:
|
||||
text = text.replace(url["url"], url["expanded_url"])
|
||||
return text
|
||||
""" Expand all URLS present in text with information found in entities"""
|
||||
urls = find_urls_in_text(text)
|
||||
for url in entities["urls"]:
|
||||
if url["url"] in text:
|
||||
text = text.replace(url["url"], url["expanded_url"])
|
||||
return text
|
||||
|
@ -3,16 +3,16 @@ from __future__ import unicode_literals
|
||||
import wx
|
||||
|
||||
class authorisationDialog(wx.Dialog):
|
||||
def __init__(self):
|
||||
super(authorisationDialog, self).__init__(parent=None, title=_(u"Authorising account..."))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
static = wx.StaticText(panel, wx.NewId(), _(u"Enter your PIN code here"))
|
||||
self.text = wx.TextCtrl(panel, -1)
|
||||
self.ok = wx.Button(panel, wx.ID_OK)
|
||||
self.cancel = wx.Button(panel, wx.ID_CANCEL)
|
||||
sizer.Add(self.text, 0, wx.ALL, 5)
|
||||
sizer.Add(self.cancel, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
min = sizer.CalcMin()
|
||||
self.SetClientSize(min)
|
||||
def __init__(self):
|
||||
super(authorisationDialog, self).__init__(parent=None, title=_(u"Authorising account..."))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
static = wx.StaticText(panel, wx.NewId(), _(u"Enter your PIN code here"))
|
||||
self.text = wx.TextCtrl(panel, -1)
|
||||
self.ok = wx.Button(panel, wx.ID_OK)
|
||||
self.cancel = wx.Button(panel, wx.ID_CANCEL)
|
||||
sizer.Add(self.text, 0, wx.ALL, 5)
|
||||
sizer.Add(self.cancel, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
min = sizer.CalcMin()
|
||||
self.SetClientSize(min)
|
||||
|
56
src/setup.py
56
src/setup.py
@ -7,44 +7,44 @@ from cx_Freeze import setup, Executable
|
||||
from requests import certs
|
||||
|
||||
def get_architecture_files():
|
||||
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", "."]]
|
||||
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", "."]]
|
||||
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", "."]]
|
||||
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", "."]]
|
||||
|
||||
def find_sound_lib_datafiles():
|
||||
import os
|
||||
import platform
|
||||
import sound_lib
|
||||
path = os.path.join(sound_lib.__path__[0], 'lib')
|
||||
if platform.architecture()[0] == '32bit' or platform.system() == 'Darwin':
|
||||
arch = 'x86'
|
||||
else:
|
||||
arch = 'x64'
|
||||
dest_dir = os.path.join('sound_lib', 'lib', arch)
|
||||
source = os.path.join(path, arch)
|
||||
return (source, dest_dir)
|
||||
import os
|
||||
import platform
|
||||
import sound_lib
|
||||
path = os.path.join(sound_lib.__path__[0], 'lib')
|
||||
if platform.architecture()[0] == '32bit' or platform.system() == 'Darwin':
|
||||
arch = 'x86'
|
||||
else:
|
||||
arch = 'x64'
|
||||
dest_dir = os.path.join('sound_lib', 'lib', arch)
|
||||
source = os.path.join(path, arch)
|
||||
return (source, dest_dir)
|
||||
|
||||
def find_accessible_output2_datafiles():
|
||||
import os
|
||||
import accessible_output2
|
||||
path = os.path.join(accessible_output2.__path__[0], 'lib')
|
||||
dest_dir = os.path.join('accessible_output2', 'lib')
|
||||
return (path, dest_dir)
|
||||
import os
|
||||
import accessible_output2
|
||||
path = os.path.join(accessible_output2.__path__[0], 'lib')
|
||||
dest_dir = os.path.join('accessible_output2', 'lib')
|
||||
return (path, dest_dir)
|
||||
|
||||
base = None
|
||||
if sys.platform == 'win32':
|
||||
base = 'Win32GUI'
|
||||
|
||||
build_exe_options = dict(
|
||||
build_exe="dist",
|
||||
optimize=1,
|
||||
includes=["enchant.tokenize.en"], # This is not handled automatically by cx_freeze.
|
||||
include_msvcr=True,
|
||||
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(),
|
||||
packages=["wxUI"],
|
||||
)
|
||||
build_exe="dist",
|
||||
optimize=1,
|
||||
includes=["enchant.tokenize.en"], # This is not handled automatically by cx_freeze.
|
||||
include_msvcr=True,
|
||||
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(),
|
||||
packages=["wxUI"],
|
||||
)
|
||||
|
||||
executables = [
|
||||
Executable('main.py', base=base, targetName="twblue")
|
||||
|
220
src/sound.py
220
src/sound.py
@ -15,11 +15,11 @@ from audio_services import youtube_utils
|
||||
import application
|
||||
system = platform.system()
|
||||
if system=="Windows" and not hasattr(sys, 'frozen'): # We are running from source on Windows
|
||||
current_dir=os.getcwd()
|
||||
os.chdir(os.environ['PYTHON_VLC_MODULE_PATH'])
|
||||
current_dir=os.getcwd()
|
||||
os.chdir(os.environ['PYTHON_VLC_MODULE_PATH'])
|
||||
import vlc
|
||||
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
|
||||
from mysc.repeating_timer import RepeatingTimer
|
||||
from mysc.thread_utils import call_threaded
|
||||
@ -29,132 +29,132 @@ URLPlayer = None
|
||||
log = original_logger.getLogger("sound")
|
||||
|
||||
def setup():
|
||||
global URLPlayer
|
||||
if not URLPlayer:
|
||||
log.debug("creating stream URL player...")
|
||||
URLPlayer = URLStream()
|
||||
global URLPlayer
|
||||
if not URLPlayer:
|
||||
log.debug("creating stream URL player...")
|
||||
URLPlayer = URLStream()
|
||||
|
||||
def recode_audio(filename, quality=4.5):
|
||||
global system
|
||||
if system == "Windows": subprocess.call(r'"%s" -q %r "%s"' % (os.path.join(paths.app_path(), 'oggenc2.exe'), quality, filename))
|
||||
global system
|
||||
if system == "Windows": subprocess.call(r'"%s" -q %r "%s"' % (os.path.join(paths.app_path(), 'oggenc2.exe'), quality, filename))
|
||||
|
||||
def recording(filename):
|
||||
# try:
|
||||
val = sound_lib.recording.WaveRecording(filename=filename)
|
||||
# try:
|
||||
val = sound_lib.recording.WaveRecording(filename=filename)
|
||||
# except sound_lib.main.BassError:
|
||||
# sound_lib.input.Input()
|
||||
# val = sound_lib.recording.WaveRecording(filename=filename)
|
||||
return val
|
||||
return val
|
||||
|
||||
class soundSystem(object):
|
||||
|
||||
def check_soundpack(self):
|
||||
""" Checks if the folder where live the current soundpack exists."""
|
||||
self.soundpack_OK = False
|
||||
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.soundpack_OK = True
|
||||
elif os.path.exists(os.path.join(paths.sound_path(), "default")):
|
||||
log.error("The soundpack does not exist, using default...")
|
||||
self.path = os.path.join(paths.sound_path(), "default")
|
||||
self.soundpack_OK = True
|
||||
else:
|
||||
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
|
||||
def check_soundpack(self):
|
||||
""" Checks if the folder where live the current soundpack exists."""
|
||||
self.soundpack_OK = False
|
||||
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.soundpack_OK = True
|
||||
elif os.path.exists(os.path.join(paths.sound_path(), "default")):
|
||||
log.error("The soundpack does not exist, using default...")
|
||||
self.path = os.path.join(paths.sound_path(), "default")
|
||||
self.soundpack_OK = True
|
||||
else:
|
||||
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
|
||||
|
||||
def __init__(self, soundConfig):
|
||||
""" Sound Player."""
|
||||
self.config = soundConfig
|
||||
# Set the output and input default devices.
|
||||
try:
|
||||
self.output = sound_lib.output.Output()
|
||||
self.input = sound_lib.input.Input()
|
||||
except:
|
||||
pass
|
||||
# Try to use the selected device from the configuration. It can fail if the machine does not has a mic.
|
||||
try:
|
||||
log.debug("Setting input and output devices...")
|
||||
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"]))
|
||||
except:
|
||||
log.error("Error in input or output devices, using defaults...")
|
||||
self.config["output_device"] = "Default"
|
||||
self.config["input_device"] = "Default"
|
||||
def __init__(self, soundConfig):
|
||||
""" Sound Player."""
|
||||
self.config = soundConfig
|
||||
# Set the output and input default devices.
|
||||
try:
|
||||
self.output = sound_lib.output.Output()
|
||||
self.input = sound_lib.input.Input()
|
||||
except:
|
||||
pass
|
||||
# Try to use the selected device from the configuration. It can fail if the machine does not has a mic.
|
||||
try:
|
||||
log.debug("Setting input and output devices...")
|
||||
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"]))
|
||||
except:
|
||||
log.error("Error in input or output devices, using defaults...")
|
||||
self.config["output_device"] = "Default"
|
||||
self.config["input_device"] = "Default"
|
||||
|
||||
self.files = []
|
||||
self.cleaner = RepeatingTimer(60, self.clear_list)
|
||||
self.cleaner.start()
|
||||
self.check_soundpack()
|
||||
self.files = []
|
||||
self.cleaner = RepeatingTimer(60, self.clear_list)
|
||||
self.cleaner.start()
|
||||
self.check_soundpack()
|
||||
|
||||
def clear_list(self):
|
||||
if len(self.files) == 0: return
|
||||
try:
|
||||
for i in range(0, len(self.files)):
|
||||
if self.files[i].is_playing == False:
|
||||
self.files[i].free()
|
||||
self.files.pop(i)
|
||||
except IndexError:
|
||||
pass
|
||||
def clear_list(self):
|
||||
if len(self.files) == 0: return
|
||||
try:
|
||||
for i in range(0, len(self.files)):
|
||||
if self.files[i].is_playing == False:
|
||||
self.files[i].free()
|
||||
self.files.pop(i)
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
def play(self, sound, argument=False):
|
||||
if self.soundpack_OK == False: return
|
||||
if self.config["session_mute"] == True: return
|
||||
sound_object = sound_lib.stream.FileStream(file="%s/%s" % (self.path, sound))
|
||||
sound_object.volume = float(self.config["volume"])
|
||||
self.files.append(sound_object)
|
||||
sound_object.play()
|
||||
def play(self, sound, argument=False):
|
||||
if self.soundpack_OK == False: return
|
||||
if self.config["session_mute"] == True: return
|
||||
sound_object = sound_lib.stream.FileStream(file="%s/%s" % (self.path, sound))
|
||||
sound_object.volume = float(self.config["volume"])
|
||||
self.files.append(sound_object)
|
||||
sound_object.play()
|
||||
|
||||
class URLStream(object):
|
||||
""" URL Stream Player implementation."""
|
||||
""" URL Stream Player implementation."""
|
||||
|
||||
def __init__(self):
|
||||
# URL status. Should be True after URL expansion and transformation.
|
||||
self.prepared = False
|
||||
log.debug("URL Player initialized")
|
||||
# LibVLC controls.
|
||||
self.instance = vlc.Instance()
|
||||
self.player = self.instance.media_player_new()
|
||||
def __init__(self):
|
||||
# URL status. Should be True after URL expansion and transformation.
|
||||
self.prepared = False
|
||||
log.debug("URL Player initialized")
|
||||
# LibVLC controls.
|
||||
self.instance = vlc.Instance()
|
||||
self.player = self.instance.media_player_new()
|
||||
|
||||
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."""
|
||||
log.debug("Preparing URL: %s" % (url,))
|
||||
self.prepared = False
|
||||
self.url = url_shortener.unshorten(url)
|
||||
if self.url == None:
|
||||
self.url = url
|
||||
log.debug("Expanded URL: %s" % (self.url,))
|
||||
if self.url != None:
|
||||
transformer = audio_services.find_url_transformer(self.url)
|
||||
transformed_url = transformer(self.url)
|
||||
self.url = transformed_url
|
||||
log.debug("Transformed URL: %s. Prepared" % (self.url,))
|
||||
self.prepared = True
|
||||
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."""
|
||||
log.debug("Preparing URL: %s" % (url,))
|
||||
self.prepared = False
|
||||
self.url = url_shortener.unshorten(url)
|
||||
if self.url == None:
|
||||
self.url = url
|
||||
log.debug("Expanded URL: %s" % (self.url,))
|
||||
if self.url != None:
|
||||
transformer = audio_services.find_url_transformer(self.url)
|
||||
transformed_url = transformer(self.url)
|
||||
self.url = transformed_url
|
||||
log.debug("Transformed URL: %s. Prepared" % (self.url,))
|
||||
self.prepared = True
|
||||
|
||||
def seek(self, step):
|
||||
pos=self.player.get_time()
|
||||
pos+=step
|
||||
pos=self.player.set_time(pos)
|
||||
def seek(self, step):
|
||||
pos=self.player.get_time()
|
||||
pos+=step
|
||||
pos=self.player.set_time(pos)
|
||||
|
||||
def playpause(self):
|
||||
if self.player.is_playing() == True:
|
||||
self.player.pause()
|
||||
else:
|
||||
self.player.play()
|
||||
def playpause(self):
|
||||
if self.player.is_playing() == True:
|
||||
self.player.pause()
|
||||
else:
|
||||
self.player.play()
|
||||
|
||||
def play(self, url=None, volume=1.0, announce=True):
|
||||
if announce:
|
||||
output.speak(_(u"Playing..."))
|
||||
log.debug("Attempting to play an URL...")
|
||||
if url != None:
|
||||
self.prepare(url)
|
||||
if self.prepared == True:
|
||||
media = self.instance.media_new(self.url)
|
||||
self.player.set_media(media)
|
||||
self.player.audio_set_volume(int(volume*100))
|
||||
self.player.play()
|
||||
log.debug("played")
|
||||
self.prepared=False
|
||||
def play(self, url=None, volume=1.0, announce=True):
|
||||
if announce:
|
||||
output.speak(_(u"Playing..."))
|
||||
log.debug("Attempting to play an URL...")
|
||||
if url != None:
|
||||
self.prepare(url)
|
||||
if self.prepared == True:
|
||||
media = self.instance.media_new(self.url)
|
||||
self.player.set_media(media)
|
||||
self.player.audio_set_volume(int(volume*100))
|
||||
self.player.play()
|
||||
log.debug("played")
|
||||
self.prepared=False
|
||||
|
||||
def stop_audio(self):
|
||||
output.speak(_(u"Stopped."), True)
|
||||
self.player.stop()
|
||||
def stop_audio(self):
|
||||
output.speak(_(u"Stopped."), True)
|
||||
self.player.stop()
|
||||
|
@ -4,10 +4,10 @@ import os.path
|
||||
import platform
|
||||
|
||||
def find_datafiles():
|
||||
system = platform.system()
|
||||
if system == 'Windows':
|
||||
file_ext = '*.exe'
|
||||
else:
|
||||
file_ext = '*.sh'
|
||||
path = os.path.abspath(os.path.join(__path__[0], 'bootstrappers', file_ext))
|
||||
return [('', glob.glob(path))]
|
||||
system = platform.system()
|
||||
if system == 'Windows':
|
||||
file_ext = '*.exe'
|
||||
else:
|
||||
file_ext = '*.sh'
|
||||
path = os.path.abspath(os.path.join(__path__[0], 'bootstrappers', file_ext))
|
||||
return [('', glob.glob(path))]
|
||||
|
@ -12,116 +12,116 @@ from wxUI import commonMessageDialogs
|
||||
import widgetUtils
|
||||
import webbrowser
|
||||
try:
|
||||
import czipfile as zipfile
|
||||
import czipfile as zipfile
|
||||
except ImportError:
|
||||
import zipfile
|
||||
import zipfile
|
||||
|
||||
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):
|
||||
requests_session = create_requests_session(app_name=app_name, version=current_version)
|
||||
available_update = find_update(endpoint, requests_session=requests_session)
|
||||
if not available_update:
|
||||
logger.debug("No update available")
|
||||
return False
|
||||
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']:
|
||||
logger.debug("No update for this architecture")
|
||||
return False
|
||||
available_description = available_update.get('description', None)
|
||||
available_date = available_update.get('date', None)
|
||||
update_url = available_update ['downloads'][platform.system()+platform.architecture()[0][:2]]
|
||||
logger.info("A new update is available. Version %s" % available_version)
|
||||
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
|
||||
logger.info("User canceled update.")
|
||||
return
|
||||
base_path = tempfile.mkdtemp()
|
||||
download_path = os.path.join(base_path, 'update.zip')
|
||||
update_path = os.path.join(base_path, 'update')
|
||||
downloaded = download_update(update_url, download_path, requests_session=requests_session, progress_callback=progress_callback)
|
||||
extracted = extract_update(downloaded, update_path, password=password)
|
||||
bootstrap_path = move_bootstrap(extracted)
|
||||
execute_bootstrap(bootstrap_path, extracted)
|
||||
logger.info("Update prepared for installation.")
|
||||
if callable(update_complete_callback):
|
||||
update_complete_callback()
|
||||
requests_session = create_requests_session(app_name=app_name, version=current_version)
|
||||
available_update = find_update(endpoint, requests_session=requests_session)
|
||||
if not available_update:
|
||||
logger.debug("No update available")
|
||||
return False
|
||||
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']:
|
||||
logger.debug("No update for this architecture")
|
||||
return False
|
||||
available_description = available_update.get('description', None)
|
||||
available_date = available_update.get('date', None)
|
||||
update_url = available_update ['downloads'][platform.system()+platform.architecture()[0][:2]]
|
||||
logger.info("A new update is available. Version %s" % available_version)
|
||||
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
|
||||
logger.info("User canceled update.")
|
||||
return
|
||||
base_path = tempfile.mkdtemp()
|
||||
download_path = os.path.join(base_path, 'update.zip')
|
||||
update_path = os.path.join(base_path, 'update')
|
||||
downloaded = download_update(update_url, download_path, requests_session=requests_session, progress_callback=progress_callback)
|
||||
extracted = extract_update(downloaded, update_path, password=password)
|
||||
bootstrap_path = move_bootstrap(extracted)
|
||||
execute_bootstrap(bootstrap_path, extracted)
|
||||
logger.info("Update prepared for installation.")
|
||||
if callable(update_complete_callback):
|
||||
update_complete_callback()
|
||||
|
||||
def create_requests_session(app_name=None, version=None):
|
||||
user_agent = ''
|
||||
session = requests.session()
|
||||
if app_name:
|
||||
user_agent = ' %s/%r' % (app_name, version)
|
||||
session.headers['User-Agent'] = session.headers['User-Agent'] + user_agent
|
||||
return session
|
||||
user_agent = ''
|
||||
session = requests.session()
|
||||
if app_name:
|
||||
user_agent = ' %s/%r' % (app_name, version)
|
||||
session.headers['User-Agent'] = session.headers['User-Agent'] + user_agent
|
||||
return session
|
||||
|
||||
def find_update(endpoint, requests_session):
|
||||
response = requests_session.get(endpoint)
|
||||
response.raise_for_status()
|
||||
content = response.json()
|
||||
return content
|
||||
response = requests_session.get(endpoint)
|
||||
response.raise_for_status()
|
||||
content = response.json()
|
||||
return content
|
||||
|
||||
def download_update(update_url, update_destination, requests_session, progress_callback=None, chunk_size=io.DEFAULT_BUFFER_SIZE):
|
||||
total_downloaded = total_size = 0
|
||||
with io.open(update_destination, 'w+b') as outfile:
|
||||
download = requests_session.get(update_url, stream=True)
|
||||
total_size = int(download.headers.get('content-length', 0))
|
||||
logger.debug("Total update size: %d" % total_size)
|
||||
download.raise_for_status()
|
||||
for chunk in download.iter_content(chunk_size):
|
||||
outfile.write(chunk)
|
||||
total_downloaded += len(chunk)
|
||||
if callable(progress_callback):
|
||||
call_callback(progress_callback, total_downloaded, total_size)
|
||||
logger.debug("Update downloaded")
|
||||
return update_destination
|
||||
total_downloaded = total_size = 0
|
||||
with io.open(update_destination, 'w+b') as outfile:
|
||||
download = requests_session.get(update_url, stream=True)
|
||||
total_size = int(download.headers.get('content-length', 0))
|
||||
logger.debug("Total update size: %d" % total_size)
|
||||
download.raise_for_status()
|
||||
for chunk in download.iter_content(chunk_size):
|
||||
outfile.write(chunk)
|
||||
total_downloaded += len(chunk)
|
||||
if callable(progress_callback):
|
||||
call_callback(progress_callback, total_downloaded, total_size)
|
||||
logger.debug("Update downloaded")
|
||||
return update_destination
|
||||
|
||||
def extract_update(update_archive, destination, password=None):
|
||||
"""Given an update archive, extracts it. Returns the directory to which it has been extracted"""
|
||||
with contextlib.closing(zipfile.ZipFile(update_archive)) as archive:
|
||||
if password:
|
||||
archive.setpassword(password)
|
||||
archive.extractall(path=destination)
|
||||
logger.debug("Update extracted")
|
||||
return destination
|
||||
"""Given an update archive, extracts it. Returns the directory to which it has been extracted"""
|
||||
with contextlib.closing(zipfile.ZipFile(update_archive)) as archive:
|
||||
if password:
|
||||
archive.setpassword(password)
|
||||
archive.extractall(path=destination)
|
||||
logger.debug("Update extracted")
|
||||
return destination
|
||||
|
||||
def move_bootstrap(extracted_path):
|
||||
working_path = os.path.abspath(os.path.join(extracted_path, '..'))
|
||||
if platform.system() == 'Darwin':
|
||||
extracted_path = os.path.join(extracted_path, 'Contents', 'Resources')
|
||||
downloaded_bootstrap = os.path.join(extracted_path, bootstrap_name())
|
||||
new_bootstrap_path = os.path.join(working_path, bootstrap_name())
|
||||
os.rename(downloaded_bootstrap, new_bootstrap_path)
|
||||
return new_bootstrap_path
|
||||
working_path = os.path.abspath(os.path.join(extracted_path, '..'))
|
||||
if platform.system() == 'Darwin':
|
||||
extracted_path = os.path.join(extracted_path, 'Contents', 'Resources')
|
||||
downloaded_bootstrap = os.path.join(extracted_path, bootstrap_name())
|
||||
new_bootstrap_path = os.path.join(working_path, bootstrap_name())
|
||||
os.rename(downloaded_bootstrap, new_bootstrap_path)
|
||||
return new_bootstrap_path
|
||||
|
||||
def execute_bootstrap(bootstrap_path, source_path):
|
||||
arguments = r'"%s" "%s" "%s" "%s"' % (os.getpid(), source_path, paths.app_path(), paths.get_executable())
|
||||
if platform.system() == 'Windows':
|
||||
import win32api
|
||||
win32api.ShellExecute(0, 'open', bootstrap_path, arguments, '', 5)
|
||||
else:
|
||||
import subprocess
|
||||
make_executable(bootstrap_path)
|
||||
subprocess.Popen(['%s %s' % (bootstrap_path, arguments)], shell=True)
|
||||
logger.info("Bootstrap executed")
|
||||
arguments = r'"%s" "%s" "%s" "%s"' % (os.getpid(), source_path, paths.app_path(), paths.get_executable())
|
||||
if platform.system() == 'Windows':
|
||||
import win32api
|
||||
win32api.ShellExecute(0, 'open', bootstrap_path, arguments, '', 5)
|
||||
else:
|
||||
import subprocess
|
||||
make_executable(bootstrap_path)
|
||||
subprocess.Popen(['%s %s' % (bootstrap_path, arguments)], shell=True)
|
||||
logger.info("Bootstrap executed")
|
||||
|
||||
def bootstrap_name():
|
||||
if platform.system() == 'Windows': return 'bootstrap.exe'
|
||||
if platform.system() == 'Darwin': return 'bootstrap-mac.sh'
|
||||
return 'bootstrap-lin.sh'
|
||||
if platform.system() == 'Windows': return 'bootstrap.exe'
|
||||
if platform.system() == 'Darwin': return 'bootstrap-mac.sh'
|
||||
return 'bootstrap-lin.sh'
|
||||
|
||||
def make_executable(path):
|
||||
import stat
|
||||
st = os.stat(path)
|
||||
os.chmod(path, st.st_mode | stat.S_IEXEC)
|
||||
import stat
|
||||
st = os.stat(path)
|
||||
os.chmod(path, st.st_mode | stat.S_IEXEC)
|
||||
|
||||
def call_callback(callback, *args, **kwargs):
|
||||
# try:
|
||||
callback(*args, **kwargs)
|
||||
# try:
|
||||
callback(*args, **kwargs)
|
||||
# except:
|
||||
# logger.exception("Failed calling callback %r with args %r and kwargs %r" % (callback, args, kwargs))
|
||||
|
||||
def donation():
|
||||
dlg = commonMessageDialogs.donation()
|
||||
if dlg == widgetUtils.YES:
|
||||
webbrowser.open_new_tab("http://twblue.es/?q=donate")
|
||||
dlg = commonMessageDialogs.donation()
|
||||
if dlg == widgetUtils.YES:
|
||||
webbrowser.open_new_tab("http://twblue.es/?q=donate")
|
||||
|
@ -11,13 +11,13 @@ from .wxUpdater import *
|
||||
logger = logging.getLogger("updater")
|
||||
|
||||
def do_update(endpoint=application.update_url):
|
||||
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)
|
||||
except:
|
||||
if endpoint == application.update_url:
|
||||
logger.error("Update failed! Using mirror URL...")
|
||||
return do_update(endpoint=application.mirror_update_url)
|
||||
else:
|
||||
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)
|
||||
return result
|
||||
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)
|
||||
except:
|
||||
if endpoint == application.update_url:
|
||||
logger.error("Update failed! Using mirror URL...")
|
||||
return do_update(endpoint=application.mirror_update_url)
|
||||
else:
|
||||
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)
|
||||
return result
|
||||
|
@ -3,42 +3,42 @@
|
||||
from __future__ import unicode_literals
|
||||
from builtins import str
|
||||
def convert_bytes(n):
|
||||
K, M, G, T, P = 1 << 10, 1 << 20, 1 << 30, 1 << 40, 1 << 50
|
||||
if n >= P:
|
||||
return '%.2fPb' % (float(n) / T)
|
||||
elif n >= T:
|
||||
return '%.2fTb' % (float(n) / T)
|
||||
elif n >= G:
|
||||
return '%.2fGb' % (float(n) / G)
|
||||
elif n >= M:
|
||||
return '%.2fMb' % (float(n) / M)
|
||||
elif n >= K:
|
||||
return '%.2fKb' % (float(n) / K)
|
||||
else:
|
||||
return '%d' % n
|
||||
K, M, G, T, P = 1 << 10, 1 << 20, 1 << 30, 1 << 40, 1 << 50
|
||||
if n >= P:
|
||||
return '%.2fPb' % (float(n) / T)
|
||||
elif n >= T:
|
||||
return '%.2fTb' % (float(n) / T)
|
||||
elif n >= G:
|
||||
return '%.2fGb' % (float(n) / G)
|
||||
elif n >= M:
|
||||
return '%.2fMb' % (float(n) / M)
|
||||
elif n >= K:
|
||||
return '%.2fKb' % (float(n) / K)
|
||||
else:
|
||||
return '%d' % n
|
||||
|
||||
def seconds_to_string(seconds, precision=0):
|
||||
day = seconds // 86400
|
||||
hour = seconds // 3600
|
||||
min = (seconds // 60) % 60
|
||||
sec = seconds - (hour * 3600) - (min * 60)
|
||||
sec_spec = "." + str(precision) + "f"
|
||||
sec_string = sec.__format__(sec_spec)
|
||||
string = ""
|
||||
if day == 1:
|
||||
string += _(u"%d day, ") % day
|
||||
elif day >= 2:
|
||||
string += _(u"%d days, ") % day
|
||||
if (hour == 1):
|
||||
string += _(u"%d hour, ") % hour
|
||||
elif (hour >= 2):
|
||||
string += _("%d hours, ") % hour
|
||||
if (min == 1):
|
||||
string += _(u"%d minute, ") % min
|
||||
elif (min >= 2):
|
||||
string += _(u"%d minutes, ") % min
|
||||
if sec >= 0 and sec <= 2:
|
||||
string += _(u"%s second") % sec_string
|
||||
else:
|
||||
string += _(u"%s seconds") % sec_string
|
||||
return string
|
||||
day = seconds // 86400
|
||||
hour = seconds // 3600
|
||||
min = (seconds // 60) % 60
|
||||
sec = seconds - (hour * 3600) - (min * 60)
|
||||
sec_spec = "." + str(precision) + "f"
|
||||
sec_string = sec.__format__(sec_spec)
|
||||
string = ""
|
||||
if day == 1:
|
||||
string += _(u"%d day, ") % day
|
||||
elif day >= 2:
|
||||
string += _(u"%d days, ") % day
|
||||
if (hour == 1):
|
||||
string += _(u"%d hour, ") % hour
|
||||
elif (hour >= 2):
|
||||
string += _("%d hours, ") % hour
|
||||
if (min == 1):
|
||||
string += _(u"%d minute, ") % min
|
||||
elif (min >= 2):
|
||||
string += _(u"%d minutes, ") % min
|
||||
if sec >= 0 and sec <= 2:
|
||||
string += _(u"%s second") % sec_string
|
||||
else:
|
||||
string += _(u"%s seconds") % sec_string
|
||||
return string
|
||||
|
@ -11,25 +11,25 @@ from . import utils
|
||||
progress_dialog = None
|
||||
|
||||
def available_update_dialog(version, description, date):
|
||||
dialog = wx.MessageDialog(None, _(u"There's a new %s version available, released on %s. Would you like to download it now?\n\n %s version: %s\n\nChanges:\n%s") % (application.name, date, application.name, version, description), _(u"New version for %s") % application.name, style=wx.YES|wx.NO|wx.ICON_WARNING)
|
||||
if dialog.ShowModal() == wx.ID_YES:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
dialog = wx.MessageDialog(None, _(u"There's a new %s version available, released on %s. Would you like to download it now?\n\n %s version: %s\n\nChanges:\n%s") % (application.name, date, application.name, version, description), _(u"New version for %s") % application.name, style=wx.YES|wx.NO|wx.ICON_WARNING)
|
||||
if dialog.ShowModal() == wx.ID_YES:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def create_progress_dialog():
|
||||
return wx.ProgressDialog(_(u"Download in Progress"), _(u"Downloading the new version..."), parent=None, maximum=100)
|
||||
return wx.ProgressDialog(_(u"Download in Progress"), _(u"Downloading the new version..."), parent=None, maximum=100)
|
||||
|
||||
def progress_callback(total_downloaded, total_size):
|
||||
global progress_dialog
|
||||
if progress_dialog == None:
|
||||
progress_dialog = create_progress_dialog()
|
||||
progress_dialog.Show()
|
||||
if total_downloaded == total_size:
|
||||
progress_dialog.Destroy()
|
||||
else:
|
||||
progress_dialog.Update(old_div((total_downloaded*100),total_size), _(u"Updating... %s of %s") % (str(utils.convert_bytes(total_downloaded)), str(utils.convert_bytes(total_size))))
|
||||
global progress_dialog
|
||||
if progress_dialog == None:
|
||||
progress_dialog = create_progress_dialog()
|
||||
progress_dialog.Show()
|
||||
if total_downloaded == total_size:
|
||||
progress_dialog.Destroy()
|
||||
else:
|
||||
progress_dialog.Update(old_div((total_downloaded*100),total_size), _(u"Updating... %s of %s") % (str(utils.convert_bytes(total_downloaded)), str(utils.convert_bytes(total_size))))
|
||||
|
||||
def update_finished():
|
||||
ms = wx.MessageDialog(None, _(u"The update has been downloaded and installed successfully. Press OK to continue."), _(u"Done!")).ShowModal()
|
||||
ms = wx.MessageDialog(None, _(u"The update has been downloaded and installed successfully. Press OK to continue."), _(u"Done!")).ShowModal()
|
||||
|
@ -4,43 +4,43 @@ from . import shorteners
|
||||
|
||||
|
||||
def service_selecter (func):
|
||||
@wraps(func)
|
||||
def wrapper (*args, **kwargs):
|
||||
tmp = dict(kwargs)
|
||||
if 'service' in tmp:
|
||||
del(tmp['service'])
|
||||
kwargs['service'] = find_service(kwargs['service'], **tmp) or default_service()
|
||||
else:
|
||||
kwargs['service'] = default_service()
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
@wraps(func)
|
||||
def wrapper (*args, **kwargs):
|
||||
tmp = dict(kwargs)
|
||||
if 'service' in tmp:
|
||||
del(tmp['service'])
|
||||
kwargs['service'] = find_service(kwargs['service'], **tmp) or default_service()
|
||||
else:
|
||||
kwargs['service'] = default_service()
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
@service_selecter
|
||||
def shorten (url, service=None, **kwargs):
|
||||
return service(**kwargs).shorten(url)
|
||||
return service(**kwargs).shorten(url)
|
||||
|
||||
|
||||
@service_selecter
|
||||
def unshorten (url, service=None, **kwargs):
|
||||
return service(**kwargs).unshorten(url)
|
||||
return service(**kwargs).unshorten(url)
|
||||
|
||||
|
||||
def default_service ():
|
||||
return shorteners.AcortameShortener
|
||||
return shorteners.AcortameShortener
|
||||
|
||||
def find_service (service, **kwargs):
|
||||
for i in shorteners.__all__:
|
||||
obj = getattr(shorteners, i)(**kwargs)
|
||||
if obj.name.lower() == service.lower():
|
||||
return getattr(shorteners, i)
|
||||
for i in shorteners.__all__:
|
||||
obj = getattr(shorteners, i)(**kwargs)
|
||||
if obj.name.lower() == service.lower():
|
||||
return getattr(shorteners, i)
|
||||
|
||||
def list_services ():
|
||||
return [getattr(shorteners, i)().name for i in shorteners.__all__]
|
||||
return [getattr(shorteners, i)().name for i in shorteners.__all__]
|
||||
|
||||
def unshorten_any (url):
|
||||
"""Unshortens an URL using any available unshortener. Check to see if unshortened URL was created by a shortener (nested) and unshorten if so."""
|
||||
unshortened_url = shorteners.URLShortener().unshorten(url)
|
||||
# None is returned if URL not unshortened
|
||||
if unshortened_url:
|
||||
return unshorten_any(unshortened_url)
|
||||
return url
|
||||
"""Unshortens an URL using any available unshortener. Check to see if unshortened URL was created by a shortener (nested) and unshorten if so."""
|
||||
unshortened_url = shorteners.URLShortener().unshorten(url)
|
||||
# None is returned if URL not unshortened
|
||||
if unshortened_url:
|
||||
return unshorten_any(unshortened_url)
|
||||
return url
|
||||
|
@ -5,26 +5,26 @@ from . url_shortener import URLShortener
|
||||
import requests
|
||||
import urllib.request, urllib.parse, urllib.error
|
||||
class AcortameShortener (URLShortener):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.name = "acorta.me"
|
||||
super(AcortameShortener, self).__init__(*args, **kwargs)
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.name = "acorta.me"
|
||||
super(AcortameShortener, self).__init__(*args, **kwargs)
|
||||
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = requests.get ("https://acorta.me/api.php?action=shorturl&format=simple&url=" + urllib.parse.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = requests.get ("https://acorta.me/api.php?action=shorturl&format=simple&url=" + urllib.parse.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
|
||||
def created_url (self, url):
|
||||
return 'acorta.me' in url
|
||||
def created_url (self, url):
|
||||
return 'acorta.me' in url
|
||||
|
||||
def unshorten (self, url):
|
||||
if not 'acorta.me' in url:
|
||||
#use generic expand method
|
||||
return super(AcortameShortener, self).unshorten(url)
|
||||
answer = url
|
||||
api = requests.get ("https://acorta.me/api.php?action=expand&format=simple&shorturl=" + urllib.parse.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
def unshorten (self, url):
|
||||
if not 'acorta.me' in url:
|
||||
#use generic expand method
|
||||
return super(AcortameShortener, self).unshorten(url)
|
||||
answer = url
|
||||
api = requests.get ("https://acorta.me/api.php?action=expand&format=simple&shorturl=" + urllib.parse.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
|
@ -7,16 +7,16 @@ from . url_shortener import URLShortener
|
||||
|
||||
|
||||
class ClckruShortener (URLShortener):
|
||||
def __init__ (self, *args, **kwargs):
|
||||
self.name = "clck.ru"
|
||||
super(ClckruShortener, self).__init__(*args, **kwargs)
|
||||
def __init__ (self, *args, **kwargs):
|
||||
self.name = "clck.ru"
|
||||
super(ClckruShortener, self).__init__(*args, **kwargs)
|
||||
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = requests.get ("http://clck.ru/--?url=" + urllib.parse.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = requests.get ("http://clck.ru/--?url=" + urllib.parse.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
|
||||
def created_url (self, url):
|
||||
return 'clck.ru' in url
|
||||
def created_url (self, url):
|
||||
return 'clck.ru' in url
|
||||
|
@ -6,16 +6,16 @@ import requests
|
||||
from . url_shortener import URLShortener
|
||||
|
||||
class HKCShortener (URLShortener):
|
||||
def __init__ (self, *args, **kwargs):
|
||||
self.name = "HKC.im"
|
||||
super(HKCShortener, self).__init__(*args, **kwargs)
|
||||
def __init__ (self, *args, **kwargs):
|
||||
self.name = "HKC.im"
|
||||
super(HKCShortener, self).__init__(*args, **kwargs)
|
||||
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = requests.get ("http://hkc.im/yourls-api.php?action=shorturl&format=simple&url=" + urllib.parse.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = requests.get ("http://hkc.im/yourls-api.php?action=shorturl&format=simple&url=" + urllib.parse.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
|
||||
def created_url (self, url):
|
||||
return 'hkc.im' in url.lower()
|
||||
def created_url (self, url):
|
||||
return 'hkc.im' in url.lower()
|
||||
|
@ -7,16 +7,16 @@ from . url_shortener import URLShortener
|
||||
|
||||
|
||||
class IsgdShortener (URLShortener):
|
||||
def __init__ (self, *args, **kwargs):
|
||||
self.name = "Is.gd"
|
||||
super(IsgdShortener, self).__init__(*args, **kwargs)
|
||||
def __init__ (self, *args, **kwargs):
|
||||
self.name = "Is.gd"
|
||||
super(IsgdShortener, self).__init__(*args, **kwargs)
|
||||
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = requests.get ("http://is.gd/api.php?longurl=" + urllib.parse.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = requests.get ("http://is.gd/api.php?longurl=" + urllib.parse.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
|
||||
def created_url (self, url):
|
||||
return 'is.gd' in url
|
||||
def created_url (self, url):
|
||||
return 'is.gd' in url
|
||||
|
@ -6,16 +6,16 @@ import requests
|
||||
from . url_shortener import URLShortener
|
||||
|
||||
class OnjmeShortener (URLShortener):
|
||||
def __init__ (self, *args, **kwargs):
|
||||
self.name = "Onj.me"
|
||||
super(OnjmeShortener, self).__init__(*args, **kwargs)
|
||||
def __init__ (self, *args, **kwargs):
|
||||
self.name = "Onj.me"
|
||||
super(OnjmeShortener, self).__init__(*args, **kwargs)
|
||||
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = requests.get ("http://onj.me/yourls-api.php?action=shorturl&format=simple&url=" + urllib.parse.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = requests.get ("http://onj.me/yourls-api.php?action=shorturl&format=simple&url=" + urllib.parse.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
|
||||
def created_url (self, url):
|
||||
return 'onj.me' in url.lower()
|
||||
def created_url (self, url):
|
||||
return 'onj.me' in url.lower()
|
||||
|
@ -6,16 +6,16 @@ import requests
|
||||
from . url_shortener import URLShortener
|
||||
|
||||
class TinyArrowsShortener (URLShortener):
|
||||
def __init__ (self, *args, **kwargs):
|
||||
self.name = "TinyArro.ws"
|
||||
super(TinyArrowsShortener, self).__init__(*args, **kwargs)
|
||||
def __init__ (self, *args, **kwargs):
|
||||
self.name = "TinyArro.ws"
|
||||
super(TinyArrowsShortener, self).__init__(*args, **kwargs)
|
||||
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = requests.get("http://tinyarro.ws/api-create.php?utfpure=1&url=%s" % urllib.parse.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer.decode('UTF-8')
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = requests.get("http://tinyarro.ws/api-create.php?utfpure=1&url=%s" % urllib.parse.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer.decode('UTF-8')
|
||||
|
||||
def created_url(self, url):
|
||||
return "tinyarro.ws" in url
|
||||
def created_url(self, url):
|
||||
return "tinyarro.ws" in url
|
||||
|
@ -5,16 +5,16 @@ from .url_shortener import URLShortener
|
||||
import requests
|
||||
import urllib.request, urllib.parse, urllib.error
|
||||
class TinyurlShortener (URLShortener):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.name = "TinyURL.com"
|
||||
super(TinyurlShortener, self).__init__(*args, **kwargs)
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.name = "TinyURL.com"
|
||||
super(TinyurlShortener, self).__init__(*args, **kwargs)
|
||||
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = requests.get ("http://tinyurl.com/api-create.php?url=" + urllib.parse.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = requests.get ("http://tinyurl.com/api-create.php?url=" + urllib.parse.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
|
||||
def created_url (self, url):
|
||||
return 'tinyurl.com' in url
|
||||
def created_url (self, url):
|
||||
return 'tinyurl.com' in url
|
||||
|
@ -4,41 +4,41 @@ import requests
|
||||
|
||||
class URLShortener (object):
|
||||
|
||||
def __init__ (self, *args, **kwargs):
|
||||
#Stub out arguments, silly object. :(
|
||||
return super(URLShortener, self).__init__()
|
||||
def __init__ (self, *args, **kwargs):
|
||||
#Stub out arguments, silly object. :(
|
||||
return super(URLShortener, self).__init__()
|
||||
|
||||
def shorten (self, url):
|
||||
if self.created_url(url):
|
||||
return url
|
||||
else:
|
||||
return self._shorten(url)
|
||||
def shorten (self, url):
|
||||
if self.created_url(url):
|
||||
return url
|
||||
else:
|
||||
return self._shorten(url)
|
||||
|
||||
def _shorten (self, url):
|
||||
raise NotImplementedError
|
||||
def _shorten (self, url):
|
||||
raise NotImplementedError
|
||||
|
||||
def created_url (self, url):
|
||||
"""Returns a boolean indicating whether or not this shortener created a provided url"""
|
||||
raise NotImplementedError
|
||||
def created_url (self, url):
|
||||
"""Returns a boolean indicating whether or not this shortener created a provided url"""
|
||||
raise NotImplementedError
|
||||
|
||||
def unshorten(self, url):
|
||||
try:
|
||||
r=requests.head(url)
|
||||
if 'location' in list(r.headers.keys()):
|
||||
if 'dropbox.com' in r.headers['location']:
|
||||
return handle_dropbox(r.headers['location'])
|
||||
else:
|
||||
return r.headers['location']
|
||||
else: # if the head method does not work, use get instead. Performance may decrease
|
||||
r=requests.get(url, allow_redirects=False, stream=True)
|
||||
# release the connection without downloading the content, we only need the response headers
|
||||
r.close()
|
||||
return r.headers['location']
|
||||
except:
|
||||
return url #we cannot expand
|
||||
def unshorten(self, url):
|
||||
try:
|
||||
r=requests.head(url)
|
||||
if 'location' in list(r.headers.keys()):
|
||||
if 'dropbox.com' in r.headers['location']:
|
||||
return handle_dropbox(r.headers['location'])
|
||||
else:
|
||||
return r.headers['location']
|
||||
else: # if the head method does not work, use get instead. Performance may decrease
|
||||
r=requests.get(url, allow_redirects=False, stream=True)
|
||||
# release the connection without downloading the content, we only need the response headers
|
||||
r.close()
|
||||
return r.headers['location']
|
||||
except:
|
||||
return url #we cannot expand
|
||||
|
||||
def handle_dropbox(url):
|
||||
if url.endswith("dl=1"):
|
||||
return url
|
||||
else:
|
||||
return url.replace("dl=0", "dl=1")
|
||||
if url.endswith("dl=1"):
|
||||
return url
|
||||
else:
|
||||
return url.replace("dl=0", "dl=1")
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user