Skip to content

feeder-python🔗

Originally appeared on nakamura-gebeit.de/scripts/ repository.

Retrieved from the depths of the Wayback Machine.

Depends on python-feedparser and python-elementtree modules as per comments.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
#-------------------------------------------------------------------------------

feeder.py - version 5
by Vlad George

#-------------------------------------------------------------------------------

Description:
    This script pipes rss and podcast feeds into the openbox menu

Usage:
    First you need the python-feedparser and python-elementtree modules (archlinux (AUR)/ ubuntu).
    Place this script under ~/.config/openbox/scripts, edit the variables under "User set variables"
    according to your likings (your list of rss_urls, browser and media-player to open links,
    number of displayed rss-entries, enable/disable caching of feeds, maximum age of feeds),
    make it executable, then add following to your ~/.config/openbox/menu.xml:
    "<menu id="feeder-menu" label="rss-feeds" execute="~/.config/openbox/scripts/feeder.py" />...
    <menu id="root-menu" label="Openbox3">...<menu id="feeder-menu" />...</menu>"
    and reconfigure openbox.

Changelog:
    01.07.2007:   1st version
    03.07.2007:   works now (changed "~")....
    05.07.2007:   added cache
    07.10.2007:   added name of rss and sorted output
    03.2008:      added podcast support

#-------------------------------------------------------------------------------

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
http://www.fsf.org/

"""

#-------------------------------------------------------------------------------
#                             User set variables
#-------------------------------------------------------------------------------

## your rss feeds:
rss_urls = [
            #('name to be shown', 'url of rss'),
            ('Arch Packages', 'http://www.archlinux.org/feeds/packages/'),
            #('', ''),
            #('', ''),
            #('', ''),
         ]

## browser and audio/video-player to use:
# open_with = "gnome-open"
open_with = "firefox"
play_with = "xmms"

## how many entries should be shown:
rss_feeds_count = 60

## use cache (1 enabled, 0 disabled)
cache = 0

### if cache enabled:

## how old should cache files get - in minutes; set to 0 for manual refresh:
## you can also use >> feeder.py --update << to only update the cache file (useful as cronjob)
age = 120

## temporary directory for cache file (default=/tmp/); leave it as it is.
cache_dir = "/tmp"


#-------------------------------------------------------------------------------
#                                   Script
#-------------------------------------------------------------------------------


# {{{ ##  fold marker start

def gettingTitles(url_list):
    # get feeds for each url:
    rss_dict = {}
    for i in xrange(len(url_list)):

        rss = feedparser.parse(url_list[i][1])
        rss_entry = []
        try:
            append = rss_entry.append
            if rss.entries[i].has_key('link') == False:
                [append((rss.entries[num].title, None, rss.entries[num].enclosures[0].href)) for num in xrange(rss_feeds_count)]
            elif rss.entries[i].has_key('enclosures') == False:
                [append((rss.entries[num].title, rss.entries[num].link, None)) for num in xrange(rss_feeds_count)]
            else:
                [append((rss.entries[num].title, rss.entries[num].link, rss.entries[num].enclosures[0].href)) for num in xrange(rss_feeds_count)]
        except IndexError:
            pass
        try:
            if url_list[i][0] == '':
                rss_dict[(rss.feed.title, url_list[i][1])] = rss_entry[0:int(rss_feeds_count)]
            else:
                rss_dict[(url_list[i][0], url_list[i][1])] = rss_entry[0:int(rss_feeds_count)]
        except:
            pass
    # rss_dict-items: { ..., ([i][0]:> rss-url, [i][1]:> rss-name):[..., ([i][j][0]:> entry-title, [i][j][1]:> entry-link, [i][j][2]:> entry-podcast_link), ...], ... }
    return rss_dict


def generateXml(dict_url_entry, outfile):
    # sort dict items according display name
    sorted_list = dict_url_entry.items()
    sorted_list.sort()
    # [ ..., (([i][0][0] -> rss-name, [i][0][1] -> rss-url), [..., ([i][1][j][0] -> entry-title, [i][1][j][1] -> entry-link, [i][1][j][2]:> entry-podcast_link), ...]), ... ]
    root = ET.Element("openbox_pipe_menu")
    for i in xrange(len(sorted_list)):
        menu = ET.SubElement(root,"menu", attrib = {"id" : sorted_list[i][0][1], "label" : unicode(sorted_list[i][0][0])})
        for j in xrange(len(sorted_list[i][1])):
            try:
                if sorted_list[i][1][j][2] == None:
                    item = ET.SubElement(menu, "item", attrib = {"label" : unicode(sorted_list[i][1][j][0])})
                    action = ET.SubElement(item, "action", attrib = {"name" : "Execute"})
                    command = ET.SubElement(action, "command")
                    tmp = str(sorted_list[i][1][j][1]).replace('~','%7E')
                    command.text = "%s %s" % (open_with, tmp)
                elif sorted_list[i][1][j][1] == None:
                    podcast_menu = ET.SubElement(menu, "menu", attrib = {"id" : str(int(random.random()*10000000)) + "-menu", "label" : unicode(sorted_list[i][1][j][0])})
                    podcast_play = ET.SubElement(podcast_menu, "item", attrib = {"label" : " play podcast"})
                    podcast_play_action = ET.SubElement(podcast_play, "action", attrib = {"name": "Execute"})
                    podcast_play_execute = ET.SubElement(podcast_play_action, "command")
                    tmp = str(sorted_list[i][1][j][2]).replace('~','%7E')
                    podcast_play_execute.text = "%s %s" % (play_with, tmp)
                else:
                    podcast_menu = ET.SubElement(menu, "menu", attrib = {"id" : str(int(random.random()*10000000)) + "-menu", "label" : unicode(sorted_list[i][1][j][0])})
                    podcast_open = ET.SubElement(podcast_menu, "item", attrib = {"label" : " open "})
                    podcast_open_action = ET.SubElement(podcast_open, "action", attrib = {"name": "Execute"})
                    podcast_open_execute = ET.SubElement(podcast_open_action, "command")
                    tmp1 = str(sorted_list[i][1][j][1]).replace('~','%7E')
                    podcast_open_execute.text = "%s %s" % (open_with, tmp1)
                    podcast_play = ET.SubElement(podcast_menu, "item", attrib = {"label" : " play podcast"})
                    podcast_play_action = ET.SubElement(podcast_play, "action", attrib = {"name": "Execute"})
                    podcast_play_execute = ET.SubElement(podcast_play_action, "command")
                    tmp2 = str(sorted_list[i][1][j][2]).replace('~','%7E')
                    podcast_play_execute.text = "%s %s" % (play_with, tmp2)
            except IndexError:
                pass
    if cache == 1:
        separator = ET.SubElement(root,"separator")
        refresh = ET.SubElement(root,"item", attrib = {"label":"Reload Cache"})
        action2 = ET.SubElement(refresh,"action",attrib = {"name":"Execute"})
        command2 = ET.SubElement(action2,"command")
        command2.text = "%s %s" % (sys.argv[0], "--update")
    tree = ET.ElementTree(root)
    tree.write(outfile)


def ageCheck(age_in_min, file_to_check):
    age_in_sec = int(age_in_min)*60
    file_age = int(time())-int(os.path.getmtime(file_to_check))
    if age_in_min == 0:
        return 1
    elif os.path.isfile(file_to_check) and file_age < age_in_sec:
        return 1
    else:
        return 0


def printXml(xml_entry):
    temp_file = file(xml_entry,'r')
    a = temp_file.read()
    temp_file.close()
    print a


#-------------------------------------------------------------------------------
#                                    Main
#-------------------------------------------------------------------------------
import os.path, sys, feedparser
import elementtree.ElementTree as ET
import random
from time import time

#-------------------------#
if __name__ == "__main__" :
#-------------------------#
    if cache == 1:
        cache_file = cache_dir + "/." + str(os.path.split(sys.argv[0])[1]) + "-" + str(os.getuid()) + ".cache"
        if ('--update' in sys.argv[1:]):
            generateXml(gettingTitles(rss_urls), cache_file)
        elif os.path.isfile(cache_file) and ageCheck(age, cache_file):
            print '<?xml version="1.0" encoding="UTF-8"?>'
            printXml(cache_file)
        else:
            generateXml(gettingTitles(rss_urls), cache_file)
            print '<?xml version="1.0" encoding="UTF-8"?>'
            printXml(cache_file)
    else:
        print '<?xml version="1.0" encoding="UTF-8"?>'
        generateXml(gettingTitles(rss_urls), sys.stdout)


# }}} ##  fold marker end

# vim: set ft=python ts=4 sw=4 foldmethod=marker :