#!perl
use strict;
use warnings;
use URI;
use URI::QueryParam;
use XML::TreePP;
use WWW::YouTube::Download;
use Getopt::Long qw(GetOptions :config bundling);
use Pod::Usage qw(pod2usage);

my $api_url = 'http://gdata.youtube.com/feeds/api/playlists';

my $proxy     = undef;
GetOptions(
    'C|no-colors!' => \my $disable_colors,
    'p|proxy=s'    => \$proxy,
    'v|verbose'    => \my $verbose,
    'h|help'       => sub { pod2usage(exitval => 0, -noperldoc => 1, -verbose => 2) },
    'V|version'    => sub { show_version() },
) or pod2usage(2);
pod2usage() unless @ARGV;

my $ua  = WWW::YouTube::Download->new->ua;
my $tpp = XML::TreePP->new;

if($proxy){
    $ua->proxy(['http','https'] => $proxy);
	print "--> Using proxy $proxy\n";
}

main: {
    for my $id_or_url (@ARGV) {
        chatty("--> Working on %s\n", $id_or_url);
        my $id = find_playlist_id($id_or_url);
        throw('%s is not supported arguments', $id_or_url) unless $id;
        my $xml = fetch_playlist_xml($id);
        my $urls = find_video_urls($xml);
        local $\ = "\n"; # auto print @_, "\n"
        print join "\n", @$urls;
    }
}

sub fetch_playlist_xml {
    my $id = shift;
    my $url = sprintf '%s/%s?v=2', $api_url, $id;
    chatty('Fetching %s ... ', $url);
    my $res = $ua->get($url);
    unless ($res->is_success) {
        throw('%s: %s', $id, $res->status_line);
    }
    chatty(pcolor(['green'], "done\n"));
    return $res->decoded_content;
}

sub find_video_urls {
    my $xml = shift;
    my $urls = [];
    chatty('Parsing XML ... ');
    my $tree = $tpp->parse($xml);
    for my $entry (@{ $tree->{feed}{entry} || [] }) {
        my $uri = URI->new($entry->{'media:group'}{'media:player'}{-url});
        $uri->query_param_delete('feature');
        push @$urls, $uri->as_string;
    }
    chatty(pcolor(['green'], "done\n"));
    return $urls;
}

sub find_playlist_id {
    my $id_or_url = shift || return;
    if ($id_or_url =~ /^http/) {
        ($id_or_url) = $id_or_url =~ m/list=PL([0-9A-F]+)/;
    }
    else {
        $id_or_url =~ s/^PL//;
    }
    return $id_or_url;
}

sub throw {
    my $format = shift;
    die pcolor(['red'], sprintf($format, @_)), "\n";
}

sub chatty {
    return unless $verbose;
    my $format = shift;
    print STDERR sprintf $format, @_;
}

sub pcolor {
    my ($color, @msg) = @_;

    if ($^O eq 'MSWin32' || $disable_colors || !-t STDOUT) {
        return @msg;
    }

    eval { require Term::ANSIColor };
    return @msg if $@; # module not available
    return Term::ANSIColor::colored($color, @msg);
}

sub show_version {
    print "youtube-playlists (WWW::YouTube::Download) version $WWW::YouTube::Download::VERSION\n";
    exit;
}
__END__

=head1 NAME

youtube-playlists - Find a YouTube video urls from playlis(s)

=head1 SYNOPSIS

  # print the list of video urls
  $ youtube-playlists http://www.youtube.com/playlist?list=PLB199169FA7413767
  $ youtube-playlists PLB199169FA7413767
  $ youtube-playlists B199169FA7413767

  # with youtube-download
  $ youtube-playlists B199169FA7413767 | youtube-download
  
  # with socks proxy
  $ youtube-playlists -p socks://<some IP>:<some port>/ B199169FA7413767

=head1 OPTIONS

=over

=item -C, --no-colors

Force disable colored output

=item -p, --proxy

Use the given proxy. Note that using a socks proxy requires LWP::protocol::socks to be installed.

=item -v, --verbose

truns on chatty output

=item -h, --help

display help

=item -V, --version

display version

=back

=head1 AUTHOR

Yuji Shiamda (xaicron)