#!/usr/bin/perl
use strict;
use warnings;
=head1
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
http://creativecommons.org/licenses/by-nc-sa/3.0/
Gets YouTube playlists and puts them in videoqueue.xml file, suitable for Roksbox.
Reads playlist IDs and user names from playlists.txt
Format:
playlist_id name
user_id
Examples:
D5066BDDA2629460 notjaph's playlist for trains
notjaph
Or, you can use as a CGI script to turn a playlist into a RSS feed for
inclusion on Roksbox's videoqueue.xml file. See the sample XML file.
Youtube playlist XML link:
http://gdata.youtube.com/feeds/api/playlists/D5066BDDA2629460
Youtube users playlists:
http://gdata.youtube.com/feeds/base/users/notjaph/playlists/
=cut
my $debug=1;
my $my_url = "http://www.thesatya.com/cgi-bin/rry/get_playlists.pl";
my $playlist_url = 'http://gdata.youtube.com/feeds/api/playlists/';
my $user_url = 'http://gdata.youtube.com/feeds/base/users/';
use Data::Dumper;
use XML::LibXML;
use LWP::Simple;
use HTML::Template;
use CGI;
my $xpc = XML::LibXML::XPathContext->new;
$xpc->registerNs('atom', 'http://www.w3.org/2005/Atom');
$xpc->registerNs('yt', 'http://gdata.youtube.com/schemas/2007');
$xpc->registerNs('media', 'http://search.yahoo.com/mrss/');
my $now = scalar(localtime).' -0500';
sub xml_escape($) {
my $s=shift;
$s=~s/&/&/g;
return $s;
}
sub parse($) {
my $s = shift;
#my $dom=XML::LibXML->load_xml(string => $s);
my $parser = XML::LibXML->new();
my $dom = $parser->parse_string($s);
my $root = $dom->documentElement();
return $root;
}
sub get_value(@) {
# Given a DOM root and an XPath, return the value, defaulting to $default
my ($xpath, $root, $default) = @_;
my @nodes = $xpc->findnodes($xpath, $root);
foreach (@nodes) {
$default = $_->textContent;
}
return $default;
}
sub get_attr(@) {
# Given a DOM root and an XPath, return the attribute value, defaulting to $default
my ($xpath, $root, $attrname, $default) = @_;
my @nodes = $xpc->findnodes($xpath, $root);
foreach my $n (@nodes) {
foreach ($n->attributes()) {
if($attrname eq $_->nodeName) {
$default = $_->textContent;
}
}
}
return $default;
}
sub get_playlist(@) {
my $playlists=shift;
my $id=shift;
my $desc=shift || '';
warn "playlist: $id, $desc\n" if $debug;
my $data = get($playlist_url . $id);
return unless $data;
my $root = parse($data);
my $genrename=xml_escape get_value('/atom:feed/atom:title', $root, $id);
my $genre="[$desc$genrename]";
warn "$genre\n" if $debug;
my $authorname=xml_escape get_value('/atom:feed/atom:author/atom:name', $root, '');
my @nodes = $xpc->findnodes('/atom:feed/atom:entry', $root);
foreach my $item (@nodes) {
unless( exists $playlists->{$genre} ) {
$playlists->{$genre}={
'items' => [],
authorname => $authorname,
};
}
my $url = xml_escape get_attr('media:group/media:player', $item, 'url', '');
next unless $url;
my %attrs=(url => $url, pubDate => $now);
foreach ('atom:updated','atom:title','atom:author/atom:name') {
$attrs{$_} = xml_escape(get_value($_, $item, ''));
}
my $video_id = $url;
$video_id =~ s/.*\?//;
$video_id = new CGI($video_id)->param('v');
$attrs{'video_id'} = $video_id;
push @{ $playlists->{$genre}->{'items'} }, \%attrs;
}
}
sub get_user(@) {
my $playlists=shift;
my $id=shift;
warn "user: $id\n" if $debug;
my $data = get($user_url . $id . '/playlists');
my $root = parse($data);
my @nodes = $xpc->findnodes('/atom:feed/atom:entry/atom:id', $root);
#print $root->toStringC14N;
foreach (@nodes) {
my $pl_id = $_->textContent;
$pl_id=~s/^.*\///g;
get_playlist($playlists, $pl_id, "$id/");
}
}
sub read_file() {
open(I, "< playlists.txt") || die "Needs playlists.txt file";
my @lines=;
close(I);
my $playlists={};
foreach my $line (@lines) {
chomp $line;
$line=~s/\s+/ /g; # collapse multiple spaces
next if $line=~/^#/ || $line=~/^\s*$/; # skip comments and empty lines
$line =~ s/#.*//; # remove trailing comments
my ($id, $desc) = split(/ /, $line, 2);
if($desc) {
get_playlist($playlists, $id);
} else {
get_user($playlists, $id);
}
}
return $playlists;
}
sub write_file(@) {
my $playlists=shift;
my $tmpl_file=shift;
my $data=[];
foreach my $genre (sort keys %$playlists) {
my $urls = $playlists->{$genre}->{'items'};
my $urllist = '';
foreach my $u (@$urls) {
next if $u->{'url'} eq '';
$urllist .= "
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
HTML } if($ARGV[0] && $ARGV[0] eq 'cli') { my $playlists = read_file; write_file($playlists, 'videoqueue.tmpl.xml'); } else { my $q=new CGI; my $id=$q->param('id'); my $pl_id=$q->param('pl_id'); if($id) { if($id eq 'get_code') { send_file("get_playlists.pl"); } elsif($id eq 'get_queuefile') { send_file("videoqueue.sample"); } elsif($id eq 'get_rssfile') { send_file("rss.tmpl.xml"); } else { my $playlists={}; get_playlist($playlists, $id); return_playlist_rss($playlists, $id); } } elsif($pl_id) { print "Content-type: text/plain\n\nYour RSS feed URL is: $my_url?id=$pl_id\n"; } else { print_page; } }