deluge/plugins/FlexRSS/plugin.py

1733 lines
56 KiB
Python

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
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
def getFilter(self, id):
if not self.filters:
return None
for filter in self.filters:
if filter['id'] == id:
return filter
return None
def setFilter(self, id, key, value):
filter = self.getFilter(id)
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
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}
self.filters.append(filter)
return id
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
def checkHistory(self, id, type, data):
filter = self.getFilter(id)
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
def checkRange(self, id, type, data):
filter = self.getFilter(id)
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 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
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
return True
else:
return True
def addHistory(self, id, type, data):
filter = self.getFilter(id)
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']]
def getFeed(self, id):
if not self.feeds:
return None
for feed in self.feeds:
if feed['id'] == id:
return feed
return None
def setFeed(self, id, key, value):
feed = self.getFeed(id)
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
if not self.feeds:
self.feeds = []
self.feeds.append({ "id" : id,
"name" : name,
"url" : url,
"interval" : interval,
"enabled" : True })
return id
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
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
icon = gtk.Image()
icon.set_from_file(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<Y>[0-9]{4})'),
('%y', '(?P<y>[0-9]{2})'),
('%m', '(?P<m>[0-9]{1,2})'),
('%d', '(?P<d>[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<s>[0-9]+)'),
('%e', '(?P<e>[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()