On 9/2/07, Renato Araujo <renatox gmail com> wrote:Hi all,
After some talk in conduit irc channel I decided start my first dataprovider for study the conduit api.
I wold like submit my provider for you, to give me some feedbacks and talk about this.
Thanks. I committed the dp because it works, and is usable even at this early stage. Well done!My first module synchronize is the youtube most watched videos of the day.
The natural extension to this would be to provide a configuration dialog to allow the user to select between
* n number of most watched vids
* n new vids
* vids posted by a certain user
* etcFirst I start read the the tutorial about "create a writing A custom dataProvider" on wiki page, after this I copy the FeedModule and start my module, I fond some differences between the implementation and the tutorial.
This is my question: In the method "get", this receive the string LUID, generate by "get_all" method, in the tutorial you use the "get_num_items" to get the total of items and pass the integer index to method "get". What is the correct way to do this, or both are correct?
Your implementation is correct, the docs were out of date. I have now updated them and also updated the ExampleModule dataprovider in the help directory.
Basically get_num_items is no longer compulsory, get_all should return a list of UIDs, and get then accepts the UIDs returned by get_all.
Style wise I like to have private functions prefixed with _, eg
extract_video_url -> _extract_video_url
Also, see the discussion about selection of UID for the dataprovider ( http://www.conduit-project.org/wiki/WritingADataProvider), i.e. it should not be too closely tied to the dp configuration
Welcome to conduit!
JohnBR
Renato Filho
_______________________________________________
Conduit-list mailing list
Conduit-list gnome org
http://mail.gnome.org/mailman/listinfo/conduit-list
Index: m4/intltool.m4 =================================================================== --- m4/intltool.m4 (revision 825) +++ m4/intltool.m4 (working copy) @@ -23,7 +23,7 @@ ## the same distribution terms that you use for the rest of that program. dnl IT_PROG_INTLTOOL([MINIMUM-VERSION], [no-xml]) -# serial 36 IT_PROG_INTLTOOL +# serial 35 IT_PROG_INTLTOOL AC_DEFUN([IT_PROG_INTLTOOL], [AC_PREREQ([2.50])dnl @@ -36,7 +36,7 @@ esac if test -n "$1"; then - AC_MSG_CHECKING([for intltool >= $1]) + AC_MSG_CHECKING(for intltool >= $1) INTLTOOL_REQUIRED_VERSION_AS_INT=`echo $1 | awk -F. '{ print $ 1 * 1000 + $ 2 * 100 + $ 3; }'` INTLTOOL_APPLIED_VERSION=`awk -F\" '/\\$VERSION / { print $ 2; }' ${ac_aux_dir}/intltool-update.in` @@ -65,7 +65,6 @@ INTLTOOL_SCHEMAS_RULE='%.schemas: %.schemas.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -s -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' INTLTOOL_THEME_RULE='%.theme: %.theme.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' INTLTOOL_SERVICE_RULE='%.service: %.service.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' - INTLTOOL_POLICY_RULE='%.policy: %.policy.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' AC_SUBST(INTLTOOL_DESKTOP_RULE) AC_SUBST(INTLTOOL_DIRECTORY_RULE) @@ -85,7 +84,6 @@ AC_SUBST(INTLTOOL_SCHEMAS_RULE) AC_SUBST(INTLTOOL_THEME_RULE) AC_SUBST(INTLTOOL_SERVICE_RULE) -AC_SUBST(INTLTOOL_POLICY_RULE) # Use the tools built into the package, not the ones that are installed. AC_SUBST(INTLTOOL_EXTRACT, '$(top_builddir)/intltool-extract') @@ -108,16 +106,19 @@ fi fi +AC_PATH_PROG(INTLTOOL_ICONV, iconv, iconv) +AC_PATH_PROG(INTLTOOL_MSGFMT, msgfmt, msgfmt) +AC_PATH_PROG(INTLTOOL_MSGMERGE, msgmerge, msgmerge) +AC_PATH_PROG(INTLTOOL_XGETTEXT, xgettext, xgettext) + # Substitute ALL_LINGUAS so we can use it in po/Makefile AC_SUBST(ALL_LINGUAS) # Set DATADIRNAME correctly if it is not set yet # (copied from glib-gettext.m4) if test -z "$DATADIRNAME"; then - AC_LINK_IFELSE( - [AC_LANG_PROGRAM([[]], - [[extern int _nl_msg_cat_cntr; - return _nl_msg_cat_cntr]])], + AC_TRY_LINK(, [extern int _nl_msg_cat_cntr; + return _nl_msg_cat_cntr], [DATADIRNAME=share], [case $host in *-*-solaris*) @@ -158,6 +159,10 @@ for file in intltool-extract intltool-merge intltool-update; do sed -e "s|@INTLTOOL_EXTRACT@|`pwd`/intltool-extract|g" \ -e "s|@INTLTOOL_LIBDIR@|${INTLTOOL_LIBDIR}|g" \ + -e "s|@INTLTOOL_ICONV@|${INTLTOOL_ICONV}|g" \ + -e "s|@INTLTOOL_MSGFMT@|${INTLTOOL_MSGFMT}|g" \ + -e "s|@INTLTOOL_MSGMERGE@|${INTLTOOL_MSGMERGE}|g" \ + -e "s|@INTLTOOL_XGETTEXT@|${INTLTOOL_XGETTEXT}|g" \ -e "s|@INTLTOOL_PERL@|${INTLTOOL_PERL}|g" \ < ${ac_aux_dir}/${file}.in > ${file}.out if cmp -s ${file} ${file}.out 2>/dev/null; then @@ -172,7 +177,9 @@ ], [INTLTOOL_PERL='${INTLTOOL_PERL}' ac_aux_dir='${ac_aux_dir}' prefix="$prefix" exec_prefix="$exec_prefix" INTLTOOL_LIBDIR="$libdir" -INTLTOOL_EXTRACT='${INTLTOOL_EXTRACT}']) +INTLTOOL_EXTRACT='${INTLTOOL_EXTRACT}' INTLTOOL_ICONV='${INTLTOOL_ICONV}' +INTLTOOL_MSGFMT='${INTLTOOL_MSGFMT}' INTLTOOL_MSGMERGE='${INTLTOOL_MSGMERGE}' +INTLTOOL_XGETTEXT='${INTLTOOL_XGETTEXT}']) ]) Index: conduit/dataproviders/YouTubeModule/YouTubeModule.py =================================================================== --- conduit/dataproviders/YouTubeModule/YouTubeModule.py (revision 825) +++ conduit/dataproviders/YouTubeModule/YouTubeModule.py (working copy) @@ -29,14 +29,6 @@ "YouTubeSource" : { "type": "dataprovider" } } -class YouTubeEntry: - Title = "" - Url = "" - def __init__ (self, title, url): - self.Title = title - self.Url = url - - class YouTubeSource(DataProvider.DataSource): _name_ = _("YouTube") @@ -47,37 +39,109 @@ _out_type_ = "file" _icon_ = "youtube" + #feeds_url + _const_feed_most_viewed_ = "http://gdata.youtube.com/feeds/standardfeeds/most_viewed?time=today" + _const_feed_top_rated_ = "http://gdata.youtube.com/feeds/standardfeeds/top_rated?time=today" + _const_feed_upload_by_ = "http://gdata.youtube.com/feeds/videos?author=%s" + _const_feed_favorites_ = "http://gdata.youtube.com/feeds/users/%s/favorites" + + #Config args + max = 0 + #filter type {0 = mostviewed, 1 = toprated, 2 = user} + filter_type = 0 + #filter user type {0 = upload, 1 = favorites} + user_filter_type = 0 + username = "" + + def __init__(self, *args): DataProvider.DataSource.__init__(self) - - self.feedUrl = "http://gdata.youtube.com/feeds/standardfeeds/top_rated?time=today" - #self.feedUrl = "" self.entries = None def initialize(self): return True def configure(self, window): - return None + tree = Utils.dataprovider_glade_get_widget ( + __file__, + "config.glade", + "YouTubeSourceConfigDialog") + dlg = tree.get_widget ("YouTubeSourceConfigDialog") + mostviewedRb = tree.get_widget("mostviewed") + topratedRb = tree.get_widget("toprated") + byuserRb = tree.get_widget("byuser") + user_frame = tree.get_widget("frame") + uploadedbyRb = tree.get_widget("uploadedby") + favoritesofRb = tree.get_widget("favoritesof") + user = tree.get_widget("user") + maxdownloads = tree.get_widget("maxdownloads") + + byuserRb.connect("toggled", self._filter_user_toggled_cb, user_frame) + + if self.filter_type == 0: + mostviewedRb.set_active(True) + elif self.filter_type == 1: + topratedRb.set_active(True) + else: + byuserRb.set_active(True) + user_frame.set_sensitive(True) + if self.user_filter_type == 0: + uploadedbyRb.set_active(True) + else: + favoritesofRb.set_active(True) + user.set_text(self.username) + + logging.debug("Max") + logging.debug(self.max) + maxdownloads.set_value(self.max) + + dlg.set_transient_for(window) + response = dlg.run() + if response == gtk.RESPONSE_OK: + if mostviewedRb.get_active(): + self.filter_type = 0 + elif topratedRb.get_active(): + self.filter_type = 1 + else: + self.filter_type = 2 + if uploadedbyRb.get_active(): + self.user_filter_type = 0 + else: + self.user_filter_type = 1 + self.username = user.get_text() + self.max = int(maxdownloads.get_value()) + + dlg.destroy() + def refresh(self): DataProvider.DataSource.refresh(self) self.entries = {} try: - logging.debug("Open") - url_info = urllib2.urlopen(self.feedUrl) + feedUrl = "" + if self.filter_type == 0: + feedUrl = self._const_feed_most_viewed_ + elif self.filter_type == 1: + feedUrl = self._const_feed_top_rated_ + else: + if self.user_filter_type == 0: + feedUrl = (self._const_feed_upload_by_ % self.username) + else: + feedUrl = (self._const_feed_favorites_ % self.username) + + if self.max > 0: + feedUrl = ("%s&max-results=%d" % (feedUrl, self.max)) + + logging.debug ("Retrieve URL: %s" % feedUrl) + url_info = urllib2.urlopen(feedUrl) if (url_info): - logging.debug("Parse") doc = ElementTree.parse(url_info).getroot() for entry in doc.findall("{http://www.w3.org/2005/Atom}entry"): - - for c in entry.getchildren(): if (c.tag == "{http://www.w3.org/2005/Atom}title"): title = c.text if (c.tag =="{http://search.yahoo.com/mrss/}group"): - logging.debug ("Has group") for cc in c.getchildren(): if (cc.tag == "{http://search.yahoo.com/mrss/}player"): url = cc.get("url") @@ -95,7 +159,7 @@ url = self.entries[LUID] logging.debug("Title: '%s', Url: '%s'"%(LUID, url)) - video_url = self.extract_video_url (url) + video_url = self._extract_video_url (url) logging.debug ("URL: %s" % video_url) f = File.File (URI=video_url) @@ -110,13 +174,23 @@ self.files = None def get_configuration(self): - return None + return { + "filter_type" : self.filter_type, + "user_filter_type" : self.user_filter_type, + "username" : self.username, + "max" : self.max + } + def get_UID(self): - return self.feedUrl + return Utils.get_user_string() + #ui callbacks + def _filter_user_toggled_cb (self, toggle, frame): + frame.set_sensitive(toggle.get_active()) + # Generic extract step - def extract_video_url (self, url): + def _extract_video_url (self, url): regexp = re.compile(r'[,{]t:\'([^\']*)\'') try: Index: conduit/dataproviders/YouTubeModule/Makefile.am =================================================================== --- conduit/dataproviders/YouTubeModule/Makefile.am (revision 825) +++ conduit/dataproviders/YouTubeModule/Makefile.am (working copy) @@ -1,5 +1,8 @@ conduit_handlersdir = $(libdir)/conduit/dataproviders/YouTubeModule conduit_handlers_PYTHON = YouTubeModule.py +conduit_handlers_DATA = config.glade +EXTRA_DIST = config.glade + clean-local: rm -rf *.pyc *.pyo
Attachment:
config.glade
Description: application/glade