From: Yves Date: Sun, 25 Apr 2010 01:20:12 +0000 (-0700) Subject: 0.6.1-1 Added dbus locking mechanism, and widget changes X-Git-Url: https://vcs.maemo.org/git/?a=commitdiff_plain;h=ee8dff327a6f2be43458d9b1d6b0a9a3c51f7947;p=feedingit 0.6.1-1 Added dbus locking mechanism, and widget changes --- diff --git a/Makefile b/Makefile index 7bf2d8c..0c4a421 100644 --- a/Makefile +++ b/Makefile @@ -14,25 +14,29 @@ install: install src/rss.py ${DESTDIR}/opt/FeedingIt install src/opml.py ${DESTDIR}/opt/FeedingIt install src/config.py ${DESTDIR}/opt/FeedingIt + #install src/feedingit_status.desktop ${DESTDIR}/opt/FeedingIt + install src/update_feeds.py ${DESTDIR}/opt/FeedingIt + install src/updatedbus.py ${DESTDIR}/opt/FeedingIt install src/BeautifulSoup.py ${DESTDIR}/opt/FeedingIt install src/feedingitdbus.py ${DESTDIR}/opt/FeedingIt install -d ${DESTDIR}/usr/share/applications/hildon install src/FeedingIt.desktop ${DESTDIR}/usr/share/applications/hildon - install -d ${DESTDIR}/usr/share/icons/hicolor/40x40/apps/ - install data/40px.png ${DESTDIR}/usr/share/icons/hicolor/40x40/apps/feedingit.png + install -d ${DESTDIR}/usr/share/icons/hicolor/48x48/apps/ + install data/48px.png ${DESTDIR}/usr/share/icons/hicolor/48x48/apps/feedingit.png install -d ${DESTDIR}/usr/share/icons/hicolor/26x26/apps/ install data/26px.png ${DESTDIR}/usr/share/icons/hicolor/26x26/apps/feedingit.png install -d ${DESTDIR}/usr/share/icons/hicolor/64x64/apps/ install data/64px.png ${DESTDIR}/usr/share/icons/hicolor/64x64/apps/feedingit.png install -d ${DESTDIR}/usr/share/dbus-1/services/ install src/feedingit.service ${DESTDIR}/usr/share/dbus-1/services/ + install src/feedingit_status.service ${DESTDIR}/usr/share/dbus-1/services/ install -d ${DESTDIR}/etc/osso-backup/applications/ install src/feedingit.conf ${DESTDIR}/etc/osso-backup/applications/ install -d ${DESTDIR}/usr/share/applications/hildon-home/ install src/feedingit_widget.desktop ${DESTDIR}/usr/share/applications/hildon-home/ install -d ${DESTDIR}/usr/lib/hildon-desktop/ install src/feedingit_widget.py ${DESTDIR}/usr/lib/hildon-desktop/ - + #install src/feedingit_status.py ${DESTDIR}/usr/lib/hildon-desktop/ clean: diff --git a/data/40px.png b/data/40px.png deleted file mode 100644 index 41be97a..0000000 Binary files a/data/40px.png and /dev/null differ diff --git a/data/48px.png b/data/48px.png new file mode 100644 index 0000000..07fbf83 Binary files /dev/null and b/data/48px.png differ diff --git a/debian/changelog b/debian/changelog index f5190b9..2f31e00 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,23 @@ +feedingit (0.6.1-1) unstable; urgency=low + + * Now use dbus as lock mechanisms + * Added setting to disable proxy support + + -- Yves Sat, 24 Apr 2010 16:57:19 -0800 + +feedingit (0.6.1-0) unstable; urgency=low + + * Added autoupdate from the widget + + -- Yves Sat, 17 Apr 2010 20:19:19 -0800 + +feedingit (0.6.0-1) stable; urgency=low + + * Added dbus communication from app to widget + * Fixed updates for articles without titles + + -- Yves Mon, 12 Apr 2010 09:50:19 -0800 + feedingit (0.6.0-0) stable; urgency=low * Added home widget diff --git a/debian/control b/debian/control index 3963b89..8a5a972 100644 --- a/debian/control +++ b/debian/control @@ -4,7 +4,7 @@ Priority: optional Maintainer: Yves Build-Depends: debhelper (>= 5) Standards-Version: 3.7.2 -XB-Maemo-Display-Name: FeedingIt +XB-Maemo-Display-Name: FeedingIt RSS Reader XSBC-Bugtracker: https://garage.maemo.org/tracker/?func=browse&group_id=1202&atid=4512 Package: feedingit @@ -14,11 +14,9 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, python, python-hildon, python-hildondesktop, hildon-desktop-python-loader Description: RSS Reader - Its main features are: - - Portrait mode support - - Auto-update - - Swipe left or right while in articles to move to the previous or next article - - Import/Export of OPML files + Its main features are portrait mode support, auto-update, swipe left or right while + in articles to move to the previous or next article, import/export of OPML files, + image caching, desktop widget XB-Maemo-Icon-26: iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAAAXNSR0IArs4c 6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAABl1J diff --git a/debian/cron.d.ex b/debian/cron.d.ex deleted file mode 100644 index cc0277d..0000000 --- a/debian/cron.d.ex +++ /dev/null @@ -1,4 +0,0 @@ -# -# Regular cron jobs for the feedingit package -# -0 4 * * * root feedingit_maintenance diff --git a/debian/emacsen-install.ex b/debian/emacsen-install.ex deleted file mode 100644 index a6adfc1..0000000 --- a/debian/emacsen-install.ex +++ /dev/null @@ -1,45 +0,0 @@ -#! /bin/sh -e -# /usr/lib/emacsen-common/packages/install/feedingit - -# Written by Jim Van Zandt , borrowing heavily -# from the install scripts for gettext by Santiago Vila -# and octave by Dirk Eddelbuettel . - -FLAVOR=$1 -PACKAGE=feedingit - -if [ ${FLAVOR} = emacs ]; then exit 0; fi - -echo install/${PACKAGE}: Handling install for emacsen flavor ${FLAVOR} - -#FLAVORTEST=`echo $FLAVOR | cut -c-6` -#if [ ${FLAVORTEST} = xemacs ] ; then -# SITEFLAG="-no-site-file" -#else -# SITEFLAG="--no-site-file" -#fi -FLAGS="${SITEFLAG} -q -batch -l path.el -f batch-byte-compile" - -ELDIR=/usr/share/emacs/site-lisp/${PACKAGE} -ELCDIR=/usr/share/${FLAVOR}/site-lisp/${PACKAGE} - -# Install-info-altdir does not actually exist. -# Maybe somebody will write it. -if test -x /usr/sbin/install-info-altdir; then - echo install/${PACKAGE}: install Info links for ${FLAVOR} - install-info-altdir --quiet --section "" "" --dirname=${FLAVOR} /usr/info/${PACKAGE}.info.gz -fi - -install -m 755 -d ${ELCDIR} -cd ${ELDIR} -FILES=`echo *.el` -cp ${FILES} ${ELCDIR} -cd ${ELCDIR} - -cat << EOF > path.el -(setq load-path (cons "." load-path) byte-compile-warnings nil) -EOF -${FLAVOR} ${FLAGS} ${FILES} -rm -f *.el path.el - -exit 0 diff --git a/debian/emacsen-remove.ex b/debian/emacsen-remove.ex deleted file mode 100644 index 9d784c7..0000000 --- a/debian/emacsen-remove.ex +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh -e -# /usr/lib/emacsen-common/packages/remove/feedingit - -FLAVOR=$1 -PACKAGE=feedingit - -if [ ${FLAVOR} != emacs ]; then - if test -x /usr/sbin/install-info-altdir; then - echo remove/${PACKAGE}: removing Info links for ${FLAVOR} - install-info-altdir --quiet --remove --dirname=${FLAVOR} /usr/info/feedingit.info.gz - fi - - echo remove/${PACKAGE}: purging byte-compiled files for ${FLAVOR} - rm -rf /usr/share/${FLAVOR}/site-lisp/${PACKAGE} -fi diff --git a/debian/emacsen-startup.ex b/debian/emacsen-startup.ex deleted file mode 100644 index 4c5a503..0000000 --- a/debian/emacsen-startup.ex +++ /dev/null @@ -1,25 +0,0 @@ -;; -*-emacs-lisp-*- -;; -;; Emacs startup file, e.g. /etc/emacs/site-start.d/50feedingit.el -;; for the Debian feedingit package -;; -;; Originally contributed by Nils Naumann -;; Modified by Dirk Eddelbuettel -;; Adapted for dh-make by Jim Van Zandt - -;; The feedingit package follows the Debian/GNU Linux 'emacsen' policy and -;; byte-compiles its elisp files for each 'emacs flavor' (emacs19, -;; xemacs19, emacs20, xemacs20...). The compiled code is then -;; installed in a subdirectory of the respective site-lisp directory. -;; We have to add this to the load-path: -(let ((package-dir (concat "/usr/share/" - (symbol-name flavor) - "/site-lisp/feedingit"))) -;; If package-dir does not exist, the feedingit package must have -;; removed but not purged, and we should skip the setup. - (when (file-directory-p package-dir) - (setq load-path (cons package-dir load-path)) - (autoload 'feedingit-mode "feedingit-mode" - "Major mode for editing feedingit files." t) - (add-to-list 'auto-mode-alist '("\\.feedingit$" . feedingit-mode)))) - diff --git a/debian/feedingit-default.ex b/debian/feedingit-default.ex deleted file mode 100644 index 7b4e24d..0000000 --- a/debian/feedingit-default.ex +++ /dev/null @@ -1,10 +0,0 @@ -# Defaults for feedingit initscript -# sourced by /etc/init.d/feedingit -# installed at /etc/default/feedingit by the maintainer scripts - -# -# This is a POSIX shell fragment -# - -# Additional options that are passed to the Daemon. -DAEMON_OPTS="" diff --git a/debian/feedingit.doc-base.EX b/debian/feedingit.doc-base.EX deleted file mode 100644 index 29ef39a..0000000 --- a/debian/feedingit.doc-base.EX +++ /dev/null @@ -1,22 +0,0 @@ -Document: feedingit -Title: Debian feedingit Manual -Author: -Abstract: This manual describes what feedingit is - and how it can be used to - manage online manuals on Debian systems. -Section: unknown - -Format: debiandoc-sgml -Files: /usr/share/doc/feedingit/feedingit.sgml.gz - -Format: postscript -Files: /usr/share/doc/feedingit/feedingit.ps.gz - -Format: text -Files: /usr/share/doc/feedingit/feedingit.text.gz - -Format: HTML -Index: /usr/share/doc/feedingit/html/index.html -Files: /usr/share/doc/feedingit/html/*.html - - diff --git a/debian/init.d.ex b/debian/init.d.ex deleted file mode 100644 index 63004c7..0000000 --- a/debian/init.d.ex +++ /dev/null @@ -1,81 +0,0 @@ -#! /bin/sh -# -# skeleton example file to build /etc/init.d/ scripts. -# This file should be used to construct scripts for /etc/init.d. -# -# Written by Miquel van Smoorenburg . -# Modified for Debian -# by Ian Murdock . -# -# Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl -# - -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin -DAEMON=/usr/sbin/feedingit -NAME=feedingit -DESC=feedingit - -test -x $DAEMON || exit 0 - -# Include feedingit defaults if available -if [ -f /etc/default/feedingit ] ; then - . /etc/default/feedingit -fi - -set -e - -case "$1" in - start) - echo -n "Starting $DESC: " - start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \ - --exec $DAEMON -- $DAEMON_OPTS - echo "$NAME." - ;; - stop) - echo -n "Stopping $DESC: " - start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \ - --exec $DAEMON - echo "$NAME." - ;; - #reload) - # - # If the daemon can reload its config files on the fly - # for example by sending it SIGHUP, do it here. - # - # If the daemon responds to changes in its config file - # directly anyway, make this a do-nothing entry. - # - # echo "Reloading $DESC configuration files." - # start-stop-daemon --stop --signal 1 --quiet --pidfile \ - # /var/run/$NAME.pid --exec $DAEMON - #;; - force-reload) - # - # If the "reload" option is implemented, move the "force-reload" - # option to the "reload" entry above. If not, "force-reload" is - # just the same as "restart" except that it does nothing if the - # daemon isn't already running. - # check wether $DAEMON is running. If so, restart - start-stop-daemon --stop --test --quiet --pidfile \ - /var/run/$NAME.pid --exec $DAEMON \ - && $0 restart \ - || exit 0 - ;; - restart) - echo -n "Restarting $DESC: " - start-stop-daemon --stop --quiet --pidfile \ - /var/run/$NAME.pid --exec $DAEMON - sleep 1 - start-stop-daemon --start --quiet --pidfile \ - /var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS - echo "$NAME." - ;; - *) - N=/etc/init.d/$NAME - # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 - echo "Usage: $N {start|stop|restart|force-reload}" >&2 - exit 1 - ;; -esac - -exit 0 diff --git a/debian/manpage.1.ex b/debian/manpage.1.ex deleted file mode 100644 index 837f0e0..0000000 --- a/debian/manpage.1.ex +++ /dev/null @@ -1,59 +0,0 @@ -.\" Hey, EMACS: -*- nroff -*- -.\" First parameter, NAME, should be all caps -.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection -.\" other parameters are allowed: see man(7), man(1) -.TH FEEDINGIT SECTION "December 28, 2009" -.\" Please adjust this date whenever revising the manpage. -.\" -.\" Some roff macros, for reference: -.\" .nh disable hyphenation -.\" .hy enable hyphenation -.\" .ad l left justify -.\" .ad b justify to both left and right margins -.\" .nf disable filling -.\" .fi enable filling -.\" .br insert line break -.\" .sp insert n+1 empty lines -.\" for manpage-specific macros, see man(7) -.SH NAME -feedingit \- program to do something -.SH SYNOPSIS -.B feedingit -.RI [ options ] " files" ... -.br -.B bar -.RI [ options ] " files" ... -.SH DESCRIPTION -This manual page documents briefly the -.B feedingit -and -.B bar -commands. -.PP -.\" TeX users may be more comfortable with the \fB\fP and -.\" \fI\fP escape sequences to invode bold face and italics, -.\" respectively. -\fBfeedingit\fP is a program that... -.SH OPTIONS -These programs follow the usual GNU command line syntax, with long -options starting with two dashes (`-'). -A summary of options is included below. -For a complete description, see the Info files. -.TP -.B \-h, \-\-help -Show summary of options. -.TP -.B \-v, \-\-version -Show version of program. -.SH SEE ALSO -.BR bar (1), -.BR baz (1). -.br -The programs are documented fully by -.IR "The Rise and Fall of a Fooish Bar" , -available via the Info system. -.SH AUTHOR -feedingit was written by . -.PP -This manual page was written by unknown , -for the Debian project (but may be used by others). diff --git a/debian/manpage.sgml.ex b/debian/manpage.sgml.ex deleted file mode 100644 index d1a98d1..0000000 --- a/debian/manpage.sgml.ex +++ /dev/null @@ -1,156 +0,0 @@ - manpage.1'. You may view - the manual page with: `docbook-to-man manpage.sgml | nroff -man | - less'. A typical entry in a Makefile or Makefile.am is: - -manpage.1: manpage.sgml - docbook-to-man $< > $@ - - - The docbook-to-man binary is found in the docbook-to-man package. - Please remember that if you create the nroff version in one of the - debian/rules file targets (such as build), you will need to include - docbook-to-man in your Build-Depends control field. - - --> - - - FIRSTNAME"> - SURNAME"> - - December 28, 2009"> - - SECTION"> - yves@marcoz.org"> - - FEEDINGIT"> - - - Debian"> - GNU"> - GPL"> -]> - - - -
- &dhemail; -
- - &dhfirstname; - &dhsurname; - - - 2003 - &dhusername; - - &dhdate; -
- - &dhucpackage; - - &dhsection; - - - &dhpackage; - - program to do something - - - - &dhpackage; - - - - - - - - DESCRIPTION - - This manual page documents briefly the - &dhpackage; and bar - commands. - - This manual page was written for the &debian; distribution - because the original program does not have a manual page. - Instead, it has documentation in the &gnu; - Info format; see below. - - &dhpackage; is a program that... - - - - OPTIONS - - These programs follow the usual &gnu; command line syntax, - with long options starting with two dashes (`-'). A summary of - options is included below. For a complete description, see the - Info files. - - - - - - - - Show summary of options. - - - - - - - - Show version of program. - - - - - - SEE ALSO - - bar (1), baz (1). - - The programs are documented fully by The Rise and - Fall of a Fooish Bar available via the - Info system. - - - AUTHOR - - This manual page was written by &dhusername; &dhemail; for - the &debian; system (but may be used by others). Permission is - granted to copy, distribute and/or modify this document under - the terms of the &gnu; General Public License, Version 2 any - later version published by the Free Software Foundation. - - - On Debian systems, the complete text of the GNU General Public - License can be found in /usr/share/common-licenses/GPL. - - - -
- - - - diff --git a/debian/manpage.xml.ex b/debian/manpage.xml.ex deleted file mode 100644 index a6011aa..0000000 --- a/debian/manpage.xml.ex +++ /dev/null @@ -1,148 +0,0 @@ - -.
will be generated. You may view the -manual page with: nroff -man .
| less'. A -typical entry in a Makefile or Makefile.am is: - -DB2MAN=/usr/share/sgml/docbook/stylesheet/xsl/nwalsh/\ -manpages/docbook.xsl -XP=xsltproc -''-nonet - -manpage.1: manpage.dbk - $(XP) $(DB2MAN) $< - -The xsltproc binary is found in the xsltproc package. The -XSL files are in docbook-xsl. Please remember that if you -create the nroff version in one of the debian/rules file -targets (such as build), you will need to include xsltproc -and docbook-xsl in your Build-Depends control field. - ---> - - - FIRSTNAME"> - SURNAME"> - - December 28, 2009"> - - SECTION"> - yves@marcoz.org"> - - FEEDINGIT"> - - - Debian"> - GNU"> - GPL"> -]> - - - -
- &dhemail; -
- - &dhfirstname; - &dhsurname; - - - 2003 - &dhusername; - - &dhdate; -
- - &dhucpackage; - - &dhsection; - - - &dhpackage; - - program to do something - - - - &dhpackage; - - - - - - - - DESCRIPTION - - This manual page documents briefly the - &dhpackage; and bar - commands. - - This manual page was written for the &debian; distribution - because the original program does not have a manual page. - Instead, it has documentation in the &gnu; - Info format; see below. - - &dhpackage; is a program that... - - - - OPTIONS - - These programs follow the usual &gnu; command line syntax, - with long options starting with two dashes (`-'). A summary of - options is included below. For a complete description, see the - Info files. - - - - - - - - Show summary of options. - - - - - - - - Show version of program. - - - - - - SEE ALSO - - bar (1), baz (1). - - The programs are documented fully by The Rise and - Fall of a Fooish Bar available via the - Info system. - - - AUTHOR - - This manual page was written by &dhusername; &dhemail; for - the &debian; system (but may be used by others). Permission is - granted to copy, distribute and/or modify this document under - the terms of the &gnu; General Public License, Version 2 any - later version published by the Free Software Foundation. - - - On Debian systems, the complete text of the GNU General Public - License can be found in /usr/share/common-licenses/GPL. - - - -
- diff --git a/debian/menu.ex b/debian/menu.ex deleted file mode 100644 index b440db3..0000000 --- a/debian/menu.ex +++ /dev/null @@ -1,2 +0,0 @@ -?package(feedingit):needs="X11|text|vc|wm" section="Apps/see-menu-manual"\ - title="feedingit" command="/usr/bin/feedingit" diff --git a/debian/postinst.ex b/debian/postinst.ex deleted file mode 100644 index ff994dd..0000000 --- a/debian/postinst.ex +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh -# postinst script for feedingit -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `configure' -# * `abort-upgrade' -# * `abort-remove' `in-favour' -# -# * `abort-remove' -# * `abort-deconfigure' `in-favour' -# `removing' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -case "$1" in - configure) - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 - - diff --git a/debian/postrm.ex b/debian/postrm.ex deleted file mode 100644 index b962cae..0000000 --- a/debian/postrm.ex +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/sh -# postrm script for feedingit -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `remove' -# * `purge' -# * `upgrade' -# * `failed-upgrade' -# * `abort-install' -# * `abort-install' -# * `abort-upgrade' -# * `disappear' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -case "$1" in - purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) - ;; - - *) - echo "postrm called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 - - diff --git a/debian/preinst.ex b/debian/preinst.ex deleted file mode 100644 index a5b99ca..0000000 --- a/debian/preinst.ex +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh -# preinst script for feedingit -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `install' -# * `install' -# * `upgrade' -# * `abort-upgrade' -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -case "$1" in - install|upgrade) - ;; - - abort-upgrade) - ;; - - *) - echo "preinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 - - diff --git a/debian/prerm.ex b/debian/prerm.ex deleted file mode 100644 index 967a168..0000000 --- a/debian/prerm.ex +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/sh -# prerm script for feedingit -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `remove' -# * `upgrade' -# * `failed-upgrade' -# * `remove' `in-favour' -# * `deconfigure' `in-favour' -# `removing' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -case "$1" in - remove|upgrade|deconfigure) - ;; - - failed-upgrade) - ;; - - *) - echo "prerm called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 - - diff --git a/src/FeedingIt b/src/FeedingIt index a0160e4..b3be2d1 100644 --- a/src/FeedingIt +++ b/src/FeedingIt @@ -1,11 +1,16 @@ #!/bin/sh case "$1" in update) - dbus-send --print-reply --dest='org.maemo.feedingit' --session /org/maemo/feedingit org.maemo.feedingit.Update + dbus-send --print-reply --dest='org.marcoz.feedingit' --session /org/marcoz/feedingit/update org.marcoz.feedingit.UpdateAll ;; status) dbus-send --print-reply --dest='org.maemo.feedingit' --session /org/maemo/feedingit org.maemo.feedingit.GetStatus ;; +dbus) + cd /opt/FeedingIt + #cp feedingit_status.desktop /usr/share/applications/hildon-status-menu/ + python2.5 update_feeds.py + ;; *) cd /opt/FeedingIt python2.5 FeedingIt.py diff --git a/src/FeedingIt.desktop b/src/FeedingIt.desktop index fa98319..eac727b 100644 --- a/src/FeedingIt.desktop +++ b/src/FeedingIt.desktop @@ -1,6 +1,6 @@ [Desktop Entry] Encoding=UTF-8 -Version=0.1.1 +Version=0.6.1 Type=Application Name=FeedingIt Exec=/usr/bin/FeedingIt diff --git a/src/FeedingIt.py b/src/FeedingIt.py index ce0369c..27f978a 100644 --- a/src/FeedingIt.py +++ b/src/FeedingIt.py @@ -19,42 +19,37 @@ # ============================================================================ # Name : FeedingIt.py # Author : Yves Marcoz -# Version : 0.5.4 +# Version : 0.6.0 # Description : Simple RSS Reader # ============================================================================ import gtk -import feedparser -import pango +from pango import FontDescription import hildon #import gtkhtml2 #try: -import webkit +from webkit import WebView # has_webkit=True #except: # import gtkhtml2 # has_webkit=False -import time -import dbus -import pickle -from os.path import isfile, isdir -from os import mkdir -import sys -import urllib2 +from os.path import isfile, isdir, exists +from os import mkdir, remove, stat import gobject from portrait import FremantleRotation -import threading -import thread +from threading import Thread, activeCount from feedingitdbus import ServerObject +from updatedbus import UpdateServerObject, get_lock from config import Config from cgi import escape -from rss import * +from rss import Listing from opml import GetOpmlData, ExportOpmlData - -import socket + +from socket import setdefaulttimeout timeout = 5 -socket.setdefaulttimeout(timeout) +setdefaulttimeout(timeout) +del timeout color_style = gtk.rc_get_style_by_paths(gtk.settings_get_default() , 'GtkButton', 'osso-logical-colors', gtk.Button) unread_color = color_style.lookup_color('ActiveTextColor') @@ -62,6 +57,38 @@ read_color = color_style.lookup_color('DefaultTextColor') del color_style CONFIGDIR="/home/user/.feedingit/" +LOCK = CONFIGDIR + "update.lock" + +from re import sub +from htmlentitydefs import name2codepoint + +## +# Removes HTML or XML character references and entities from a text string. +# +# @param text The HTML (or XML) source text. +# @return The plain text, as a Unicode string, if necessary. +# http://effbot.org/zone/re-sub.htm#unescape-html +def unescape(text): + def fixup(m): + text = m.group(0) + if text[:2] == "&#": + # character reference + try: + if text[:3] == "&#x": + return unichr(int(text[3:-1], 16)) + else: + return unichr(int(text[2:-1])) + except ValueError: + pass + else: + # named entity + try: + text = unichr(name2codepoint[text[1:-1]]) + except KeyError: + pass + return text # leave as is + return sub("&#?\w+;", fixup, text) + class AddWidgetWizard(hildon.WizardDialog): @@ -121,92 +148,52 @@ class AddWidgetWizard(hildon.WizardDialog): return False else: return True - -#class GetImage(threading.Thread): -# def __init__(self, url, stream): -# threading.Thread.__init__(self) -# self.url = url -# self.stream = stream -# -# def run(self): -# f = urllib2.urlopen(self.url) -# data = f.read() -# f.close() -# self.stream.write(data) -# self.stream.close() -# -#class ImageDownloader(): -# def __init__(self): -# self.images = [] -# self.downloading = False -# -# def queueImage(self, url, stream): -# self.images.append((url, stream)) -# if not self.downloading: -# self.downloading = True -# gobject.timeout_add(50, self.checkQueue) -# -# def checkQueue(self): -# for i in range(4-threading.activeCount()): -# if len(self.images) > 0: -# (url, stream) = self.images.pop() -# GetImage(url, stream).start() -# if len(self.images)>0: -# gobject.timeout_add(200, self.checkQueue) -# else: -# self.downloading=False -# -# def stopAll(self): -# self.images = [] - - -class Download(threading.Thread): + +class Download(Thread): def __init__(self, listing, key, config): - threading.Thread.__init__(self) + Thread.__init__(self) self.listing = listing self.key = key self.config = config def run (self): (use_proxy, proxy) = self.config.getProxy() - if use_proxy: - self.listing.updateFeed(self.key, self.config.getExpiry(), proxy=proxy, imageCache=self.config.getImageCache() ) - else: - self.listing.updateFeed(self.key, self.config.getExpiry(), imageCache=self.config.getImageCache() ) + key_lock = get_lock(self.key) + if key_lock != None: + if use_proxy: + from urllib2 import install_opener, build_opener + install_opener(build_opener(proxy)) + self.listing.updateFeed(self.key, self.config.getExpiry(), proxy=proxy, imageCache=self.config.getImageCache() ) + else: + self.listing.updateFeed(self.key, self.config.getExpiry(), imageCache=self.config.getImageCache() ) + del key_lock class DownloadBar(gtk.ProgressBar): def __init__(self, parent, listing, listOfKeys, config, single=False): - gtk.ProgressBar.__init__(self) - self.listOfKeys = listOfKeys[:] - self.listing = listing - self.total = len(self.listOfKeys) - self.config = config - self.current = 0 - self.single = single - - if self.total>0: - #self.progress = gtk.ProgressBar() - #self.waitingWindow = hildon.Note("cancel", parent, "Downloading", - # progressbar=self.progress) - self.set_text("Updating...") - self.fraction = 0 - self.set_fraction(self.fraction) - self.show_all() - # Create a timeout - self.timeout_handler_id = gobject.timeout_add(50, self.update_progress_bar) - #self.waitingWindow.show_all() - #response = self.waitingWindow.run() - #self.listOfKeys = [] - #while threading.activeCount() > 1: - # Wait for current downloads to finish - # time.sleep(0.1) - #self.waitingWindow.destroy() + + update_lock = get_lock("update_lock") + if update_lock != None: + gtk.ProgressBar.__init__(self) + self.listOfKeys = listOfKeys[:] + self.listing = listing + self.total = len(self.listOfKeys) + self.config = config + self.current = 0 + self.single = single + + if self.total>0: + self.set_text("Updating...") + self.fraction = 0 + self.set_fraction(self.fraction) + self.show_all() + # Create a timeout + self.timeout_handler_id = gobject.timeout_add(50, self.update_progress_bar) def update_progress_bar(self): #self.progress_bar.pulse() - if threading.activeCount() < 4: - x = threading.activeCount() - 1 + if activeCount() < 4: + x = activeCount() - 1 k = len(self.listOfKeys) fin = self.total - k - x fraction = float(fin)/float(self.total) + float(x)/(self.total*2.) @@ -216,16 +203,20 @@ class DownloadBar(gtk.ProgressBar): if len(self.listOfKeys)>0: self.current = self.current+1 key = self.listOfKeys.pop() - if (not self.listing.getCurrentlyDisplayedFeed() == key) or (self.single == True): + #if self.single == True: # Check if the feed is being displayed - download = Download(self.listing, key, self.config) - download.start() + download = Download(self.listing, key, self.config) + download.start() return True - elif threading.activeCount() > 1: + elif activeCount() > 1: return True else: #self.waitingWindow.destroy() #self.destroy() + try: + del self.update_lock + except: + pass self.emit("download-done", "success") return False return True @@ -385,7 +376,7 @@ class DisplayArticle(hildon.StackableWindow): # Init the article display #if self.config.getWebkitSupport(): - self.view = webkit.WebView() + self.view = WebView() #self.view.set_editable(False) #else: # import gtkhtml2 @@ -510,6 +501,7 @@ class DisplayArticle(hildon.StackableWindow): # self.show_all() def _signal_link_clicked(self, object, link): + import dbus bus = dbus.SessionBus() proxy = bus.get_object("com.nokia.osso_browser", "/com/nokia/osso_browser/request") iface = dbus.Interface(proxy, 'com.nokia.osso_browser') @@ -572,17 +564,18 @@ class DisplayFeed(hildon.StackableWindow): self.buttons = {} for id in self.feed.getIds(): title = self.feed.getTitle(id) - esc_title = title.replace("","").replace("","").replace("&","&").replace("—", "-").replace("’", "'") + esc_title = unescape(title) + #title.replace("","").replace("","").replace("&","&").replace("—", "-").replace("’", "'") button = gtk.Button(esc_title) button.set_alignment(0,0) label = button.child if self.feed.isEntryRead(id): - #label.modify_font(pango.FontDescription("sans 16")) - label.modify_font(pango.FontDescription(self.config.getReadFont())) + #label.modify_font(FontDescription("sans 16")) + label.modify_font(FontDescription(self.config.getReadFont())) label.modify_fg(gtk.STATE_NORMAL, read_color) # gtk.gdk.color_parse("white")) else: #print self.listing.getFont() + " bold" - label.modify_font(pango.FontDescription(self.config.getUnreadFont())) + label.modify_font(FontDescription(self.config.getUnreadFont())) label.modify_fg(gtk.STATE_NORMAL, unread_color) label.set_line_wrap(True) @@ -629,21 +622,21 @@ class DisplayFeed(hildon.StackableWindow): def nextArticle(self, object, index): label = self.buttons[index].child - label.modify_font(pango.FontDescription(self.config.getReadFont())) + label.modify_font(FontDescription(self.config.getReadFont())) label.modify_fg(gtk.STATE_NORMAL, read_color) # gtk.gdk.color_parse("white")) id = self.feed.getNextId(index) self.button_clicked(object, id, next=True) def previousArticle(self, object, index): label = self.buttons[index].child - label.modify_font(pango.FontDescription(self.config.getReadFont())) + label.modify_font(FontDescription(self.config.getReadFont())) label.modify_fg(gtk.STATE_NORMAL, read_color) # gtk.gdk.color_parse("white")) id = self.feed.getPreviousId(index) self.button_clicked(object, id, previous=True) def onArticleClosed(self, object, index): label = self.buttons[index].child - label.modify_font(pango.FontDescription(self.config.getReadFont())) + label.modify_font(FontDescription(self.config.getReadFont())) label.modify_fg(gtk.STATE_NORMAL, read_color) # gtk.gdk.color_parse("white")) self.buttons[index].show() @@ -662,12 +655,13 @@ class DisplayFeed(hildon.StackableWindow): self.vbox.destroy() self.feed = self.listing.getFeed(self.key) self.displayFeed() + self.updateDbusHandler.ArticleCountUpdated() def buttonReadAllClicked(self, button): for index in self.feed.getIds(): self.feed.setEntryRead(index) label = self.buttons[index].child - label.modify_font(pango.FontDescription(self.config.getReadFont())) + label.modify_font(FontDescription(self.config.getReadFont())) label.modify_fg(gtk.STATE_NORMAL, read_color) # gtk.gdk.color_parse("white")) self.buttons[index].show() @@ -687,6 +681,11 @@ class FeedingIt: gobject.idle_add(self.createWindow) def createWindow(self): + self.app_lock = get_lock("app_lock") + if self.app_lock == None: + self.pannableListing.set_label("Update in progress, please wait.") + gobject.timeout_add_seconds(3, self.createWindow) + return False self.listing = Listing(CONFIGDIR) self.downloadDialog = False @@ -739,6 +738,7 @@ class FeedingIt: def enableDbus(self): self.dbusHandler = ServerObject(self) + self.updateDbusHandler = UpdateServerObject(self) def button_markAll(self, button): for key in self.listing.getListOfFeeds(): @@ -778,6 +778,7 @@ class FeedingIt: def button_update_clicked(self, button, key): if not type(self.downloadDialog).__name__=="DownloadBar": + self.updateDbusHandler.UpdateStarted() self.downloadDialog = DownloadBar(self.window, self.listing, self.listing.getListOfFeeds(), self.config ) self.downloadDialog.connect("download-done", self.onDownloadsDone) self.mainVbox.pack_end(self.downloadDialog, expand=False, fill=False) @@ -789,7 +790,8 @@ class FeedingIt: self.downloadDialog = False #self.displayListing() self.refreshList() - self.dbusHandler.ArticleCountUpdated() + self.updateDbusHandler.UpdateFinished() + self.updateDbusHandler.ArticleCountUpdated() def button_preferences_clicked(self, button): dialog = self.config.createDialog() @@ -851,18 +853,25 @@ class FeedingIt: break def buttonFeedClicked(widget, button, self, window, key): - self.disp = DisplayFeed(self.listing, self.listing.getFeed(key), self.listing.getFeedTitle(key), key, self.config) - self.disp.connect("feed-closed", self.onFeedClosed) + try: + self.feed_lock + except: + # If feed_lock doesn't exist, we can open the feed, else we do nothing + self.feed_lock = get_lock(key) + self.disp = DisplayFeed(self.listing, self.listing.getFeed(key), self.listing.getFeedTitle(key), key, self.config) + self.disp.connect("feed-closed", self.onFeedClosed) def onFeedClosed(self, object, key): self.listing.saveConfig() + del self.feed_lock self.refreshList() - self.dbusHandler.ArticleCountUpdated() + self.updateDbusHandler.ArticleCountUpdated() def run(self): self.window.connect("destroy", gtk.main_quit) gtk.main() self.listing.saveConfig() + del self.app_lock def prefsClosed(self, *widget): self.orientation.set_mode(self.config.getOrientation()) @@ -891,6 +900,13 @@ class FeedingIt: self.button_update_clicked(None, None) return True + def stopUpdate(self): + # Not implemented in the app (see update_feeds.py) + try: + self.downloadDialog.listOfKeys = [] + except: + pass + def getStatus(self): status = "" for key in self.listing.getListOfFeeds(): @@ -912,6 +928,7 @@ if __name__ == "__main__": mkdir(CONFIGDIR) except: print "Error: Can't create configuration directory" - sys.exit(1) + from sys import exit + exit(1) app = FeedingIt() app.run() diff --git a/src/config.py b/src/config.py index 2e7f817..409f93e 100644 --- a/src/config.py +++ b/src/config.py @@ -19,18 +19,18 @@ # ============================================================================ # Name : FeedingIt.py # Author : Yves Marcoz -# Version : 0.5.4 +# Version : 0.6.1 # Description : Simple RSS Reader # ============================================================================ import gtk import hildon -import ConfigParser -import gobject -import gconf -import urllib2 +from ConfigParser import RawConfigParser +from gobject import idle_add +from gconf import client_get_default +from urllib2 import ProxyHandler -VERSION = "0.5.4" +VERSION = "0.6.1" section = "FeedingIt" ranges = { "updateInterval":[0.5, 1, 2, 4, 12, 24], "expiry":[24, 48, 72], "fontSize":range(12,24), "orientation":["Automatic", "Landscape", "Portrait"], "artFontSize":[10, 12, 14, 16, 18, 20]} @@ -65,7 +65,7 @@ class Config(): vbox.pack_start(picker, expand=False) button = hildon.CheckButton(gtk.HILDON_SIZE_FINGER_HEIGHT) - button.set_label("Auto-update Enabled") + button.set_label("Auto-update Enabled.") button.set_active(self.config["autoupdate"]) button.connect("toggled", self.button_toggled, "autoupdate") vbox.pack_start(button, expand=False) @@ -76,6 +76,12 @@ class Config(): button.connect("toggled", self.button_toggled, "imageCache") vbox.pack_start(button, expand=False) + button = hildon.CheckButton(gtk.HILDON_SIZE_FINGER_HEIGHT) + button.set_label("Proxy Support Enabled") + button.set_active(self.config["proxy"]) + button.connect("toggled", self.button_toggled, "proxy") + vbox.pack_start(button, expand=False) + button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL) button.set_label("View Known Issues and Tips") button.connect("clicked", self.button_tips_clicked) @@ -124,7 +130,7 @@ class Config(): def loadConfig(self): self.config = {} try: - configParser = ConfigParser.RawConfigParser() + configParser = RawConfigParser() configParser.read(self.configFilename) self.config["fontSize"] = configParser.getint(section, "fontSize") self.config["artFontSize"] = configParser.getint(section, "artFontSize") @@ -141,9 +147,13 @@ class Config(): self.config["updateInterval"] = 4 self.config["orientation"] = "Automatic" self.config["imageCache"] = False + try: + self.config["proxy"] = configParser.getboolean(section, "proxy") + except: + self.config["proxy"] = True def saveConfig(self): - configParser = ConfigParser.RawConfigParser() + configParser = RawConfigParser() configParser.add_section(section) configParser.set(section, 'fontSize', str(self.config["fontSize"])) configParser.set(section, 'artFontSize', str(self.config["artFontSize"])) @@ -152,6 +162,7 @@ class Config(): configParser.set(section, 'updateInterval', str(self.config["updateInterval"])) configParser.set(section, 'orientation', str(self.config["orientation"])) configParser.set(section, 'imageCache', str(self.config["imageCache"])) + configParser.set(section, 'proxy', str(self.config["proxy"])) # Writing our configuration file file = open(self.configFilename, 'wb') @@ -191,9 +202,11 @@ class Config(): def getImageCache(self): return self.config["imageCache"] def getProxy(self): - if gconf.client_get_default().get_bool('/system/http_proxy/use_http_proxy'): - port = gconf.client_get_default().get_int('/system/http_proxy/port') - http = gconf.client_get_default().get_string('/system/http_proxy/host') - proxy = proxy = urllib2.ProxyHandler( {"http":"http://%s:%s/"% (http,port)} ) + if self.config["proxy"] == False: + return (False, None) + if client_get_default().get_bool('/system/http_proxy/use_http_proxy'): + port = client_get_default().get_int('/system/http_proxy/port') + http = client_get_default().get_string('/system/http_proxy/host') + proxy = ProxyHandler( {"http":"http://%s:%s/"% (http,port)} ) return (True, proxy) return (False, None) \ No newline at end of file diff --git a/src/feedingit.service b/src/feedingit.service index 86c7613..5e3bece 100644 --- a/src/feedingit.service +++ b/src/feedingit.service @@ -1,3 +1,3 @@ [D-BUS Service] Name=org.maemo.feedingit -Exec=/usr/bin/FeedingIt \ No newline at end of file +Exec=/usr/bin/FeedingIt diff --git a/src/feedingit_status.desktop b/src/feedingit_status.desktop new file mode 100644 index 0000000..8601e66 --- /dev/null +++ b/src/feedingit_status.desktop @@ -0,0 +1,4 @@ +[Desktop Entry] +Name=Example +Type=python +X-Path=feedingit_status \ No newline at end of file diff --git a/src/feedingit_status.py b/src/feedingit_status.py new file mode 100644 index 0000000..744fab9 --- /dev/null +++ b/src/feedingit_status.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python2.5 +# +# Copyright (c) 2007-2008 INdT. +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program 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 program. If not, see . +# + +# ============================================================================ +# Name : FeedingIt.py +# Author : Yves Marcoz +# Version : 0.6.1 +# Description : Simple RSS Reader +# ============================================================================ + +import gtk +import hildondesktop + +class FeedingItStatusPlugin(hildondesktop.StatusMenuItem): + def __init__(self): + hildondesktop.StatusMenuItem.__init__(self) + + icon_theme = gtk.icon_theme_get_default() + pixbuf = icon_theme.load_icon("feedingit", 22, gtk.ICON_LOOKUP_NO_SVG) + self.set_status_area_icon(pixbuf) + + label = gtk.Label("Example message") + self.add(label) + self.show_all() + +hd_plugin_type = FeedingItStatusPlugin \ No newline at end of file diff --git a/src/feedingit_status.service b/src/feedingit_status.service new file mode 100644 index 0000000..9fc5897 --- /dev/null +++ b/src/feedingit_status.service @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.marcoz.feedingit +Exec=/usr/bin/FeedingIt dbus diff --git a/src/feedingit_widget.py b/src/feedingit_widget.py index ed080b3..c6eeb78 100644 --- a/src/feedingit_widget.py +++ b/src/feedingit_widget.py @@ -19,12 +19,10 @@ # ============================================================================ # Name : FeedingIt.py # Author : Yves Marcoz -# Version : 0.5.4 +# Version : 0.6.0 # Description : Simple RSS Reader # ============================================================================ #import sys -#sys.path.insert(0, '/opt/FeedingIt') -#sys.path.insert(0, '/home/user/workspace/feedingit/src/') import gtk, pickle, gobject, dbus import hildondesktop, hildon @@ -34,10 +32,23 @@ import hildondesktop, hildon import dbus from dbus.mainloop.glib import DBusGMainLoop dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) -bus = dbus.SessionBus() +#bus = dbus.SessionBus() + +from os import environ +bus = dbus.bus.BusConnection(environ["DBUS_SESSION_BUS_ADDRESS"]) + +color_style = gtk.rc_get_style_by_paths(gtk.settings_get_default() , 'GtkButton', 'osso-logical-colors', gtk.Button) +active_color = color_style.lookup_color('ActiveTextColor') +default_color = color_style.lookup_color('DefaultTextColor') +del color_style CONFIGDIR="/home/user/.feedingit/" +#DBusConnection *hd_home_plugin_item_get_dbus_connection ( HDHomePluginItem *item, DBusBusType type, DBusError *error); +#import ctypes +#libc = ctypes.CDLL('libc.so.6') +#libc.printf('Hello world!') + class FeedingItHomePlugin(hildondesktop.HomePluginItem): def __init__(self): try: @@ -45,13 +56,30 @@ class FeedingItHomePlugin(hildondesktop.HomePluginItem): self.set_settings(True) self.connect("show-settings", self.show_settings) self.feed_list = {} + self.total = 0 + self.autoupdateID=False vbox = gtk.VBox(False, 0) - button = gtk.Button("Update") - button.connect("clicked", self.update_list) - button.show_all() - vbox.pack_start(button) + #self.button = gtk.Button() + self.button = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL) + self.button.set_text("FeedingIt","") + self.button.set_sensitive(False) + self.label1 = self.button.child.child.get_children()[0].get_children()[0] + self.label2 = self.button.child.child.get_children()[0].get_children()[1] + self.label1.modify_fg(gtk.STATE_INSENSITIVE, default_color) + self.label2.modify_fg(gtk.STATE_INSENSITIVE, active_color) + icon_theme = gtk.icon_theme_get_default() + pixbuf = icon_theme.load_icon("feedingit", 48, gtk.ICON_LOOKUP_USE_BUILTIN ) + image = gtk.Image() + image.set_from_pixbuf(pixbuf) + self.button.set_image(image) + self.button.set_image_position(gtk.POS_LEFT) + + #button = gtk.Button("Update") + self.button.connect("clicked", self.button_clicked) + #button.show_all() + vbox.pack_start(self.button, expand=False) #for feed in ["Slashdot", "Engadget", "Cheez"]: # self.treestore.append([feed, "0"]) @@ -67,12 +95,31 @@ class FeedingItHomePlugin(hildondesktop.HomePluginItem): self.add(vbox) self.treeview.connect("row-activated", self.row_activated) vbox.show_all() - #self.setupDbus() - gobject.timeout_add_seconds(30*60, self.update_list) + self.setupDbus() + #gobject.timeout_add_seconds(30*60, self.update_list) except: import traceback - file = open("/home/user/.feedingit/feedingit_widget.log", "w") + file = open("/home/user/.feedingit/feedingit_widget.log", "a") traceback.print_exc(file=file) + file.close() + + def button_clicked(self, *widget): + self.button.set_sensitive(False) + self.label1.modify_fg(gtk.STATE_NORMAL, default_color) + self.label2.modify_fg(gtk.STATE_NORMAL, active_color) + self.update_label("Stopping") + remote_object = bus.get_object("org.marcoz.feedingit", # Connection name + "/org/marcoz/feedingit/update" # Object's path + ) + iface = dbus.Interface(remote_object, 'org.marcoz.feedingit') + iface.StopUpdate() + + def update_label(self, title, value=None): + self.button.set_title(title) + if value != None: + self.button.set_value(value) + else: + self.button.set_value("") def row_activated(self, treeview, treepath, column): (model, iter) = self.treeview.get_selection().get_selected() @@ -92,6 +139,8 @@ class FeedingItHomePlugin(hildondesktop.HomePluginItem): self.load_config() list = [] + oldtotal = self.total + self.total = 0 #for key in listOfFeeds["feedingit-order"]: for key in self.feed_list.keys(): try: @@ -103,6 +152,7 @@ class FeedingItHomePlugin(hildondesktop.HomePluginItem): if readItems[id]==False: countUnread = countUnread + 1 list.append([self.feed_list[key], countUnread, key]) + self.total += countUnread except: pass list = sorted(list, key=lambda item: item[1], reverse=True) @@ -110,13 +160,54 @@ class FeedingItHomePlugin(hildondesktop.HomePluginItem): treestore.append(item) self.treeview.set_model(treestore) self.treeview.get_selection().unselect_all() + if self.total > oldtotal: + self.update_label("%s Unread" %str(self.total), "%s more articles" %str(self.total-oldtotal)) + else: + self.update_label("%s Unread" %str(self.total)) return True + + def create_selector(self, choices, setting): + #self.pickerDialog = hildon.PickerDialog(self.parent) + selector = hildon.TouchSelector(text=True) + index = 0 + for item in choices: + iter = selector.append_text(str(item)) + if str(self.autoupdate) == str(item): + selector.set_active(0, index) + index += 1 + selector.connect("changed", self.selection_changed, setting) + #self.pickerDialog.set_selector(selector) + return selector + + def selection_changed(self, selector, button, setting): + tmp = selector.get_current_text() + if tmp == "Disabled": + self.autoupdate = 0 + else: + self.autoupdate = tmp + #current_selection = selector.get_current_text() + #if current_selection: + # self.config[setting] = current_selection + #gobject.idle_add(self.updateButton, setting) + #self.saveConfig() + + def create_autoupdate_picker(self): + picker = hildon.PickerButton(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL) + selector = self.create_selector(["Disabled", 0.02, 0.5, 1, 2, 4, 12, 24], "autoupdate") + picker.set_selector(selector) + picker.set_title("Frequency of updates from the widget") + picker.set_text("Setup Feed Auto-updates","Update every %s hours" %str(self.autoupdate) ) + picker.set_name('HildonButton-finger') + picker.set_alignment(0,0,1,1) + #self.buttons[setting] = picker + #vbox.pack_start(picker, expand=False) + return picker def show_settings(self, widget): file = open(CONFIGDIR+"feeds.pickle") listOfFeeds = pickle.load(file) file.close() - dialog = gtk.Dialog("Settings", None, gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) + dialog = gtk.Dialog("Choose feeds to display", None, gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) self.pannableArea = hildon.PannableArea() @@ -140,12 +231,16 @@ class FeedingItHomePlugin(hildondesktop.HomePluginItem): self.pannableArea.add(self.treeview_settings) self.pannableArea.show_all() dialog.set_default_size(-1, 600) + + dialog.action_area.pack_start(self.create_autoupdate_picker()) + dialog.show_all() response = dialog.run() - print response + if response == gtk.RESPONSE_ACCEPT: self.feed_list = self.getItems() dialog.destroy() + self.save_config() self.update_list() #self.treeview_settings.get_selection().select_all() @@ -158,40 +253,69 @@ class FeedingItHomePlugin(hildondesktop.HomePluginItem): return list def setupDbus(self): + bus.add_signal_receiver(self.update_list, dbus_interface="org.marcoz.feedingit", + signal_name="ArticleCountUpdated", path="/org/marcoz/feedingit/update") + bus.add_signal_receiver(self.update_started, dbus_interface="org.marcoz.feedingit", + signal_name="UpdateStarted", path="/org/marcoz/feedingit/update") + bus.add_signal_receiver(self.update_finished, dbus_interface="org.marcoz.feedingit", + signal_name="UpdateFinished", path="/org/marcoz/feedingit/update") + + def update_started(self, *widget): + self.button.set_sensitive(True) + self.update_label("Updating...", "Click to stop update") + + def update_finished(self, *widget): + self.button.set_sensitive(False) + self.update_label("Update done") - #from dbus.mainloop.glib import DBusGMainLoop - #dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) - #import gobject - #loop = gobject.MainLoop() - #bus = dbus.Bus(dbus.Bus.TYPE_SESSION) - #bus = dbus.SessionBus(mainloop=loop) - #bus = dbus.Bus.get_system() - #bus = dbus.Bus.get_session(True) - #bus.set_exit_on_disconnect(False) - - remote_object = bus.get_object("org.maemo.feedingit", # Connection name - "/org/maemo/feedingit" # Object's path + def start_update(self): + try: + if self.autoupdate >0: + import traceback + file = open("/home/user/.feedingit/feedingit_widget.log", "a") + from time import gmtime, strftime + file.write(strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime())) + file.close() + remote_object = bus.get_object("org.marcoz.feedingit", # Connection name + "/org/marcoz/feedingit/update" # Object's path ) - iface = dbus.Interface(remote_object, 'org.maemo.feedingit') - iface.connect_to_signal("ArticleCountUpdated", self.update_list) + iface = dbus.Interface(remote_object, 'org.marcoz.feedingit') + iface.UpdateAll() + return True + except: + import traceback + file = open("/home/user/.feedingit/feedingit_widget.log", "a") + traceback.print_exc(file=file) + file.close() - #bus.add_signal_receiver(self.update_list, - # dbus_interface="org.maemo.feedingit", - # signal_name="ArticleCountUpdated", - # path="/org/maemo/feedingit") - def save_config(self): + from os.path import isdir if not isdir(CONFIGDIR): + from os import mkdir mkdir(CONFIGDIR) file = open(CONFIGDIR+"widget", "w") pickle.dump(self.feed_list, file ) + pickle.dump(self.autoupdate, file) file.close() - + self.setup_autoupdate() + + def setup_autoupdate(self): + if (float(self.autoupdate) > 0): + if (not self.autoupdateID==False): + gobject.disconnect(self.autoupdateId) + self.autoupdateId = gobject.timeout_add_seconds(int(float(self.autoupdate)*3600), self.start_update) + else: + if (not self.autoupdateID==False): + gobject.disconnect(self.autoupdateId) + self.autoupdateID=False + def load_config(self): try: file = open(CONFIGDIR+"widget", "r") self.feed_list = pickle.load( file ) + self.autoupdate = pickle.load( file ) file.close() + self.setup_autoupdate() except: file = open(CONFIGDIR+"feeds.pickle") listOfFeeds = pickle.load(file) @@ -201,6 +325,7 @@ class FeedingItHomePlugin(hildondesktop.HomePluginItem): for key in listOfFeeds["feedingit-order"]: self.feed_list[key] = listOfFeeds[key]["title"] del listOfFeeds + self.autoupdate = 0 hd_plugin_type = FeedingItHomePlugin diff --git a/src/feedingitdbus.py b/src/feedingitdbus.py index 68d73d7..7081c41 100644 --- a/src/feedingitdbus.py +++ b/src/feedingitdbus.py @@ -43,18 +43,8 @@ class ServerObject(dbus.service.Object): @dbus.service.method('org.maemo.feedingit') def GetStatus(self): return self.app.getStatus() - - @dbus.service.method('org.maemo.feedingit') - def Update(self): - self.app.automaticUpdate() - return "Done" @dbus.service.method('org.maemo.feedingit') def OpenFeed(self, key): self.app.buttonFeedClicked(None, self.app, None, key) - return "Done" - - # A signal that will be exported to dbus - @dbus.service.signal('org.maemo.feedingit', signature='') - def ArticleCountUpdated(self): - pass + return "Done" diff --git a/src/rss.py b/src/rss.py index 8a30f7f..61e910b 100644 --- a/src/rss.py +++ b/src/rss.py @@ -23,8 +23,7 @@ # Description : Simple RSS Reader # ============================================================================ -from os.path import isfile -from os.path import isdir +from os.path import isfile, isdir from shutil import rmtree from os import mkdir, remove import pickle @@ -40,20 +39,20 @@ from urlparse import urlparse def getId(string): return md5.new(string).hexdigest() -def getProxy(): - import gconf - if gconf.client_get_default().get_bool('/system/http_proxy/use_http_proxy'): - port = gconf.client_get_default().get_int('/system/http_proxy/port') - http = gconf.client_get_default().get_string('/system/http_proxy/host') - proxy = proxy = urllib2.ProxyHandler( {"http":"http://%s:%s/"% (http,port)} ) - return (True, proxy) - return (False, None) +#def getProxy(): +# import gconf +# if gconf.client_get_default().get_bool('/system/http_proxy/use_http_proxy'): +# port = gconf.client_get_default().get_int('/system/http_proxy/port') +# http = gconf.client_get_default().get_string('/system/http_proxy/host') +# proxy = proxy = urllib2.ProxyHandler( {"http":"http://%s:%s/"% (http,port)} ) +# return (True, proxy) +# return (False, None) # Enable proxy support for images and ArchivedArticles -(proxy_support, proxy) = getProxy() -if proxy_support: - opener = urllib2.build_opener(proxy) - urllib2.install_opener(opener) +#(proxy_support, proxy) = getProxy() +#if proxy_support: +# opener = urllib2.build_opener(proxy) +# urllib2.install_opener(opener) # Entry = {"title":XXX, "content":XXX, "date":XXX, "link":XXX, images = [] } @@ -157,6 +156,14 @@ class Feed: tmpIds = [] for entry in tmp["entries"]: (dateTuple, date) = self.extractDate(entry) + try: + entry["title"] + except: + entry["title"] = "No Title" + try: + entry["link"] + except: + entry["link"] = "" tmpEntry = {"title":entry["title"], "content":self.extractContent(entry), "date":date, "dateTuple":dateTuple, "link":entry["link"], "images":[] } id = self.generateUniqueId(tmpEntry) diff --git a/src/update_feeds.py b/src/update_feeds.py new file mode 100644 index 0000000..29f4bb7 --- /dev/null +++ b/src/update_feeds.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python2.5 + +# +# Copyright (c) 2007-2008 INdT. +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program 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 program. If not, see . +# + +# ============================================================================ +# Name : update_feeds.py +# Author : Yves Marcoz +# Version : 0.6.1 +# Description : Simple RSS Reader +# ============================================================================ + +from rss import Listing +from config import Config + +import threading +import os +import gobject + +CONFIGDIR="/home/user/.feedingit/" +LOCK = CONFIGDIR + "update.lock" +#DESKTOP_FILE = "/usr/share/applications/hildon-status-menu/feedingit_status.desktop" + +from updatedbus import UpdateServerObject, get_lock + +class Download(threading.Thread): + def __init__(self, listing, config, dbusHandler): + threading.Thread.__init__(self) + self.running = True + self.listing = listing + self.config = config + self.dbusHandler = dbusHandler + self.dbug = open(CONFIGDIR+"dbug.log", "w") + self.dbug.flush() + + def run(self): + self.dbug.write("Starting updates") + self.dbug.flush() + try: + self.dbusHandler.UpdateStarted() + (use_proxy, proxy) = self.config.getProxy() + for key in self.listing.getListOfFeeds(): + self.dbug.write("updating %s\n" %key) + self.dbug.flush() + try: + if use_proxy: + from urllib2 import install_opener, build_opener + install_opener(build_opener(proxy)) + self.listing.updateFeed(key, self.config.getExpiry(), proxy=proxy, imageCache=self.config.getImageCache() ) + else: + self.listing.updateFeed(key, self.config.getExpiry(), imageCache=self.config.getImageCache() ) + except: + import traceback + file = open("/home/user/.feedingit/feedingit_update.log", "a") + traceback.print_exc(file=file) + file.close() + if not self.running: + self.dbug.write("received stopUpdate after %s\n" %key) + self.dbug.flush() + break + self.dbusHandler.UpdateFinished() + self.dbusHandler.ArticleCountUpdated() + self.dbug.write("Dbus ArticleCountUpdated signal sent\n") + self.dbug.flush() + try: + os.remove(LOCK) + #os.remove(DESKTOP_FILE) + except: + pass + except: + pass + self.listing.saveConfig() + self.dbug.write("About to main_quit\n") + self.dbug.flush() + mainloop.quit() + file.write("After main_quit\n") + self.dbug.flush() + self.dbug.close() + +class FeedUpdate(): + def __init__(self): + self.listing = Listing(CONFIGDIR) + self.config = Config(self, CONFIGDIR+"config.ini") + self.dbusHandler = UpdateServerObject(self) + self.updateThread = False + + def automaticUpdate(self): + #self.listing.updateFeeds() + if self.updateThread == False: + self.updateThread = Download(self.listing, self.config, self.dbusHandler) + self.updateThread.start() + + def stopUpdate(self): + try: + self.updateThread.running = False + except: + pass + +import dbus.mainloop.glib +dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + +gobject.threads_init() +mainloop = gobject.MainLoop() + +app_lock = get_lock("app_lock") + +if app_lock != None: + try: + feed = FeedUpdate() + mainloop.run() + del app_lock + except: + import traceback + file = open("/home/user/.feedingit/feedingit_update.log", "a") + traceback.print_exc(file=file) + file.close() +else: + file = open("/home/user/.feedingit/feedingit_update.log", "a") + file.write("Update in progress") + file.close() + diff --git a/src/updatedbus.py b/src/updatedbus.py new file mode 100644 index 0000000..e712c7e --- /dev/null +++ b/src/updatedbus.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python2.5 + +# +# Copyright (c) 2007-2008 INdT. +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program 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 program. If not, see . +# + +# ============================================================================ +# Name : FeedingIt.py +# Author : Yves Marcoz +# Version : 0.6.1 +# Description : Simple RSS Reader +# ============================================================================ + +import dbus +import dbus.service + +def get_lock(key): + try: + bus_name = dbus.service.BusName('org.marcoz.feedingit.lock_%s' %key,bus=dbus.SessionBus(), do_not_queue=True) + except: + bus_name = None + return bus_name + + +class UpdateServerObject(dbus.service.Object): + def __init__(self, app): + # Here the service name + bus_name = dbus.service.BusName('org.marcoz.feedingit',bus=dbus.SessionBus()) + # Here the object path + dbus.service.Object.__init__(self, bus_name, '/org/marcoz/feedingit/update') + self.app = app + + @dbus.service.method('org.marcoz.feedingit') + def UpdateAll(self): + self.app.automaticUpdate() + return "Done" + + @dbus.service.method('org.marcoz.feedingit') + def StopUpdate(self): + self.app.stopUpdate() + return "Done" + + # A signal that will be exported to dbus + @dbus.service.signal('org.marcoz.feedingit', signature='') + def ArticleCountUpdated(self): + pass + + # A signal that will be exported to dbus + @dbus.service.signal('org.marcoz.feedingit', signature='') + def UpdateStarted(self): + pass + + # A signal that will be exported to dbus + @dbus.service.signal('org.marcoz.feedingit', signature='') + def UpdateFinished(self): + pass \ No newline at end of file