#!/usr/bin/perl # Local configuration $use_auth = 1; my $username = "SOMEBODY"; my $password = "SOMEPASSWORD"; my $owner = "SOME@EMAIL.ADDRESS"; $ENV{'QUERY_STRING'} = 'user=$username'; my $no_http = 1; # Set this to avoid querying LJ - for testing only! my $cache_override = 0; # Also see $limit, $cache_folder, etc below. ############################################################################ # # Friend RSS Generator # Written by Ben Gutierrez (nullmemoirs) # Local (non-CGI) operation and updates by Daniel Jacobowitz # # Usage: # http://www.domain.com/cgi-bin/ljfriendfeed.pl?user=username # http://www.domain.com/cgi-bin/ljfriendfeed.pl?user=username&limit=5 # http://www.domain.com/cgi-bin/ljfriendfeed.pl?user=username&friend=stalked1&friend=stalked2 # http://www.domain.com/cgi-bin/ljfriendfeed.pl?user=username&skip=5 # http://www.domain.com/cgi-bin/ljfriendfeed.pl?user=username&rmfriend=unwanted # # Installation: Very easy. Just drop it in your cgi-bin. Needs only # LWP::Simple # # Creating a cache folder is highly recommended. Make sure it is writeable # by the web server. # # Email me at mowgli@mowgli.org # ############################################################################ # Uncomment for LWP::Simple logging. # use LWP::Debug qw(+); use LWP::Simple qw(get mirror $ua); $ua->agent("ljfriendfeed.pl; $owner; "); if ($use_auth) { $ua->credentials ('www.livejournal.com:80', 'lj', $username, $password); } # Use this to set the limit my $limit = 1000; # Uncomment this to use a cache (Recommended highly!) # my $cache_folder = '/home/user/lj'; my $cache_enabled = (defined($cache_folder) && -d $cache_folder && -w $cache_folder); if (!$no_http) { print "Content-Type: text/xml; charset=utf-8\n\n"; } # So far, only works if there is a user. if ($ENV{'QUERY_STRING'} =~ /user=(\w+)/ ) { make_feed($1); } else { print error_message('no user') and die; }; # Primary function # Usage: makefeed('user_name'); sub make_feed{ my $user = shift; my @friends = friends($user); # RSS Beginning print " Friends of $user http://www.livejournal.com/users/$user/friends News Feed of all $user's friends. http://www.mowgli.org/cgi-bin/ljfriendfeed.pl\n"; print all_feeds(@friends); #RSS End print "\n"; } # Returns all friends for user, plus any in the url. # Usage: friends('user_name') sub friends { my $user = shift; # The user data is always generated new. my $user_info = get "http://www.livejournal.com/users/$user/data/foaf"; if (!$user_info) { print error_message('no server') and die; } # Friends of user my @user_friends; while ($user_info =~ s/(\w*?)/) { my $friend = $1; next if ($ENV{'QUERY_STRING'} =~ /rmfriend=($friend)/); push @user_friends, $friend; } # Friends in the url. if (my @q_friends = $ENV{'QUERY_STRING'} =~ /[^m]friend=(\w+)/g) { push @user_friends, @q_friends; } # First friend is the user. Baleeted! shift @user_friends; return @user_friends; } # Get friends, get feeds for each, # sort them, return them. # Usage: all_feeds(@friend_list) sub all_feeds { my @friends = @_; my @feeds; push @feeds, news_feed($_) foreach(@friends); @feeds = sort by_date @feeds; # Skip feature @feeds = splice(@feeds, $1) if ($ENV{'QUERY_STRING'} =~ /skip=(\d+)/); # Set the appropriate limit. $limit = $1 if ($ENV{'QUERY_STRING'} =~ /limit=(\d+)/ && $1 < $limit); @feeds = @feeds[0 .. ($limit-1)]; return @feeds; } # Gets a feed for one user # Usage: news_feed('user_name') sub news_feed { my $user = shift; my $rss; my $url = "http://www.livejournal.com/users/$user/data/rss"; if ($use_auth) { $url .= "?auth=digest"; # Around 2006-01-18 LiveJournal switched to using redirects... if ($user =~ /^_/) { $ua->credentials ("users.livejournal.com:80", 'lj', $username, $password); } else { my $tmpuser = $user; $tmpuser =~ s/_/-/g; $ua->credentials ("${tmpuser}.livejournal.com:80", 'lj', $username, $password); } } # Use a cache whenever possible. if ($cache_enabled) { my $local_copy = "$cache_folder/$user.xml"; if (!$cache_override || !-e $local_copy) { mirror($url, $local_copy); } $rss = `cat $local_copy`; } else { $rss = get($url); } # Just return if there are no feeds if (!$rss) { return; } my @items; # Gets each item and sticks it in an array. while($rss =~ /(.*?<\/item>)/sg) { my $item = $1; # If there isn't a title, make one based on description. unless ($item =~ s/(.*)<\/title>/<title>$user - $1<\/title>/) { $item =~ /<description>(.*)<\/description>/s; my $content = $1; $content =~ s/<br \/>.*/./g; # Remove everything after first <br /> $content =~ s/<.*?>//g; # Remove tags (may be assuming too much here) $content =~ s/(.+?[\.\n!\?]).*/$1/sg; # Remove everything after end of first sentance # Insert title after pubDate $item =~ s/<\/pubDate>/<\/pubDate>\n<title>$user - $content<\/title>/; } push @items, $item; } return @items; } # Sorting function for items based on date. sub by_date { $a =~ /<pubDate>.* (\d\d) (\w+) (\d{4}) ([\d:]+).*<\/pubDate>/; my $mon = month_to_num($2); my $a_date = "$3$mon$1$4"; $b =~ /<pubDate>.* (\d\d) (\w+) (\d{4}) ([\d:]+) .*<\/pubDate>/; $mon = month_to_num($2); my $b_date = "$3$mon$1$4"; $b_date cmp $a_date; } # Simple month to number conversion. sub month_to_num { my $month = shift; return '01' if ($month eq 'Jan'); return '02' if ($month eq 'Feb'); return '03' if ($month eq 'Mar'); return '04' if ($month eq 'Apr'); return '05' if ($month eq 'May'); return '06' if ($month eq 'Jun'); return '07' if ($month eq 'Jul'); return '08' if ($month eq 'Aug'); return '09' if ($month eq 'Sep'); return '10' if ($month eq 'Oct'); return '11' if ($month eq 'Nov'); return '12'; } # Handle an error or two. sub error_message { my $error_type = shift; my $error; if ($error_type eq 'no server') { $error = "Unable to connect to livejournal.com"; } elsif ($error_type eq 'no user') { $error = "No user: Use http://www.mowgli.org/cgi-bin/ljfriendfeed.pl?user=username"; } my $error_message = "<rss version=\"2.0\"> <channel> <title>Empty Feed - $error "; # # $error # return $error_message; }