Merge branch 'next-gen' of https://github.com/manuelcortez/twblue into next-gen

This commit is contained in:
Iván Novegil Cancelas 2017-11-29 18:07:19 +01:00
commit 74b0b9eccf
12 changed files with 152 additions and 31 deletions

View File

@ -2,6 +2,11 @@
## changes in this version
* Added filtering capabilities to TWBlue. ([#102](https://github.com/manuelcortez/TWBlue/issues/102))
* You can create a filter for the current buffer from the buffer menu in the menu bar. At this moment, invisible interface does not have any shorcut for this.
* You can create filters by word or languages.
* For deleting already created filters, you can go to the filter manager in the buffer menu and delete the filters you won't need.
* Links should be opened properly in quoted tweets ([#167,](https://github.com/manuelcortez/TWBlue/issues/167) [#184](https://github.com/manuelcortez/TWBlue/issues/184))
* Increased display name limit up to 50 characters in update profile dialog.
* When authorising an account, you will see a dialogue with a cancel button, in case you want to abort the process. Also, NVDA will not be blocked when the process starts. ([#101](https://github.com/manuelcortez/TWBlue/issues/101))
* In the translator module, the list of available languages is fetched automatically from the provider. That means all of these languages will work and there will not be inconsistencies. Also we've removed the first combo box, because the language is detected automatically by Yandex'S API. ([#153](https://github.com/manuelcortez/TWBlue/issues/153))

View File

@ -6,7 +6,7 @@ if snapshot == False:
update_url = 'https://twblue.es/updates/stable.php'
mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json'
else:
version = "1"
version = "2"
update_url = 'https://twblue.es/updates/snapshot.php'
mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.json'
authors = [u"Manuel Cortéz", u"José Manuel Delicado"]

View File

@ -9,8 +9,6 @@ log = getLogger("config_utils")
class ConfigLoadError(Exception): pass
def load_config(config_path, configspec_path=None, copy=True, *args, **kwargs):
if os.path.exists(config_path):
clean_config(config_path)
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)

View File

@ -3,12 +3,14 @@ import time
import widgetUtils
import application
from wxUI.dialogs import filterDialogs
from wxUI import commonMessageDialogs
class filter(object):
def __init__(self, buffer):
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")
@ -25,6 +27,48 @@ class filter(object):
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)
filter_title = "filter_{0}".format(str(time.time()))
self.buffer.session.settings["filters"][filter_title] = d
self.buffer.session.settings.write()
if self.buffer.session.settings["filters"].has_key(title):
return commonMessageDialogs.existing_filter()
self.buffer.session.settings["filters"][title] = d
self.buffer.session.settings.write()
class filterManager(object):
def __init__(self, session):
self.session = session
self.dialog = filterDialogs.filterManagerDialog()
self.insert_filters(self.session.settings["filters"])
if self.dialog.filters.get_count() == 0:
self.dialog.edit.Enable(False)
self.dialog.delete.Enable(False)
else:
widgetUtils.connect_event(self.dialog.edit, widgetUtils.BUTTON_PRESSED, self.edit_filter)
widgetUtils.connect_event(self.dialog.delete, widgetUtils.BUTTON_PRESSED, self.delete_filter)
response = self.dialog.get_response()
def insert_filters(self, filters):
self.dialog.filters.clear()
for f in filters.keys():
# ToDo: Add titles to filters.
filterName = f
buffer = filters[f]["in_buffer"]
if filters[f]["if_word_exists"] == "True" and filters[f]["word"] != "":
filter_by_word = "True"
else:
filter_by_word = "False"
filter_by_lang = ""
if filters[f]["in_lang"] != "None":
filter_by_lang = "True"
b = [f, buffer, filter_by_word, filter_by_lang]
self.dialog.filters.insert_item(False, *b)
def edit_filter(self, *args, **kwargs):
pass
def delete_filter(self, *args, **kwargs):
filter_title = self.dialog.filters.get_text_column(self.dialog.filters.get_selected(), 0)
response = commonMessageDialogs.delete_filter()
if response == widgetUtils.YES:
self.session.settings["filters"].pop(filter_title)
self.session.settings.write()
self.insert_filters(self.session.settings["filters"])

View File

@ -141,6 +141,7 @@ class Controller(object):
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.list_manager, menuitem=self.view.lists)
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.get_trending_topics, menuitem=self.view.trends)
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.filter, menuitem=self.view.filter)
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.manage_filters, menuitem=self.view.manage_filters)
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.find, menuitem=self.view.find)
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.accountConfiguration, menuitem=self.view.account_settings)
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.configuration, menuitem=self.view.prefs)
@ -490,8 +491,16 @@ class Controller(object):
if not hasattr(page.buffer, "list"):
output.speak(_(u"No session is currently in focus. Focus a session with the next or previous session shortcut."), True)
return
# Let's prevent filtering of some buffers (people buffers, direct messages, events and sent items).
if (page.name == "direct_messages" or page.name =="sent_direct_messages" or page.name == "sent_tweets" or page.name == "events") or page.type == "people":
output.speak(_(u"Filters cannot be applied on this buffer"))
return
new_filter = filterController.filter(page)
def manage_filters(self, *args, **kwargs):
page = self.get_best_buffer()
manage_filters = filterController.filterManager(page.session)
def seekLeft(self, *args, **kwargs):
try:
sound.URLPlayer.seek(-5)

View File

@ -5,7 +5,6 @@ import threading
import wx
from pubsub import pub
from twython import TwythonRateLimitError
import time
def call_threaded(func, *args, **kwargs):
#Call the given function in a daemonized thread and return the thread.

View File

@ -363,7 +363,6 @@ class Session(object):
for z in i.users:
ids += str(z) + ", "
if ids != "":
# print ids
stream_threaded(self.timelinesStream.statuses.filter, self.session_id, follow=ids)
def add_friends(self):

View File

@ -27,21 +27,23 @@ class streamer(TwythonStreamer):
def put_data(self, place, data):
if self.session.db.has_key(place):
if utils.find_item(data["id"], self.session.db[place]) != None and utils.is_allowed(data, self.session.settings, place):
if utils.find_item(data["id"], self.session.db[place]) != None:
log.error("duplicated tweet. Ignoring it...")
return False
# try:
data_ = self.session.check_quoted_status(data)
data_ = self.session.check_long_tweet(data_)
data = data_
if utils.is_allowed(data, self.session.settings, place):
data_ = self.session.check_quoted_status(data)
data_ = self.session.check_long_tweet(data_)
data = data_
# except:
# pass
if self.session.settings["general"]["reverse_timelines"] == False:
self.session.db[place].append(data)
else:
self.session.db[place].insert(0, data)
utils.is_audio(data)
return True
if self.session.settings["general"]["reverse_timelines"] == False:
self.session.db[place].append(data)
else:
self.session.db[place].insert(0, data)
utils.is_audio(data)
return True
return False
def block_user(self, data):
id = data["target"]["id"]

View File

@ -140,15 +140,19 @@ def is_allowed(tweet, settings, buffer_name):
return filter_tweet(tweet, settings, buffer_name)
def filter_tweet(tweet, settings, buffer_name):
if tweet.has_key("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"]
if word != "" and settings["filters"][i]["if_word_exists"]:
if word not in tweet["full_text"]:
if word in tweet[value]:
return False
elif word != "" and settings["filters"][i]["if_word_exists"] == False:
if word in tweet["full_text"]:
if word not in tweet[value]:
return False
if settings["filters"][i]["in_lang"] == "True":
if tweet["lang"] not in settings["filters"][i]["languages"]:

View File

@ -79,4 +79,10 @@ def blocked_timeline():
return wx.MessageDialog(None, _(u"You have been blocked from viewing someone's content. In order to avoid conflicts with the full session, TWBlue will remove the affected timeline."), _(u"Error"), wx.OK).ShowModal()
def suspended_user():
return wx.MessageDialog(None, _(u"TWBlue cannot load this timeline because the user has been suspended from Twitter."), _(u"Error"), wx.OK).ShowModal()
return wx.MessageDialog(None, _(u"TWBlue cannot load this timeline because the user has been suspended from Twitter."), _(u"Error"), wx.OK).ShowModal()
def delete_filter():
return wx.MessageDialog(None, _(u"Do you really want to delete this filter?"), _(u"Attention"), style=wx.ICON_QUESTION|wx.YES_NO).ShowModal()
def existing_filter():
return wx.MessageDialog(None, _(u"This filter already exists. Please use a different title"), _(u"Error"), wx.OK).ShowModal()

View File

@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
import baseDialog
import wx
import widgetUtils
from multiplatform_widgets import widgets
class filterDialog(baseDialog.BaseWXDialog):
def __init__(self, value="", languages=[]):
@ -9,28 +11,42 @@ class filterDialog(baseDialog.BaseWXDialog):
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
self.SetTitle(_(u"Create a filter for this buffer"))
self.contains = wx.RadioButton(panel, -1, _(u"Contains"), style=wx.RB_GROUP)
self.doesnt_contain = wx.RadioButton(panel, -1, _(u"Doesn't contain"))
radioSizer1 = wx.BoxSizer(wx.HORIZONTAL)
label = wx.StaticText(panel, wx.NewId(), _(u"Filter title"))
self.title = wx.TextCtrl(panel, -1, value)
dc = wx.WindowDC(self.title)
dc.SetFont(self.title.GetFont())
self.title.SetSize(dc.GetTextExtent("0"*40))
tsizer = wx.BoxSizer(wx.HORIZONTAL)
tsizer.Add(label, 0, wx.ALL, 5)
tsizer.Add(self.title, 0, wx.ALL, 5)
sizer.Add(tsizer, 0, wx.ALL, 5)
staticbox = wx.StaticBox(panel, label=_(u"Filter by word"))
self.contains = wx.RadioButton(panel, -1, _(u"Ignore tweets wich contain the following word"), style=wx.RB_GROUP)
self.doesnt_contain = wx.RadioButton(panel, -1, _(u"Ignore tweets without the following word"))
radioSizer1 = wx.StaticBoxSizer(staticbox, wx.HORIZONTAL)
radioSizer1.Add(self.contains, 0, wx.ALL, 5)
radioSizer1.Add(self.doesnt_contain, 0, wx.ALL, 5)
sizer.Add(radioSizer1, 0, wx.ALL, 5)
label = wx.StaticText(panel, -1, _(u"word"))
self.term = wx.TextCtrl(panel, -1, value)
dc = wx.WindowDC(self.contains)
dc.SetFont(self.contains.GetFont())
self.contains.SetSize(dc.GetTextExtent("0"*40))
dc = wx.WindowDC(self.term)
dc.SetFont(self.term.GetFont())
self.term.SetSize(dc.GetTextExtent("0"*40))
bsizer = wx.BoxSizer(wx.HORIZONTAL)
bsizer.Add(label, 0, wx.ALL, 5)
bsizer.Add(self.contains, 0, wx.ALL, 5)
bsizer.Add(self.term, 0, wx.ALL, 5)
sizer.Add(bsizer, 0, wx.ALL, 5)
self.regexp = wx.CheckBox(panel, wx.NewId(), _(u"Use this term as a regular expression"))
sizer.Add(self.regexp, 0, wx.ALL, 5)
staticbox = wx.StaticBox(panel, label=_(u"Filter by language"))
self.load_language = wx.RadioButton(panel, -1, _(u"Load tweets in the following languages"), style=wx.RB_GROUP)
self.ignore_language = wx.RadioButton(panel, -1, _(u"Ignore tweets in the following languages"))
self.skip_language_filtering = wx.RadioButton(panel, -1, _(u"Don't filter by language"))
self.skip_language_filtering.SetValue(True)
radioSizer2 = wx.BoxSizer(wx.HORIZONTAL)
widgetUtils.connect_event(self.load_language, widgetUtils.RADIOBUTTON, self.show_language_options)
widgetUtils.connect_event(self.ignore_language, widgetUtils.RADIOBUTTON, self.show_language_options)
widgetUtils.connect_event(self.skip_language_filtering, widgetUtils.RADIOBUTTON, self.hide_language_options)
radioSizer2 = wx.StaticBoxSizer(staticbox, wx.HORIZONTAL)
radioSizer2.Add(self.load_language, 0, wx.ALL, 5)
radioSizer2.Add(self.ignore_language, 0, wx.ALL, 5)
radioSizer2.Add(self.skip_language_filtering, 0, wx.ALL, 5)
@ -62,6 +78,7 @@ class filterDialog(baseDialog.BaseWXDialog):
btnsizer.Add(cancel, 0, wx.ALL, 5)
sizer.Add(btnsizer, 0, wx.ALL, 5)
panel.SetSizer(sizer)
self.hide_language_options()
self.SetClientSize(sizer.CalcMin())
def get_lang(self):
@ -81,3 +98,40 @@ class filterDialog(baseDialog.BaseWXDialog):
def get_selected_langs(self):
return self.indexes
def hide_language_options(self, *args, **kwargs):
for i in [self.cb, self.add, self.langs, self.remove]:
i.Hide()
def show_language_options(self, *args, **kwargs):
for i in [self.cb, self.add, self.langs, self.remove]:
i.Show()
class filterManagerDialog(widgetUtils.BaseDialog):
def __init__(self, *args, **kwargs):
super(filterManagerDialog, self).__init__(parent=None, *args, **kwargs)
self.SetTitle(_(u"Manage filters"))
panel = wx.Panel(self)
label = wx.StaticText(panel, -1, _(u"Filters"))
self.filters = widgets.list(panel, _(u"Filter"), _(u"Buffer"), _(u"Filter by word"), _(u"Filter by language"), size=(800, 800), style=wx.LC_REPORT|wx.LC_SINGLE_SEL)
self.filters.list.SetFocus()
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(label)
sizer.Add(self.filters.list)
self.edit = wx.Button(panel, wx.NewId(), _(u"Edit"))
self.edit.Enable(False)
self.delete = wx.Button(panel, wx.NewId(), _(u"Remove"))
self.cancel = wx.Button(panel, wx.ID_CANCEL)
btnSizer = wx.BoxSizer()
btnSizer.Add(self.edit, 0, wx.ALL, 5)
btnSizer.Add(self.delete, 0, wx.ALL, 5)
btnSizer.Add(self.cancel, 0, wx.ALL, 5)
sizer.Add(btnSizer, 0, wx.ALL, 5)
panel.SetSizer(sizer)
def get_item(self):
return self.filters.get_selected()
def clear(self):
self.filters.clear()

View File

@ -50,7 +50,8 @@ class mainFrame(wx.Frame):
buffer = wx.Menu()
self.update_buffer = buffer.Append(wx.NewId(), _(u"&Update buffer"))
self.trends = buffer.Append(wx.NewId(), _(u"New &trending topics buffer..."))
self.filter = buffer.Append(wx.NewId(), _(u"Create a filter"))
self.filter = buffer.Append(wx.NewId(), _(u"Create a &filter"))
self.manage_filters = buffer.Append(wx.NewId(), _(u"&Manage filters"))
self.find = buffer.Append(wx.NewId(), _(u"Find a string in the currently focused buffer..."))
self.load_previous_items = buffer.Append(wx.NewId(), _(u"&Load previous items"))
buffer.AppendSeparator()