Adding log information to events

This commit is contained in:
Manuel Cortez 2015-01-18 17:19:39 -06:00
parent bd1b0b5e32
commit fd70bedc05
28 changed files with 204 additions and 41 deletions

7
doc/application.py Normal file
View File

@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
name = 'TWBlue'
snapshot = False
if snapshot == False:
version = "0.51"
else:
version = "7"

View File

@ -1,12 +1,13 @@
# -*- coding: utf-8 -*-
import application
documentation = []
documentation.append(_(u"""Documentation for TW Blue 0.46"""))
documentation.append(_(u"""Documentation for {0} - {1}""").format(application.name, application.version))
# Translators: This is the new line character, don't change it in the translations.
documentation.append(_(u"""
"""))
documentation.append(_(u"""## Table of contents"""))
# Table of contents for the python markdown extension
documentation.append("""[TOC]""")
#documentation.append(_(u"""# Version 0.46 (alpha)"""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""## Warning!"""))
@ -41,22 +42,25 @@ documentation.append(_(u"""
documentation.append(_(u"""In order to use an application like TW Blue which allows you to manage your Twitter account, you must first be registered on it. It's beyond the scope of this document to explain how to do so. We'll start from the premise that you have an account with its corresponding user name and password."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""## Authorising the application"""))
documentation.append(_(u"""### Authorising the application"""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""First off, it's necessary to authorise the program so it can access your Twitter account and act on your behalf. The authorisation process is quite simple, and the program never gets data such as your username and password. In order to authorise the application, you just need to run the main executable file, called TWBlue.exe (on some computers it may appear simply as TWBlue)."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""When executed, if you have not previously configured the program, it will show a dialogue box where it tells you'll be taken to Twitter in order to authorise the application as soon as you press OK. To begin the authorisation process, press the only available button on the box."""))
documentation.append(_(u"""Whether this is the first time you open TWBlue or you don't have any session, you will see the session manager. This dialog allows you to authorise as many accounts as you wish, though by now you can open only one session a time. If you press the "new account" button a dialog will tell you that your default browser will be opened in order to authorise the application. Press "yes" so the process may star."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""Your default browser will open on the Twitter page to request authorisation. Enter your user name and password if you're not already logged in, look for the authorise button, and press it."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""Read the instructions you will get if the process is successful. In summary, you will be given a numeric code with several digits you must paste on an edit field open by the application on another window."""))
documentation.append(_(u"""Once you've authorised your twitter account, Twitter will redirect you to a web page which will notify you that TWBlue has been authorised successfully. Now you are able to close that window and come back to the session manager. You will see on the session list a new item temporally called "Authorised account x" -where x is a number. The session name will change once you open that session."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""Paste the verification code, and press the enter key. """))
documentation.append(_(u"""Note: For any strange reason, it is not possible to authorise more than one session at the time of executing TWBlue. A solution for this issue is to authorise your first session and close the software, and repeat this process every time you need authorise any new account. That is to say, you must authorise only one session every time you execute TWBlue. We are working in finding out what causes this issue so that we may solve it efficiently."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""To start running TWBlue, select from the session list the one you wish open and press the Ok button."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""If all went well, the application will start playing sounds, indicating your data are being updated."""))
@ -65,16 +69,16 @@ documentation.append(_(u"""
documentation.append(_(u"""When the process is finished,the program will play another sound, and the screen reader will say "ready"."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""## The program's interface {#interface}"""))
documentation.append(_(u"""## The program's interface"""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""The easiest way to describe the graphical interface of the application is a window with a menu bar with four menus (application, tweet, user and help), a list with several elements, and, in most cases, three buttons: tweet, retweet and reply. The actions available for each element are described below."""))
documentation.append(_(u"""The easiest way to describe the graphical user interface of TWBlue is saying that the application has a window which contains a menu bar with five menus (application, tweet, user, buffer and help); one tree view, one list of items and, mostly in every case, three buttons: Tweet, retweet and reply. The actions that are available for every item will be described later."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""Elements on the lists may be tweets, direct messages or users. TW Blue creates different tabs for each list, which can be sent tweets, main timeline tweets, favourites, or direct messages, and each tab contains a single type of tweet. These tabs are called lists or buffers."""))
documentation.append(_(u"""In the tree view are inserted buffers which are lists to manage the processed data. When you configure a new session on TWBlue and start it, your account is the root of the tree view. Inside of it are created many buffers. Every one of them may contain some of the items which TWBlue works with: Tweets, direct messages, users, trends or events. According to the buffer you were, you will be able to make different actions with these items."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""To switch from list to list press control-tab to go forward, and control-shift-tab to go back. Screen readers will announce the list that gains the focus at all times. These are the basic lists of TW Blue, which are configured by default."""))
documentation.append(_(u"""The following is a description for every kind of TWBlue's buffer and the kind of items they work with."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""* Home: it shows all the tweets on the main timeline. These are the tweets by users you follow."""))
@ -86,38 +90,39 @@ documentation.append(_(u"""* Followers: when users follow you, you'll be able to
documentation.append(_(u"""* Friends: the same as the previous list, but these are the users you follow."""))
documentation.append(_(u"""* User timelines: these are lists you may create. They contain only the tweets by a specific user. They're used so you can see the tweets by a single person and you don't want to look all over your timeline. You may create as many as you like."""))
documentation.append(_(u"""* Events: An event is anything that happens on Twitter, such as when someone follows you, when someone adds or removes one of your tweets from their favorites list, or when you subscribe to a list. There are many more but TW Blue shows the most common ones in the events buffer so that you can easily keep track of what is happening on your account."""))
documentation.append(_(u"""* Lists: A list is similar to a temporary timeline, except that you can configure it to contain tweets from multiple users. This is currently an experimental feature. If you decide to use it, please report any problems you encounter."""))
documentation.append(_(u"""* Lists: A list is similar to a temporary timeline, except that you can configure it to contain tweets from multiple users."""))
documentation.append(_(u"""* Search: A search buffer contains the results of a search operation."""))
documentation.append(_(u"""* User favorites: You can have TW Blue create a buffer containing tweets favorited by a particular user."""))
### add here the trending buffers description.
documentation.append(_(u"""* Trending Topics: a trend buffer shows the top ten most used terms in a geographical region. This region may be a country or a city. Trends are updated every five minutes."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""Note: In this version of TW Blue, you will be able to see up to (or around) 400 friends and followers in their respective buffers. In the next version, we will provide a solution for those who have more to be able to see them."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""Bear in mind the default configuration only allows getting the last 200 tweets for the home,, mentions, direct messages, and user timeline lists. You can change this on the setup dialogue. For the sent list, the last 200 tweets and the last 200 sent direct messages will be retrieved. Future versions will allow changing this parameter."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""If there's a URL on a tweet TW Blue will try to open it when you press enter on it. If there are several, it will show you a list with all of them so you choose the one you want. If you're on the followers or friends dialogue, the enter key will show you additional information on them."""))
documentation.append(_(u"""If there's a URL on a tweet TW Blue will try to open it when you press enter on it. If there are several, it will show you a list with all of them so you choose the one you want. If you're on the followers or friends buffer, the enter key will show you additional information on them."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""If you press control-enter, TW Blue will try to play the audio from the focused tweet, as long as it has a URL. If it has the #audio hashtag, you will hear a sound when it is selected, letting you know you can try to play it. However, a tweet can be missing the hashtag and TW Blue will still be able to play it so long as it contains a URL with audio."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""## Controls {#controls}"""))
documentation.append(_(u"""Also, you will hear a sound when you see any tweet containing geographical information. You can see someone's location by selecting the option "view address" from the tweet menu on the menu bar."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""Beginning with the latest version, there's support for an interface which does not require a visible window. It can be activated by pressing control-m, or choosing hide window from the application menu. This interface is entirely driven through shortcut keys. These shortcuts are different from those used to drive the graphical interface. Each interface can use only its own shortcuts, so you may not use the invisible shortcuts if you have the graphical interface opened. This section describes both the graphical and the invisible interface."""))
documentation.append(_(u"""## Controls"""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""### The graphical user interface (GUI) {#gui}"""))
### add more information about using invisible shorcuts in the GUI mode in the next variable.
documentation.append(_(u"""Beginning with the 0.36 version, there's support for an interface which does not require a visible window. It can be activated by pressing control-m, or choosing hide window from the application menu. This interface is entirely driven through shortcut keys. These shortcuts are different from those used to drive the graphical interface. By default, you can't use the invisible interface shortcuts on the GUI. It has been made this way to keep compatibility with applications like TheQube and Chicken nugget which may use the same shortcuts. If you wish to have available the invisible interface shortcuts even if you are using the GUI, activate this option on the General tab of the preferences dialogue. This section describes both the graphical and the invisible interface."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""### The graphical user interface (GUI)"""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""Here you have a list divided into two parts. On the one hand, the buttons you will find while tabbing around on the program's interface, and on the other, the different elements present on the menu bar."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""#### Buttons on the application {#buttons}"""))
documentation.append(_(u"""#### Buttons on the application"""))
documentation.append(_(u"""
"""))
### Add information on spell correction, translate, attach images and audio.
documentation.append(_(u"""* Tweet: this button opens up a dialogue box to write your tweet. The message must not exceed 140 characters. If you write past this limit, a sound will play to warn you. You may use the shorten and expand URL buttons to comply with the character limit. Press enter to send the tweet. If all goes well, you'll hear a sound confirming it. Otherwise, the screen reader will say an error message in English describing the problem."""))
documentation.append(_(u"""* Retweet: this button retweets the message you're reading. After you press it, you'll be asked if you want to add a comment or simply send it as written."""))
documentation.append(_(u"""* Reply: when you're viewing a tweet, you can reply to the user who sent it by pressing this button. A dialogue will open up like the one for tweeting, but with the name of the user already filled in (for example @user) so you only need to write your message. If there are more users mentioned on the tweet, you can press shift-tab and press the mention all users button. When you're on the friends or followers lists, the button will be called mention instead."""))
@ -127,13 +132,13 @@ documentation.append(_(u"""
documentation.append(_(u"""Bear in mind that buttons will appear according to which actions are possible on the list you are browsing. For example, on the home timeline, mentions, sent, favourites and user timelines you will see the four buttons, while on the direct messages list you'll only get the direct message and tweet buttons, and on friends and followers lists you will get the direct message, tweet, and mention buttons."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""#### Menus {#menus}"""))
documentation.append(_(u"""#### Menus"""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""On top of the program window there's a menu bar which has the same functions, and some more. To access the menu bar, press alt. You will find four menus: application, tweet, user and help. This section describes the items on each one of them."""))
documentation.append(_(u"""On top of the program window there's a menu bar which has the same functions, and some more. To access the menu bar, press alt. You will find five: application, tweet, user, buffer and help. This section describes the items on each one of them."""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""##### Application menu {#app}"""))
documentation.append(_(u"""##### Application menu"""))
documentation.append(_(u"""
"""))
documentation.append(_(u"""* Update profile: opens a dialogue box where you can update your information on Twitter: name, location, URL and bio. If you have already set this up the fields will be prefilled with the existing information. Also, you can upload a photo to your profile."""))

View File

@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
import argparse
import paths
import logging
log = logging.getLogger("commandlineLauncher")
parser = argparse.ArgumentParser(description="TW Blue command line launcher")
group = parser.add_mutually_exclusive_group()
@ -8,6 +10,7 @@ group.add_argument("-p", "--portable", help="Use TW Blue as a portable aplicatio
group.add_argument("-i", "--installed", help="Use TW Blue as an installed application. Config files will be saved on the user data directory", action="store_true")
parser.add_argument("-d", "--data-directory", action="store", dest="directory", help="Specifies the directory where TW Blue saves the data files")
args = parser.parse_args()
log.debug("Starting TWBlue with the following arguments: installed = %s, portable = %s and directory = %s" % (args.installed, args.portable, args.directory))
if args.installed == True: paths.mode = "installed"
elif args.portable == True:
paths.mode = "portable"

View File

@ -1,6 +1,9 @@
# -*- coding: cp1252 -*-
from config_utils import Configuration, ConfigurationResetException
import paths
import logging
log = logging.getLogger("config")
MAINFILE = "twblue.conf"
MAINSPEC = "app-configuration.defaults"
@ -9,6 +12,7 @@ app = None
def setup ():
global app
log.debug("Loading global app settings...")
try:
app = Configuration(paths.config_path(MAINFILE), paths.app_path(MAINSPEC))
except ConfigurationResetException:

View File

@ -8,11 +8,13 @@ import config
import sound
import messages
import languageHandler
import logging
from twitter import compose, utils
from wxUI import buffers, dialogs, commonMessageDialogs
from mysc.thread_utils import call_threaded
from twython import TwythonError
log = logging.getLogger("controller.buffers")
class bufferController(object):
def __init__(self, parent=None, function=None, session=None, *args, **kwargs):
super(bufferController, self).__init__()
@ -113,6 +115,7 @@ class bufferController(object):
class accountPanel(bufferController):
def __init__(self, parent, name, account):
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
@ -126,6 +129,7 @@ class accountPanel(bufferController):
class emptyPanel(bufferController):
def __init__(self, parent, name, account):
super(emptyPanel, self).__init__(parent, None, name)
log.debug("Initializing buffer %s, account %s" % (name, account,))
self.buffer = buffers.emptyPanel(parent, name)
self.type = self.buffer.type
self.compose_function = None
@ -139,6 +143,7 @@ class emptyPanel(bufferController):
class baseBufferController(bufferController):
def __init__(self, parent, function, name, sessionObject, account, bufferType=None, *args, **kwargs):
super(baseBufferController, self).__init__(parent, function, *args, **kwargs)
log.debug("Initializing buffer %s, account %s" % (name, account,))
if bufferType != None:
self.buffer = getattr(buffers, bufferType)(parent, name)
else:
@ -148,6 +153,7 @@ class baseBufferController(bufferController):
self.id = self.buffer.GetId()
self.session = sessionObject
self.compose_function = compose.compose_tweet
log.debug("Compose_function: %s" % (self.compose_function,))
self.account = account
self.buffer.account = account
self.bind_events()
@ -156,11 +162,16 @@ class baseBufferController(bufferController):
return " ".join(self.compose_function(self.get_right_tweet(), self.session.db, self.session.settings["general"]["relative_times"])[1:-2])
def start_stream(self):
log.debug("Starting stream for buffer %s, account %s and type %s" % (self.name, self.account, self.type))
log.debug("args: %s, kwargs: %s" % (self.args, self.kwargs))
val = self.session.call_paged(self.function, *self.args, **self.kwargs)
number_of_items = self.session.order_buffer(self.name, val)
log.debug("Number of items retrieved: %d" % (number_of_items,))
self.put_items_on_list(number_of_items)
def put_items_on_list(self, number_of_items):
log.debug("The list contains %d items " % (self.buffer.list.get_count(),))
log.debug("Putting %d items on the list" % (number_of_items,))
if self.buffer.list.get_count() == 0:
for i in self.session.db[self.name]:
tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"])
@ -175,6 +186,7 @@ class baseBufferController(bufferController):
for i in self.session.db[self.name][0:number_of_items]:
tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"])
self.buffer.list.insert_item(True, *tweet)
log.debug("Now the list contains %d items " % (self.buffer.list.get_count(),))
def add_new_item(self, item):
tweet = self.compose_function(item, self.session.db, self.session.settings["general"]["relative_times"])
@ -184,6 +196,7 @@ class baseBufferController(bufferController):
self.buffer.list.insert_item(True, *tweet)
def bind_events(self):
log.debug("Binding events...")
self.buffer.list.list.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.onFocus)
self.buffer.list.list.Bind(wx.EVT_CHAR_HOOK, self.get_event)
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.post_tweet, self.buffer.tweet)
@ -305,6 +318,7 @@ class baseBufferController(bufferController):
class eventsBufferController(bufferController):
def __init__(self, parent, name, session, account, *args, **kwargs):
super(eventsBufferController, self).__init__(parent, *args, **kwargs)
log.debug("Initializing buffer %s, account %s" % (name, account,))
self.buffer = buffers.eventsPanel(parent, name)
self.name = name
self.account = account
@ -332,7 +346,9 @@ class eventsBufferController(bufferController):
class peopleBufferController(baseBufferController):
def __init__(self, parent, function, name, sessionObject, account, bufferType=None, *args, **kwargs):
super(peopleBufferController, self).__init__(parent, function, name, sessionObject, account, bufferType="peoplePanel")
log.debug("Initializing buffer %s, account %s" % (name, account,))
self.compose_function = compose.compose_followers_list
log.debug("Compose_function: self.compose_function" % (self.compose_function,))
self.get_tweet = self.get_right_tweet
def onFocus(self, ev):
@ -344,11 +360,16 @@ class peopleBufferController(baseBufferController):
def delete_item(self): pass
def start_stream(self):
log.debug("Starting stream for %s buffer, %s account" % (self.name, self.account,))
log.debug("args: %s, kwargs: %s" % (self.args, self.kwargs))
val = self.session.get_cursored_stream(self.name, self.function, *self.args, **self.kwargs)
# self.session.order_cursored_buffer(self.name, self.session.db[self.name])
log.debug("Number of items retrieved: %d" % (val,))
self.put_items_on_list(val)
def put_items_on_list(self, number_of_items):
log.debug("The list contains %d items" % (self.buffer.list.get_count(),))
log.debug("Putting %d items on the list..." % (number_of_items,))
if self.buffer.list.get_count() == 0:
for i in self.session.db[self.name]["items"]:
tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"])
@ -363,6 +384,7 @@ class peopleBufferController(baseBufferController):
for i in self.session.db[self.name]["items"][0:number_of_items]:
tweet = self.compose_function(i, self.session.db)
self.buffer.list.insert_item(True, *tweet)
log.debug("now the list contains %d items" % (self.buffer.list.get_count(),))
def get_right_tweet(self):
tweet = self.session.db[self.name]["items"][self.buffer.list.get_selected()]
@ -370,8 +392,12 @@ class peopleBufferController(baseBufferController):
class searchBufferController(baseBufferController):
def start_stream(self):
log.debug("Starting stream for %s buffer, %s account and %s type" % (self.name, self.account, self.type))
log.debug("args: %s, kwargs: %s" % (self.args, self.kwargs))
log.debug("Function: %s" % (self.function,))
val = getattr(self.session.twitter.twitter, self.function)(*self.args, **self.kwargs)
number_of_items = self.session.order_buffer(self.name, val["statuses"])
log.debug("Number of items retrieved: %d" % (number_of_items,))
self.put_items_on_list(number_of_items)
if number_of_items > 0:
sound.player.play("search_updated.ogg")
@ -380,11 +406,17 @@ class searchPeopleBufferController(searchBufferController):
def __init__(self, parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs):
super(searchPeopleBufferController, self).__init__(parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs)
log.debug("Initializing buffer %s, account %s" % (name, account,))
self.compose_function = compose.compose_followers_list
log.debug("Compose_function: %s" % (self.compose_function,))
def start_stream(self):
log.debug("starting stream for %s buffer, %s account and %s type" % (self.name, self.account, self.type))
log.debug("args: %s, kwargs: %s" % (self.args, self.kwargs))
log.debug("Function: %s" % (self.function,))
val = getattr(self.session.twitter.twitter, self.function)(*self.args, **self.kwargs)
number_of_items = self.session.order_buffer(self.name, val)
log.debug("Number of items retrieved: %d" % (number_of_items,))
self.put_items_on_list(number_of_items)
if number_of_items > 0:
sound.player.play("search_updated.ogg")

View File

@ -50,6 +50,7 @@ class Controller(object):
return buffer
def bind_stream_events(self):
log.debug("Binding events for the Twitter stream API...")
pub.subscribe(self.manage_home_timelines, "item-in-home")
pub.subscribe(self.manage_mentions, "mention")
pub.subscribe(self.manage_direct_messages, "direct-message")
@ -67,6 +68,7 @@ class Controller(object):
widgetUtils.connect_event(self.view, widgetUtils.CLOSE_EVENT, self.exit)
def bind_other_events(self):
log.debug("Binding other application events...")
pub.subscribe(self.editing_keystroke, "editing_keystroke")
pub.subscribe(self.manage_stream_errors, "stream-error")
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.search, menuitem=self.view.menuitem_search)
@ -165,6 +167,7 @@ class Controller(object):
tl.timer.start()
def search(self, *args, **kwargs):
log.debug("Creating a new search...")
dlg = dialogs.search.searchDialog()
if dlg.get_response() == widgetUtils.OK:
term = dlg.get("term")
@ -174,6 +177,7 @@ class Controller(object):
buffer.session.settings["other_buffers"]["tweet_searches"].append(term)
search = buffersController.searchBufferController(self.view.nb, "search", "%s-searchterm" % (term,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", q=term)
else:
log.error("A buffer for the %s search term is already created. You can't create a duplicate buffer." % (term,))
return
elif dlg.get("users") == True:
search = buffersController.searchPeopleBufferController(self.view.nb, "search_users", "%s-searchUser" % (term,), buffer.session, buffer.session.db["user_name"], bufferType=None, q=term)
@ -230,8 +234,11 @@ class Controller(object):
buffer.destroy_status()
def exit(self, *args, **kwargs):
log.debug("Exiting...")
for item in session_.sessions:
log.debug("Saving config for %s session" % (session_.sessions[item].session_id,))
session_.sessions[item].settings.write()
log.debug("Disconnecting streams for %s session" % (session_.sessions[item].session_id,))
session_.sessions[item].main_stream.disconnect()
session_.sessions[item].timelinesStream.disconnect()
sound.player.cleaner.cancel()
@ -404,9 +411,8 @@ class Controller(object):
print "i've pressed"
def start_buffers(self, session):
log.debug("starting buffers... Session %s" % (session,))
log.debug("starting buffers... Session %s" % (session.session_id,))
for i in self.buffers:
log.debug("Starting %s for %s" % (i.name, session))
if i.session == session and i.needs_init == True:
i.start_stream()
log.debug("Starting the streaming endpoint")

View File

@ -28,7 +28,9 @@ import config
from pubsub import pub
from mysc.thread_utils import call_threaded
import sound_lib
import logging
log = logging.getLogger("extra.AudioUploader.audioUploader")
class audioUploader(object):
def __init__(self, configFile, completed_callback):
self.config = configFile
@ -45,6 +47,7 @@ class audioUploader(object):
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") == "Dropbox":

View File

@ -4,11 +4,13 @@ import time
import os
import exceptions
import dropbox
import logging
from utils import *
from dropbox.rest import ErrorResponse
from StringIO import StringIO
from pubsub import pub
log = logging.getLogger("extra.AudioUploader.dropbox_transfer")
class UnauthorisedError(exceptions.Exception):
def __init__(self, *args, **kwargs):
super(UnauthorisedError, self).__init__(*args, **kwargs)
@ -38,25 +40,31 @@ class newChunkedUploader(dropbox.client.ChunkedUploader):
class dropboxLogin(object):
def __init__(self, config):
log.debug("Trying to login in Dropbox...")
self.logged = False
self.app_key = "c8ikm0gexqvovol"
self.app_secret = "gvvi6fzfecooast"
self.config = config
def get_url(self):
log.debug("Getting autorisation URL...")
self.flow = dropbox.client.DropboxOAuth2FlowNoRedirect(self.app_key, self.app_secret)
return self.flow.start()
def authorise(self, code):
log.debug("Authorising TWBlue in Dropbox...")
access_token, user_id = self.flow.finish(code)
log.debug("Saving tokens...")
config["services"]["dropbox_token"] = access_token
self.logged = True
class dropboxUploader(object):
def __init__(self, config, filename, completed_callback, short_url=False):
if config["services"]["dropbox_token"] != "":
log.debug("logging in Dropbox...")
self.client = dropbox.client.DropboxClient(config["services"]["dropbox_token"])
else:
log.error("Dropbox is not authorised for this session.")
raise UnauthorisedError("You need authorise TWBlue")
self.filename = filename
self.short_url = short_url
@ -68,6 +76,7 @@ class dropboxUploader(object):
self.background_thread = None
self.current = 0
self.transfer_rate = 0
log.debug("File Size: %d " % (self.file_size,))
def elapsed_time(self):
if not self.start_time:
@ -75,6 +84,7 @@ class dropboxUploader(object):
return time.time() - self.start_time
def perform_transfer(self):
log.debug("Starting transfer...")
self.start_time = time.time()
while self.uploader.offset < self.file_size:
self.uploader.upload_chunked(self.file_size/100)
@ -100,6 +110,7 @@ class dropboxUploader(object):
self.background_thread.start()
def transfer_completed(self):
log.debug("Transfer completed")
self.uploader.finish(os.path.basename(self.filename))
if callable(self.completed_callback):
self.completed_callback()

View File

@ -4,14 +4,17 @@ import sys
import threading
import time
import json
import logging
from utils import *
from pubsub import pub
log = logging.getLogger("extra.AudioUploader.transfer")
class Transfer(object):
def __init__(self, url=None, filename=None, follow_location=True, completed_callback=None, verbose=False, *args, **kwargs):
self.url = url
self.filename = filename
log.debug("Uploading audio to %s, filename %s" % (url, filename))
self.curl = pycurl.Curl()
self.start_time = None
self.completed_callback = completed_callback
@ -51,9 +54,11 @@ class Transfer(object):
pub.sendMessage("uploading", data=progress)
def perform_transfer(self):
log.debug("starting upload...")
self.start_time = time.time()
self.curl.perform()
self.curl.close()
log.debug("Upload finished.")
self.complete_transfer()
def perform_threaded(self):

View File

@ -19,9 +19,12 @@
import wx
import widgetUtils
import output
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)
@ -50,10 +53,12 @@ class audioDialog(widgetUtils.BaseDialog):
sizer.Add(self.attach)
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()

View File

@ -3,20 +3,29 @@ import widgetUtils
import config
import os
import paths
import logging
log = logging.getLogger("extra.SoundsTutorial.soundsTutorial")
import sound
import wx_ui
import soundsTutorial_constants
class soundsTutorial(object):
def __init__(self):
log.debug("Creating sounds tutorial object...")
super(soundsTutorial, self).__init__()
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 = wx_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):
sound.player.play(self.files[self.dialog.items.GetSelection()]+".ogg")
try:
sound.player.play(self.files[self.dialog.items.GetSelection()]+".ogg")
except:
log.exception("Error playing the %s sound" % (self.files[self.dialog.items.GetSelection()],))

View File

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
import logging
log = logging.getLogger("extra.SpellChecker.spellChecker")
import wx_ui
import widgetUtils
import output
@ -10,15 +12,22 @@ from enchant.errors import DictNotFoundError
class spellChecker(object):
def __init__(self, text, dictionary):
super(spellChecker, self).__init__()
log.debug("Creating the SpellChecker object. Dictionary: %s" % (dictionary,))
self.active = True
try:
if config.app["app-settings"]["language"] == "system": self.checker = SpellChecker()
else: self.checker = SpellChecker(languageHandler.getLanguage())
if config.app["app-settings"]["language"] == "system":
log.debug("Using the system language")
self.checker = SpellChecker()
else:
log.debug("Using language: %s" % (languageHandler.getLanguage(),))
self.checker = SpellChecker(languageHandler.getLanguage())
self.checker.set_text(text)
except DictNotFoundError:
log.exception("Dictionary for language %s not found." % (dictionary,))
wx_ui.dict_not_found_error()
self.active = False
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)
@ -37,6 +46,7 @@ class spellChecker(object):
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()
# except AttributeError:

View File

@ -6,6 +6,9 @@ import locale
import gettext
import paths
import platform
import logging
log = logging.getLogger("languageHandler")
# A fix for the mac locales
#if platform.system() == 'Darwin':
@ -116,6 +119,7 @@ def makePgettext(translations):
return pgettext
def setLanguage(lang):
log.debug("Setting language for: %s" % (lang,))
system = platform.system()
global curLang
try:
@ -161,6 +165,7 @@ def setLanguage(lang):
trans=gettext.translation("twblue",fallback=True)
curLang="en"
trans.install(unicode=True)
log.debug("Current language: %s" % (curLang,))
# Install our pgettext function.
# __builtin__.__dict__["pgettext"] = makePgettext(trans)

View File

@ -15,6 +15,8 @@ requests_log = logging.getLogger("requests")
requests_log.setLevel(logging.WARNING)
oauthlib_log = logging.getLogger("oauthlib")
oauthlib_log.setLevel(logging.WARNING)
requests_oauthlib_log = logging.getLogger("requests_oauthlib")
requests_oauthlib_log.setLevel(logging.WARNING)
suds_log = logging.getLogger("suds")
suds_log.setLevel(logging.WARNING)
server_log = logging.getLogger("BaseHTTPServer")
@ -26,12 +28,12 @@ logger.setLevel(logging.DEBUG)
#handlers
app_handler = RotatingFileHandler(paths.logs_path(APP_LOG_FILE), maxBytes=1000000)
app_handler = RotatingFileHandler(paths.logs_path(APP_LOG_FILE), maxBytes=1000000, mode="w")
app_handler.setFormatter(formatter)
app_handler.setLevel(logging.DEBUG)
logger.addHandler(app_handler)
error_handler = logging.FileHandler(paths.logs_path(ERROR_LOG_FILE))
error_handler = logging.FileHandler(paths.logs_path(ERROR_LOG_FILE), mode="w")
error_handler.setFormatter(formatter)
error_handler.setLevel(logging.ERROR)
logger.addHandler(error_handler)

View File

@ -1,12 +1,15 @@
# -*- coding: utf-8 -*-
import wx
import platform
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)
# self.set_size()

View File

@ -1,12 +1,17 @@
import os
import languageHandler
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"

View File

@ -1,4 +1,6 @@
import threading
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
@ -20,6 +22,7 @@ class RepeatingTimer(threading.Thread):
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
@ -27,8 +30,7 @@ class RepeatingTimer(threading.Thread):
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:
# pass
# logging.exception("Execution failed. Function: %r args: %r and kwargs: %r" % (self.function, self.args, self.kwargs))
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))

View File

@ -12,7 +12,8 @@ def call_threaded(func, *args, **kwargs):
func(*a, **k)
except TwythonRateLimitError:
pass
# except:
except:
logging.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
@ -21,7 +22,6 @@ def call_threaded(func, *args, **kwargs):
def stream_threaded(func, *args, **kwargs):
def new_func(*a, **k):
# global session
try:
func(**k)
except:

View File

@ -2,6 +2,7 @@
import platform
import os
import sys
import logging
from platform_utils import paths as paths_
from functools import wraps
@ -9,6 +10,8 @@ from functools import wraps
mode = None
directory = None
log = logging.getLogger("paths")
def merge_paths(func):
@wraps(func)
def merge_paths_wrapper(*a):
@ -28,6 +31,7 @@ def config_path():
elif mode == "installed":
path = data_path("config")
if not os.path.exists(path):
log.debug("%s path does not exist, creating..." % (path,))
os.mkdir(path)
return path
@ -40,6 +44,7 @@ def logs_path():
elif mode == "installed":
path = data_path("logs")
if not os.path.exists(path):
log.debug("%s path does not exist, creating..." % (path,))
os.mkdir(path)
return path

View File

@ -3,6 +3,8 @@
import config
import paths
import os
import logging
log = logging.getLogger("sessionmanager.manager")
import session_exceptions
manager = None
@ -26,8 +28,10 @@ class sessionManager(object):
return False
def add_session(self, id):
log.debug("Adding a new session: %s" % (id,))
path = paths.config_path(id)
if not os.path.exists(path):
log.debug("Creating %s path" % (paths.config_path(path),))
os.mkdir(path)
config.app["sessions"]["sessions"].append(id)

View File

@ -7,10 +7,12 @@ import paths
import output
import time
import sound
import logging
from twitter import utils
from twython import TwythonError, TwythonRateLimitError, TwythonAuthError
from config_utils import Configuration, ConfigurationResetException
from mysc.thread_utils import stream_threaded
log = logging.getLogger("sessionmanager.session")
sessions = {}
@ -96,8 +98,10 @@ class Session(object):
file_ = "%s/session.conf" % (self.session_id,)
try:
log.debug("Creating config file %s" % (file_,))
self.settings = Configuration(paths.config_path(file_), paths.app_path("Conf.defaults"))
except:
log.exception("The session configuration has failed.")
self.settings = None
@_require_configuration
@ -107,8 +111,10 @@ class Session(object):
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:
log.debug("Logging in to twitter...")
self.twitter.login(self.settings["twitter"]["user_key"], self.settings["twitter"]["user_secret"])
self.logged = True
log.debug("Logged.")
else:
self.logged = False
raise Exceptions.RequireCredentialsSessionError
@ -262,10 +268,12 @@ class Session(object):
self.get_timelines()
def get_main_stream(self):
log.debug("Starting the main stream...")
self.main_stream = twitter.buffers.stream.streamer(application.app_key, application.app_secret, self.settings["twitter"]["user_key"], self.settings["twitter"]["user_secret"], self)
stream_threaded(self.main_stream.user, self.session_id)
def get_timelines(self):
log.debug("Starting the timelines stream...")
self.timelinesStream = twitter.buffers.indibidual.timelinesStreamer(application.app_key, application.app_secret, self.settings["twitter"]["user_key"], self.settings["twitter"]["user_secret"], session=self)
ids = ""
for i in self.settings["other_buffers"]["timelines"]:
@ -275,9 +283,11 @@ class Session(object):
def listen_stream_error(self):
if hasattr(self, "main_stream"):
log.debug("Disconnecting the main stream...")
self.main_stream.disconnect()
del self.main_stream
if hasattr(self, "timelinesStream"):
log.debug("disconnecting the timelines stream...")
self.timelinesStream.disconnect()
del self.timelinesStream

View File

@ -4,27 +4,35 @@ import wxUI as view
import paths
import time
import os
import logging
import session
import manager
from config_utils import Configuration
import config
log = logging.getLogger("sessionmanager.sessionManager")
class sessionManagerController(object):
def __init__(self):
super(sessionManagerController, self).__init__()
log.debug("Setting up the session manager.")
manager.setup()
def fill_list(self):
sessionsList = []
log.debug("Filling the sessions list.")
self.sessions = []
for i in os.listdir(paths.config_path()):
if os.path.isdir(paths.config_path(i)) and i not in config.app["sessions"]["ignored_sessions"]:
log.debug("Adding session %s" % (i,))
strconfig = "%s/session.conf" % (paths.config_path(i))
config_test = Configuration(strconfig)
name = config_test["twitter"]["user_name"]
if name != "" and config_test["twitter"]["user_key"] != "" and config_test["twitter"]["user_secret"] != "":
sessionsList.append(name)
self.sessions.append(i)
else:
log.debug("Ignoring session %s" % (i,))
if hasattr(self, "view"): self.view.fill_list(sessionsList)
def show(self):
@ -33,6 +41,7 @@ class sessionManagerController(object):
self.view.Destroy()
def do_ok(self):
log.debug("Starting sessions...")
for i in self.sessions:
s = session.Session(i)
s.get_configuration()
@ -41,6 +50,7 @@ class sessionManagerController(object):
def manage_new_account(self):
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()
@ -49,5 +59,6 @@ class sessionManagerController(object):
self.sessions.append(location)
self.view.add_new_session_to_list()
except:
log.exception("Error authorising the session")
self.view.show_unauthorised_error()
return

View File

@ -19,8 +19,10 @@ player = URLPlayer = None
def setup():
global player, URLPlayer
if not player:
log.debug("Creating sound player...")
player = soundSystem()
if not URLPlayer:
log.debug("creating stream URL player...")
URLPlayer = URLStream()
def recode_audio(filename, quality=4.5):
@ -44,9 +46,11 @@ class soundSystem(object):
self.path = paths.sound_path(config.app["app-settings"]["current_soundpack"])
self.soundpack_OK = True
elif os.path.exists(paths.sound_path("default")):
log.error("The soundpack does not exist, using default...")
self.path = paths.sound_path("default")
self.soundpack_OK = True
else:
log.error("Path for the current soundpack does not exist and the default soundpack is deleted, TWBlue will not play sounds.")
self.soundpack_OK = False
def __init__(self):
@ -56,9 +60,11 @@ class soundSystem(object):
self.input = sound_lib.input.Input()
# 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(config.app["app-settings"]["output_device"]))
self.input.set_device(self.input.find_device_by_name(config.app["app-settings"]["input_device"]))
except:
log.error("Error in input or output devices, using defaults...")
config.app["app-settings"]["output_device"] = "Default"
config.app["app-settings"]["input_device"] = "Default"

View File

@ -13,6 +13,10 @@ class timelinesStreamer(TwythonStreamer):
def on_error(self, status_code, data):
log.debug("%s: %s" % (status_code, data))
def on_timeout(self, *args, **kwargs):
log.debug("Twitter timeout Error")
pub.sendMessage("stream-error")
def check_tls(self, data):
for i in self.session.settings["other_buffers"]["timelines"]:
if data["user"]["screen_name"] == i:

View File

@ -12,6 +12,10 @@ class streamer(TwythonStreamer):
self.muted_users = self.session.db["muted_users"]
# self.blocked_users = []
def on_timeout(self, *args, **kwargs):
log.debug("Twitter timeout Error")
pub.sendMessage("stream-error")
def on_error(self, status_code, data):
log.debug("Error %s: %s" % (status_code, data))

View File

@ -97,5 +97,7 @@ def is_allowed(tweet):
if tweet.has_key("retweeted_status"): tweet = tweet["retweeted_status"]
source = re.sub(r"(?s)<.*?>", "", tweet["source"])
for i in config.main["twitter"]["ignored_clients"]:
if i.lower() == source.lower(): allowed = False
if i.lower() == source.lower():
allowed = False
log.exception("Tuit not allowed: %s" % (tweet["text"],))
return allowed