The world lamest GUI newsreader... in 130 LOC
I started this as an experiment to see how hard it was to build apps using QT and Elixir. This is how it looks after two hours of coding:
And here's the code: http://urssus.googlecode.com
You will need:
PyQt 4.4 or later
Mark Pilgrim's feedparser
Python 2.5 (or whenever elementtree got included)
A OPML file
The Python SQLite bindings
Elixir (the declarative layer over SQL Alchemy)
You can find the real code at
And then you can use these 131 LOC ;-)
# -*- coding: utf-8 -*- # Mark Pilgrim's feed parser import feedparser as fp # DB Classes from elixir import * metadata.bind = "sqlite:///urssus.sqlite" metadata.bind.echo = True class Feed(Entity): htmlUrl = Field(Text) xmlUrl = Field(Text) title = Field(Text) text = Field(Text) description = Field(Text) children = OneToMany('Feed') parent = ManyToOne('Feed') posts = OneToMany('Post') def __repr__(self): return self.text def update(self): d=fp.parse(self.xmlUrl) class Post(Entity): feed = ManyToOne('Feed') title = Field(Text) post_id = Field(Text) content = Field(Text) # This is just temporary setup_all() create_all() # UI Classes from PyQt4 import QtGui, QtCore from Ui_main import Ui_MainWindow class MainWindow(QtGui.QMainWindow): def __init__(self): QtGui.QMainWindow.__init__(self) # Set up the UI from designer self.ui=Ui_MainWindow() self.ui.setupUi(self) # Initialize the tree from the Feeds self.model=QtGui.QStandardItemModel() # Internal function def addSubTree(parent, node): nn=QtGui.QStandardItem(unicode(node)) parent.appendRow(nn) nn.feed=node if not node.children: return else: for child in node.children: addSubTree(nn, child) roots=Feed.query.filter(Feed.parent==None) iroot=self.model.invisibleRootItem() iroot.feed=None for root in roots: addSubTree(iroot, root) self.ui.feeds.setModel(self.model) QtCore.QObject.connect(self.ui.feeds, QtCore.SIGNAL("clicked(QModelIndex)"), self.openFeed) QtCore.QObject.connect(self.ui.posts, QtCore.SIGNAL("clicked(QModelIndex)"), self.openPost) def openFeed(self, index): item=self.model.itemFromIndex(index) feed=item.feed if not feed.xmlUrl: return d=fp.parse(feed.xmlUrl) posts=[] for post in d['entries']: print post print '----------------------------------\n\n' if 'content' in post: posts.append(Post(feed=feed, title=post['title'], post_id=post['id'], content='<hr>'.join([ c.value for c in post['content']]))) elif 'summary' in post: posts.append(Post(feed=feed, title=post['title'], post_id=post['id'], content=post['summary'])) elif 'value' in post: posts.append(Post(feed=feed, title=post['title'], post_id=post['id'], content=post['value'])) session.flush() self.ui.posts.__model=QtGui.QStandardItemModel() for post in posts: item=QtGui.QStandardItem(post.title) item.post=post self.ui.posts.__model.appendRow(item) self.ui.posts.setModel(self.ui.posts.__model) def openPost(self, index): item=self.ui.posts.__model.itemFromIndex(index) post=item.post self.ui.view.setHtml(post.content) if __name__ == "__main__": import sys # For starters, lets import a OPML file into the DB so we have some data to work with from xml.etree import ElementTree tree = ElementTree.parse(sys.argv[1]) current=None for outline in tree.findall("//outline"): xu=outline.get('xmlUrl') if xu: f=Feed(xmlUrl=outline.get('xmlUrl'), htmlUrl=outline.get('htmlUrl'), title=outline.get('title'), text=outline.get('text'), description=outline.get('description') ) if current: current.children.append(f) f.parent=current else: current=Feed(text=outline.get('text')) session.flush() app=QtGui.QApplication(sys.argv) window=MainWindow() window.show() sys.exit(app.exec_())