tidy.
[umph.git] / bin / umph
blob9ffa53384a80a2f24452a5f0dcb96d65fd96c7bd
1 #!/usr/bin/perl
2 # -*- coding: ascii -*-
5 # Copyright (C) 2010 Toni Gundogdu <legatvs@gmail.com>.
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 use warnings;
22 use strict;
24 binmode( STDOUT, ":utf8" );
25 binmode( STDERR, ":utf8" );
27 use Getopt::ArgvFile( home => 1, startupFilename => [qw(.umphrc)] );
28 use Getopt::Long qw(:config bundling);
30 my $VERSION = "0.1.1";
31 my %config;
32 my @entries;
33 my $done = 0;
35 init();
36 main();
37 exit 0;
39 sub init {
40 GetOptions(
41 \%config,
42 'interactive|i',
43 'version|v' => \&print_version,
44 'help|h' => \&print_help,
45 ) or exit(1);
48 sub print_version {
49 print
50 "umph $VERSION. Copyright (C) 2010 Toni Gundogdu. License: GNU GPL version 3
51 or later This is free software; see the source for copying conditions. There
52 is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
53 PURPOSE.
55 exit(0);
58 sub print_help {
59 require Pod::Usage;
60 Pod::Usage::pod2usage( -exitstatus => 0, -verbose => 1 );
63 sub main {
65 print_help if scalar @ARGV == 0;
67 my $req_body = "http://gdata.youtube.com/feeds/api/playlists/";
69 my $url = $ARGV[0];
71 if ( $url =~ /^http:/i ) {
73 # Looks like an URL.
74 if ( $url =~ /view_play_list\?p=(.*?)$/i ) {
75 $url = "$req_body$1";
78 else {
80 # Assume playlist id.
81 $url = "$req_body$url";
83 $url .= "?v=2";
85 print STDERR "Fetch $url ...\n";
87 require XML::DOM;
89 my $p = new XML::DOM::Parser;
90 my $doc = $p->parsefile($url);
91 my $root = $doc->getDocumentElement;
93 print STDERR ":: Parse playlist for video entries ...\n";
95 for my $entry ( $root->getElementsByTagName("entry") ) {
97 my $title = to_item( $entry, "title" )->getFirstChild->getNodeValue;
99 my $link
100 = to_item( $entry, "link" )->getAttributeNode("href")->getValue;
102 my %data = ( title => $title, url => $link, selected => 1 );
103 push @entries, \%data;
106 $doc->dispose;
108 print STDERR "::: Found " . scalar @entries . " video entries\n";
110 prompt() if $config{interactive};
112 foreach (@entries) {
113 print "$_->{url}\n" if $_->{selected} || !$config{interactive};
117 sub to_item {
118 my ( $entry, $name ) = @_;
119 return $entry->getElementsByTagName($name)->item(0);
122 sub prompt {
123 my $p = "(umph) ";
124 my %cmds = (
125 'h' => \&help,
126 'q' => \&quit,
127 'l' => \&list,
128 'd' => \&dump,
129 'a' => \&select_all,
130 'n' => \&select_none,
131 'r' => \&revert_selection,
133 print STDERR "Enter prompt\nNote: all videos selected by default\n";
134 print STDERR "Type \"help\" to get a list of commands\n";
135 while ( !$done ) {
136 print STDERR $p;
137 my $ln = <STDIN>;
138 next if !$ln;
139 chomp $ln;
140 if ( $ln =~ /(\d+)/ ) {
141 toggle_number($1);
143 else {
144 next if $ln !~ /(\w)/;
145 $cmds{$1}() if defined $cmds{$1};
150 sub toggle_number {
151 my $i = (shift) - 1;
152 if ( $i >= 0 && exists $entries[$i] ) {
153 $entries[$i]->{selected} = !$entries[$i]->{selected};
154 list();
156 else {
157 printf STDERR "error: out of range\n";
161 sub help {
162 print STDERR "
163 Commands:
164 help .. this
165 list .. display playlist entries (numbered, *=selected)
166 all .. select all videos
167 none .. select none
168 revert .. revert selection
169 (number) .. toggle (select, unselect) video, see list output
171 dump .. dump selected video urls to stdout and exit
172 quit .. terminate program
174 Command name abbreviations are allowed, e.g. \"a\" instead of \"all\".
178 sub quit {
179 exit 0;
182 sub list {
183 my $i = 0;
184 foreach (@entries) {
185 printf STDERR "%2d: $_->{title}%s\n", ++$i, $_->{selected} ? "*" : "";
189 sub dump {
190 $done = 1;
193 sub select_all {
194 $_->{selected} = 1 foreach @entries;
195 list();
198 sub select_none {
199 $_->{selected} = 0 foreach @entries;
200 list();
203 sub revert_selection {
204 $_->{selected} = !$_->{selected} foreach @entries;
205 list();
208 __END__
210 =head1 NAME
212 umph - Youtube video playlist parser for cclive and alike tools
214 =head1 SYNOPSIS
216 umph [options] [URL|PLAYLIST_ID]
218 =head1 DESCRIPTION
220 umph is a command line tool for parsing Youtube playlists.
221 It was written to be used with cclive but other tools may
222 use it also.
224 =head1 OPTIONS
226 -h, --help print help and exit
227 -v, --version print version and exit
228 -i, --interactive be interactive, default is no
230 =head1 OPTIONS DESCRIPTIONS
232 =over 4
234 =item B<-h, --help>
236 Print help and exit.
238 =item B<-v, --version>
240 Print version and exit.
242 =item B<-i, --interactive>
244 Be interactive, default is no. Implies prompting, or selecting videos.
246 =back
248 =head1 EXAMPLES
250 =over 4
252 =item umph "http://www.youtube.com/view_play_list?p=AAF3A1D0CA1E304F"
254 =item umph "http://gdata.youtube.com/feeds/api/playlists/AAF3A1D0CA1E304F?v=2"
256 =item umph AAF3A1D0CA1E304F
258 All of the three above do the same.
260 =item umph AAF3A1D0CA1E304F | cclive -f mp4
262 Passes the parsed video links to cclive.
264 =back
266 =head1 EXIT STATUS
268 Exits 0 on success, otherwise 1.
270 =head1 FILES
272 =over 4
274 =item $HOME/.umphrc, for example:
276 echo "--interactive" >> ~/.umphrc
278 =back
280 =head1 OTHER
282 umph depends on XML::DOM which uses LWP::UserAgent to retrieve
283 the playlist data. Note that LWP::UserAgent reads http_proxy
284 environment setting.
286 Project:
287 http://umph.googlecode.com/
289 Development repository:
290 git clone git://repo.or.cz/umph.git
292 =head1 SEE ALSO
294 C<cclive(1)> C<clive(1)>
296 =head1 AUTHOR
298 Toni Gundogdu <legatvs@gmail.com>
300 =cut