Mercurial > pidgin.yaz
view finch/libgnt/pygnt/example/rss/gntrss.py @ 18722:8b5082d54c1d
Make the rss-reader look and behave nicer.
author | Sadrul Habib Chowdhury <imadil@gmail.com> |
---|---|
date | Sun, 29 Jul 2007 19:00:14 +0000 |
parents | 64a7b13d3b8d |
children | 1aeda1e812a8 |
line wrap: on
line source
#!/usr/bin/env python """ gr - An RSS-reader built using libgnt and feedparser. Copyright (C) 2007 Sadrul Habib Chowdhury <sadrul@pidgin.im> This application is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This application is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this application; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ """ This file deals with the rss parsing part (feedparser) of the application """ import threading import feedparser import gobject import sys import time ## # The FeedItem class. It will update emit 'delete' signal when it's # destroyed. ## class FeedItem(gobject.GObject): __gproperties__ = { 'unread' : (gobject.TYPE_BOOLEAN, 'read', 'The unread state of the item.', False, gobject.PARAM_READWRITE) } __gsignals__ = { 'delete' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_OBJECT,)) } def __init__(self, item, parent): self.__gobject_init__() self.date = item['date'] self.date_parsed = item['date_parsed'] self.title = item['title'] self.summary = item['summary'] self.link = item['link'] self.parent = parent self.unread = True def remove(self): self.emit('delete', self.parent) if self.unread: self.parent.set_property('unread', self.parent.unread - 1) def do_set_property(self, property, value): if property.name == 'unread': self.unread = value def mark_unread(self, unread): if self.unread == unread: return self.set_property('unread', unread) gobject.type_register(FeedItem) def item_hash(item): return str(item['date'] + item['title']) """ The Feed class. It will update the 'link', 'title', 'desc' and 'items' attributes if/when they are updated (triggering 'notify::<attr>' signal) TODO: - Add a 'count' attribute - Each feed will have a 'uidata', which will be its display window - Look into 'category'. Is it something that feed defines, or the user? - Have separate refresh times for each feed. - Have 'priority' for each feed. (somewhat like category, perhaps?) """ class Feed(gobject.GObject): __gproperties__ = { 'link' : (gobject.TYPE_STRING, 'link', 'The web page this feed is associated with.', '...', gobject.PARAM_READWRITE), 'title' : (gobject.TYPE_STRING, 'title', 'The title of the feed.', '...', gobject.PARAM_READWRITE), 'desc' : (gobject.TYPE_STRING, 'description', 'The description for the feed.', '...', gobject.PARAM_READWRITE), 'items' : (gobject.TYPE_POINTER, 'items', 'The items in the feed.', gobject.PARAM_READWRITE), 'unread' : (gobject.TYPE_INT, 'unread', 'Number of unread items in the feed.', 0, 10000, 0, gobject.PARAM_READWRITE) } __gsignals__ = { 'added' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_OBJECT,)) } def __init__(self, url): self.__gobject_init__() self.url = url # The url of the feed itself self.link = url # The web page associated with the feed self.desc = url self.title = url self.unread = 0 self.timer = 0 self.items = [] self.hash = {} def do_set_property(self, property, value): if property.name == 'link': self.link = value elif property.name == 'desc': self.desc = value elif property.name == 'title': self.title = value elif property.name == 'unread': self.unread = value pass def check_thread_for_death(self): #if self.thread.running: # sys.stderr.write(time.ctime() + "continue") # return True # The thread has ended!! #result = self.thread.result #self.thread = None result = feedparser.parse(self.url) # XXX Look at result['bozo'] first, and emit some signal that the UI can use # to indicate (dim the row?) that the feed has invalid XML format or something channel = result['channel'] self.set_property('link', channel['link']) self.set_property('desc', channel['description']) self.set_property('title', channel['title']) self.timer = 0 items = result['items'] tmp = {} for item in self.items: tmp[hash(item)] = item unread = self.unread for item in items: try: exist = self.hash[item_hash(item)] del tmp[hash(exist)] except: itm = FeedItem(item, self) self.items.append(itm) self.emit('added', itm) self.hash[item_hash(item)] = itm unread = unread + 1 for hv in tmp: tmp[hv].remove() if unread != self.unread: self.set_property('unread', unread) return False def refresh(self): #if self.thread == 0: # self.thread = FeedReader(self) # self.thread.start() if self.timer == 0: self.timer = gobject.timeout_add(1000, self.check_thread_for_death) gobject.type_register(Feed) ## # A FeedReader class, which is threaded to make sure it doesn't freeze the ui # (this thing doesn't quite work ... yet) ## class FeedReader(threading.Thread): def __init__(self, feed): self.feed = feed self.running = True threading.Thread.__init__(self) def run(self): sys.stderr.write(str(time.ctime()) + " STARTED!!!\n\n\n") self.running = True self.result = feedparser.parse(self.feed.url) self.running = False sys.stderr.write(str(time.ctime()) + " DONE!!!\n\n\n") feeds = [] urls = ("http://rss.slashdot.org/Slashdot/slashdot", "http://www.python.org/channews.rdf", "http://pidgin.im/rss.php", "http://kerneltrap.org/node/feed" ) for url in urls: feed = Feed(url) feeds.append(feed)