Commits

Anonymous committed 1bff303

Added support for watched.li

  • Participants
  • Parent commits 0f09962

Comments (0)

Files changed (5)

 syntax: glob
 test.html
+test.py
 test.sh
 test.xml
 *.torrent
 *.html
+*.pyc
 #!/usr/bin/env python
 
-import cPickle, os, sys
-import urllib, urlparse
+import ConfigParser
+import cPickle
+import os
+import sys
+import urllib
+import urlparse
 
 from BeautifulSoup import BeautifulSoup as bsoup
 from feedparser import parse as rssparse
+from watchedli import WatchedLi
 
 
 BASE_URL = 'http://showrss.karmorra.info/?cs=feeds'
 FEED_URL = 'http://showrss.karmorra.info/feeds/%s.rss'
-CACHE_FILE = os.path.expandvars('$HOME/.shores')
-TARGET_DIR = '.'
+CFG_DIR = os.path.expandvars('$HOME/.shores')
 
+CACHE_FILE = os.path.join(CFG_DIR, 'cache')
+CFG_FILE = os.path.join(CFG_DIR, 'config')
 
-def dlfile(link):
-	url = urlparse.urlparse(link)
-	path = os.path.join(TARGET_DIR, os.path.basename(url[2]))
-	if os.path.exists(path):
-		return False
-	u = urllib.urlopen(link)
-	torrent = u.read()
-	f = file(path, 'wb')
-	f.write(torrent)
-	f.close()
-	return True
+
+def dlfile(link, targetDir):
+    url = urlparse.urlparse(link)
+    path = os.path.join(targetDir, os.path.basename(url[2]))
+    if os.path.exists(path):
+        return False
+    u = urllib.urlopen(link)
+    torrent = u.read()
+    f = file(path, 'wb')
+    f.write(torrent)
+    f.close()
+    return True
+
 
 def list_shows():
-	result = []
-	inputFP = urllib.urlopen(BASE_URL)
-	for option in bsoup(inputFP)('option'):
-		optContents = ''.join(option.contents)
-		optValue = option['value']
-		if optValue.isnumeric():
-			result.append({optContents: optValue})
-	inputFP.close()
-	return result
+    result = []
+    try:
+        inputFP = urllib.urlopen(BASE_URL)
+    except Exception, e:
+        print e
+        return result
+    for option in bsoup(inputFP)('option'):
+        optContents = ''.join(option.contents)
+        optValue = option['value']
+        if optValue.isnumeric():
+            result.append({optContents: optValue})
+    inputFP.close()
+    return result
+
 
 def is_in_cache(cache, key, element):
-	if cache.has_key(key):
-		return element in cache[key]
-	return False
+    if cache.has_key(key):
+        return element in cache[key]
+    return False
+
 
 def store_in_cache(cache, key, element):
-	if not cache.has_key(key):
-		cache[key] = []
-	cache[key].append(element)
+    if not cache.has_key(key):
+        cache[key] = []
+    cache[key].append(element)
+
 
 def load_cache():
-	if not os.path.exists(CACHE_FILE):
-		return {}
-	inputFP = file(CACHE_FILE)
-	result = cPickle.load(inputFP)
-	inputFP.close()
-	return result
+    if not os.path.exists(CACHE_FILE):
+        return {}
+    inputFP = file(CACHE_FILE)
+    result = cPickle.load(inputFP)
+    inputFP.close()
+    return result
+
 
 def store_cache(to_cache):
-	outputFP = file(CACHE_FILE, 'w')
-	cPickle.dump(to_cache, outputFP)
-	outputFP.close()
+    outputFP = file(CACHE_FILE, 'w')
+    cPickle.dump(to_cache, outputFP)
+    outputFP.close()
+
+
+def handle_feed(feed_url, cache, feed_id):
+    inputFP = urllib.urlopen(feed_url)
+    for item in rssparse(inputFP)['entries']:
+        for link in item['links']:
+            linked = link['href']
+            if not is_in_cache(cache, feed_id, linked):
+                try:
+                    if dlfile(linked):
+                        store_in_cache(cache, feed_id, linked)
+                        print 'Fetched torrent file "%s".' % linked
+                except Exception, e:
+                    print e
+    inputFP.close()
+
+
+def handle_show(showName, listOfShows):
+    for show in listOfShows:
+        curShowName = show.keys()[0]
+        if curShowName.lower() == showName.lower():
+            print 'Found matching show "%s".' % curShowName
+            handle_feed(FEED_URL % show[curShowName], cache, curShowName)
+            store_cache(cache)
+            return
+    print 'Show "%s" does not exist.' % showName
 
 
 if __name__ == '__main__':
-	cache = load_cache()
+    if not os.path.exists(CFG_DIR):
+        os.mkdir(CFG_DIR)
 
-	if len(sys.argv) == 1:
-		print 'Available shows:'
-		for show in list_shows():
-			print '\t%s' % show.keys()[0]
-	else:
-		showName = ' '.join(sys.argv[1:])
-		for show in list_shows():
-			curShowName = show.keys()[0]
-			if curShowName.lower() == showName.lower():
-				print 'Found matching show "%s".' % curShowName
-				inputFP = urllib.urlopen(FEED_URL % show[curShowName])
-				for item in rssparse(inputFP)['entries']:
-					for link in item['links']:
-						linked = link['href']
-						if not is_in_cache(cache, curShowName, linked):
-							if dlfile(linked):
-								store_in_cache(cache, curShowName, linked)
-								print 'Fetched torrent file "%s".' % linked
-				inputFP.close()
-				store_cache(cache)
-				sys.exit(0)
-		print 'Show "%s" does not exist.' % showName
+        dummy_config = file(CFG_FILE, 'w')
+        dummy_config.write('[shores]\ntargetDir = %s' % os.path.expandvars('$HOME'))
+        dummy_config.close()
+
+    config = ConfigParser.ConfigParser()
+    config.read(CFG_FILE)
+
+    targetDir = config.get('shores', 'targetDir')
+
+    cache = load_cache()
+    listOfShows = list_shows()
+
+    if len(sys.argv) == 1:
+        try:
+            watchedLiUser = config.get('shores', 'watchedLiUser')
+            watchedLiPass = config.get('shores', 'watchedLiPass')
+
+            watched = WatchedLi(watchedLiUser, watchedLiPass)
+            for show in watched.shows():
+                handle_show(show, listOfShows)
+        except:
+            print 'Available shows:'
+            for show in listOfShows:
+                print '\t%s' % show.keys()[0]
+    else:
+        showName = ' '.join(sys.argv[1:])
+        handle_show(showName, listOfShows)

File watchedli.py

+#!/usr/bin/env python
+
+##
+# Watched.li "API" using some scraping.
+##
+
+import cookielib
+import mechanize
+from BeautifulSoup import BeautifulSoup as soup
+
+BASE_URL = 'http://alpha.watched.li/user/index'
+
+
+class WatchedLi:
+    def __init__(self, user, password):
+        self.browser = mechanize.Browser()
+        self.browser.set_cookiejar(cookielib.LWPCookieJar())
+
+        self.browser.open(BASE_URL)
+        self.browser.select_form(nr=1)
+        self.browser.form['User[email]'] = user
+        self.browser.form['User[pass0]'] = password
+        self.browser.submit()
+
+    def shows(self):
+        shows = []
+
+        index = soup(self.browser.response())
+        show_section = index('section', {'class': 'shows'})[0]
+
+        for div in show_section('div'):
+            if not div.has_key('class') or not div['class'].startswith('show-tile show-'):
+                continue
+            for divInner in div('div', {'class': 'inner'}):
+                for h2 in divInner('h2'):
+                    shows.append(h2.text)
+
+        return shows

File web/Makefile

-.PHONY: all clean
+.PHONY: all clean deploy
 
 FILES = index.html
 
+deploy: all
+	scp $(FILES) vu0:vu0.org/projects/shores
+
 all: $(FILES)
 
 clean:

File web/index.md

 shores
 ======
 
-Shores is a ShowRSS client, which downloads the
+Shores is a [ShowRSS][2] client, which downloads the
 latest torrents of TV shows and can take actions
-on them.
+on them. You can also log into your [watched.li][1]
+and automatically download torrents for your 
+favourite shows.
 
-Boris Buegling <boris@icculus.org>
+[Boris Buegling][3]
+
+[1]: http://alpha.watched.li/
+[2]: http://showrss.kamorra.info/
+[3]: mailto:boris@icculus.org