clean branch for qml reimplementation

This commit is contained in:
Jeena 2014-11-11 23:57:52 +01:00
parent c798e60300
commit 3ff4969946
8 changed files with 0 additions and 10548 deletions

BIN
Icon.icns

Binary file not shown.

View file

@ -1,30 +0,0 @@
BSD license
===========
Copyright (c) 2013, Jeena Paradies
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of Bungloo nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,58 +0,0 @@
<img align=right src="http://jabs.nu/feedthemonkey/feedthemonkey-icon.png" width='256' alt='Icon'>
# Feed the Monkey
Feed the Monkey is a desktop client for [TinyTinyRSS](http://tt-rss.org). That means that it doesn't work as a standalone feed reader but only as a client for the TinyTinyRSS API which it uses to get the normalized feeds and to synchronize the "article read" marks.
It is written in PyQt and uses WebKit to show the contents.
You need to have PyQt installed and a account on a TinyTinyRSS server.
License: BSD
## Installation
### Linux + Windows
Download the [ZIP](https://github.com/jeena/feedthemonkey/archive/master.zip)-file, unzip it and then run:
On Linux you can just do (if you have PyQt4, python2 and python2-autotools already installed):
`sudo python2 setup.py install`
On Windows you need to install (those are links to the binary packages):
- [Python2 x32](http://www.python.org/ftp/python/2.7.4/python-2.7.4.msi) or [Python x64](http://www.python.org/ftp/python/2.7.4/python-2.7.4.amd64.msi)
- [PyQt4 x32](http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.10.1/PyQt4-4.10.1-gpl-Py2.7-Qt4.8.4-x32.exe) or [PyQt x64](http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.10.1/PyQt4-4.10.1-gpl-Py2.7-Qt4.8.4-x64.exe)
Then rename `feedthemonkey` to `feedthemonkey.pyw` and then you can run it by double-clicking.
### OS X
Download [FeedTheMonkey.app.zip](http://jabs.nu/feedthemonkey/download/FeedTheMonkey.app.zip) unzip it and move it to your Applications folder. After that just run it like every other app.
## Keyboard shortcuts
The keyboard shortcuts are inspired by other feed readers which are inspired by the text editor vi.
`j` or `→` show nex article
`k` or `←` show previous article
`n` or `Return` open current article in the default browser
`r` reload articles
`s` star current article
`Ctrl S` show starred articles
`Ctrl Q` quit
`Ctrl +` zoom in
`Ctrl -` zoom out
`Ctrl 0` reset zoom
On OS X use `Cmd` instead of `Ctrl`.
## Trivia
I just hacked together this one within one day so it is not feature complete yet and has no real error handling.
Right now it only loads unread articles and shows them one after another. I might add a sidebar in the future, we will see.
## Screenshot
![Feed the Monkey screenshot](http://jabs.nu/feedthemonkey/feedthemonkey-screenshot.png)

View file

@ -1,17 +0,0 @@
#!/bin/bash
HERE=`pwd`
TMP="/tmp"
rm -rf FeedTheMonkey.app
rm -rf $TMP/feedthemonkey
mkdir $TMP/feedthemonkey
cp Icon.icns $TMP/feedthemonkey/
cp setup.py $TMP/feedthemonkey
cp feedthemonkey $TMP/feedthemonkey/
cd $TMP/feedthemonkey
python setup.py py2app
mv $TMP/feedthemonkey/dist/FeedTheMonkey.app $HERE
cd $HERE
rm -rf $TMP/feedthemonkey
FeedTheMonkey.app/Contents/MacOS/FeedTheMonkey

View file

@ -1,564 +0,0 @@
#!/usr/bin/env python2
try:
import urllib.request as urllib2
except:
import urllib2
import sys, os, json, tempfile, urllib, json
from PyQt4 import QtGui, QtCore, QtWebKit, QtNetwork
from threading import Thread
from sys import platform as _platform
settings = QtCore.QSettings("jabs.nu", "feedthemonkey")
class MainWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setWindowIcon(QtGui.QIcon("feedmonkey"))
self.addAction(QtGui.QAction("Full Screen", self, checkable=True, toggled=lambda v: self.showFullScreen() if v else self.showNormal(), shortcut="F11"))
self.history = self.get("history", [])
self.restoreGeometry(QtCore.QByteArray.fromRawData(settings.value("geometry").toByteArray()))
self.restoreState(QtCore.QByteArray.fromRawData(settings.value("state").toByteArray()))
self.initUI()
session_id = self.get("session_id")
server_url = self.get("server_url")
if not (session_id and server_url):
self.authenticate()
else:
self.initApp()
def initUI(self):
self.list = List(self)
self.content = Content(self)
self.splitter = QtGui.QSplitter(QtCore.Qt.Vertical, self)
self.splitter.setHandleWidth(1)
self.splitter.addWidget(self.list)
self.splitter.addWidget(self.content)
self.splitter.restoreState(settings.value("splitterSizes").toByteArray());
self.splitter.splitterMoved.connect(self.splitterMoved)
self.setCentralWidget(self.splitter)
def mkAction(name, connect, shortcut=None):
action = QtGui.QAction(name, self)
action.triggered.connect(connect)
if shortcut:
action.setShortcut(shortcut)
return action
mb = self.menuBar()
fileMenu = mb.addMenu("&File")
fileMenu.addAction(mkAction("&Close", self.close, "Ctrl+W"))
fileMenu.addAction(mkAction("&Log Out", self.logOut))
fileMenu.addSeparator()
fileMenu.addAction(mkAction("&Exit", self.close, "Ctrl+Q"))
actionMenu = mb.addMenu("&Action")
actionMenu.addAction(mkAction("&Reload", self.content.reload, "R"))
actionMenu.addAction(mkAction("Show &Starred", self.content.showStarred, "Ctrl+S"))
actionMenu.addAction(mkAction("Set &Starred", self.content.setStarred, "S"))
actionMenu.addAction(mkAction("Set &Unread", self.content.setUnread, "U"))
actionMenu.addAction(mkAction("&Next", self.content.showNext, "J"))
actionMenu.addAction(mkAction("&Previous", self.content.showPrevious, "K"))
actionMenu.addAction(mkAction("&Open in Browser", self.content.openCurrent, "N"))
viewMenu = mb.addMenu("&View")
viewMenu.addAction(mkAction("Zoom &In", lambda: self.content.wb.setZoomFactor(self.content.wb.zoomFactor() + 0.2), "Ctrl++"))
viewMenu.addAction(mkAction("Zoom &Out", lambda: self.content.wb.setZoomFactor(self.content.wb.zoomFactor() - 0.2), "Ctrl+-"))
viewMenu.addAction(mkAction("&Reset", lambda: self.content.wb.setZoomFactor(1), "Ctrl+0"))
windowMenu = mb.addMenu("&Window")
windowMenu.addAction(mkAction("Reset to Default", self.resetSplitter, "Ctrl+D"))
helpMenu = mb.addMenu("&Help")
helpMenu.addAction(mkAction("&About", lambda: QtGui.QDesktopServices.openUrl(QtCore.QUrl("http://jabs.nu/feedthemonkey", QtCore.QUrl.TolerantMode)) ))
def initApp(self):
session_id = self.get("session_id")
server_url = self.get("server_url")
self.tinyTinyRSS = TinyTinyRSS(self, server_url, session_id)
self.content.evaluateJavaScript("setArticle('loading')")
self.content.reload()
self.show()
def closeEvent(self, ev):
settings.setValue("geometry", self.saveGeometry())
settings.setValue("state", self.saveState())
return QtGui.QMainWindow.closeEvent(self, ev)
def put(self, key, value):
"Persist an object somewhere under a given key"
settings.setValue(key, json.dumps(value))
settings.sync()
def get(self, key, default=None):
"Get the object stored under 'key' in persistent storage, or the default value"
v = settings.value(key)
return json.loads(unicode(v.toString())) if v.isValid() else default
def setWindowTitle(self, t):
super(QtGui.QMainWindow, self).setWindowTitle("Feed the Monkey" + t)
def splitterMoved(self, pos, index):
settings.setValue("splitterSizes", self.splitter.saveState());
def resetSplitter(self):
sizes = self.splitter.sizes()
top = sizes[0]
bottom = sizes[1]
sizes[0] = 200
sizes[1] = bottom + top - 200
self.splitter.setSizes(sizes)
def authenticate(self):
dialog = Login()
def callback():
server_url = str(dialog.textServerUrl.text())
user = str(dialog.textName.text())
password = str(dialog.textPass.text())
session_id = TinyTinyRSS.login(server_url, user, password)
if session_id:
self.put("session_id", session_id)
self.put("server_url", server_url)
self.initApp()
else:
self.authenticate()
dialog.accepted.connect(callback)
dialog.exec_()
def logOut(self):
self.hide()
self.content.evaluateJavaScript("setArticle('logout')")
self.tinyTinyRSS.logOut()
self.tinyTinyRSS = None
self.put("session_id", None)
self.put("server_url", None)
self.authenticate()
class List(QtGui.QTableWidget):
def __init__(self, container):
QtGui.QTableWidget.__init__(self)
self.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
self.app = container
self.itemSelectionChanged.connect(self.rowSelected)
self.setShowGrid(False)
self.setAlternatingRowColors(True)
def initHeader(self):
self.clear()
self.setColumnCount(5)
self.setHorizontalHeaderLabels(("*", "Feed", "Title", "Date", "Author"))
self.horizontalHeader().setResizeMode(0, QtGui.QHeaderView.ResizeToContents)
self.horizontalHeader().setResizeMode(1, QtGui.QHeaderView.ResizeToContents)
self.horizontalHeader().setResizeMode(2, QtGui.QHeaderView.Stretch)
self.horizontalHeader().setResizeMode(3, QtGui.QHeaderView.ResizeToContents)
self.horizontalHeader().setResizeMode(4, QtGui.QHeaderView.ResizeToContents)
self.verticalHeader().hide()
def setItems(self, articles):
self.initHeader()
self.setRowCount(len(articles))
row = 0
for article in articles:
if "marked" in article:
starred = QtGui.QTableWidgetItem("*" if article["marked"] else "")
starred.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
self.setItem(row, 0, starred)
if "feed_title" in article:
feed_title = QtGui.QTableWidgetItem(article["feed_title"])
feed_title.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
self.setItem(row, 1, feed_title)
if "title" in article:
title = QtGui.QTableWidgetItem(article["title"])
title.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
self.setItem(row, 2, title)
if "updated" in article:
date = QtCore.QDateTime.fromTime_t(article["updated"]).toString(QtCore.Qt.SystemLocaleShortDate)
d = QtGui.QTableWidgetItem(date)
d.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
self.setItem(row, 3, d)
if "author" in article:
author = QtGui.QTableWidgetItem(article["author"])
author.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
self.setItem(row, 4, author)
self.resizeRowToContents(row)
row += 1
self.selectRow(0)
def rowSelected(self):
indexes = self.selectedIndexes()
if len(indexes) > 0:
row = indexes[0].row()
self.app.content.showIndex(row)
def updateRead(self):
for row, article in enumerate(self.app.content.unread_articles):
for x in xrange(0,5):
item = self.item(row, x)
font = item.font()
font.setBold(article["unread"])
item.setFont(font)
def setStarred(self, index, starred):
widget = self.itemAt(index, 0)
widget.setText("*" if starred else "")
class Content(QtGui.QWidget):
def __init__(self, container):
QtGui.QWidget.__init__(self)
self.app = container
self.index = 0
self.wb = QtWebKit.QWebView(titleChanged=lambda t: container.setWindowTitle(t))
self.wb.page().setLinkDelegationPolicy(QtWebKit.QWebPage.DelegateAllLinks)
self.wb.linkClicked.connect(lambda url: self.openLink(url))
self.setLayout(QtGui.QVBoxLayout(spacing=0))
self.layout().setContentsMargins(0, 0, 0, 0)
self.layout().addWidget(self.wb)
self.do_show_next = QtGui.QShortcut(QtCore.Qt.Key_Right, self, activated=self.showNext)
self.do_show_previous = QtGui.QShortcut(QtCore.Qt.Key_Left, self, activated=self.showPrevious)
self.do_open = QtGui.QShortcut("Return", self, activated=self.openCurrent)
self.wb.settings().setAttribute(QtWebKit.QWebSettings.PluginsEnabled, True)
self.wb.settings().setIconDatabasePath(tempfile.mkdtemp())
self.wb.setHtml(self.templateString())
self.unread_articles = []
def openLink(self, url):
QtGui.QDesktopServices.openUrl(url)
def reload(self):
w = WorkerThread(self.app, self._reload)
self.connect(w, QtCore.SIGNAL("reload_done()"), self.reload_done)
w.start()
def showStarred(self):
w = WorkerThread(self.app, self._showStarred)
self.connect(w, QtCore.SIGNAL("reload_done()"), self.reload_done)
w.start()
def setUnread(self):
article = self.unread_articles[self.index]
article["unread"] = True
article["set_unread"] = True
self.app.list.updateRead()
self.app.tinyTinyRSS.setArticleRead(article["id"], False)
def setStarred(self):
article = self.unread_articles[self.index]
article["marked"] = not article["marked"]
self.app.tinyTinyRSS.setArticleStarred(article["id"], article["marked"])
self.app.list.setStarred(self.index, article["marked"])
self.setArticle(article)
def _reload(self):
self.unread_articles = self.app.tinyTinyRSS.getUnreadFeeds()
self.index = -1
def _showStarred(self):
self.unread_articles = self.app.tinyTinyRSS.getStarredFeeds()
self.index = -1
def reload_done(self):
self.setUnreadCount()
self.app.list.setItems(self.unread_articles)
def showIndex(self, index):
if self.index > -1:
previous = self.unread_articles[self.index]
if not "set_unread" in previous or not previous["set_unread"]:
self.app.tinyTinyRSS.setArticleRead(previous["id"])
previous["unread"] = False
else:
previous["set_unread"] = False
self.app.list.updateRead()
self.index = index
current = self.unread_articles[self.index]
self.setArticle(current)
self.setUnreadCount()
def showNext(self):
if self.index + 1 < len(self.unread_articles):
self.app.list.selectRow(self.index + 1)
def showPrevious(self):
if self.index > 0:
self.app.list.selectRow(self.index - 1)
def openCurrent(self):
current = self.unread_articles[self.index]
url = QtCore.QUrl(current["link"])
self.openLink(url)
def setArticle(self, article):
func = u"setArticle({});".format(json.dumps(article))
self.evaluateJavaScript(func)
def evaluateJavaScript(self, func):
return self.wb.page().mainFrame().evaluateJavaScript(func)
def setUnreadCount(self):
length = len(self.unread_articles)
i = 0
if self.index > 0:
i = self.index
unread = length - i
self.app.setWindowTitle(" (" + str(unread) + "/" + str(length) + ")")
if unread < 1:
self.evaluateJavaScript("setArticle('empty')")
def templateString(self):
html="""
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ttrssl</title>
<script type="text/javascript">
function $(id) {
return document.getElementById(id);
}
function setArticle(article) {
window.scrollTo(0, 0);
$("date").innerHTML = "";
$("title").innerHTML = "";
$("title").href = "";
$("title").title = "";
$("feed_title").innerHTML = "";
$("author").innerHTML = "";
$("article").innerHTML = "";
if(article == "empty") {
$("article").innerHTML = "No unread articles to display.";
} else if(article == "loading") {
$("article").innerHTML = "Loading <blink>&hellip;</blink>";
} else if (article == "logout") {
} else if(article) {
$("date").innerHTML = (new Date(parseInt(article.updated, 10) * 1000));
$("title").innerHTML = article.title;
$("title").href = article.link;
$("title").title = article.link;
$("feed_title").innerHTML = article.feed_title;
$("title").className = article.marked ? "starred" : "";
$("author").innerHTML = "";
if(article.author && article.author.length > 0)
$("author").innerHTML = "&ndash; " + article.author
$("article").innerHTML = article.content;
}
}
</script>
<style type="text/css">
body {
font-family: "Ubuntu", "Lucida Grande", "Tahoma", sans-serif;
padding: 1em 2em 1em 2em;
}
body.darwin {
font-family: "LucidaGrande", sans-serif;
}
h1 {
font-weight: normal;
margin: 0;
padding: 0;
}
header {
margin-bottom: 1em;
border-bottom: 1px solid #aaa;
padding-bottom: 1em;
}
.starred:after {
content: "*";
}
header p {
color: #aaa;
margin: 0;
padding: 0
}
a {
color: #772953;
text-decoration: none;
}
img {
max-width: 100%;
height: auto;
}
article {
line-height: 1.6;
}
</style>
</head>
<body class='""" + _platform + """''>
<header>
<p><span id="feed_title"></span> <span id="author"></span></p>
<h1><a id="title" href=""></a></h1>
<p><timedate id="date"></timedate></p>
</header>
<article id="article"></article>
</body>
</html>"""
return html
class TinyTinyRSS:
def __init__(self, app, server_url, session_id):
self.app = app
if server_url and session_id:
self.server_url = server_url
self.session_id = session_id
else:
self.app.authenticate()
def doOperation(self, operation, options=None):
url = self.server_url + "/api/"
default_options = {'sid': self.session_id, 'op': operation}
if options:
options = dict(default_options.items() + options.items())
else:
options = default_options
json_string = json.dumps(options)
req = urllib2.Request(url)
fd = urllib2.urlopen(req, json_string)
body = ""
while True:
data = fd.read(1024)
if not len(data):
break
body += data
return json.loads(body)["content"]
def getUnreadFeeds(self, view_mode="unread"):
unread_articles = []
def more(skip):
return self.doOperation("getHeadlines", {"show_excerpt": False, "view_mode": view_mode, "show_content": True, "feed_id": -4, "skip": skip})
skip = 0
while True:
new = more( skip)
unread_articles += new
length = len(new)
if length < 1:
break
skip += length
return unread_articles
def getStarredFeeds(self):
return self.getUnreadFeeds("marked")
def setArticleRead(self, article_id, read=True):
self.updateArticle(article_id, 2, not read)
def setArticleStarred(self, article_id, starred=True):
self.updateArticle(article_id, 0, starred)
def updateArticle(self, article_id, field, true=True):
l = lambda: self.doOperation("updateArticle", {'article_ids':article_id, 'mode': 1 if true else 0, 'field': field})
t = Thread(target=l)
t.start()
def logOut(self):
self.doOperation("logout")
@classmethod
def login(self, server_url, user, password):
url = server_url + "/api/"
options = {"op": "login", "user": user, "password": password}
json_string = json.dumps(options)
req = urllib2.Request(url)
fd = urllib2.urlopen(req, json_string)
body = ""
while 1:
data = fd.read(1024)
if not len(data):
break
body += data
body = json.loads(body)["content"]
if body.has_key("error"):
msgBox = QtGui.QMessageBox()
msgBox.setText(body["error"])
msgBox.exec_()
return None
return body["session_id"]
class Login(QtGui.QDialog):
def __init__(self):
QtGui.QDialog.__init__(self)
self.setWindowIcon(QtGui.QIcon("feedmonkey.png"))
self.setWindowTitle("Feed the Monkey - Login")
self.label = QtGui.QLabel(self)
self.label.setText("Please specify a server url, a username and a password.")
self.textServerUrl = QtGui.QLineEdit(self)
self.textServerUrl.setPlaceholderText("http://example.com/ttrss/")
self.textServerUrl.setText("http://")
self.textName = QtGui.QLineEdit(self)
self.textName.setPlaceholderText("username")
self.textPass = QtGui.QLineEdit(self)
self.textPass.setEchoMode(QtGui.QLineEdit.Password);
self.textPass.setPlaceholderText("password")
self.buttons = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok)
self.buttons.accepted.connect(self.accept)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.label)
layout.addWidget(self.textServerUrl)
layout.addWidget(self.textName)
layout.addWidget(self.textPass)
layout.addWidget(self.buttons)
class WorkerThread(QtCore.QThread):
def __init__(self, parent, do_reload):
super(WorkerThread, self).__init__(parent)
self.do_reload = do_reload
def run(self):
self.do_reload()
self.emit(QtCore.SIGNAL("reload_done()"))
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
wb = MainWindow()
wb.show()
sys.exit(app.exec_())

View file

@ -1,12 +0,0 @@
[Desktop Entry]
Version=0.1.0
Comment=A desktop client for the TinyTinyRSS feed reader.
Exec=feedthemonkey
GenericName=Feed Reader
Icon=feedthemonkey
Name=Feed the Monkey
NoDisplay=false
StartupNotify=true
Terminal=false
Type=Application
Categories=Network;Qt

File diff suppressed because it is too large Load diff

View file

@ -1,74 +0,0 @@
#!/usr/bin/env python2
import os, PyQt4
from setuptools import setup
from sys import platform as _platform
VERSION = "0.1.2"
files = []
options = {}
setup_requires = []
is_osx = _platform == "darwin"
is_win = os.name == "nt"
is_linux = not is_osx and not is_win
if is_linux:
setup(
name = "FeedTheMonkey",
version = VERSION,
author = "Jeena Paradies",
author_email = "spam@jeenaparadies.net",
url = "http://jabs.nu/feedthemonkey",
license = "BSD license",
scripts = ["feedthemonkey"],
data_files=[
('/usr/share/applications', ["feedthemonkey.desktop"]),
('/usr/share/pixmaps', ["feedthemonkey.xpm"])
]
)
if is_osx:
options = {
'py2app': {
'argv_emulation': False,
'iconfile': 'Icon.icns',
'plist': {
'CFBundleShortVersionString': VERSION,
'CFBundleIdentifier': "nu.jabs.apps.feedthemonkey",
'LSMinimumSystemVersion': "10.4",
'CFBundleURLTypes': [
{
'CFBundleURLName': 'nu.jabs.apps.feedthemonkey.handler',
'CFBundleURLSchemes': ['feedthemonkey']
}
]
},
'includes':['PyQt4.QtWebKit', 'PyQt4', 'PyQt4.QtCore', 'PyQt4.QtGui', 'PyQt4.QtNetwork'],
'excludes': ['PyQt4.QtDesigner', 'PyQt4.QtOpenGL', 'PyQt4.QtScript', 'PyQt4.QtSql', 'PyQt4.QtTest', 'PyQt4.QtXml', 'PyQt4.phonon', 'simplejson'],
'qt_plugins': 'imageformats',
}
}
setup_requires = ["py2app"]
APP = ["feedthemonkey"]
for dirname, dirnames, filenames in os.walk('.'):
for filename in filenames:
if filename == "Icon.icns":
files += [(dirname, [os.path.join(dirname, filename)])]
setup(
app = APP,
name = "FeedTheMonkey",
options = options,
version = VERSION,
author = "Jeena Paradies",
author_email = "spam@jeenaparadies.net",
url = "http://jabs.nu/feedthemonkey",
license = "BSD license",
scripts = ["feedthemonkey"],
data_files = files,
setup_requires = setup_requires
)