The site uses cookies that you may not want. Continued use means acceptance. For more information see our privacy policy.

Messing with TT-RSS in Python

Some sample code I wrote to feel my way around the TT-RSS API in Python.

I use the feed reader TT-RSS to read RSS/ATOM feeds. It’s a good reader, and I also use TTRSS-Reader for Android (there are others, which I’ve not tried yet) on my (ancient) Android mobile device to quickly go through incoming feed items. But I have some itches to the web interface that I am considering scratching, so I decided to see how hard it is to start building a simpler interface.

One of the things I knew from setting up the Android application is that TT-RSS has an API, which is where I started. It communicates via JSON, which is great because it is ubiquitous and easy to use.

You have to have a session to talk to the API, so I built a class to handle all requests and the session:

class TTRSSSession():
    def __init__(self, url, user, password):
        self.session_id = None
        self.url = url
        self.user = user
        self.password = password
        self._login()

    def headlines(self, feed):
        data = {
            "feed_id": feed,
            "limit": 10,
            #"skip": 11,
        }
        resp = self._request('getHeadlines', data)
        return resp

    def _login(self):
        login_data = {
            "user": self.user,
            "password": self.password,
        }
        result = self._request("login", login_data)
        self.session_id = result['session_id']

    def _request(self, op, data):
        request_data = {
            "op": op,
        }
        if not self.session_id and op != "login":
            raise OpException("Tried to execute without a session/login.")
            return None
        elif self.session_id and op != "login":
            request_data['sid'] = self.session_id

        request_data = dict_join((request_data, data))
        request_data_j = json.dumps(request_data).encode('utf-8')
        response = urllib.request.urlopen(self.url, data=request_data_j)
        r_data_j = response.read()
        encoding = chardet.detect(r_data_j)['encoding']
        r_data_j = r_data_j.decode(encoding, 'replace')
        r_data = json.loads(r_data_j)
        if r_data['status'] != 0:
            raise OpException(
                "Bad request: {0}".format(r_data['content']['error']))
            return None
        # FIXME handling multiple parts (seq = #)?
        return r_data['content']

That’s the main guts. This isn’t very advanced/functional yet, but it’s enough for me to mess with. I also built a very simple Flask application that uses this class so I can begin sketching some UI I might want (though for now it’s very bare bones, just showing the result of TTRSSSession.headlines()).

I was going to use Django, but I think it’s too heavy for what I want out of it. Flask is very light.

A sample invocation of the class:

feeds = {
    'FRESH': -3,
    'STARRED': -1,
    'ALL': -4,
}
url = 'http://example.com/tt-rss/api/'
user = 'random_hacker'
passw = 'xyzzy'
ttr = TTRSSSession(url, user, passw)
ttr.headlines(feeds['ALL'])

The headlines() method will return the first ten items in the feed containing all items (a special feed that throws everything read and unread together).

As you can see in the class’ _request() method, I haven’t added support for pulling multiple calls together. That will likely require a JavaScript frontend to integrate with my Flask application (or the data would all get pulled by the backend first, which seems wrong). And that begs the question of why not to forgo Python altogether and just write this as a pure client-side JavaScript thing?

Maybe I will. For now I am just messing around. Depending, I might prefer to use a Python backend to help filter or manage some of the items automatically. So at this point the versatility seems useful. Also, I always feel slightly silly when I find myself doing something that feels too close to rewriting part of an application that already (and still will) have that part, so who knows. I may just use this to learn more about Flask.

Tiny Tiny RSS and Feed Reading

Discusses the Tiny Tiny RSS (self-hosted) web application as a replacement for Google Reader (which will be end-of-life in July 2013).

Google Reader, a popular web application for organizing and reading RSS feeds (computer-friendly lists of posts from websites), will go away in July 2013. Scrambling for a replacement, many flock to monolithic, hosted substitutes.

I already had a perfect substitute up and running. A few months back I decided to add some feeds that did not fit my usual reading patterns on Google Reader. I looked around for an alternative and decided upon Tiny Tiny RSS (aka tt-rss), a free software implementation that manages and allows easy reading of feeds.

I only added the feeds that didn’t fit my Google Reader usage at the time. I would check tt-rss once a day, and continued checking Google Reader more regularly as always for the bulk of my reading.

Then the Google Reader announcement came, and while I looked at and tried a few of the alternatives, tt-rss fit my use best. Google Reader did not have feed filtering (to my knowledge) where tt-rss does. The ability to “clean up” some of the noise on some feeds means a more pleasant reading experience. For a mobile solution, the web interface has a mobile version (if Google Reader does, I never tried it; I did use their Android application, though), and an Android application can talk to tt-rss as well (requires enabling the API).

Google Reader served many people well for years, but it never went as far as it could have. With people forced out, a lot of projects like tt-rss will hopefully see increased relevance and improvement. But RSS itself never achieved the recognition it deserves.

RSS would serve us best if it were somewhat automatic. Google never took the obvious step of showing you feed items from recently-viewed sites, for example. Auto-management of feeds would have gone a long way toward improving the usage and importance of RSS. Manually adding and removing feeds, not being able to disable them, no filtering, and needing to understand feeds; these things made it a mess.

When you visit a site, they do everything they can to get you to stay. They try to pull you in with other materials, they beg you to subscribe. But as with just about every other industry, they fail to see their role in that process. They should work with browser builders to add next-generation discovery and subscription models.

For its part, tt-rss now has more feeds than Google Reader ever did. I’ve added more feeds knowing I can filter them easily, though I suspect the worst feeds will soon go away. While it isn’t perfect, it’s at least on par with Google Reader. And once I set it up (admittedly easy for someone at my level of knowledge), it’s no challenge to keep using.

The main thing I wish it had (and something I’m continuing to look into for several services I run for myself) is a single-sign-on solution. The last time I checked, my various services had differing support for different authentication technologies. Having just one that worked for them all would be delightful.