Replace spew_e with say stderr
[umph.git] / bin / umph
blobe2df04c213cf18c17d7aa231fdeb6ed107141d61
1 #!/usr/bin/perl
2 # -*- coding: ascii -*-
4 # umph
5 # Copyright (C) 2010-2011 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;
23 use v5.10;
25 binmode STDOUT, ":utf8";
26 binmode STDERR, ":utf8";
28 use version 0.77 (); our $VERSION = version->declare("0.1.9");
30 use Getopt::ArgvFile(home => 1, startupFilename => [qw(.umphrc)]);
31 use Getopt::Long qw(:config bundling);
33 exit main();
35 my %config;
37 sub init
39 GetOptions(
40 \%config,
41 'type|t=s',
42 'start_index|start-index|s=s',
43 'max_results|max-results|m=s',
44 'interactive|i',
45 'json',
46 'csv',
47 'proxy=s',
48 'no_proxy|no-proxy',
49 'quiet|q',
50 'version' => sub {say "umph version $VERSION"; exit 0},
51 'license' => \&print_license,
52 'help' => \&print_help,
53 ) or exit 1;
55 $config{type} ||= 'p'; # Default to "playlist".
56 $config{start_index} ||= 1; # Default to 1.
57 $config{max_results} ||= 25; # Default 25.
60 sub print_license
62 print "# Copyright (C) 2010-2011 Toni Gundogdu.
64 # This program is free software: you can redistribute it and/or modify
65 # it under the terms of the GNU General Public License as published by
66 # the Free Software Foundation, either version 3 of the License, or
67 # (at your option) any later version.
69 # This program is distributed in the hope that it will be useful,
70 # but WITHOUT ANY WARRANTY; without even the implied warranty of
71 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
72 # GNU General Public License for more details.
74 # You should have received a copy of the GNU General Public License
75 # along with this program. If not, see <http://www.gnu.org/licenses/>.
77 exit 0;
80 sub print_help
82 require Pod::Usage;
83 Pod::Usage::pod2usage(-exitstatus => 0, -verbose => 1);
86 sub spew_qe {print STDERR @_ unless $config{quiet}}
88 my @items;
90 sub main
92 init;
93 print_help if scalar @ARGV == 0;
94 spew_qe "Checking ... ";
96 require LWP;
97 my $a = new LWP::UserAgent;
98 $a->env_proxy; # http://search.cpan.org/perldoc?LWP::UserAgent
99 $a->proxy('http', $config{proxy}) if $config{proxy};
100 $a->no_proxy('') if $config{no_proxy};
102 require XML::DOM;
104 my $p = new XML::DOM::Parser(LWP_UserAgent => $a);
105 my $doc = $p->parsefile(from_arg($ARGV[0]));
106 my $root = $doc->getDocumentElement;
108 for my $entry ($root->getElementsByTagName("entry"))
110 my $t = to_item($entry, "title")->getFirstChild->getNodeValue;
111 my $l = to_item($entry, "link")->getAttributeNode("href")->getValue;
112 my %data = (title => $t, url => $l, selected => 1);
113 push @items, \%data;
114 spew_qe ".";
116 $doc->dispose;
118 spew_qe "done.\n";
120 say STDERR "error: nothing found." and return 1
121 unless scalar @items;
123 prompt() if $config{interactive};
125 if ($config{json}) {print qq/{\n "video": [\n/}
127 my $i = 0;
129 foreach (@items)
131 if ($_->{selected} or not $config{interactive})
133 ++$i;
135 my $t = $_->{title} || "";
136 $t =~ s/"/\\"/g;
138 if ($config{json})
140 print ",\n" if $i > 1;
141 print " {\n"
142 . qq/ "title": "$t",\n/
143 . qq/ "url": "$_->{url}"\n/ . " }",
146 elsif ($config{csv}) {print qq/"$t","$_->{url}"\n/}
147 else {print "$_->{url}\n"}
151 if ($config{json}) {print "\n ]\n}\n"}
155 sub from_arg
157 my ($arg0, $u) = @_;
159 my $c = "http://gdata.youtube.com/feeds/api";
161 if ($config{type} eq "u" or $config{type} eq "uploads")
163 $u = "$c/users/$arg0/uploads?v=2";
165 elsif ($config{type} eq "f" or $config{type} eq "favorites")
167 $u = "$c/users/$arg0/favorites?v=2";
169 else
171 $u = "$c/playlists/$arg0?v=2";
174 $u .= "&start-index=$config{start_index}";
175 $u .= "&max-results=$config{max_results}";
179 sub to_item
181 my ($entry, $name) = @_;
182 $entry->getElementsByTagName($name)->item(0);
185 my $done = 0;
187 sub prompt
189 my %cmds = (
190 'h' => \&help,
191 'q' => sub {exit 0},
192 'd' => sub {$done = 1},
193 'l' => \&list,
194 'a' => \&select_all,
195 'n' => \&select_none,
196 'r' => \&revert_selection,
199 say STDERR qq/Enter prompt. Type "help" to get a list of commands./;
200 list();
202 use constant P => "(umph) ";
204 while (not $done)
206 print STDERR P;
208 my $ln = <STDIN>;
209 next unless $ln;
210 chomp $ln;
212 if ($ln =~ /(\d+)/) {toggle_number($1)}
213 else
215 next if $ln !~ /(\w)/;
216 $cmds{$1}() if defined $cmds{$1};
221 sub toggle_number
223 my $i = (shift) - 1;
224 if ($i >= 0 && exists $items[$i])
226 $items[$i]->{selected} = not $items[$i]->{selected};
227 list();
229 else {say STDERR "error: out of range"}
232 sub help
234 say STDERR qq/Commands:
235 help .. this
236 list .. list found videos (> indicates selected)
237 all .. select all videos
238 none .. select none
239 revert .. revert selection
240 (number) .. toggle (select, unselect) video, see list output
241 dump .. dump selected video urls to stdout and exit
242 quit .. terminate program
243 Command name abbreviations are allowed, e.g. "a" instead of "all"./;
246 sub list
248 my $i = 0;
249 foreach (@items)
251 printf STDERR "%2s%02d: $_->{title}\n", $_->{selected}
252 ? ">"
253 : "",
254 ++$i;
258 sub select_all
260 $_->{selected} = 1 foreach @items;
261 list();
264 sub select_none
266 $_->{selected} = 0 foreach @items;
267 list();
270 sub revert_selection
272 $_->{selected} = not $_->{selected} foreach @items;
273 list();
276 __END__
278 =head1 SYNOPSIS
280 umph [-q] [-i] [--csv | --json] [-t E<lt>typeE<gt>]
281 [--proxy E<lt>addrE<gt> | --no-proxy]
282 [E<lt>playlist_idE<gt> | E<lt>usernameE<gt>]
284 =head1 OPTIONS
286 --help Print help and exit
287 --version Print version and exit
288 --license Print license and exit
289 -q, --quiet Be quiet
290 -i, --interactive Run in interactive mode
291 -t, --type arg (=p) Get feed type
292 -s, --start-index arg (=1) Index of first matching result
293 -m, --max-results arg (=25) Max number of results included
294 --json Print details in JSON
295 --csv Print details in CSV
296 --proxy arg (=http_proxy) Use proxy for HTTP connections
297 --no-proxy Disable use of HTTP proxy
299 =cut
301 # vim: set ts=4 sw=4 tw=72 expandtab: