mirror of
https://github.com/correl/trss.git
synced 2024-11-27 11:09:56 +00:00
Initial commit
This commit is contained in:
commit
68da185e5e
2 changed files with 201 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# Compiled python files
|
||||||
|
*.py[oc]
|
199
trss.py
Normal file
199
trss.py
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import csv
|
||||||
|
from ConfigParser import SafeConfigParser
|
||||||
|
import feedparser
|
||||||
|
import urllib2
|
||||||
|
|
||||||
|
_config_file = os.path.expanduser('~/.trss/config')
|
||||||
|
_feed_file = os.path.expanduser('~/.trss/feeds')
|
||||||
|
config = SafeConfigParser()
|
||||||
|
|
||||||
|
class TorrentFeed:
|
||||||
|
def __init__(self, url, name=None, lastguid=None):
|
||||||
|
self.url = url
|
||||||
|
self.name = name
|
||||||
|
self.lastguid = lastguid
|
||||||
|
self._parsed = None
|
||||||
|
def parse(self):
|
||||||
|
if not self._parsed:
|
||||||
|
self._parsed = feedparser.parse(self.url)
|
||||||
|
if self._parsed.feed.has_key('title'):
|
||||||
|
self.name = self._parsed.feed.title
|
||||||
|
return self._parsed
|
||||||
|
def set_last_index(self, index=0):
|
||||||
|
parsed = self.parse()
|
||||||
|
self.lastguid = parsed.entries[index].guid
|
||||||
|
|
||||||
|
def download(self, folder):
|
||||||
|
parsed = self.parse()
|
||||||
|
downloads = []
|
||||||
|
for entry in parsed.entries:
|
||||||
|
if entry.guid == self.lastguid:
|
||||||
|
break
|
||||||
|
downloads.append(entry)
|
||||||
|
downloads.reverse()
|
||||||
|
for download in downloads:
|
||||||
|
# Download, break on failure
|
||||||
|
if download.enclosures:
|
||||||
|
enclosure = download.enclosures[0]
|
||||||
|
print 'Downloading {0} to {1}'.format(download.title, folder)
|
||||||
|
remote = urllib2.urlopen(enclosure.href)
|
||||||
|
filename = os.path.basename(enclosure.href)
|
||||||
|
if filename.endswith('.torrent'):
|
||||||
|
# Strip the extension, it'll be re-applied later
|
||||||
|
filename = filename[:filename.rfind('.torrent')]
|
||||||
|
local_file = '{0}.torrent'.format(filename)
|
||||||
|
attempt = 0
|
||||||
|
while os.path.exists(os.path.join(folder, local_file)):
|
||||||
|
attempt += 1
|
||||||
|
local_file = '{0} ({1}).torrent'.format(filename, attempt)
|
||||||
|
local = open(os.path.join(folder, local_file), 'wb')
|
||||||
|
local.write(remote.read())
|
||||||
|
local.close()
|
||||||
|
remote.close()
|
||||||
|
self.lastguid = download.guid
|
||||||
|
|
||||||
|
def read_cfg():
|
||||||
|
config.read(_config_file)
|
||||||
|
|
||||||
|
def write_cfg():
|
||||||
|
try:
|
||||||
|
if not os.path.exists(os.path.dirname(_config_file)):
|
||||||
|
os.makedirs(os.path.dirname(_config_file))
|
||||||
|
with open(_config_file, 'w') as config_file:
|
||||||
|
config.write(config_file)
|
||||||
|
except:
|
||||||
|
print 'Could not write config file'
|
||||||
|
|
||||||
|
def read_feeds():
|
||||||
|
try:
|
||||||
|
feed_file = csv.reader(open(_feed_file, 'rb'))
|
||||||
|
for url, name, lastguid in feed_file:
|
||||||
|
feed = TorrentFeed(name, url, lastguid)
|
||||||
|
feeds.append(feed)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return feeds
|
||||||
|
|
||||||
|
def write_feeds():
|
||||||
|
try:
|
||||||
|
if not os.path.exists(os.path.dirname(_feed_file)):
|
||||||
|
os.makedirs(os.path.dirname(_feed_file))
|
||||||
|
feed_file = csv.writer(open(_feed_file, 'wb'))
|
||||||
|
for feed in feeds:
|
||||||
|
feed_file.writerow((feed.name, feed.url, feed.lastguid))
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
print 'Could not write feeds file'
|
||||||
|
|
||||||
|
def add_rss(url, recent=0):
|
||||||
|
existing = [f for f in feeds if f.url == url]
|
||||||
|
if existing:
|
||||||
|
feed = existing[0]
|
||||||
|
feeds.remove(feed)
|
||||||
|
else:
|
||||||
|
feed = TorrentFeed(url)
|
||||||
|
feed.set_last_index(recent)
|
||||||
|
feeds.append(feed)
|
||||||
|
return feed
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
print """Usage:
|
||||||
|
{0} add <rss-url> [<recent-items>]
|
||||||
|
Adds an RSS feed to follow
|
||||||
|
|
||||||
|
rss-url: Full URL to the RSS feed
|
||||||
|
recent-items: (Optional) number of recent items to queue
|
||||||
|
for downloading
|
||||||
|
{0} remove <index>
|
||||||
|
Remove an RSS feed
|
||||||
|
|
||||||
|
index: Numeric index of the feed to remove as
|
||||||
|
reported by the list command
|
||||||
|
{0} list
|
||||||
|
Displays a list of followed feeds
|
||||||
|
|
||||||
|
{0} download
|
||||||
|
Fetch all feeds and download new items
|
||||||
|
""".format(sys.argv[0])
|
||||||
|
|
||||||
|
feeds = []
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
read_cfg()
|
||||||
|
read_feeds()
|
||||||
|
|
||||||
|
arguments = sys.argv[1:]
|
||||||
|
try:
|
||||||
|
command = arguments.pop(0).lower()
|
||||||
|
except:
|
||||||
|
usage()
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
if command == 'add':
|
||||||
|
try:
|
||||||
|
url = arguments.pop(0)
|
||||||
|
except:
|
||||||
|
print 'You must specify an RSS url to add'
|
||||||
|
exit(1)
|
||||||
|
try:
|
||||||
|
recent = int(arguments.pop(0))
|
||||||
|
except:
|
||||||
|
recent = 0
|
||||||
|
feed = add_rss(url, recent)
|
||||||
|
print "Added feed '{0}'".format(feed.name)
|
||||||
|
write_feeds()
|
||||||
|
elif command == 'remove':
|
||||||
|
try:
|
||||||
|
index = int(arguments.pop(0))
|
||||||
|
feed = feeds.pop(index)
|
||||||
|
print "Removed feed '{0}'".format(feed.name)
|
||||||
|
except:
|
||||||
|
print 'Invalid feed index'
|
||||||
|
exit(1)
|
||||||
|
write_feeds()
|
||||||
|
elif command == 'list':
|
||||||
|
for index, feed in enumerate(feeds):
|
||||||
|
print '{0}: {1} - {2}'.format(index, feed.name, feed.url)
|
||||||
|
elif command == 'download':
|
||||||
|
try:
|
||||||
|
folder = config.get('trss', 'download_folder')
|
||||||
|
except:
|
||||||
|
print 'Download folder is not set, using current directory'
|
||||||
|
folder = os.getcwd()
|
||||||
|
for feed in feeds:
|
||||||
|
print 'FEED', feed.name
|
||||||
|
feed.download(folder)
|
||||||
|
write_feeds()
|
||||||
|
elif command == 'set':
|
||||||
|
try:
|
||||||
|
key = arguments.pop(0)
|
||||||
|
except:
|
||||||
|
for section in config.sections():
|
||||||
|
for key in config.options(section):
|
||||||
|
print "{0}.{1}: {2}".format(section, key, config.get(section, key))
|
||||||
|
exit()
|
||||||
|
try:
|
||||||
|
value = arguments.pop(0)
|
||||||
|
except:
|
||||||
|
value = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
section, key = key.split('.')
|
||||||
|
except:
|
||||||
|
section = 'trss'
|
||||||
|
|
||||||
|
if value is None:
|
||||||
|
try:
|
||||||
|
print "{0}.{1}: {2}".format(section, key, config.get(section, key))
|
||||||
|
except:
|
||||||
|
print "Value {0}.{1} does not exist".format(section, key)
|
||||||
|
else:
|
||||||
|
if not config.has_section(section):
|
||||||
|
config.add_section(section)
|
||||||
|
config.set(section, key, value)
|
||||||
|
write_cfg()
|
||||||
|
else:
|
||||||
|
usage()
|
||||||
|
exit(1)
|
Loading…
Reference in a new issue