Stonemind WEB rss feed aggregation with Lylina

rss feed aggregation with Lylina

My employer, Cornell University Library (CUL), hosts a few dozen departmental and staff blogs that I help support. These blogs are primarily meant to be read internally, and I felt that aggregating the RSS feeds from these blogs and making them available in one place would increase the readership and usefulness of these blogs, perhaps even attracting readers outside the organization as well.

In addition to serving as an entry point for all CUL blogs, I wanted an aggregator that could be used by CUL employees internally to manage their own feeds and optionally share those feeds as recommendations to others. So, for example, I, as a software developer, could add Joel On Software and other blogs I read and then recommend them to others so that non-technical staff could get a sense of what I think is important in my field. In this way, they could better understand my specialty and in turn, better understand me. Well, that’s the theory anyway.

In other words, the RSS aggregator would not only be for personal information management, it would be a unique way for people to communicate about what they think is important. Front line employees often feel like they don’t understand the perspectives of those in management, but scanning your boss’s boss’s feeds might give you a better sense of their vision for the organization. Likewise, management could do the same with their front line employees, giving employees power to influence the “corporate culture” at a grass roots level.

So, I set out to find an open source RSS aggregator that would allow for a default set of feeds to be available to everyone on the home page, but also allow for multiple users to save, view, and share their own feeds. I also wanted something I could deploy, configure and support easily.

I didn’t find the perfect software package for my needs, but I found something that fit my general philosophy that I could comfortably customize: Lylina, a open source, LAMP based aggregator that supports multiple users, default feeds, searching capabilities and a “river of news” approach to viewing posts by date posted, not by the site to which they belong. This blog post focuses on my installation and configuration of this software, its good points and bad.

I should also mention another very nice RSS aggregator, Tiny Tiny RSS, another LAMP based package with a slick AJAX interface. Tiny Tiny RSS is meant for one user, and doesn’t really seem to support the “river of news” viewing paradigm, so it ultimately didn’t fit my needs on this project, but I thought it deserved a mention.

Also, for viewing my own individual RSS feeds, I have been happy with Google Reader which has both individual feed views, a “river of news” view as well as a few different ways of displaying new posts. I can tag feeds, import and export OPML, etc. and it also has a very nice AJAX interface of course.

Installing and Configuring Lylina

You can get Lylina at its home page:

http://lylina.sourceforge.net

…and unpack it where you want it installed. Lylina comes with comprehensive installation documentation, although I did hit a few bumps along the way. To begin, in MySQL, I ran the following:

create database lylina; grant select, insert, update, delete on lylina.* to lylina@’localhost’ identified by ‘password’;

In the conf.php file, I added the database information and turned on all the bookmarklets and searching. I initially left the mode ‘normal’. I set the usecron option to true and changed the page title and description to my own.

Instead of setting file permissions to 777 as the installation documentation suggests for the cache/ and favicons/ directories and the lockfile file, I changed their permissions to 775 (and they could probably be less) and changed their owner to the user running Apache, which is typically ‘nobody’. These settings seem to work and are a little more secure.

The admin password is supposed to be set to ‘admin’ initially, but the insert statement in the database code is either for another password, or using a different encryption algorithm, because I couldn’t log in initially. I printed the query in inc/auth.php to know which string it was trying to match: the true admin password is encrypted as: ‘$1$$CoERg7ynjYLsj2j4glJ34.’ without quotes. I ran the following query to change it:

update lylina_users set pass=’$1$$CoERg7ynjYLsj2j4glJ34.’;

I was then able to log in to Lylina and change the password to what I would use going forward.

Customizations

I created a version of the logo I wanted to use in Lylina, and uploaded it to:

/img/logo.png

I also uploaded a copy of CUL’s bookmark icon to the root of the Lylina installation, overwriting Lylina’s logo icon.

You will also undoubtedly want to modify the style sheet being used. All style sheets are in the style/ directory of the Lylina installation, and you can either change one of the existing files or create a new CSS file there. If you create a new style sheet, be sure to update the conf[‘pages_style’] entry in conf.php to indicate the file name of the new style sheet.

In my case, I substituted a larger logo for the default Lylina logo, which shifted the navigation on the screen. If you need to customize the navigation and form elements on the screen in ways that can’t be done through style sheet manipulations, find the html_navigation() function in inc/html.php, where you can control how the calendar navigation and the login and search forms are displayed.

For example, you can create new calendar links, that pass the amount of time in hours, to selectively display retrieved posts. In my case, I decided to run the feed update cron job once a day in the middle of the night, so the default calendar links that were less than a day in length didn’t make a whole lot of sense for me. Here is my customized list of calendar links:

print ‘<img src=”img/calendar.png” alt=”” /> ‘; print ”; print $lang[‘1day’]; print ”.NL; print ”; print $lang[‘1week’]; print ”.NL; print ”; print $lang[‘1month’]; print ”.NL; print ”; print $lang[‘1year’]; print ”.NL;

I also added this to the top of index.php to default to the weekly display:

if (! array_key_exists(‘hours’, $_REQUEST)) { $_REQUEST[‘hours’] = 168; }

And I added this to lang/en.inc.php to properly display the labels for the new calendar links I added:

$lang[‘1month’] = ‘1 month’; $lang[‘1year’] = ‘1 year’;

I also wanted to allow anyone to search feeds, not just logged in users, as Lylina functions by default. So, I again modified the html_navigation() function in inc/html.php to not check for $UID before displaying the search form. I also modified the search box to display the query text in the box on the results page:

print ‘<img src=”img/search.png” alt=”search” /> <input type=”text” name=”q” value=”‘.$_REQUEST[‘q’].'” />’.NL;

I then modified search.php, first by commenting out this section:

/* if(!$UID) { header(“HTTP/1.1 403 Forbidden”); die(‘Forbidden’); } */

Then, I modified the following section in the same file, adding the conditional check which otherwise returned an error when no results were found:

$items=array(); if (isset($results) && ! empty($results)) { $test = implode(“, “,$results); $sql = “SELECT A.id, A.url, A.title, A.body, B.name, B.url as feedurl, DATE_FORMAT(A.dt, ‘%H:%i’) as time, DATE_FORMAT(A.dt, ‘%W %D %M %Y’) as date FROM lylina_items A, lylina_feeds B, lylina_userfeeds C WHERE B.id = A.feed_id AND B.id = C.feed_id AND C.user_id = $UID AND A.id IN($test) ORDER BY A.id DESC LIMIT 50”; $items = runSQL($sql); }

For the same reason, I added the following condition:

if ( ! empty($rss->items)) {

…around this block starting at line 70 of fetch.php:

foreach($rss->items as $item) {

Finally, I created the following cron job to retrieve new posts:

01 3 * * * cd /usr/local/apache/htdocs/lylina && /opt/bin/php -q fetch.php

But if your system doesn’t have a command line binary for PHP, you can always call the URL for fetch.php using wget.

General Notes

  • In Lylina, for a feed to appear on the main page, it needs to have an entry in the lylina_userfeeds table with a user_id value of 0.
  • Feed names are automatically updated when feeds are fetched, so there is no need to add them initially, unless you want to give them a custom name.

Issues Encountered

  • When I log in and view preferences, the “your feeds | main feeds” links don’t appear to function correctly.
  • It appears that the search may not work properly, I can’t seem to get it to return results with searches of known strings.

Future Enhancements

At this point, I have spent a few hours customizing Lylina enough that I can demonstrate it to people and discuss its possible future use. Until I get approval to work on this officially, I probably won’t customize it further, or try to fix bugs. If I do get approval to work on this, I will try to be a better open source community member and work with the project developers to submit bug reports and fixes and perhaps add new functionality.

Some features and other changes I would propose and consider implementing would include:

  • search box javascript functionality like Mambo,
  • display search terms and obvious return links on results page,
  • user self registration/password reminder,
  • integration with Cornell’s authentication infrastructure,
  • just like all users should be able to search, all users should have ‘your feeds, main feeds’ links,
  • sharing vs. private user feeds,
  • user tags,
  • ‘starring’ posts,
  • integrate search with Cornell search?, and
  • OPML import/export.

In particular, tagging is of interest to me, because I want to implement similar features in other systems, and I would not only like the experience of implementing this feature, but I would want others in the library to get more comfortable with tagging from a user perspective so they can better understand the power of this social networking tool and how it might enhance other systems we support.

Related Post

The 416The 416

Last night during one of my final email checks of the day, I got an email message from a recruiter. What made this particular email interesting was that the recruiter