From 2317bb4d5247b7bdb3510ae3e3bf4e79a5336c02 Mon Sep 17 00:00:00 2001 From: Marcos Pinto Date: Fri, 14 Dec 2007 01:23:09 +0000 Subject: [PATCH] change tabs to spaces --- plugins/FlexRSS/plugin.py | 3376 ++++++++++++++++++------------------- 1 file changed, 1688 insertions(+), 1688 deletions(-) diff --git a/plugins/FlexRSS/plugin.py b/plugins/FlexRSS/plugin.py index 25cbce735..0176f2d6f 100644 --- a/plugins/FlexRSS/plugin.py +++ b/plugins/FlexRSS/plugin.py @@ -1,1733 +1,1733 @@ def gtk_treeview_search_cb_stristr(model, column, key, iter, data=None): - value = model.get_value(iter, column) - if value.lower().find(key.lower()) > -1: - return False - else: - return True + value = model.get_value(iter, column) + if value.lower().find(key.lower()) > -1: + return False + else: + return True class plugin_FlexRSS_Config: - constants = { - 'Generic' : 0, - 'TV Show' : 1, - 'TV Show (dated)' : 2 } - feeds_counter = 0 - filters_counter = 0 - feeds = None - filters = None - version = 0 - show_toolbar_button = False - threaded_retrieval = False + constants = { + 'Generic' : 0, + 'TV Show' : 1, + 'TV Show (dated)' : 2 } + feeds_counter = 0 + filters_counter = 0 + feeds = None + filters = None + version = 0 + show_toolbar_button = False + threaded_retrieval = False - def getFilter(self, id): - if not self.filters: - return None + def getFilter(self, id): + if not self.filters: + return None - for filter in self.filters: - if filter['id'] == id: - return filter + for filter in self.filters: + if filter['id'] == id: + return filter - return None + return None - def setFilter(self, id, key, value): - filter = self.getFilter(id) + def setFilter(self, id, key, value): + filter = self.getFilter(id) - if not filter: - return False - else: - filter[key] = value - return True + if not filter: + return False + else: + filter[key] = value + return True - def addFilter(self, name, type, patterns, feeds): - id = self.feeds_counter + 1 - self.feeds_counter = id + def addFilter(self, name, type, patterns, feeds): + id = self.feeds_counter + 1 + self.feeds_counter = id - if not self.filters: - self.filters = [] + if not self.filters: + self.filters = [] - filter = { "id" : id, - "name" : name, - "type" : type, - "patterns" : patterns, - "feeds" : feeds, - "history" : {}, - "path" : None, - "enabled" : True, - "queue_top": False, - "pause" : False, - "delete" : False} + filter = { "id" : id, + "name" : name, + "type" : type, + "patterns" : patterns, + "feeds" : feeds, + "history" : {}, + "path" : None, + "enabled" : True, + "queue_top": False, + "pause" : False, + "delete" : False} - self.filters.append(filter) + self.filters.append(filter) - return id + return id - def deleteFilter(self, id): - if not self.filters: - return False + def deleteFilter(self, id): + if not self.filters: + return False - i = 0 - while i < len(self.filters): - if self.filters[i]['id'] == id: - del self.filters[i] - return True - i = i + 1 + i = 0 + while i < len(self.filters): + if self.filters[i]['id'] == id: + del self.filters[i] + return True + i = i + 1 - def checkHistory(self, id, type, data): - filter = self.getFilter(id) + def checkHistory(self, id, type, data): + filter = self.getFilter(id) - if not filter: - return False + if not filter: + return False - try: - if type == self.constants['TV Show']: - filter['history'][type][data['series']].index(data['episode']) - return True - elif type == self.constants['TV Show (dated)']: - filter['history'][type][data['year']][data['month']].index(data['day']) - return True - else: - filter['history'][type].index(data['url']) - return True - except: - return False + try: + if type == self.constants['TV Show']: + filter['history'][type][data['series']].index(data['episode']) + return True + elif type == self.constants['TV Show (dated)']: + filter['history'][type][data['year']][data['month']].index(data['day']) + return True + else: + filter['history'][type].index(data['url']) + return True + except: + return False - def checkRange(self, id, type, data): - filter = self.getFilter(id) + def checkRange(self, id, type, data): + filter = self.getFilter(id) - if not filter: - return False + if not filter: + return False - if type == self.constants['TV Show']: - if filter['history'][type].has_key('from'): - if data['series'] < filter['history'][type]['from']['season']: - return False - elif data['series'] == filter['history'][type]['from']['season']: - if data['episode'] < filter['history'][type]['from']['episode']: - return False + if type == self.constants['TV Show']: + if filter['history'][type].has_key('from'): + if data['series'] < filter['history'][type]['from']['season']: + return False + elif data['series'] == filter['history'][type]['from']['season']: + if data['episode'] < filter['history'][type]['from']['episode']: + return False - if filter['history'][type].has_key('thru'): - if data['series'] > filter['history'][type]['thru']['season']: - return False - elif data['series'] == filter['history'][type]['thru']['season']: - if data['episode'] > filter['history'][type]['thru']['episode']: - return False + if filter['history'][type].has_key('thru'): + if data['series'] > filter['history'][type]['thru']['season']: + return False + elif data['series'] == filter['history'][type]['thru']['season']: + if data['episode'] > filter['history'][type]['thru']['episode']: + return False - return True + return True - elif type == self.constants['TV Show (dated)']: - if filter['history'][type].has_key('from'): - if data['year'] < filter['history'][type]['from']['year']: - return False - elif data['year'] == filter['history'][type]['from']['year']: - if data['month'] < filter['history'][type]['from']['month']: - return False - elif data['month'] == filter['history'][type]['from']['month']: - if data['day'] < filter['history'][type]['from']['day']: - return False + elif type == self.constants['TV Show (dated)']: + if filter['history'][type].has_key('from'): + if data['year'] < filter['history'][type]['from']['year']: + return False + elif data['year'] == filter['history'][type]['from']['year']: + if data['month'] < filter['history'][type]['from']['month']: + return False + elif data['month'] == filter['history'][type]['from']['month']: + if data['day'] < filter['history'][type]['from']['day']: + return False - if filter['history'][type].has_key('thru'): - if data['year'] > filter['history'][type]['thru']['year']: - return False - elif data['year'] == filter['history'][type]['thru']['year']: - if data['month'] > filter['history'][type]['thru']['month']: - return False - elif data['month'] == filter['history'][type]['thru']['month']: - if data['day'] > filter['history'][type]['thru']['day']: - return False + if filter['history'][type].has_key('thru'): + if data['year'] > filter['history'][type]['thru']['year']: + return False + elif data['year'] == filter['history'][type]['thru']['year']: + if data['month'] > filter['history'][type]['thru']['month']: + return False + elif data['month'] == filter['history'][type]['thru']['month']: + if data['day'] > filter['history'][type]['thru']['day']: + return False - return True + return True - else: - return True + else: + return True - def addHistory(self, id, type, data): - filter = self.getFilter(id) + def addHistory(self, id, type, data): + filter = self.getFilter(id) - if not filter: - return False + if not filter: + return False - if type == self.constants['TV Show']: - if not filter['history'].has_key(type): - filter['history'][type] = {} - if not filter['history'][type].has_key(data['series']): - filter['history'][type][data['series']] = [] - filter['history'][type][data['series']].append(data['episode']) - elif type == self.constants['TV Show (dated)']: - if not filter['history'].has_key(type): - filter['history'][type] = {} - if not filter['history'][type].has_key(data['year']): - filter['history'][type][data['year']] = {} - if not filter['history'][type][data['year']].has_key(data['month']): - filter['history'][type][data['year']][data['month']] = [] - filter['history'][type][data['year']][data['month']].append(data['day']) - else: - if not filter['history'].has_key(type): - filter['history'][type] = [] - try: - filter['history'][type].append(data['url']) - except AttributeError, e: - filter['history'][type] = [data['url']] + if type == self.constants['TV Show']: + if not filter['history'].has_key(type): + filter['history'][type] = {} + if not filter['history'][type].has_key(data['series']): + filter['history'][type][data['series']] = [] + filter['history'][type][data['series']].append(data['episode']) + elif type == self.constants['TV Show (dated)']: + if not filter['history'].has_key(type): + filter['history'][type] = {} + if not filter['history'][type].has_key(data['year']): + filter['history'][type][data['year']] = {} + if not filter['history'][type][data['year']].has_key(data['month']): + filter['history'][type][data['year']][data['month']] = [] + filter['history'][type][data['year']][data['month']].append(data['day']) + else: + if not filter['history'].has_key(type): + filter['history'][type] = [] + try: + filter['history'][type].append(data['url']) + except AttributeError, e: + filter['history'][type] = [data['url']] - def getFeed(self, id): - if not self.feeds: - return None + def getFeed(self, id): + if not self.feeds: + return None - for feed in self.feeds: - if feed['id'] == id: - return feed + for feed in self.feeds: + if feed['id'] == id: + return feed - return None + return None - def setFeed(self, id, key, value): - feed = self.getFeed(id) + def setFeed(self, id, key, value): + feed = self.getFeed(id) - if not feed: - return False - else: - feed[key] = value - return True + if not feed: + return False + else: + feed[key] = value + return True - def addFeed(self, name, url, interval): - # Uhhh... no ++? WTF is the increment operator? - id = self.feeds_counter + 1 - self.feeds_counter = id + def addFeed(self, name, url, interval): + # Uhhh... no ++? WTF is the increment operator? + id = self.feeds_counter + 1 + self.feeds_counter = id - if not self.feeds: - self.feeds = [] + if not self.feeds: + self.feeds = [] - self.feeds.append({ "id" : id, - "name" : name, - "url" : url, - "interval" : interval, - "enabled" : True }) + self.feeds.append({ "id" : id, + "name" : name, + "url" : url, + "interval" : interval, + "enabled" : True }) - return id + return id - def deleteFeed(self, id): - if not self.feeds: - return False + def deleteFeed(self, id): + if not self.feeds: + return False - i = 0 - while i < len(self.feeds): - if self.feeds[i]['id'] == id: - del self.feeds[i] - return True - i = i + 1 + i = 0 + while i < len(self.feeds): + if self.feeds[i]['id'] == id: + del self.feeds[i] + return True + i = i + 1 class plugin_FlexRSS: - config = None - glade = None - feeds = None - toolbar_button = None - history_calendarbuttons = None - - def update_config(self): - if self.config.version >= 5: - return - - if self.config.version < 1: - print 'Updating config to v1' - i = 0 - while i < len(self.config.filters): - self.config.filters[i]['enabled'] = True - i = i + 1 - - if self.config.version < 2: - print 'Updating config to v2' - i = 0 - while i < len(self.config.feeds): - self.config.feeds[i]['enabled'] = True - i = i + 1 - - if self.config.version < 3: - print 'Updating config to v3' - i = 0 - while i < len(self.config.filters): - type_s = self.config.filters[i]['type'] - type_i = self.config.constants[type_s] - if self.config.filters[i]['history'].has_key(type_s): - history = { type_i: self.config.filters[i]['history'][type_s] } - self.config.filters[i]['history'] = history - self.config.filters[i]['type'] = self.config.constants[self.config.filters[i]['type']]; - i = i + 1 - - if self.config.version < 4: - print 'Updating config to v4' - i = 0 - while i < len(self.config.filters): - self.config.filters[i]['queue_top'] = False - self.config.filters[i]['pause'] = False - i = i + 1 - - if self.config.version < 5: - print 'Updating config to v5' - i = 0 - while i < len(self.config.filters): - self.config.filters[i]['delete'] = False - i = i + 1 - - self.config.version = 5 - self.write_config() - - def load_config(self): - import deluge.common, os, cookielib - - file = deluge.common.CONFIG_DIR + "/flexrss.dat" - if os.path.isfile(file): - import pickle - - fd = open(file, 'r') - self.config = pickle.load(fd) - fd.close() - else: - self.config = plugin_FlexRSS_Config() - self.config.version = 5 - - self.update_config() - - cookie_file = deluge.common.CONFIG_DIR + "/flexrss-cookies.txt" - self.cookies = cookielib.MozillaCookieJar() - if os.path.isfile(cookie_file): - self.cookies.load(cookie_file) - - def write_config(self, write_cookies=False): - import deluge.common, os, pickle - - file = deluge.common.CONFIG_DIR + "/flexrss.dat" - fd = open(file, 'w') - pickle.dump(self.config, fd) - fd.close() - - if write_cookies: - print "Saving cookies." - self.cookies.save(deluge.common.CONFIG_DIR + "/flexrss-cookies.txt") - - def configure_cb_closed(self, args): - self.glade = None - self.history_calendarbuttons = None - - def configure_cb_feed_new(self, args): - feed = { "name" : 'Untitled', - "url" : 'http://', - "interval" : 900, - "id" : 0 } - - feed["id"] = self.config.addFeed(feed["name"], feed["url"], feed["interval"]) - - view = self.glade.get_widget("FlexRSS_Feeds") - model = view.get_model() - view.get_selection().select_iter(model.append(None, (feed["id"], feed["name"], feed["url"]))) - - def configure_cb_feed_selected(self, selection): - model, iter = selection.get_selected() - - if not iter: - return - - parent = model.iter_parent(iter) - if parent: # Selected a filter - self.glade.get_widget('FlexRSS_Filters_Test_Pattern').set_text(model.get_value(iter, 1)) - self.configure_cb_test_filter(None) - - iter = parent - - # We want to edit a feed. - feed = self.config.getFeed(model.get_value(iter, 0)) - if not feed: - print 'Error: could not find feed #' + str(model.get_value(iter, 0)) - return - - self.glade.get_widget("FlexRSS_EditFeed_Name").set_text(feed["name"]) - self.glade.get_widget("FlexRSS_EditFeed_URL").set_text(feed["url"]) - self.glade.get_widget("FlexRSS_EditFeed_Interval").set_text(str(feed["interval"])) - if feed["enabled"] == True: - self.glade.get_widget("FlexRSS_EditFeed_Status_Enabled").set_active(True) - else: - self.glade.get_widget("FlexRSS_EditFeed_Status_Disabled").set_active(True) - self.glade.get_widget('FlexRSS_Feeds_Editor').show() - - def configure_cb_feed_delete(self, arg, id=None): - if not id: - # Which feed is selected? - selection = self.glade.get_widget("FlexRSS_Feeds").get_selection() - model, iter = selection.get_selected() - - if not iter: - return - - id = model.get_value(iter, 0) - if id == 0: - id = model.get_value(model.iter_parent(iter), 0) - else: - model = self.glade.get_widget("FlexRSS_Feeds").get_model() - iter = model.get_iter_first() - while iter: - if model.get_value(iter, 0) == id: - break - iter = model.iter_next(iter) - - if not iter: - print 'Couldn\'t find feed.' - return - - # Remove from config - if not self.config.deleteFeed(id): - print 'Unable to delete feed #' + str(id) - return - - # Remove from UI - model.remove(iter) - - self.write_config() - - # We are no longer editing a feed, so hide the editing widgets. - self.glade.get_widget('FlexRSS_Feeds_Editor').hide() - - def configure_cb_feed_save(self, arg, id=None): - if not id: - # Which feed is selected? - selection = self.glade.get_widget("FlexRSS_Feeds").get_selection() - model, iter = selection.get_selected() - - if not iter: - return - - id = model.get_value(iter, 0) - if id == 0: - iter = model.iter_parent(iter) - id = model.get_value(iter, 0) - else: - model = self.glade.get_widget("FlexRSS_Feeds").get_model() - iter = model.iter_first() - while iter: - if model.get_value(iter, 0) == id: - break - iter = iter.iter_next(iter) - - if not iter: - print 'Couldn\'t find feed.' - return - - # Update configuration - self.config.setFeed(id, "name", self.glade.get_widget("FlexRSS_EditFeed_Name").get_text()) - self.config.setFeed(id, "url", self.glade.get_widget("FlexRSS_EditFeed_URL").get_text()) - interval = self.configure_ui_get_text_as_int("FlexRSS_EditFeed_Interval", 900) - if interval < 300: - # It's just not polite to hit a server that often. - self.glade.get_widget("FlexRSS_EditFeed_Interval").set_text('300') - interval = 300 - self.config.setFeed(id, "interval", interval) - self.config.setFeed(id, "enabled", self.glade.get_widget("FlexRSS_EditFeed_Status_Enabled").get_active()) - self.write_config() - - # Update UI - feed = self.config.getFeed(id) - model.set_value(iter, 0, feed["id"]) - model.set_value(iter, 1, feed["name"]) - model.set_value(iter, 2, feed["url"]) - - if not self.feeds.has_key(id): - self.feeds[id] = { 'cfg' : feed, - 'updated' : 0, - 'data' : [] } - - def escape_regex_special_chars(self, pattern): - escape_chars = '[]()^$\\.?*+|' - out = [] - for c in pattern: - try: - escape_chars.index(c) - out.append('\\' + c) - except: - out.append(c) - return ''.join(out) - - def configure_cb_filter_new(self, arg, test_pattern=None): - filter = { "name" : "Untitled", - "type" : "Generic", - "patterns" : [('', 'Title')], - "feeds" : [0], - "id" : 0 } - - if test_pattern: - # Try to guess a good pattern - import re, string - - trans_table = string.maketrans(' ', '.') - - # TV Show - exp = re.compile(r'(.*?)S([0-9]+)E([0-9]+)', re.IGNORECASE) - match = exp.match(test_pattern) - if match: - pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + 's%se%e' - filter['patterns'][0] = (pattern, 'Title') - filter['name'] = match.group(1) - filter['type'] = self.config.constants['TV Show'] - - if not match: - exp = re.compile(r'(.*?)([0-9]{4}).([0-9]{1,2}).([0-9]{1,2})', re.IGNORECASE) - match = exp.match(test_pattern) - if match: - pattern = None - if ((int(match.group(3)) <= 12) and (int(match.group(4)) <= 31)): - pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + '%Y.%m.%d' - elif ((int(match.group(3)) <= 31) and (int(match.group(4)) <= 12)): - pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + '%Y.%d.%m' - - if pattern: - filter['patterns'][0] = (pattern, 'Title') - filter['name'] = match.group(1) - filter['type'] = self.config.constants['TV Show (dated)'] - else: - match = None - - if not match: - exp = re.compile(r'(.*?)([0-9]{2}).([0-9]{2}).([0-9]{2})', re.IGNORECASE) - match = exp.match(test_pattern) - if match: - pattern = None - if ((int(match.group(2)) <= 12) and (int(match.group(3)) <= 31)): - pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + '%m.%d.%y' - elif ((int(match.group(3)) <= 31) and (int(match.group(2)) <= 12)): - pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + '%d.%m.%y' - - if pattern: - filter['patterns'][0] = (pattern, 'Title') - filter['name'] = match.group(1) - filter['type'] = self.config.constants['TV Show (dated)'] - else: - match = None - - if not match: - exp = re.compile(r'(.*?)([0-9]+)([x\.\-_]{1})([0-9]+)', re.IGNORECASE) - match = exp.match(test_pattern) - if match: - pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + '%s' + self.escape_regex_special_chars(match.group(3)) + '%e' - filter['patterns'][0] = (pattern, 'Title') - filter['name'] = match.group(1) - filter['type'] = self.config.constants['TV Show'] - - if not match: - exp = re.compile(r'(.*?)([0-9]+)$', re.IGNORECASE) - match = exp.match(test_pattern) - if match: - pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + '%e' - filter['patterns'][0] = (pattern, 'Title') - filter['name'] = match.group(1) - filter['type'] = self.config.constants['TV Show'] - - # Add to config - filter['id'] = self.config.addFilter(filter['name'], filter['type'], filter['patterns'], [0]) - - # Add to UI - self.configure_ui_add_filter(self.config.getFilter(filter['id']), test_pattern) - - def configure_cb_filter_selected(self, selection): - model, iter = selection.get_selected() - - if not iter: - return - - # We want to edit a filter. - filter = self.config.getFilter(model.get_value(iter, 0)) - if not filter: - print 'Error: could not find filter #' + str(model.get_value(iter, 0)) - return - - self.configure_ui_reset_filter() - - self.glade.get_widget('FlexRSS_Filters_Name').set_text(filter['name']) - - if filter['type'] == self.config.constants['TV Show']: - type_i = 1 - elif filter['type'] == self.config.constants['TV Show (dated)']: - type_i = 2 - else: - type_i = 0 - - self.glade.get_widget('FlexRSS_Filters_Type').set_active(type_i) - - selection = self.glade.get_widget('FlexRSS_Filters_Feed').get_selection() - selection.unselect_all() - feed_model = self.glade.get_widget('FlexRSS_Filters_Feed').get_model() - for i in filter['feeds']: - if i == 0: - selection.select_all() - else: - iter = feed_model.get_iter_first() - while iter: - if feed_model.get_value(iter, 0) == i: - selection.select_iter(iter) - iter = feed_model.iter_next(iter) - - for pattern in filter['patterns']: - self.configure_ui_add_pattern(pattern) - - if filter['type'] == self.config.constants['TV Show']: - if filter['history'].has_key(filter['type']) and filter['history'][filter['type']].has_key('from'): - self.glade.get_widget('FlexRSS_History_TVShow_From_Enabled').set_active(True) - self.glade.get_widget('FlexRSS_History_TVShow_From_Season').set_sensitive(True) - self.glade.get_widget('FlexRSS_History_TVShow_From_Episode').set_sensitive(True) - self.glade.get_widget('FlexRSS_History_TVShow_From_Season').set_text(str(filter['history'][filter['type']]['from']['season'])) - self.glade.get_widget('FlexRSS_History_TVShow_From_Episode').set_text(str(filter['history'][filter['type']]['from']['episode'])) - else: - self.glade.get_widget('FlexRSS_History_TVShow_From_Enabled').set_active(False) - self.glade.get_widget('FlexRSS_History_TVShow_From_Season').set_sensitive(False) - self.glade.get_widget('FlexRSS_History_TVShow_From_Episode').set_sensitive(False) - self.glade.get_widget('FlexRSS_History_TVShow_From_Season').set_text('0') - self.glade.get_widget('FlexRSS_History_TVShow_From_Episode').set_text('0') - - if filter['history'].has_key(filter['type']) and filter['history'][filter['type']].has_key('thru'): - self.glade.get_widget('FlexRSS_History_TVShow_Thru_Enabled').set_active(True) - self.glade.get_widget('FlexRSS_History_TVShow_Thru_Season').set_sensitive(True) - self.glade.get_widget('FlexRSS_History_TVShow_Thru_Episode').set_sensitive(True) - self.glade.get_widget('FlexRSS_History_TVShow_Thru_Season').set_text(str(filter['history'][filter['type']]['thru']['season'])) - self.glade.get_widget('FlexRSS_History_TVShow_Thru_Episode').set_text(str(filter['history'][filter['type']]['thru']['episode'])) - else: - self.glade.get_widget('FlexRSS_History_TVShow_Thru_Enabled').set_active(False) - self.glade.get_widget('FlexRSS_History_TVShow_Thru_Season').set_sensitive(False) - self.glade.get_widget('FlexRSS_History_TVShow_Thru_Episode').set_sensitive(False) - self.glade.get_widget('FlexRSS_History_TVShow_Thru_Season').set_text('0') - self.glade.get_widget('FlexRSS_History_TVShow_Thru_Episode').set_text('0') - - self.glade.get_widget("FlexRSS_History_TVShow_Dated").hide() - self.glade.get_widget("FlexRSS_History_TVShow").show() - self.glade.get_widget("FlexRSS_Filter_History_Range").show() - elif filter['type'] == self.config.constants['TV Show (dated)']: - import time - - cal_from, cal_thru = self.history_calendarbuttons - today = time.localtime() - - if filter['history'].has_key(filter['type']) and filter['history'][filter['type']].has_key('from'): - self.glade.get_widget('FlexRSS_History_TVShow_Dated_From_Enabled').set_active(True) - cal_from.set_sensitive(True) - cal_from.set_date(filter['history'][filter['type']]['from']['year'], - filter['history'][filter['type']]['from']['month'], - filter['history'][filter['type']]['from']['day']) - else: - self.glade.get_widget('FlexRSS_History_TVShow_Dated_From_Enabled').set_active(False) - cal_from.set_sensitive(False) - cal_from.set_date(today[0], today[1], today[2]) - - if filter['history'].has_key(filter['type']) and filter['history'][filter['type']].has_key('thru'): - self.glade.get_widget('FlexRSS_History_TVShow_Dated_Thru_Enabled').set_active(True) - cal_thru.set_sensitive(True) - cal_thru.set_date(filter['history'][filter['type']]['thru']['year'], - filter['history'][filter['type']]['thru']['month'], - filter['history'][filter['type']]['thru']['day']) - else: - self.glade.get_widget('FlexRSS_History_TVShow_Dated_Thru_Enabled').set_active(False) - cal_thru.set_sensitive(False) - cal_thru.set_date(today[0], today[1], today[2]) - - self.glade.get_widget("FlexRSS_History_TVShow").hide() - self.glade.get_widget("FlexRSS_History_TVShow_Dated").show() - self.glade.get_widget("FlexRSS_Filter_History_Range").show() - else: - self.glade.get_widget("FlexRSS_History_TVShow").hide() - self.glade.get_widget("FlexRSS_History_TVShow_Dated").hide() - self.glade.get_widget("FlexRSS_Filter_History_Range").hide() - - self.glade.get_widget('FlexRSS_Filter_Download_QueueTop').set_active(filter.get('queue_top', False)) - self.glade.get_widget('FlexRSS_Filter_Download_Pause').set_active(filter.get('pause', False)) - self.glade.get_widget('FlexRSS_Filter_Download_Delete').set_active(filter.get('delete', False)) - - self.configure_cb_test_filter(None) - - if filter['path'] != None: - self.glade.get_widget('FlexRSS_Filter_Output_Location').set_current_folder(filter['path']) - self.glade.get_widget('FlexRSS_Filter_Output_Type_Custom').set_active(True) - else: - self.glade.get_widget('FlexRSS_Filter_Output_Type_Default').set_active(True) - - replace = filter.get('replace', {'pattern': '', 'with': ''}) - self.glade.get_widget('FlexRSS_Filter_Rewrite_Pattern').set_text(replace['pattern']) - self.glade.get_widget('FlexRSS_Filter_Rewrite_Replacement').set_text(replace['with']) - - def configure_cb_filter_history_toggle(self, box): - name = box.get_name() - active = box.get_active() - - if name == 'FlexRSS_History_TVShow_From_Enabled': - self.glade.get_widget('FlexRSS_History_TVShow_From_Season').set_sensitive(active) - self.glade.get_widget('FlexRSS_History_TVShow_From_Episode').set_sensitive(active) - elif name == 'FlexRSS_History_TVShow_Thru_Enabled': - self.glade.get_widget('FlexRSS_History_TVShow_Thru_Season').set_sensitive(active) - self.glade.get_widget('FlexRSS_History_TVShow_Thru_Episode').set_sensitive(active) - elif name == 'FlexRSS_History_TVShow_Dated_From_Enabled': - self.history_calendarbuttons[0].set_sensitive(active) - elif name == 'FlexRSS_History_TVShow_Dated_Thru_Enabled': - self.history_calendarbuttons[1].set_sensitive(active) - - self.configure_cb_test_filter(None) - - def configure_ui_get_text_as_int(self, widget_name, default=0): - try: - return int(self.glade.get_widget(widget_name).get_text()) - except: - return default - - def configure_ui_get_history_restriction(self): - h_from = None - h_thru = None - - type = self.glade.get_widget('FlexRSS_Filters_Type').get_active() - if type == 1: - type_s = self.config.constants['TV Show'] - elif type == 2: - type_s = self.config.constants['TV Show (dated)'] - else: - type_s = self.config.constants['Generic'] - - if type_s == self.config.constants['TV Show']: - if self.glade.get_widget('FlexRSS_History_TVShow_From_Enabled').get_active(): - from_season = self.configure_ui_get_text_as_int('FlexRSS_History_TVShow_From_Season') - from_episode = self.configure_ui_get_text_as_int('FlexRSS_History_TVShow_From_Episode') - h_from = {'season': from_season, 'episode': from_episode} - elif type_s == self.config.constants['TV Show (dated)']: - if self.glade.get_widget('FlexRSS_History_TVShow_Dated_From_Enabled').get_active(): - from_y, from_m, from_d = self.history_calendarbuttons[0].get_date() - h_from = {'year': from_y, 'month': from_m, 'day': from_d} - - if type_s == self.config.constants['TV Show']: - if self.glade.get_widget('FlexRSS_History_TVShow_Thru_Enabled').get_active(): - thru_season = self.configure_ui_get_text_as_int('FlexRSS_History_TVShow_Thru_Season') - thru_episode = self.configure_ui_get_text_as_int('FlexRSS_History_TVShow_Thru_Episode') - h_thru = {'season': thru_season, 'episode': thru_episode} - elif type_s == self.config.constants['TV Show (dated)']: - if self.glade.get_widget('FlexRSS_History_TVShow_Dated_Thru_Enabled').get_active(): - thru_y, thru_m, thru_d = self.history_calendarbuttons[1].get_date() - h_thru = {'year': thru_y, 'month': thru_m, 'day': thru_d} - - return (h_from, h_thru) - - def configure_cb_filter_save(self, arg): - # Which feed is selected? - selection = self.glade.get_widget("FlexRSS_Filters_List").get_selection() - model, iter = selection.get_selected() - - if not iter: - return - - id = model.get_value(iter, 0) - name = self.glade.get_widget('FlexRSS_Filters_Name').get_text() - self.config.setFilter(id, 'name', name) - iter = model.get_iter_first() - while iter: - if model.get_value(iter, 0) == id: - model.set_value(iter, 1, name) - iter = model.iter_next(iter) - - type = self.glade.get_widget('FlexRSS_Filters_Type').get_active() - if type == 1: - type_s = self.config.constants['TV Show'] - elif type == 2: - type_s = self.config.constants['TV Show (dated)'] - else: - type_s = self.config.constants['Generic'] - self.config.setFilter(id, 'type', type_s) - - model, paths = self.glade.get_widget('FlexRSS_Filters_Feed').get_selection().get_selected_rows() - feeds = [] - for path in paths: - feeds.append(model.get_value(model.get_iter(path), 0)) - if len(feeds) == 0: - feeds.append(0) - self.config.setFilter(id, 'feeds', feeds) - - patterns = [] - filter_patterns = self.glade.get_widget('FlexRSS_Filter_Patterns_List') - for i in filter_patterns.get_children(): - data = i.get_children() - pattern = data[0].get_text() - if data[2].get_active() == 1: - type = 'Link' - else: - type = 'Title' - patterns.append((pattern, type)) - self.config.setFilter(id, 'patterns', patterns) - - if self.glade.get_widget('FlexRSS_Filter_Output_Type_Custom').get_active(): - path = self.glade.get_widget('FlexRSS_Filter_Output_Location').get_current_folder() - else: - path = None - - self.config.setFilter(id, 'path', path) - - self.config.setFilter(id, 'queue_top', self.glade.get_widget('FlexRSS_Filter_Download_QueueTop').get_active()) - self.config.setFilter(id, 'pause', self.glade.get_widget('FlexRSS_Filter_Download_Pause').get_active()) - self.config.setFilter(id, 'delete', self.glade.get_widget('FlexRSS_Filter_Download_Delete').get_active()) - - filter = self.config.getFilter(id) - - h_from, h_thru = self.configure_ui_get_history_restriction() - if filter['type'] != self.config.constants['Generic']: - if not filter['history'].has_key(filter['type']): - filter['history'][filter['type']] = {} - - if h_from != None: - filter['history'][filter['type']]['from'] = h_from - else: - if filter['history'][filter['type']].has_key('from'): - del filter['history'][filter['type']]['from'] - - if h_thru != None: - filter['history'][filter['type']]['thru'] = h_thru - else: - if filter['history'][filter['type']].has_key('thru'): - del filter['history'][filter['type']]['thru'] - - filter['replace'] = { 'pattern': self.glade.get_widget('FlexRSS_Filter_Rewrite_Pattern').get_text(), - 'with' : self.glade.get_widget('FlexRSS_Filter_Rewrite_Replacement').get_text() } - - self.write_config() - - def configure_cb_remove_pattern(self, arg): - arg.get_parent().destroy() - - def configure_ui_add_pattern(self, pattern): - import gtk, gobject - - filter_patterns = self.glade.get_widget('FlexRSS_Filter_Patterns_List') - - hbox = gtk.HBox() - filter_patterns.pack_start(hbox) - - input = gtk.Entry() - input.set_text(pattern[0]) - input.connect("changed", self.configure_cb_test_filter) - - on = gtk.Label() - on.set_text('On') - on.show() - - combo = gtk.combo_box_new_text() - combo.append_text('Title') - combo.append_text('Link') - if pattern[1] == 'Link': - combo.set_active(1) - else: - combo.set_active(0) - - remove = gtk.Button(stock=gtk.STOCK_REMOVE) - remove.connect("pressed", self.configure_cb_remove_pattern) - - hbox.pack_start(input) - hbox.pack_start(on, expand=False) - hbox.pack_start(combo, expand=False) - hbox.pack_start(remove, expand=False) - - hbox.show_all() - - def configure_cb_add_pattern(self, args): - self.configure_ui_add_pattern(('', 'Title')) - - def configure_ui_add_filter(self, filter, test_pattern=None): - if not filter: - print 'No filter to add' - return None - - self.configure_ui_reset_filter() - - model = self.glade.get_widget("FlexRSS_Filters_List").get_model() - iter = model.append((filter['id'], filter['name'], filter['enabled'])) - - if not iter: - return - - view = self.glade.get_widget("FlexRSS_Filters_List") - model = view.get_model() - view.get_selection().select_iter(iter) - - if test_pattern: - self.glade.get_widget('FlexRSS_Filters_Test_Pattern').set_text(test_pattern) - self.configure_cb_test_filter(None) - - self.glade.get_widget('FlexRSS_MainNotebook').set_current_page(1) - - def configure_ui_test_result(self, result, h_match=False): - if result and h_match: - self.glade.get_widget('FlexRSS_Filters_Test_Result').set_text('Match') - else: - self.glade.get_widget('FlexRSS_Filters_Test_Result').set_text('Doesn\'t match') - - type = self.glade.get_widget('FlexRSS_Filters_Type').get_active() - - if type == 0: # Generic - self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow').hide() - self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated').hide() - self.glade.get_widget('FlexRSS_History_TVShow').hide() - self.glade.get_widget('FlexRSS_History_TVShow_Dated').hide() - elif type == 1: # TV Show - self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow').show() - self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated').hide() - self.glade.get_widget('FlexRSS_History_TVShow').show() - self.glade.get_widget('FlexRSS_History_TVShow_Dated').hide() - if result: - self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Series').set_text(str(result['series'])) - self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Episode').set_text(str(result['episode'])) - else: - self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Series').set_text('0') - self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Episode').set_text('0') - else: # TV Show (dated) - self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow').hide() - self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated').show() - self.glade.get_widget('FlexRSS_History_TVShow').hide() - self.glade.get_widget('FlexRSS_History_TVShow_Dated').show() - if result: - self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Year').set_text(str(result['year'])) - self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Month').set_text(str(result['month'])) - self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Day').set_text(str(result['day'])) - else: - self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Year').set_text('0') - self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Month').set_text('0') - self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Day').set_text('0') - - def configure_cb_test_filter(self, source=None, date=None): - subject = self.glade.get_widget('FlexRSS_Filters_Test_Pattern').get_text() - - type = self.glade.get_widget('FlexRSS_Filters_Type').get_active() - if type == 1: - type_s = self.config.constants['TV Show'] - elif type == 2: - type_s = self.config.constants['TV Show (dated)'] - else: - type_s = self.config.constants['Generic'] - - filter_patterns = self.glade.get_widget('FlexRSS_Filter_Patterns_List') - for i in filter_patterns.get_children(): - data = i.get_children() - pattern = data[0].get_text() - result = self.test_pattern(type_s, subject, pattern) - if result: - # Pattern matched, let's try history restriction. - h_from, h_thru = self.configure_ui_get_history_restriction() - h_match = self.test_range(type_s, result, h_from, h_thru) - self.configure_ui_test_result(result, h_match) - return - - self.configure_ui_test_result(False) - - def configure_cb_delete_filter(self, arg): - # Which filter is selected? - selection = self.glade.get_widget("FlexRSS_Filters_List").get_selection() - model, iter = selection.get_selected() - - if not iter: - return - - id = model.get_value(iter, 0) - - # Remove from config - if not self.config.deleteFilter(id): - print 'Unable to delete filter #' + str(id) - return - self.write_config() - - # Remove from UI - model.remove(iter) - - self.configure_ui_reset_filter() - - def configure_cb_feed_refresh(self, caller, id=None): - if not id: - selection = self.glade.get_widget("FlexRSS_Feeds").get_selection() - model, iter = selection.get_selected() - - if not iter: - return - - id = model.get_value(iter, 0) - - if id: - if ( self.config.threaded_retrieval ): - import threading - threading.Thread(target=self.parse_feed, args=(id,)).start() - else: - self.parse_feed(id) - - def configure_cb_download_torrent(self, caller, url): - self.download_torrent(url) - - def configure_cb_feed_popup(self, view, event): - if event.button != 3: - return - - model = view.get_model() - coords = event.get_coords() - path = view.get_path_at_pos(int(coords[0]), int(coords[1])) - if path: - iter = model.get_iter(path[0]) - else: - iter = None - - import gtk - - popup = gtk.Menu() - - if iter: - id = model.get_value(iter, 0) - if id: # Feed - item_refresh = gtk.MenuItem(_("Refresh feed")) - item_refresh.connect("activate", self.configure_cb_feed_refresh, id) - popup.append(item_refresh) - - item_delete = gtk.MenuItem(_("Delete feed")) - item_delete.connect("activate", self.configure_cb_feed_delete, id) - popup.append(item_delete) - - else: # Filter - item_filter = gtk.MenuItem(_("Create filter")) - item_filter.connect("activate", self.configure_cb_filter_new, model.get_value(iter, 1)) - popup.append(item_filter) - - item_download = gtk.MenuItem(_("Download torrent")) - item_download.connect("activate", self.configure_cb_download_torrent, model.get_value(iter, 2)) - popup.append(item_download) - - else: # Neither - item_new = gtk.MenuItem("New feed") - item_new.connect("activate", self.configure_cb_feed_new) - popup.append(item_new) - - popup.popup(None, None, None, event.button, event.time) - popup.show_all() - - def configure_cb_output_set(self, chooser): - self.glade.get_widget('FlexRSS_Filter_Output_Type_Custom').set_active(True) - - def configure_ui_reset_filter(self): - # Just resets the crap in the filter tab to defaults. - self.glade.get_widget('FlexRSS_Filters_Name').set_text('') - self.glade.get_widget('FlexRSS_Filters_Type').set_active(0) - self.glade.get_widget('FlexRSS_Filters_Feed').get_selection().unselect_all() - for filter in self.glade.get_widget('FlexRSS_Filter_Patterns_List').get_children(): - filter.destroy() - self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow').hide() - self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated').hide() - file_chooser = self.glade.get_widget('FlexRSS_Filter_Output_Location') - file_chooser.set_current_folder(self.interface.config.get('default_download_path')) - self.glade.get_widget('FlexRSS_Filter_Output_Type_Default').set_active(True) - - def strcasecmp(self, s1, s2): - try: - t1 = s1.lower() - t2 = s2.lower() - - if s1 < s2: - return -1 - elif s1 > s2: - return 1 - except: - pass - - return 0 - - def configure_ui_sort_cmp(self, model, iter1, iter2, user_data=None): - if (model.get_value(iter1, 0) == 0) or (model.get_value(iter2, 0) == 0): - return 0 - - return self.strcasecmp(model.get_value(iter1, 1), model.get_value(iter2, 1)) - - def configure_cb_filter_toggled(self, renderer, path): - old_val = renderer.get_active() - model = self.glade.get_widget('FlexRSS_Filters_List').get_model() - iter = model.get_iter(path) - if old_val: - model.set_value(iter, 2, False) - self.config.setFilter(model.get_value(iter, 0), 'enabled', False) - else: - model.set_value(iter, 2, True) - self.config.setFilter(model.get_value(iter, 0), 'enabled', True) - self.write_config() - - def configure_cb_cookie_new(self, src): - self.configure_ui_cookie_reset() - self.glade.get_widget("FlexRSS_Cookies_Editor").show() - - def configure_cb_cookie_save(self, src): - import cookielib, time - - domain = self.glade.get_widget("FlexRSS_Cookie_Domain").get_text() - path = self.glade.get_widget("FlexRSS_Cookie_Path").get_text() - name = self.glade.get_widget("FlexRSS_Cookie_Name").get_text() - value = self.glade.get_widget("FlexRSS_Cookie_Value").get_text() - - if (domain == ""): - return - - if path == '': - path = '/' - - # Fragile. - self.cookies._policy._now = self.cookies._now = int(time.time()) - cookie = self.cookies._cookie_from_cookie_tuple((name, value, {"domain": domain, "path":path, "expires":2147483647}, {}), None) - - self.cookies.set_cookie(cookie) - self.configure_ui_add_cookie(None, cookie) - self.configure_ui_cookie_reset() - self.glade.get_widget("FlexRSS_Cookies_Editor").hide() - self.write_config(True) - - def configure_ui_add_cookie(self, model, cookie): - if cookie.domain[0] == '.': - domain = cookie.domain[1:] - else: - domain = cookie.domain - - if model == None: - model = self.glade.get_widget("FlexRSS_Cookies_List").get_model() - - parent = None - iter = model.get_iter_first() - while iter: - t = model.get_value(iter, 0) - if t == domain: - parent = iter - break - iter = model.iter_next(iter) - - if parent == None: - parent = model.append(iter, (domain, "", "", "")) - model.append(parent, (cookie.domain, cookie.path, cookie.name, cookie.value)) - - def configure_ui_cookie_reset(self): - self.glade.get_widget("FlexRSS_Cookie_Domain").set_text('') - self.glade.get_widget("FlexRSS_Cookie_Path").set_text('/') - self.glade.get_widget("FlexRSS_Cookie_Name").set_text('') - self.glade.get_widget("FlexRSS_Cookie_Value").set_text('') - - def configure_cb_cookie_selected(self, selection): - model, iter = selection.get_selected() - - self.configure_ui_cookie_reset() - self.glade.get_widget("FlexRSS_Cookies_Editor").hide() - - def configure_cb_cookie_delete(self, src): - selection = self.glade.get_widget("FlexRSS_Cookies_List").get_selection() - model, iter = selection.get_selected() - - domain = None - path = None - name = None - - if not model.iter_has_child(iter): - path = model.get_value(iter, 1) - name = model.get_value(iter, 2) - domain = model.get_value(iter, 0) - - try: - self.cookies.clear("." + domain, path, name) - except: - pass - try: - self.cookies.clear(domain, path, name) - except: - pass - - # UI - if model.iter_has_child(iter): - i = model.iter_children(iter) - while model.remove(i): - pass - model.remove(iter) - else: - p = model.iter_parent(iter) - model.remove(iter) - if not model.iter_has_child(p): - model.remove(p) - - self.write_config(True) - - def configure_cb_toolbar_clicked(self, button): - self.configure() - - def configure_ui_show_toolbar_button(self): - if self.toolbar_button == None: - import gtk + config = None + glade = None + feeds = None + toolbar_button = None + history_calendarbuttons = None + + def update_config(self): + if self.config.version >= 5: + return + + if self.config.version < 1: + print 'Updating config to v1' + i = 0 + while i < len(self.config.filters): + self.config.filters[i]['enabled'] = True + i = i + 1 + + if self.config.version < 2: + print 'Updating config to v2' + i = 0 + while i < len(self.config.feeds): + self.config.feeds[i]['enabled'] = True + i = i + 1 + + if self.config.version < 3: + print 'Updating config to v3' + i = 0 + while i < len(self.config.filters): + type_s = self.config.filters[i]['type'] + type_i = self.config.constants[type_s] + if self.config.filters[i]['history'].has_key(type_s): + history = { type_i: self.config.filters[i]['history'][type_s] } + self.config.filters[i]['history'] = history + self.config.filters[i]['type'] = self.config.constants[self.config.filters[i]['type']]; + i = i + 1 + + if self.config.version < 4: + print 'Updating config to v4' + i = 0 + while i < len(self.config.filters): + self.config.filters[i]['queue_top'] = False + self.config.filters[i]['pause'] = False + i = i + 1 + + if self.config.version < 5: + print 'Updating config to v5' + i = 0 + while i < len(self.config.filters): + self.config.filters[i]['delete'] = False + i = i + 1 + + self.config.version = 5 + self.write_config() + + def load_config(self): + import deluge.common, os, cookielib + + file = deluge.common.CONFIG_DIR + "/flexrss.dat" + if os.path.isfile(file): + import pickle + + fd = open(file, 'r') + self.config = pickle.load(fd) + fd.close() + else: + self.config = plugin_FlexRSS_Config() + self.config.version = 5 + + self.update_config() + + cookie_file = deluge.common.CONFIG_DIR + "/flexrss-cookies.txt" + self.cookies = cookielib.MozillaCookieJar() + if os.path.isfile(cookie_file): + self.cookies.load(cookie_file) + + def write_config(self, write_cookies=False): + import deluge.common, os, pickle + + file = deluge.common.CONFIG_DIR + "/flexrss.dat" + fd = open(file, 'w') + pickle.dump(self.config, fd) + fd.close() + + if write_cookies: + print "Saving cookies." + self.cookies.save(deluge.common.CONFIG_DIR + "/flexrss-cookies.txt") + + def configure_cb_closed(self, args): + self.glade = None + self.history_calendarbuttons = None + + def configure_cb_feed_new(self, args): + feed = { "name" : 'Untitled', + "url" : 'http://', + "interval" : 900, + "id" : 0 } + + feed["id"] = self.config.addFeed(feed["name"], feed["url"], feed["interval"]) + + view = self.glade.get_widget("FlexRSS_Feeds") + model = view.get_model() + view.get_selection().select_iter(model.append(None, (feed["id"], feed["name"], feed["url"]))) + + def configure_cb_feed_selected(self, selection): + model, iter = selection.get_selected() + + if not iter: + return + + parent = model.iter_parent(iter) + if parent: # Selected a filter + self.glade.get_widget('FlexRSS_Filters_Test_Pattern').set_text(model.get_value(iter, 1)) + self.configure_cb_test_filter(None) + + iter = parent + + # We want to edit a feed. + feed = self.config.getFeed(model.get_value(iter, 0)) + if not feed: + print 'Error: could not find feed #' + str(model.get_value(iter, 0)) + return + + self.glade.get_widget("FlexRSS_EditFeed_Name").set_text(feed["name"]) + self.glade.get_widget("FlexRSS_EditFeed_URL").set_text(feed["url"]) + self.glade.get_widget("FlexRSS_EditFeed_Interval").set_text(str(feed["interval"])) + if feed["enabled"] == True: + self.glade.get_widget("FlexRSS_EditFeed_Status_Enabled").set_active(True) + else: + self.glade.get_widget("FlexRSS_EditFeed_Status_Disabled").set_active(True) + self.glade.get_widget('FlexRSS_Feeds_Editor').show() + + def configure_cb_feed_delete(self, arg, id=None): + if not id: + # Which feed is selected? + selection = self.glade.get_widget("FlexRSS_Feeds").get_selection() + model, iter = selection.get_selected() + + if not iter: + return + + id = model.get_value(iter, 0) + if id == 0: + id = model.get_value(model.iter_parent(iter), 0) + else: + model = self.glade.get_widget("FlexRSS_Feeds").get_model() + iter = model.get_iter_first() + while iter: + if model.get_value(iter, 0) == id: + break + iter = model.iter_next(iter) + + if not iter: + print 'Couldn\'t find feed.' + return + + # Remove from config + if not self.config.deleteFeed(id): + print 'Unable to delete feed #' + str(id) + return + + # Remove from UI + model.remove(iter) + + self.write_config() + + # We are no longer editing a feed, so hide the editing widgets. + self.glade.get_widget('FlexRSS_Feeds_Editor').hide() + + def configure_cb_feed_save(self, arg, id=None): + if not id: + # Which feed is selected? + selection = self.glade.get_widget("FlexRSS_Feeds").get_selection() + model, iter = selection.get_selected() + + if not iter: + return + + id = model.get_value(iter, 0) + if id == 0: + iter = model.iter_parent(iter) + id = model.get_value(iter, 0) + else: + model = self.glade.get_widget("FlexRSS_Feeds").get_model() + iter = model.iter_first() + while iter: + if model.get_value(iter, 0) == id: + break + iter = iter.iter_next(iter) + + if not iter: + print 'Couldn\'t find feed.' + return + + # Update configuration + self.config.setFeed(id, "name", self.glade.get_widget("FlexRSS_EditFeed_Name").get_text()) + self.config.setFeed(id, "url", self.glade.get_widget("FlexRSS_EditFeed_URL").get_text()) + interval = self.configure_ui_get_text_as_int("FlexRSS_EditFeed_Interval", 900) + if interval < 300: + # It's just not polite to hit a server that often. + self.glade.get_widget("FlexRSS_EditFeed_Interval").set_text('300') + interval = 300 + self.config.setFeed(id, "interval", interval) + self.config.setFeed(id, "enabled", self.glade.get_widget("FlexRSS_EditFeed_Status_Enabled").get_active()) + self.write_config() + + # Update UI + feed = self.config.getFeed(id) + model.set_value(iter, 0, feed["id"]) + model.set_value(iter, 1, feed["name"]) + model.set_value(iter, 2, feed["url"]) + + if not self.feeds.has_key(id): + self.feeds[id] = { 'cfg' : feed, + 'updated' : 0, + 'data' : [] } + + def escape_regex_special_chars(self, pattern): + escape_chars = '[]()^$\\.?*+|' + out = [] + for c in pattern: + try: + escape_chars.index(c) + out.append('\\' + c) + except: + out.append(c) + return ''.join(out) + + def configure_cb_filter_new(self, arg, test_pattern=None): + filter = { "name" : "Untitled", + "type" : "Generic", + "patterns" : [('', 'Title')], + "feeds" : [0], + "id" : 0 } + + if test_pattern: + # Try to guess a good pattern + import re, string + + trans_table = string.maketrans(' ', '.') + + # TV Show + exp = re.compile(r'(.*?)S([0-9]+)E([0-9]+)', re.IGNORECASE) + match = exp.match(test_pattern) + if match: + pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + 's%se%e' + filter['patterns'][0] = (pattern, 'Title') + filter['name'] = match.group(1) + filter['type'] = self.config.constants['TV Show'] + + if not match: + exp = re.compile(r'(.*?)([0-9]{4}).([0-9]{1,2}).([0-9]{1,2})', re.IGNORECASE) + match = exp.match(test_pattern) + if match: + pattern = None + if ((int(match.group(3)) <= 12) and (int(match.group(4)) <= 31)): + pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + '%Y.%m.%d' + elif ((int(match.group(3)) <= 31) and (int(match.group(4)) <= 12)): + pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + '%Y.%d.%m' + + if pattern: + filter['patterns'][0] = (pattern, 'Title') + filter['name'] = match.group(1) + filter['type'] = self.config.constants['TV Show (dated)'] + else: + match = None + + if not match: + exp = re.compile(r'(.*?)([0-9]{2}).([0-9]{2}).([0-9]{2})', re.IGNORECASE) + match = exp.match(test_pattern) + if match: + pattern = None + if ((int(match.group(2)) <= 12) and (int(match.group(3)) <= 31)): + pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + '%m.%d.%y' + elif ((int(match.group(3)) <= 31) and (int(match.group(2)) <= 12)): + pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + '%d.%m.%y' + + if pattern: + filter['patterns'][0] = (pattern, 'Title') + filter['name'] = match.group(1) + filter['type'] = self.config.constants['TV Show (dated)'] + else: + match = None + + if not match: + exp = re.compile(r'(.*?)([0-9]+)([x\.\-_]{1})([0-9]+)', re.IGNORECASE) + match = exp.match(test_pattern) + if match: + pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + '%s' + self.escape_regex_special_chars(match.group(3)) + '%e' + filter['patterns'][0] = (pattern, 'Title') + filter['name'] = match.group(1) + filter['type'] = self.config.constants['TV Show'] + + if not match: + exp = re.compile(r'(.*?)([0-9]+)$', re.IGNORECASE) + match = exp.match(test_pattern) + if match: + pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + '%e' + filter['patterns'][0] = (pattern, 'Title') + filter['name'] = match.group(1) + filter['type'] = self.config.constants['TV Show'] + + # Add to config + filter['id'] = self.config.addFilter(filter['name'], filter['type'], filter['patterns'], [0]) + + # Add to UI + self.configure_ui_add_filter(self.config.getFilter(filter['id']), test_pattern) + + def configure_cb_filter_selected(self, selection): + model, iter = selection.get_selected() + + if not iter: + return + + # We want to edit a filter. + filter = self.config.getFilter(model.get_value(iter, 0)) + if not filter: + print 'Error: could not find filter #' + str(model.get_value(iter, 0)) + return + + self.configure_ui_reset_filter() + + self.glade.get_widget('FlexRSS_Filters_Name').set_text(filter['name']) + + if filter['type'] == self.config.constants['TV Show']: + type_i = 1 + elif filter['type'] == self.config.constants['TV Show (dated)']: + type_i = 2 + else: + type_i = 0 + + self.glade.get_widget('FlexRSS_Filters_Type').set_active(type_i) + + selection = self.glade.get_widget('FlexRSS_Filters_Feed').get_selection() + selection.unselect_all() + feed_model = self.glade.get_widget('FlexRSS_Filters_Feed').get_model() + for i in filter['feeds']: + if i == 0: + selection.select_all() + else: + iter = feed_model.get_iter_first() + while iter: + if feed_model.get_value(iter, 0) == i: + selection.select_iter(iter) + iter = feed_model.iter_next(iter) + + for pattern in filter['patterns']: + self.configure_ui_add_pattern(pattern) + + if filter['type'] == self.config.constants['TV Show']: + if filter['history'].has_key(filter['type']) and filter['history'][filter['type']].has_key('from'): + self.glade.get_widget('FlexRSS_History_TVShow_From_Enabled').set_active(True) + self.glade.get_widget('FlexRSS_History_TVShow_From_Season').set_sensitive(True) + self.glade.get_widget('FlexRSS_History_TVShow_From_Episode').set_sensitive(True) + self.glade.get_widget('FlexRSS_History_TVShow_From_Season').set_text(str(filter['history'][filter['type']]['from']['season'])) + self.glade.get_widget('FlexRSS_History_TVShow_From_Episode').set_text(str(filter['history'][filter['type']]['from']['episode'])) + else: + self.glade.get_widget('FlexRSS_History_TVShow_From_Enabled').set_active(False) + self.glade.get_widget('FlexRSS_History_TVShow_From_Season').set_sensitive(False) + self.glade.get_widget('FlexRSS_History_TVShow_From_Episode').set_sensitive(False) + self.glade.get_widget('FlexRSS_History_TVShow_From_Season').set_text('0') + self.glade.get_widget('FlexRSS_History_TVShow_From_Episode').set_text('0') + + if filter['history'].has_key(filter['type']) and filter['history'][filter['type']].has_key('thru'): + self.glade.get_widget('FlexRSS_History_TVShow_Thru_Enabled').set_active(True) + self.glade.get_widget('FlexRSS_History_TVShow_Thru_Season').set_sensitive(True) + self.glade.get_widget('FlexRSS_History_TVShow_Thru_Episode').set_sensitive(True) + self.glade.get_widget('FlexRSS_History_TVShow_Thru_Season').set_text(str(filter['history'][filter['type']]['thru']['season'])) + self.glade.get_widget('FlexRSS_History_TVShow_Thru_Episode').set_text(str(filter['history'][filter['type']]['thru']['episode'])) + else: + self.glade.get_widget('FlexRSS_History_TVShow_Thru_Enabled').set_active(False) + self.glade.get_widget('FlexRSS_History_TVShow_Thru_Season').set_sensitive(False) + self.glade.get_widget('FlexRSS_History_TVShow_Thru_Episode').set_sensitive(False) + self.glade.get_widget('FlexRSS_History_TVShow_Thru_Season').set_text('0') + self.glade.get_widget('FlexRSS_History_TVShow_Thru_Episode').set_text('0') + + self.glade.get_widget("FlexRSS_History_TVShow_Dated").hide() + self.glade.get_widget("FlexRSS_History_TVShow").show() + self.glade.get_widget("FlexRSS_Filter_History_Range").show() + elif filter['type'] == self.config.constants['TV Show (dated)']: + import time + + cal_from, cal_thru = self.history_calendarbuttons + today = time.localtime() + + if filter['history'].has_key(filter['type']) and filter['history'][filter['type']].has_key('from'): + self.glade.get_widget('FlexRSS_History_TVShow_Dated_From_Enabled').set_active(True) + cal_from.set_sensitive(True) + cal_from.set_date(filter['history'][filter['type']]['from']['year'], + filter['history'][filter['type']]['from']['month'], + filter['history'][filter['type']]['from']['day']) + else: + self.glade.get_widget('FlexRSS_History_TVShow_Dated_From_Enabled').set_active(False) + cal_from.set_sensitive(False) + cal_from.set_date(today[0], today[1], today[2]) + + if filter['history'].has_key(filter['type']) and filter['history'][filter['type']].has_key('thru'): + self.glade.get_widget('FlexRSS_History_TVShow_Dated_Thru_Enabled').set_active(True) + cal_thru.set_sensitive(True) + cal_thru.set_date(filter['history'][filter['type']]['thru']['year'], + filter['history'][filter['type']]['thru']['month'], + filter['history'][filter['type']]['thru']['day']) + else: + self.glade.get_widget('FlexRSS_History_TVShow_Dated_Thru_Enabled').set_active(False) + cal_thru.set_sensitive(False) + cal_thru.set_date(today[0], today[1], today[2]) + + self.glade.get_widget("FlexRSS_History_TVShow").hide() + self.glade.get_widget("FlexRSS_History_TVShow_Dated").show() + self.glade.get_widget("FlexRSS_Filter_History_Range").show() + else: + self.glade.get_widget("FlexRSS_History_TVShow").hide() + self.glade.get_widget("FlexRSS_History_TVShow_Dated").hide() + self.glade.get_widget("FlexRSS_Filter_History_Range").hide() + + self.glade.get_widget('FlexRSS_Filter_Download_QueueTop').set_active(filter.get('queue_top', False)) + self.glade.get_widget('FlexRSS_Filter_Download_Pause').set_active(filter.get('pause', False)) + self.glade.get_widget('FlexRSS_Filter_Download_Delete').set_active(filter.get('delete', False)) + + self.configure_cb_test_filter(None) + + if filter['path'] != None: + self.glade.get_widget('FlexRSS_Filter_Output_Location').set_current_folder(filter['path']) + self.glade.get_widget('FlexRSS_Filter_Output_Type_Custom').set_active(True) + else: + self.glade.get_widget('FlexRSS_Filter_Output_Type_Default').set_active(True) + + replace = filter.get('replace', {'pattern': '', 'with': ''}) + self.glade.get_widget('FlexRSS_Filter_Rewrite_Pattern').set_text(replace['pattern']) + self.glade.get_widget('FlexRSS_Filter_Rewrite_Replacement').set_text(replace['with']) + + def configure_cb_filter_history_toggle(self, box): + name = box.get_name() + active = box.get_active() + + if name == 'FlexRSS_History_TVShow_From_Enabled': + self.glade.get_widget('FlexRSS_History_TVShow_From_Season').set_sensitive(active) + self.glade.get_widget('FlexRSS_History_TVShow_From_Episode').set_sensitive(active) + elif name == 'FlexRSS_History_TVShow_Thru_Enabled': + self.glade.get_widget('FlexRSS_History_TVShow_Thru_Season').set_sensitive(active) + self.glade.get_widget('FlexRSS_History_TVShow_Thru_Episode').set_sensitive(active) + elif name == 'FlexRSS_History_TVShow_Dated_From_Enabled': + self.history_calendarbuttons[0].set_sensitive(active) + elif name == 'FlexRSS_History_TVShow_Dated_Thru_Enabled': + self.history_calendarbuttons[1].set_sensitive(active) + + self.configure_cb_test_filter(None) + + def configure_ui_get_text_as_int(self, widget_name, default=0): + try: + return int(self.glade.get_widget(widget_name).get_text()) + except: + return default + + def configure_ui_get_history_restriction(self): + h_from = None + h_thru = None + + type = self.glade.get_widget('FlexRSS_Filters_Type').get_active() + if type == 1: + type_s = self.config.constants['TV Show'] + elif type == 2: + type_s = self.config.constants['TV Show (dated)'] + else: + type_s = self.config.constants['Generic'] + + if type_s == self.config.constants['TV Show']: + if self.glade.get_widget('FlexRSS_History_TVShow_From_Enabled').get_active(): + from_season = self.configure_ui_get_text_as_int('FlexRSS_History_TVShow_From_Season') + from_episode = self.configure_ui_get_text_as_int('FlexRSS_History_TVShow_From_Episode') + h_from = {'season': from_season, 'episode': from_episode} + elif type_s == self.config.constants['TV Show (dated)']: + if self.glade.get_widget('FlexRSS_History_TVShow_Dated_From_Enabled').get_active(): + from_y, from_m, from_d = self.history_calendarbuttons[0].get_date() + h_from = {'year': from_y, 'month': from_m, 'day': from_d} + + if type_s == self.config.constants['TV Show']: + if self.glade.get_widget('FlexRSS_History_TVShow_Thru_Enabled').get_active(): + thru_season = self.configure_ui_get_text_as_int('FlexRSS_History_TVShow_Thru_Season') + thru_episode = self.configure_ui_get_text_as_int('FlexRSS_History_TVShow_Thru_Episode') + h_thru = {'season': thru_season, 'episode': thru_episode} + elif type_s == self.config.constants['TV Show (dated)']: + if self.glade.get_widget('FlexRSS_History_TVShow_Dated_Thru_Enabled').get_active(): + thru_y, thru_m, thru_d = self.history_calendarbuttons[1].get_date() + h_thru = {'year': thru_y, 'month': thru_m, 'day': thru_d} + + return (h_from, h_thru) + + def configure_cb_filter_save(self, arg): + # Which feed is selected? + selection = self.glade.get_widget("FlexRSS_Filters_List").get_selection() + model, iter = selection.get_selected() + + if not iter: + return + + id = model.get_value(iter, 0) + name = self.glade.get_widget('FlexRSS_Filters_Name').get_text() + self.config.setFilter(id, 'name', name) + iter = model.get_iter_first() + while iter: + if model.get_value(iter, 0) == id: + model.set_value(iter, 1, name) + iter = model.iter_next(iter) + + type = self.glade.get_widget('FlexRSS_Filters_Type').get_active() + if type == 1: + type_s = self.config.constants['TV Show'] + elif type == 2: + type_s = self.config.constants['TV Show (dated)'] + else: + type_s = self.config.constants['Generic'] + self.config.setFilter(id, 'type', type_s) + + model, paths = self.glade.get_widget('FlexRSS_Filters_Feed').get_selection().get_selected_rows() + feeds = [] + for path in paths: + feeds.append(model.get_value(model.get_iter(path), 0)) + if len(feeds) == 0: + feeds.append(0) + self.config.setFilter(id, 'feeds', feeds) + + patterns = [] + filter_patterns = self.glade.get_widget('FlexRSS_Filter_Patterns_List') + for i in filter_patterns.get_children(): + data = i.get_children() + pattern = data[0].get_text() + if data[2].get_active() == 1: + type = 'Link' + else: + type = 'Title' + patterns.append((pattern, type)) + self.config.setFilter(id, 'patterns', patterns) + + if self.glade.get_widget('FlexRSS_Filter_Output_Type_Custom').get_active(): + path = self.glade.get_widget('FlexRSS_Filter_Output_Location').get_current_folder() + else: + path = None + + self.config.setFilter(id, 'path', path) + + self.config.setFilter(id, 'queue_top', self.glade.get_widget('FlexRSS_Filter_Download_QueueTop').get_active()) + self.config.setFilter(id, 'pause', self.glade.get_widget('FlexRSS_Filter_Download_Pause').get_active()) + self.config.setFilter(id, 'delete', self.glade.get_widget('FlexRSS_Filter_Download_Delete').get_active()) + + filter = self.config.getFilter(id) + + h_from, h_thru = self.configure_ui_get_history_restriction() + if filter['type'] != self.config.constants['Generic']: + if not filter['history'].has_key(filter['type']): + filter['history'][filter['type']] = {} + + if h_from != None: + filter['history'][filter['type']]['from'] = h_from + else: + if filter['history'][filter['type']].has_key('from'): + del filter['history'][filter['type']]['from'] + + if h_thru != None: + filter['history'][filter['type']]['thru'] = h_thru + else: + if filter['history'][filter['type']].has_key('thru'): + del filter['history'][filter['type']]['thru'] + + filter['replace'] = { 'pattern': self.glade.get_widget('FlexRSS_Filter_Rewrite_Pattern').get_text(), + 'with' : self.glade.get_widget('FlexRSS_Filter_Rewrite_Replacement').get_text() } + + self.write_config() + + def configure_cb_remove_pattern(self, arg): + arg.get_parent().destroy() + + def configure_ui_add_pattern(self, pattern): + import gtk, gobject + + filter_patterns = self.glade.get_widget('FlexRSS_Filter_Patterns_List') + + hbox = gtk.HBox() + filter_patterns.pack_start(hbox) + + input = gtk.Entry() + input.set_text(pattern[0]) + input.connect("changed", self.configure_cb_test_filter) + + on = gtk.Label() + on.set_text('On') + on.show() + + combo = gtk.combo_box_new_text() + combo.append_text('Title') + combo.append_text('Link') + if pattern[1] == 'Link': + combo.set_active(1) + else: + combo.set_active(0) + + remove = gtk.Button(stock=gtk.STOCK_REMOVE) + remove.connect("pressed", self.configure_cb_remove_pattern) + + hbox.pack_start(input) + hbox.pack_start(on, expand=False) + hbox.pack_start(combo, expand=False) + hbox.pack_start(remove, expand=False) + + hbox.show_all() + + def configure_cb_add_pattern(self, args): + self.configure_ui_add_pattern(('', 'Title')) + + def configure_ui_add_filter(self, filter, test_pattern=None): + if not filter: + print 'No filter to add' + return None + + self.configure_ui_reset_filter() + + model = self.glade.get_widget("FlexRSS_Filters_List").get_model() + iter = model.append((filter['id'], filter['name'], filter['enabled'])) + + if not iter: + return + + view = self.glade.get_widget("FlexRSS_Filters_List") + model = view.get_model() + view.get_selection().select_iter(iter) + + if test_pattern: + self.glade.get_widget('FlexRSS_Filters_Test_Pattern').set_text(test_pattern) + self.configure_cb_test_filter(None) + + self.glade.get_widget('FlexRSS_MainNotebook').set_current_page(1) + + def configure_ui_test_result(self, result, h_match=False): + if result and h_match: + self.glade.get_widget('FlexRSS_Filters_Test_Result').set_text('Match') + else: + self.glade.get_widget('FlexRSS_Filters_Test_Result').set_text('Doesn\'t match') + + type = self.glade.get_widget('FlexRSS_Filters_Type').get_active() + + if type == 0: # Generic + self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow').hide() + self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated').hide() + self.glade.get_widget('FlexRSS_History_TVShow').hide() + self.glade.get_widget('FlexRSS_History_TVShow_Dated').hide() + elif type == 1: # TV Show + self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow').show() + self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated').hide() + self.glade.get_widget('FlexRSS_History_TVShow').show() + self.glade.get_widget('FlexRSS_History_TVShow_Dated').hide() + if result: + self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Series').set_text(str(result['series'])) + self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Episode').set_text(str(result['episode'])) + else: + self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Series').set_text('0') + self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Episode').set_text('0') + else: # TV Show (dated) + self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow').hide() + self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated').show() + self.glade.get_widget('FlexRSS_History_TVShow').hide() + self.glade.get_widget('FlexRSS_History_TVShow_Dated').show() + if result: + self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Year').set_text(str(result['year'])) + self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Month').set_text(str(result['month'])) + self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Day').set_text(str(result['day'])) + else: + self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Year').set_text('0') + self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Month').set_text('0') + self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Day').set_text('0') + + def configure_cb_test_filter(self, source=None, date=None): + subject = self.glade.get_widget('FlexRSS_Filters_Test_Pattern').get_text() + + type = self.glade.get_widget('FlexRSS_Filters_Type').get_active() + if type == 1: + type_s = self.config.constants['TV Show'] + elif type == 2: + type_s = self.config.constants['TV Show (dated)'] + else: + type_s = self.config.constants['Generic'] + + filter_patterns = self.glade.get_widget('FlexRSS_Filter_Patterns_List') + for i in filter_patterns.get_children(): + data = i.get_children() + pattern = data[0].get_text() + result = self.test_pattern(type_s, subject, pattern) + if result: + # Pattern matched, let's try history restriction. + h_from, h_thru = self.configure_ui_get_history_restriction() + h_match = self.test_range(type_s, result, h_from, h_thru) + self.configure_ui_test_result(result, h_match) + return + + self.configure_ui_test_result(False) + + def configure_cb_delete_filter(self, arg): + # Which filter is selected? + selection = self.glade.get_widget("FlexRSS_Filters_List").get_selection() + model, iter = selection.get_selected() + + if not iter: + return + + id = model.get_value(iter, 0) + + # Remove from config + if not self.config.deleteFilter(id): + print 'Unable to delete filter #' + str(id) + return + self.write_config() + + # Remove from UI + model.remove(iter) + + self.configure_ui_reset_filter() + + def configure_cb_feed_refresh(self, caller, id=None): + if not id: + selection = self.glade.get_widget("FlexRSS_Feeds").get_selection() + model, iter = selection.get_selected() + + if not iter: + return + + id = model.get_value(iter, 0) + + if id: + if ( self.config.threaded_retrieval ): + import threading + threading.Thread(target=self.parse_feed, args=(id,)).start() + else: + self.parse_feed(id) + + def configure_cb_download_torrent(self, caller, url): + self.download_torrent(url) + + def configure_cb_feed_popup(self, view, event): + if event.button != 3: + return + + model = view.get_model() + coords = event.get_coords() + path = view.get_path_at_pos(int(coords[0]), int(coords[1])) + if path: + iter = model.get_iter(path[0]) + else: + iter = None + + import gtk + + popup = gtk.Menu() + + if iter: + id = model.get_value(iter, 0) + if id: # Feed + item_refresh = gtk.MenuItem(_("Refresh feed")) + item_refresh.connect("activate", self.configure_cb_feed_refresh, id) + popup.append(item_refresh) + + item_delete = gtk.MenuItem(_("Delete feed")) + item_delete.connect("activate", self.configure_cb_feed_delete, id) + popup.append(item_delete) + + else: # Filter + item_filter = gtk.MenuItem(_("Create filter")) + item_filter.connect("activate", self.configure_cb_filter_new, model.get_value(iter, 1)) + popup.append(item_filter) + + item_download = gtk.MenuItem(_("Download torrent")) + item_download.connect("activate", self.configure_cb_download_torrent, model.get_value(iter, 2)) + popup.append(item_download) + + else: # Neither + item_new = gtk.MenuItem("New feed") + item_new.connect("activate", self.configure_cb_feed_new) + popup.append(item_new) + + popup.popup(None, None, None, event.button, event.time) + popup.show_all() + + def configure_cb_output_set(self, chooser): + self.glade.get_widget('FlexRSS_Filter_Output_Type_Custom').set_active(True) + + def configure_ui_reset_filter(self): + # Just resets the crap in the filter tab to defaults. + self.glade.get_widget('FlexRSS_Filters_Name').set_text('') + self.glade.get_widget('FlexRSS_Filters_Type').set_active(0) + self.glade.get_widget('FlexRSS_Filters_Feed').get_selection().unselect_all() + for filter in self.glade.get_widget('FlexRSS_Filter_Patterns_List').get_children(): + filter.destroy() + self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow').hide() + self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated').hide() + file_chooser = self.glade.get_widget('FlexRSS_Filter_Output_Location') + file_chooser.set_current_folder(self.interface.config.get('default_download_path')) + self.glade.get_widget('FlexRSS_Filter_Output_Type_Default').set_active(True) + + def strcasecmp(self, s1, s2): + try: + t1 = s1.lower() + t2 = s2.lower() + + if s1 < s2: + return -1 + elif s1 > s2: + return 1 + except: + pass + + return 0 + + def configure_ui_sort_cmp(self, model, iter1, iter2, user_data=None): + if (model.get_value(iter1, 0) == 0) or (model.get_value(iter2, 0) == 0): + return 0 + + return self.strcasecmp(model.get_value(iter1, 1), model.get_value(iter2, 1)) + + def configure_cb_filter_toggled(self, renderer, path): + old_val = renderer.get_active() + model = self.glade.get_widget('FlexRSS_Filters_List').get_model() + iter = model.get_iter(path) + if old_val: + model.set_value(iter, 2, False) + self.config.setFilter(model.get_value(iter, 0), 'enabled', False) + else: + model.set_value(iter, 2, True) + self.config.setFilter(model.get_value(iter, 0), 'enabled', True) + self.write_config() + + def configure_cb_cookie_new(self, src): + self.configure_ui_cookie_reset() + self.glade.get_widget("FlexRSS_Cookies_Editor").show() + + def configure_cb_cookie_save(self, src): + import cookielib, time + + domain = self.glade.get_widget("FlexRSS_Cookie_Domain").get_text() + path = self.glade.get_widget("FlexRSS_Cookie_Path").get_text() + name = self.glade.get_widget("FlexRSS_Cookie_Name").get_text() + value = self.glade.get_widget("FlexRSS_Cookie_Value").get_text() + + if (domain == ""): + return + + if path == '': + path = '/' + + # Fragile. + self.cookies._policy._now = self.cookies._now = int(time.time()) + cookie = self.cookies._cookie_from_cookie_tuple((name, value, {"domain": domain, "path":path, "expires":2147483647}, {}), None) + + self.cookies.set_cookie(cookie) + self.configure_ui_add_cookie(None, cookie) + self.configure_ui_cookie_reset() + self.glade.get_widget("FlexRSS_Cookies_Editor").hide() + self.write_config(True) + + def configure_ui_add_cookie(self, model, cookie): + if cookie.domain[0] == '.': + domain = cookie.domain[1:] + else: + domain = cookie.domain + + if model == None: + model = self.glade.get_widget("FlexRSS_Cookies_List").get_model() + + parent = None + iter = model.get_iter_first() + while iter: + t = model.get_value(iter, 0) + if t == domain: + parent = iter + break + iter = model.iter_next(iter) + + if parent == None: + parent = model.append(iter, (domain, "", "", "")) + model.append(parent, (cookie.domain, cookie.path, cookie.name, cookie.value)) + + def configure_ui_cookie_reset(self): + self.glade.get_widget("FlexRSS_Cookie_Domain").set_text('') + self.glade.get_widget("FlexRSS_Cookie_Path").set_text('/') + self.glade.get_widget("FlexRSS_Cookie_Name").set_text('') + self.glade.get_widget("FlexRSS_Cookie_Value").set_text('') + + def configure_cb_cookie_selected(self, selection): + model, iter = selection.get_selected() + + self.configure_ui_cookie_reset() + self.glade.get_widget("FlexRSS_Cookies_Editor").hide() + + def configure_cb_cookie_delete(self, src): + selection = self.glade.get_widget("FlexRSS_Cookies_List").get_selection() + model, iter = selection.get_selected() + + domain = None + path = None + name = None + + if not model.iter_has_child(iter): + path = model.get_value(iter, 1) + name = model.get_value(iter, 2) + domain = model.get_value(iter, 0) + + try: + self.cookies.clear("." + domain, path, name) + except: + pass + try: + self.cookies.clear(domain, path, name) + except: + pass + + # UI + if model.iter_has_child(iter): + i = model.iter_children(iter) + while model.remove(i): + pass + model.remove(iter) + else: + p = model.iter_parent(iter) + model.remove(iter) + if not model.iter_has_child(p): + model.remove(p) + + self.write_config(True) + + def configure_cb_toolbar_clicked(self, button): + self.configure() + + def configure_ui_show_toolbar_button(self): + if self.toolbar_button == None: + import gtk import os.path - icon = gtk.Image() - icon.set_from_file(os.path.join(self.path, "FlexRSS.png")) - self.toolbar_button = gtk.ToolButton(icon_widget=icon, label="FlexRSS") - self.toolbar_button.connect("clicked", self.configure_cb_toolbar_clicked) - self.interface.toolbar.add(self.toolbar_button) - self.toolbar_button.show_all() - - def configure_cb_toolbar_toggled(self, box): - if box.get_active(): - self.configure_ui_show_toolbar_button() - self.config.show_toolbar_button = True - self.write_config() - else: - self.toolbar_button.destroy() - self.toolbar_button = None - self.config.show_toolbar_button = False - self.write_config() - - def configure_cb_threaded_toggled(self, box): - self.config.threaded_retrieval = box.get_active() - self.write_config() - - def configure(self, widget=None): - if self.glade: # Dialog already running - return - - import gtk, gtk.glade, gobject - - self.glade = gtk.glade.XML(self.path + "/FlexRSS.glade") - - # Intialize feed lists - feeds_model = gtk.TreeStore(gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_STRING) - feeds_view = self.glade.get_widget("FlexRSS_Feeds") - filters_feeds_view = self.glade.get_widget("FlexRSS_Filters_Feed") - feeds_view.set_model(feeds_model) - filters_feeds_view.set_model(feeds_model) - feeds_model.set_sort_func(1, self.configure_ui_sort_cmp) - feeds_model.set_sort_column_id(1, gtk.SORT_ASCENDING) - - # Setup columns for feeds tab - renderer_name = gtk.CellRendererText() - column_name = gtk.TreeViewColumn(_("Feed Name"), renderer_name, text=1) - feeds_view.append_column(column_name) - renderer_url = gtk.CellRendererText() - column_url = gtk.TreeViewColumn(_("URL"), renderer_url, text=2) - feeds_view.append_column(column_url) - feeds_view.set_search_column(1) - feeds_view.set_search_equal_func(gtk_treeview_search_cb_stristr) - - # Set callback for when selection is changed in feeds tab - # I can't figure out how to do this in Glade - feeds_view.get_selection().connect("changed", self.configure_cb_feed_selected) - - # Setup columns for feed list on filters tab - renderer_name = gtk.CellRendererText() - column_name = gtk.TreeViewColumn(_("Feed Name"), renderer_name, text=1) - filters_feeds_view.append_column(column_name) - - # Allow multiple selections of feeds in filters tab - # I can't figure out how to do this in Glade - filters_feeds_view.get_selection().set_mode(gtk.SELECTION_MULTIPLE) - - # Populate feed lists - if self.config.feeds: - for feed in self.config.feeds: - this_feed = feeds_model.append(None, (feed['id'], feed['name'], feed['url'])) - for item in self.feeds[feed['id']]['data']: - feeds_model.append(this_feed, (0, item['title'], item['link'])) - - - # Initialize filters list - filters_model = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_BOOLEAN) - filters_view = self.glade.get_widget("FlexRSS_Filters_List") - filters_view.set_model(filters_model) - feeds_model.set_sort_func(1, self.configure_ui_sort_cmp) - filters_model.set_sort_column_id(1, gtk.SORT_ASCENDING) - - # Setup columns for filters list - renderer_enabled = gtk.CellRendererToggle() - column_enabled = gtk.TreeViewColumn(_("Enabled"), renderer_enabled, active=2) - filters_view.append_column(column_enabled) - renderer_enabled.connect('toggled', self.configure_cb_filter_toggled) - renderer_name = gtk.CellRendererText() - column_name = gtk.TreeViewColumn(_("Filter Name"), renderer_name, text=1) - filters_view.append_column(column_name) - - # Set callback for when selection is changed in feeds tab - # I can't figure out how to do this in Glade - filters_view.get_selection().connect("changed", self.configure_cb_filter_selected) - - # Populate filters list - if self.config.filters: - for filter in self.config.filters: - filters_model.append((filter['id'], filter['name'], filter['enabled'])) - - # Filter types - filter_types = self.glade.get_widget('FlexRSS_Filters_Type') - filter_types.append_text(_("Generic")) - filter_types.append_text(_("TV Show")) - filter_types.append_text(_("TV Show (dated)")) - - # Calendar buttons for dated tv show history restrictions - from CalendarButton import CalendarButton - dated_from = CalendarButton() - dated_from.connect('date-selected', self.configure_cb_test_filter) - dated_to = CalendarButton() - dated_to.connect('date-selected', self.configure_cb_test_filter) - dated_from.show() - dated_to.show() - history_table = self.glade.get_widget('FlexRSS_History_TVShow_Dated') - history_table.attach(dated_from, 1, 2, 0, 1, gtk.EXPAND|gtk.FILL, gtk.FILL) - history_table.attach(dated_to, 1, 2, 1, 2, gtk.EXPAND|gtk.FILL, gtk.FILL) - self.history_calendarbuttons = (dated_from, dated_to) - - # Initialize cookies list - cookies_model = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING) - cookies_view = self.glade.get_widget("FlexRSS_Cookies_List") - cookies_view.set_model(cookies_model) - cookies_view.get_selection().connect("changed", self.configure_cb_cookie_selected) - - # Setup column for cookies - domain_renderer = gtk.CellRendererText() - domain_column = gtk.TreeViewColumn(_("Domain"), domain_renderer, text=0) - path_renderer = gtk.CellRendererText() - path_column = gtk.TreeViewColumn(_("Path"), path_renderer, text=1) - name_renderer = gtk.CellRendererText() - name_column = gtk.TreeViewColumn(_("Name"), name_renderer, text=2) - value_renderer = gtk.CellRendererText() - value_column = gtk.TreeViewColumn(_("Value"), value_renderer, text=3) - cookies_view.append_column(domain_column) - cookies_view.append_column(path_column) - cookies_view.append_column(name_column) - cookies_view.append_column(value_column) - - for cookie in self.cookies: - self.configure_ui_add_cookie(cookies_model, cookie) - - # Interface - self.glade.get_widget("FlexRSS_Interface_ShowButton").set_active(self.config.show_toolbar_button) - self.glade.get_widget("FlexRSS_Retrieval_Threaded").set_active(self.config.threaded_retrieval) - - # Callbacks for UI events - actions = { - # Feeds tab - "on_FlexRSS_MainWindow_destroy" : self.configure_cb_closed, - "on_FlexRSS_Feeds_New_pressed" : self.configure_cb_feed_new, - "on_FlexRSS_Feeds_Save_pressed" : self.configure_cb_feed_save, - "on_FlexRSS_Feeds_Delete_pressed" : self.configure_cb_feed_delete, - "on_FlexRSS_Feeds_button_press_event" : self.configure_cb_feed_popup, - - # Filters tab - "on_FlexRSS_Filters_Add_pressed" : self.configure_cb_filter_new, - "on_FlexRSS_Action_Save_pressed" : self.configure_cb_filter_save, - "on_FlexRSS_Filter_Patern_Add_pressed" : self.configure_cb_add_pattern, - "on_FlexRSS_Filters_Type_changed" : self.configure_cb_test_filter, - "on_FlexRSS_Filters_Test_Pattern" : self.configure_cb_test_filter, - "on_FlexRSS_Filters_Delete_pressed" : self.configure_cb_delete_filter, - "on_FlexRSS_History_TVShow_From_Enabled_toggled" : self.configure_cb_filter_history_toggle, - "on_FlexRSS_History_TVShow_Thru_Enabled_toggled" : self.configure_cb_filter_history_toggle, - "on_FlexRSS_History_TVShow_Dated_From_Enabled_toggled" : self.configure_cb_filter_history_toggle, - "on_FlexRSS_History_TVShow_Dated_Thru_Enabled_toggled" : self.configure_cb_filter_history_toggle, - "on_FlexRSS_History_TVShow_From_Season_changed" : self.configure_cb_test_filter, - "on_FlexRSS_History_TVShow_From_Episode_changed" : self.configure_cb_test_filter, - "on_FlexRSS_History_TVShow_Thru_Season_changed" : self.configure_cb_test_filter, - "on_FlexRSS_History_TVShow_Thru_Episode_changed" : self.configure_cb_test_filter, - - # Configuration tab - "on_FlexRSS_Cookie_New_pressed" : self.configure_cb_cookie_new, - "on_FlexRSS_Cookie_Save_pressed" : self.configure_cb_cookie_save, - "on_FlexRSS_Cookie_Delete_pressed" : self.configure_cb_cookie_delete, - "on_FlexRSS_Interface_ShowButton_toggled" : self.configure_cb_toolbar_toggled, - "on_FlexRSS_Retrieval_Threaded_toggled" : self.configure_cb_threaded_toggled } - if hasattr(self.interface, 'interactive_add_torrent_path'): - actions["on_FlexRSS_Filter_Output_Location_current_folder_changed"] = self.configure_cb_output_set - else: - self.glade.get_widget('FlexRSS_Filter_Output').hide() - self.glade.signal_autoconnect(actions) - - self.glade.get_widget("FlexRSS_MainWindow").show() - - def cmp_history(a, b): - try: - if a.has_key('series'): - if a['series'] > b['series']: - return 1 - elif a['series'] < b['series']: - return -1 - else: - if a['episode'] > b['episode']: - return 1 - elif a['episode'] < b['episode']: - return -1 - else: - return 0 - except: - return 0 - - def strptime2regex(self, input): - # Does'n exactly live up to its name yet. Currently just - # replaces %y,%Y,%m,%d with named patterns. In the future, it - # would be nice to allow escaping (e.g., %%Y means literal %Y) - # and expand it to support other formats. - patterns = [('%Y', '(?P[0-9]{4})'), - ('%y', '(?P[0-9]{2})'), - ('%m', '(?P[0-9]{1,2})'), - ('%d', '(?P[0-9]{1,2})')] - - out = input - for p in patterns: - out = out.replace(p[0], p[1]) - - return out - - def replace_tv_show_patterns(self, input): - patterns = [('%s', '(?P[0-9]+)'), - ('%e', '(?P[0-9]+)')] - - out = input - for p in patterns: - out = out.replace(p[0], p[1]) - - return out - - def test_range(self, type, data, h_from=None, h_thru=None): - if type == self.config.constants['TV Show']: - if h_from != None: - if data['series'] < h_from['season']: - return False - elif data['series'] == h_from['season']: - if data['episode'] < h_from['episode']: - return False - - if h_thru != None: - if data['series'] > h_thru['season']: - return False - elif data['series'] == h_thru['season']: - if data['episode'] > h_thru['episode']: - return False - - return True - - elif type == self.config.constants['TV Show (dated)']: - if h_from != None: - if data['year'] < h_from['year']: - return False - elif data['year'] == h_from['year']: - if data['month'] < h_from['month']: - return False - elif data['month'] == h_from['month']: - if data['day'] < h_from['day']: - return False - - if h_thru != None: - if data['year'] < h_thru['year']: - return False - elif data['year'] == h_thru['year']: - if data['month'] < h_thru['month']: - return False - elif data['month'] == h_thru['month']: - if data['day'] < h_thru['day']: - return False - - return True - - else: - return True - - def test_pattern(self, type, subject, pattern): - import re, time - result = False - - if len(pattern) < 1: - return False - - if type == self.config.constants['TV Show (dated)']: - pattern = self.strptime2regex(pattern) - elif type == self.config.constants['TV Show']: - pattern = self.replace_tv_show_patterns(pattern) - - # Wow, so this is lame... - if pattern[0] != '^': - pattern = '.*' + pattern - - try: - exp = re.compile(pattern, re.IGNORECASE) - except: - print 'Broken expression: ' + pattern - return False - - match = exp.match(subject) - if match: -# print 'Match: ' + subject -# print ' ' + pattern - if type == self.config.constants['TV Show']: - try: - series = int(match.group('s')) - except: - series = 0 - - try: - episode = int(match.group('e')) - except: - episode = 0 - - result = { 'series' : series, - 'episode' : episode } - - elif type == self.config.constants['TV Show (dated)']: - try: - year = int(match.group('Y')) - except: - try: - year = int(match.group('y')) - if year > 70: - year += 1900 - else: - year += 2000 - except: - year = 0 - - try: - month = int(match.group('m')) - except: - month = 0 - - try: - day = int(match.group('d')) - except: - day = 0 - - result = { 'year' : year, - 'month' : month, - 'day' : day } - - else: - result = True - - return result - - def make_opener(self): - import urllib2 - - return urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookies)) - - def make_request(self, location, referer=None): - import urllib2, deluge.common - - req = urllib2.Request(location) - req.add_header("User-Agent", "FlexRSS/%d.%d.%d (%s/%s)" % (self.version[0], self.version[1], self.version[2], deluge.common.PROGRAM_NAME, deluge.common.PROGRAM_VERSION)) - if referer != None: - req.add_header('Referer', referer) - - return req - - def open_url(self, location): - return self.make_opener().open(self.make_request(location)) - - def download_torrent(self, location, path=None, queue_top=False, pause=False, referer=None): - import tempfile, os, deluge.core - - try: - fd = self.open_url(location) - except: - return False - - inf = fd.info() - if inf["content-type"] != "application/x-bittorrent": - print "Warning: torrent content-type not application/x-bittorrent" - - (tmpfd, filename) = tempfile.mkstemp(".torrent", "flexrss-") - tfd = os.fdopen(tmpfd, 'wb') - tfd.write(fd.read()) - fd.close() - tfd.close() - - unique_id = False - - try: - if path is None: - path = self.interface.config.get('default_download_path') - unique_id = self.interface.manager.add_torrent(filename, path, self.interface.config.get('use_compact_storage')) - self.interface.torrent_model_append(unique_id) - - if queue_top == True: - try: - self.interface.manager.queue_top(unique_id) - except: - pass - if pause == True: - try: - self.interface.manager.set_user_pause(unique_id, True) - except: - pass - except deluge.core.DuplicateTorrentError, e: - print 'FlexRSS: torrent already exists.' - return True - except: - print '*** FlexRSS error: unable to add torrent.' - return False - - return True - - def parse_feed(self, id): - import time, feedparser, urllib2, cookielib - - feed = self.config.getFeed(id) - - #print 'Parsing feed: ' + feed['url'] - try: - parsed = feedparser.parse(self.open_url(feed['url'])) - if (not parsed) or (not parsed.entries): - print 'Unable to parse feed: ' + feed['url'] - return - except: - print 'Unable to update feed: ' + feed['url'] - return - #print 'Retrieval successful: ' + feed['url'] - - data = [] - - for entry in parsed.entries: - entryTitle = entry['title'] - - try: - entryLink = entry.links[0]['href'] - except: - try: - entryLink = entry.enclosures[0]['href'] - except: - print "Skipping %s\n" % entryTitle - continue - - try: - data.append({ 'title': entryTitle, 'link': entryLink }) - except: - continue - - if self.config.filters: - for filter in self.config.filters: - try: - if not ((feed['id'] in filter['feeds']) or (0 in filter['feeds'])): - continue - except TypeError: - filter['feeds'] = [0] - - if filter['enabled'] != True: - continue - - for pattern in filter['patterns']: - # (setq python-indent 4 - # tab-width 4) - # Okay, I dislike python substantially less now. - # Edit (~a month later): I still dislike it a lot, though. - try: - if pattern[1] == 'Title': - subject = entryTitle - else: - subject = entryLink - except: - print 'Unable to find subject.' - - match = self.test_pattern(filter['type'], subject, pattern[0]) - if match: - # Filter matched. Check history to see if - # we should download it. - if filter['type'] == self.config.constants['Generic']: # Dirty hack. - match = { 'url' : entryLink } - - torrent_url = entryLink - replace = filter.get('replace', {'pattern': '', 'with': ''}) - if len(replace['pattern']) > 0: - try: - import re - - p = re.compile(replace['pattern'], re.IGNORECASE) - torrent_url = p.sub(replace['with'], torrent_url) - except: - print '*** FlexRSS error: s/%s/%s/i failed.' % (replace['pattern'], replace['with']) - return - - if not self.config.checkHistory(filter['id'], filter['type'], match): - print filter - if filter.has_key('history'): - res = False - - if filter['type'] == self.config.constants['Generic']: - if filter['history'].get(filter['type'], []).count(torrent_url) == 0: - res = self.download_torrent(torrent_url, filter.get('path', None), filter['queue_top'], filter['pause'], feed['url']) - else: - h_from = filter['history'][filter['type']].get('from', None) - h_thru = filter['history'][filter['type']].get('thru', None) - if self.test_range(filter['type'], match, h_from, h_thru): - res = self.download_torrent(torrent_url, filter.get('path', None), filter['queue_top'], filter['pause'], feed['url']) - - print res - if res == True: - if filter['delete'] == True: - self.config.deleteFilter(filter['id']) - self.write_config() - - model = self.glade.get_widget("FlexRSS_Filters_List").get_model() - iter = model.get_iter_first(); - while iter != None: - if model.get_value(iter, 0) == filter['id']: - model.remove(iter) - break - iter = model.iter_next(iter) - else: - self.config.addHistory(filter['id'], filter['type'], match) - self.write_config() - - self.feeds[feed['id']]['data'] = data - if self.glade: # Update config window... - feeds_model = self.glade.get_widget("FlexRSS_Feeds").get_model() - iter = feeds_model.get_iter_first() - while iter != None: - if id == feeds_model.get_value(iter, 0): - break - iter = feeds_model.iter_next(iter) - - i = feeds_model.iter_children(iter) - if i != None: - while feeds_model.remove(i): - pass - - for item in data: - feeds_model.append(iter, (0, item['title'], item['link'])) - - def update(self): - import time, threading - - current_time = time.time() - - # I feel dirty for this. Oh, how I miss C. - for id in self.feeds: - if self.feeds[id]['cfg']['enabled'] == True: - if (current_time - self.feeds[id]['cfg']['interval']) > self.feeds[id]['updated']: - self.feeds[id]['updated'] = current_time - if ( self.config.threaded_retrieval ): - threading.Thread(target=self.parse_feed, args=(self.feeds[id]['cfg']['id'],)).start() - else: - self.parse_feed(self.feeds[id]['cfg']['id']) - - def unload(self): - if self.toolbar_button: - self.toolbar_button.destroy() - self.toolbar_button = None - - def deluge_version_compare(self, version): - import deluge.common - va = deluge.common.PROGRAM_VERSION.split('.') - dv = int(va[0]) * 1000000 - dv = dv + (int(va[1]) * 10000) - dv = dv + (int(va[2]) * 100) - if len(va) >= 4: - dv = dv + int(va[3]) - - if dv < version: - return -1 - elif dv > version: - return 1 - else: - return 0 - - def __init__(self, path, core, interface, defaults): - self.path = path - self.core = core - self.interface = interface - self.version = defaults['VERSION'] - - self.load_config() - - if self.config.show_toolbar_button == True: - self.configure_ui_show_toolbar_button() - - self.feeds = {} - if self.config.feeds: - for feed in self.config.feeds: - self.feeds[feed['id']] = { 'cfg' : feed, - 'updated' : 0, - 'data' : [] } - - # Debugging - # self.configure() + icon = gtk.Image() + icon.set_from_file(os.path.join(self.path, "FlexRSS.png")) + self.toolbar_button = gtk.ToolButton(icon_widget=icon, label="FlexRSS") + self.toolbar_button.connect("clicked", self.configure_cb_toolbar_clicked) + self.interface.toolbar.add(self.toolbar_button) + self.toolbar_button.show_all() + + def configure_cb_toolbar_toggled(self, box): + if box.get_active(): + self.configure_ui_show_toolbar_button() + self.config.show_toolbar_button = True + self.write_config() + else: + self.toolbar_button.destroy() + self.toolbar_button = None + self.config.show_toolbar_button = False + self.write_config() + + def configure_cb_threaded_toggled(self, box): + self.config.threaded_retrieval = box.get_active() + self.write_config() + + def configure(self, widget=None): + if self.glade: # Dialog already running + return + + import gtk, gtk.glade, gobject + + self.glade = gtk.glade.XML(self.path + "/FlexRSS.glade") + + # Intialize feed lists + feeds_model = gtk.TreeStore(gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_STRING) + feeds_view = self.glade.get_widget("FlexRSS_Feeds") + filters_feeds_view = self.glade.get_widget("FlexRSS_Filters_Feed") + feeds_view.set_model(feeds_model) + filters_feeds_view.set_model(feeds_model) + feeds_model.set_sort_func(1, self.configure_ui_sort_cmp) + feeds_model.set_sort_column_id(1, gtk.SORT_ASCENDING) + + # Setup columns for feeds tab + renderer_name = gtk.CellRendererText() + column_name = gtk.TreeViewColumn(_("Feed Name"), renderer_name, text=1) + feeds_view.append_column(column_name) + renderer_url = gtk.CellRendererText() + column_url = gtk.TreeViewColumn(_("URL"), renderer_url, text=2) + feeds_view.append_column(column_url) + feeds_view.set_search_column(1) + feeds_view.set_search_equal_func(gtk_treeview_search_cb_stristr) + + # Set callback for when selection is changed in feeds tab + # I can't figure out how to do this in Glade + feeds_view.get_selection().connect("changed", self.configure_cb_feed_selected) + + # Setup columns for feed list on filters tab + renderer_name = gtk.CellRendererText() + column_name = gtk.TreeViewColumn(_("Feed Name"), renderer_name, text=1) + filters_feeds_view.append_column(column_name) + + # Allow multiple selections of feeds in filters tab + # I can't figure out how to do this in Glade + filters_feeds_view.get_selection().set_mode(gtk.SELECTION_MULTIPLE) + + # Populate feed lists + if self.config.feeds: + for feed in self.config.feeds: + this_feed = feeds_model.append(None, (feed['id'], feed['name'], feed['url'])) + for item in self.feeds[feed['id']]['data']: + feeds_model.append(this_feed, (0, item['title'], item['link'])) + + + # Initialize filters list + filters_model = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_BOOLEAN) + filters_view = self.glade.get_widget("FlexRSS_Filters_List") + filters_view.set_model(filters_model) + feeds_model.set_sort_func(1, self.configure_ui_sort_cmp) + filters_model.set_sort_column_id(1, gtk.SORT_ASCENDING) + + # Setup columns for filters list + renderer_enabled = gtk.CellRendererToggle() + column_enabled = gtk.TreeViewColumn(_("Enabled"), renderer_enabled, active=2) + filters_view.append_column(column_enabled) + renderer_enabled.connect('toggled', self.configure_cb_filter_toggled) + renderer_name = gtk.CellRendererText() + column_name = gtk.TreeViewColumn(_("Filter Name"), renderer_name, text=1) + filters_view.append_column(column_name) + + # Set callback for when selection is changed in feeds tab + # I can't figure out how to do this in Glade + filters_view.get_selection().connect("changed", self.configure_cb_filter_selected) + + # Populate filters list + if self.config.filters: + for filter in self.config.filters: + filters_model.append((filter['id'], filter['name'], filter['enabled'])) + + # Filter types + filter_types = self.glade.get_widget('FlexRSS_Filters_Type') + filter_types.append_text(_("Generic")) + filter_types.append_text(_("TV Show")) + filter_types.append_text(_("TV Show (dated)")) + + # Calendar buttons for dated tv show history restrictions + from CalendarButton import CalendarButton + dated_from = CalendarButton() + dated_from.connect('date-selected', self.configure_cb_test_filter) + dated_to = CalendarButton() + dated_to.connect('date-selected', self.configure_cb_test_filter) + dated_from.show() + dated_to.show() + history_table = self.glade.get_widget('FlexRSS_History_TVShow_Dated') + history_table.attach(dated_from, 1, 2, 0, 1, gtk.EXPAND|gtk.FILL, gtk.FILL) + history_table.attach(dated_to, 1, 2, 1, 2, gtk.EXPAND|gtk.FILL, gtk.FILL) + self.history_calendarbuttons = (dated_from, dated_to) + + # Initialize cookies list + cookies_model = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING) + cookies_view = self.glade.get_widget("FlexRSS_Cookies_List") + cookies_view.set_model(cookies_model) + cookies_view.get_selection().connect("changed", self.configure_cb_cookie_selected) + + # Setup column for cookies + domain_renderer = gtk.CellRendererText() + domain_column = gtk.TreeViewColumn(_("Domain"), domain_renderer, text=0) + path_renderer = gtk.CellRendererText() + path_column = gtk.TreeViewColumn(_("Path"), path_renderer, text=1) + name_renderer = gtk.CellRendererText() + name_column = gtk.TreeViewColumn(_("Name"), name_renderer, text=2) + value_renderer = gtk.CellRendererText() + value_column = gtk.TreeViewColumn(_("Value"), value_renderer, text=3) + cookies_view.append_column(domain_column) + cookies_view.append_column(path_column) + cookies_view.append_column(name_column) + cookies_view.append_column(value_column) + + for cookie in self.cookies: + self.configure_ui_add_cookie(cookies_model, cookie) + + # Interface + self.glade.get_widget("FlexRSS_Interface_ShowButton").set_active(self.config.show_toolbar_button) + self.glade.get_widget("FlexRSS_Retrieval_Threaded").set_active(self.config.threaded_retrieval) + + # Callbacks for UI events + actions = { + # Feeds tab + "on_FlexRSS_MainWindow_destroy" : self.configure_cb_closed, + "on_FlexRSS_Feeds_New_pressed" : self.configure_cb_feed_new, + "on_FlexRSS_Feeds_Save_pressed" : self.configure_cb_feed_save, + "on_FlexRSS_Feeds_Delete_pressed" : self.configure_cb_feed_delete, + "on_FlexRSS_Feeds_button_press_event" : self.configure_cb_feed_popup, + + # Filters tab + "on_FlexRSS_Filters_Add_pressed" : self.configure_cb_filter_new, + "on_FlexRSS_Action_Save_pressed" : self.configure_cb_filter_save, + "on_FlexRSS_Filter_Patern_Add_pressed" : self.configure_cb_add_pattern, + "on_FlexRSS_Filters_Type_changed" : self.configure_cb_test_filter, + "on_FlexRSS_Filters_Test_Pattern" : self.configure_cb_test_filter, + "on_FlexRSS_Filters_Delete_pressed" : self.configure_cb_delete_filter, + "on_FlexRSS_History_TVShow_From_Enabled_toggled" : self.configure_cb_filter_history_toggle, + "on_FlexRSS_History_TVShow_Thru_Enabled_toggled" : self.configure_cb_filter_history_toggle, + "on_FlexRSS_History_TVShow_Dated_From_Enabled_toggled" : self.configure_cb_filter_history_toggle, + "on_FlexRSS_History_TVShow_Dated_Thru_Enabled_toggled" : self.configure_cb_filter_history_toggle, + "on_FlexRSS_History_TVShow_From_Season_changed" : self.configure_cb_test_filter, + "on_FlexRSS_History_TVShow_From_Episode_changed" : self.configure_cb_test_filter, + "on_FlexRSS_History_TVShow_Thru_Season_changed" : self.configure_cb_test_filter, + "on_FlexRSS_History_TVShow_Thru_Episode_changed" : self.configure_cb_test_filter, + + # Configuration tab + "on_FlexRSS_Cookie_New_pressed" : self.configure_cb_cookie_new, + "on_FlexRSS_Cookie_Save_pressed" : self.configure_cb_cookie_save, + "on_FlexRSS_Cookie_Delete_pressed" : self.configure_cb_cookie_delete, + "on_FlexRSS_Interface_ShowButton_toggled" : self.configure_cb_toolbar_toggled, + "on_FlexRSS_Retrieval_Threaded_toggled" : self.configure_cb_threaded_toggled } + if hasattr(self.interface, 'interactive_add_torrent_path'): + actions["on_FlexRSS_Filter_Output_Location_current_folder_changed"] = self.configure_cb_output_set + else: + self.glade.get_widget('FlexRSS_Filter_Output').hide() + self.glade.signal_autoconnect(actions) + + self.glade.get_widget("FlexRSS_MainWindow").show() + + def cmp_history(a, b): + try: + if a.has_key('series'): + if a['series'] > b['series']: + return 1 + elif a['series'] < b['series']: + return -1 + else: + if a['episode'] > b['episode']: + return 1 + elif a['episode'] < b['episode']: + return -1 + else: + return 0 + except: + return 0 + + def strptime2regex(self, input): + # Does'n exactly live up to its name yet. Currently just + # replaces %y,%Y,%m,%d with named patterns. In the future, it + # would be nice to allow escaping (e.g., %%Y means literal %Y) + # and expand it to support other formats. + patterns = [('%Y', '(?P[0-9]{4})'), + ('%y', '(?P[0-9]{2})'), + ('%m', '(?P[0-9]{1,2})'), + ('%d', '(?P[0-9]{1,2})')] + + out = input + for p in patterns: + out = out.replace(p[0], p[1]) + + return out + + def replace_tv_show_patterns(self, input): + patterns = [('%s', '(?P[0-9]+)'), + ('%e', '(?P[0-9]+)')] + + out = input + for p in patterns: + out = out.replace(p[0], p[1]) + + return out + + def test_range(self, type, data, h_from=None, h_thru=None): + if type == self.config.constants['TV Show']: + if h_from != None: + if data['series'] < h_from['season']: + return False + elif data['series'] == h_from['season']: + if data['episode'] < h_from['episode']: + return False + + if h_thru != None: + if data['series'] > h_thru['season']: + return False + elif data['series'] == h_thru['season']: + if data['episode'] > h_thru['episode']: + return False + + return True + + elif type == self.config.constants['TV Show (dated)']: + if h_from != None: + if data['year'] < h_from['year']: + return False + elif data['year'] == h_from['year']: + if data['month'] < h_from['month']: + return False + elif data['month'] == h_from['month']: + if data['day'] < h_from['day']: + return False + + if h_thru != None: + if data['year'] < h_thru['year']: + return False + elif data['year'] == h_thru['year']: + if data['month'] < h_thru['month']: + return False + elif data['month'] == h_thru['month']: + if data['day'] < h_thru['day']: + return False + + return True + + else: + return True + + def test_pattern(self, type, subject, pattern): + import re, time + result = False + + if len(pattern) < 1: + return False + + if type == self.config.constants['TV Show (dated)']: + pattern = self.strptime2regex(pattern) + elif type == self.config.constants['TV Show']: + pattern = self.replace_tv_show_patterns(pattern) + + # Wow, so this is lame... + if pattern[0] != '^': + pattern = '.*' + pattern + + try: + exp = re.compile(pattern, re.IGNORECASE) + except: + print 'Broken expression: ' + pattern + return False + + match = exp.match(subject) + if match: +# print 'Match: ' + subject +# print ' ' + pattern + if type == self.config.constants['TV Show']: + try: + series = int(match.group('s')) + except: + series = 0 + + try: + episode = int(match.group('e')) + except: + episode = 0 + + result = { 'series' : series, + 'episode' : episode } + + elif type == self.config.constants['TV Show (dated)']: + try: + year = int(match.group('Y')) + except: + try: + year = int(match.group('y')) + if year > 70: + year += 1900 + else: + year += 2000 + except: + year = 0 + + try: + month = int(match.group('m')) + except: + month = 0 + + try: + day = int(match.group('d')) + except: + day = 0 + + result = { 'year' : year, + 'month' : month, + 'day' : day } + + else: + result = True + + return result + + def make_opener(self): + import urllib2 + + return urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookies)) + + def make_request(self, location, referer=None): + import urllib2, deluge.common + + req = urllib2.Request(location) + req.add_header("User-Agent", "FlexRSS/%d.%d.%d (%s/%s)" % (self.version[0], self.version[1], self.version[2], deluge.common.PROGRAM_NAME, deluge.common.PROGRAM_VERSION)) + if referer != None: + req.add_header('Referer', referer) + + return req + + def open_url(self, location): + return self.make_opener().open(self.make_request(location)) + + def download_torrent(self, location, path=None, queue_top=False, pause=False, referer=None): + import tempfile, os, deluge.core + + try: + fd = self.open_url(location) + except: + return False + + inf = fd.info() + if inf["content-type"] != "application/x-bittorrent": + print "Warning: torrent content-type not application/x-bittorrent" + + (tmpfd, filename) = tempfile.mkstemp(".torrent", "flexrss-") + tfd = os.fdopen(tmpfd, 'wb') + tfd.write(fd.read()) + fd.close() + tfd.close() + + unique_id = False + + try: + if path is None: + path = self.interface.config.get('default_download_path') + unique_id = self.interface.manager.add_torrent(filename, path, self.interface.config.get('use_compact_storage')) + self.interface.torrent_model_append(unique_id) + + if queue_top == True: + try: + self.interface.manager.queue_top(unique_id) + except: + pass + if pause == True: + try: + self.interface.manager.set_user_pause(unique_id, True) + except: + pass + except deluge.core.DuplicateTorrentError, e: + print 'FlexRSS: torrent already exists.' + return True + except: + print '*** FlexRSS error: unable to add torrent.' + return False + + return True + + def parse_feed(self, id): + import time, feedparser, urllib2, cookielib + + feed = self.config.getFeed(id) + + #print 'Parsing feed: ' + feed['url'] + try: + parsed = feedparser.parse(self.open_url(feed['url'])) + if (not parsed) or (not parsed.entries): + print 'Unable to parse feed: ' + feed['url'] + return + except: + print 'Unable to update feed: ' + feed['url'] + return + #print 'Retrieval successful: ' + feed['url'] + + data = [] + + for entry in parsed.entries: + entryTitle = entry['title'] + + try: + entryLink = entry.links[0]['href'] + except: + try: + entryLink = entry.enclosures[0]['href'] + except: + print "Skipping %s\n" % entryTitle + continue + + try: + data.append({ 'title': entryTitle, 'link': entryLink }) + except: + continue + + if self.config.filters: + for filter in self.config.filters: + try: + if not ((feed['id'] in filter['feeds']) or (0 in filter['feeds'])): + continue + except TypeError: + filter['feeds'] = [0] + + if filter['enabled'] != True: + continue + + for pattern in filter['patterns']: + # (setq python-indent 4 + # tab-width 4) + # Okay, I dislike python substantially less now. + # Edit (~a month later): I still dislike it a lot, though. + try: + if pattern[1] == 'Title': + subject = entryTitle + else: + subject = entryLink + except: + print 'Unable to find subject.' + + match = self.test_pattern(filter['type'], subject, pattern[0]) + if match: + # Filter matched. Check history to see if + # we should download it. + if filter['type'] == self.config.constants['Generic']: # Dirty hack. + match = { 'url' : entryLink } + + torrent_url = entryLink + replace = filter.get('replace', {'pattern': '', 'with': ''}) + if len(replace['pattern']) > 0: + try: + import re + + p = re.compile(replace['pattern'], re.IGNORECASE) + torrent_url = p.sub(replace['with'], torrent_url) + except: + print '*** FlexRSS error: s/%s/%s/i failed.' % (replace['pattern'], replace['with']) + return + + if not self.config.checkHistory(filter['id'], filter['type'], match): + print filter + if filter.has_key('history'): + res = False + + if filter['type'] == self.config.constants['Generic']: + if filter['history'].get(filter['type'], []).count(torrent_url) == 0: + res = self.download_torrent(torrent_url, filter.get('path', None), filter['queue_top'], filter['pause'], feed['url']) + else: + h_from = filter['history'][filter['type']].get('from', None) + h_thru = filter['history'][filter['type']].get('thru', None) + if self.test_range(filter['type'], match, h_from, h_thru): + res = self.download_torrent(torrent_url, filter.get('path', None), filter['queue_top'], filter['pause'], feed['url']) + + print res + if res == True: + if filter['delete'] == True: + self.config.deleteFilter(filter['id']) + self.write_config() + + model = self.glade.get_widget("FlexRSS_Filters_List").get_model() + iter = model.get_iter_first(); + while iter != None: + if model.get_value(iter, 0) == filter['id']: + model.remove(iter) + break + iter = model.iter_next(iter) + else: + self.config.addHistory(filter['id'], filter['type'], match) + self.write_config() + + self.feeds[feed['id']]['data'] = data + if self.glade: # Update config window... + feeds_model = self.glade.get_widget("FlexRSS_Feeds").get_model() + iter = feeds_model.get_iter_first() + while iter != None: + if id == feeds_model.get_value(iter, 0): + break + iter = feeds_model.iter_next(iter) + + i = feeds_model.iter_children(iter) + if i != None: + while feeds_model.remove(i): + pass + + for item in data: + feeds_model.append(iter, (0, item['title'], item['link'])) + + def update(self): + import time, threading + + current_time = time.time() + + # I feel dirty for this. Oh, how I miss C. + for id in self.feeds: + if self.feeds[id]['cfg']['enabled'] == True: + if (current_time - self.feeds[id]['cfg']['interval']) > self.feeds[id]['updated']: + self.feeds[id]['updated'] = current_time + if ( self.config.threaded_retrieval ): + threading.Thread(target=self.parse_feed, args=(self.feeds[id]['cfg']['id'],)).start() + else: + self.parse_feed(self.feeds[id]['cfg']['id']) + + def unload(self): + if self.toolbar_button: + self.toolbar_button.destroy() + self.toolbar_button = None + + def deluge_version_compare(self, version): + import deluge.common + va = deluge.common.PROGRAM_VERSION.split('.') + dv = int(va[0]) * 1000000 + dv = dv + (int(va[1]) * 10000) + dv = dv + (int(va[2]) * 100) + if len(va) >= 4: + dv = dv + int(va[3]) + + if dv < version: + return -1 + elif dv > version: + return 1 + else: + return 0 + + def __init__(self, path, core, interface, defaults): + self.path = path + self.core = core + self.interface = interface + self.version = defaults['VERSION'] + + self.load_config() + + if self.config.show_toolbar_button == True: + self.configure_ui_show_toolbar_button() + + self.feeds = {} + if self.config.feeds: + for feed in self.config.feeds: + self.feeds[feed['id']] = { 'cfg' : feed, + 'updated' : 0, + 'data' : [] } + + # Debugging + # self.configure()