def recommend_with_google(request): """ Make a recommendation by parsing the user's google reader feeds """ form = GoogleLoginForm(request.POST) if form.is_valid(): cache_key = "feed-hashes-%s" % form.cleaned_data.get("username") feed_hashes = cache.get(cache_key) if not feed_hashes: reader = GoogleReader() reader.identify(form.cleaned_data.get("username"), form.cleaned_data.get("password")) if reader.login(): feeds = reader.get_subscription_list() client = PostRank() feed_hashes = [] for feed in feeds.get("subscriptions"): if feed.get("id"): feed_hash = client.get_feed_hash(feed.get("id")[5:]) if feed_hash: feed_hashes.append(feed_hash) cache.set(cache_key, feed_hashes, 24 * 60 * 60) else: if request.is_ajax(): template = "google_error.html" else: template = "google_error_page.html" return render_to_response("recommender/%s" % template, { }, context_instance=RequestContext(request)) if feed_hashes: recommendations = client.get_recommendations(feed_hashes, limit=5) if recommendations: if request.is_ajax(): template = "results.html" else: template = "results_page.html" return render_to_response("recommender/%s" % template, { "results": recommendations, }, context_instance=RequestContext(request)) return render_to_response("recommender/google.html", { "recommend_form": form, }, context_instance=RequestContext(request))
class Reader(object): def __init__(self, email, password): self.reader = GoogleReader() self.reader.identify(email, password) if not self.reader.login(): raise Exception(u'Failed to login to Google Reader') self.clear_cache() def clear_cache(self): self.cache = {} @cache('subscriptions') def get_subscriptions(self): subscriptions = {} for x in self.reader.get_subscription_list()['subscriptions']: subscriptions[x['id']] = x return subscriptions @cache('feed_title') def get_feed_title(self): return self.get_unread_feed().get_title() @cache('unread_feed') def get_unread_feed(self): return self.reader.get_feed(count=CONF.unread.max_count, exclude_target=CONST.ATOM_STATE_READ) @cache('unread_entries') def get_unread_entries(self): subscriptions = self.get_subscriptions() entries = [] for entry in self.get_unread_feed().get_entries(): if self.ad_filter(entry): continue id = entry['sources'].keys()[0] entry['subscription_id'] = id entry['subscription_title'] = subscriptions[id]['title'] entry['pinned'] = False # XXX cat = entry['categories'] entry['starred'] = cat.has_key(CONST.ATOM_STATE_STARRED) # FIXME fresh? or unread? entry['unread'] = cat.has_key(CONST.ATOM_STATE_FRESH) entries.append(entry) ChildThread(self.decode, entries).start() return entries @cache('unread_counts') def get_unread_counts(self): counts = {} for x in self.reader.get_unread_count_list()['unreadcounts']: counts[x['id']] = x['count'] return counts @cache('unread_count') def get_unread_count(self): for k,v in self.get_unread_counts().iteritems(): if k.endswith('/state/com.google/reading-list'): return v return 0 def get_pinned_count(self): return len(self.get_pinned_entries()) @cache('starred_count') def get_starred_count(self): return len(filter(lambda x: x['starred'], self.get_unread_entries())) @cache('pinned_entries') def get_pinned_entries(self): return [] def toggle_pin(self, entry): entry['pinned'] = not entry['pinned'] if entry['pinned']: self.get_pinned_entries().append(entry) else: self.get_pinned_entries().remove(entry) def toggle_star(self, entry): # XXX if entry['starred']: ChildThread(self.reader.del_star, entry['google_id']).start() self.cache['starred_count'] -= 1 else: ChildThread(self.reader.add_star, entry['google_id']).start() self.cache['starred_count'] += 1 entry['starred'] = not entry['starred'] def set_read(self, entry): if not entry['unread']: return ChildThread(self.reader.set_read, entry['google_id']).start() entry['unread'] = False self.cache['unread_count'] -= 1 def set_unread(self, entry): if entry['unread']: return ChildThread(self.reader.set_unread, entry['google_id']).start() entry['unread'] = True self.cache['unread_count'] += 1 def toggle_read(self, entry): if entry['unread']: self.set_read(entry) else: self.set_unread(entry) def ad_filter(self, entry): if not CONF.ad_filter.enable: return False if CONF.ad_filter.pattern.match(entry['title']): Thread(target=self.reader.set_read, args=(entry['google_id'],)).run() return True return False def decode(self, entries): for entry in entries: cmd = 'w3m -dump -T text/html' proc = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE) proc.stdin.write(entry['content'].encode('utf-8')) proc.stdin.close() entry['content'] = proc.stdout.readlines()