123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- #!/usr/bin/perl
- # List and play the most recent videos from: https://www.wimp.com/
- # Requires 'youtube-viewer' and 'mpv'
- use 5.010;
- use strict;
- use warnings;
- use open ':std' => ':utf8';
- use Encode qw(encode_utf8);
- use XML::Fast qw(xml2hash);
- use Term::ANSIColor qw(colored);
- use Getopt::Std qw(getopts);
- my $appname = 'wimp-viewer';
- my $version = '0.33';
- my $BASE_URL = 'https://www.wimp.com';
- require Term::ReadLine;
- my $term = Term::ReadLine->new($appname);
- require WWW::Mechanize;
- my $mech = WWW::Mechanize->new(
- autocheck => 1,
- env_proxy => 1,
- show_progress => 0,
- agent => 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1941.0 Safari/537.36',
- );
- $mech->default_header('Accept-Encoding' => scalar HTTP::Message::decodable());
- sub output_usage {
- print <<"HELP";
- usage: $0 [options] [url]
- options:
- -f : fullscreen mode
- -r <i> : play i of random videos and exit
- -v : print the version number and exit
- -h : print this help message and exit
- HELP
- }
- sub output_version {
- say "$appname $version";
- }
- my %opt;
- if (@ARGV) {
- getopts('r:fvh', \%opt);
- }
- if ($opt{h}) {
- output_usage();
- exit 0;
- }
- if ($opt{v}) {
- output_version();
- exit 0;
- }
- if (exists $opt{r}) {
- if (defined($opt{r}) and $opt{r} > 0) {
- for my $i (1 .. $opt{r}) {
- play_random_video();
- }
- }
- else {
- die "error: option '-r' requires a positive integer!\n";
- }
- exit;
- }
- # Play the command-line URIs
- foreach my $url (@ARGV) {
- play($url);
- exit;
- }
- sub play {
- my ($url) = @_;
- my $resp = $mech->get($url);
- my $content = $resp->decoded_content // $resp->content;
- my $real_url = $mech->uri;
- if ( $content =~ m{\byoutube\.com/watch\?v=([\w-]{11})"}
- or $content =~ m{<div data-autoplay='1' data-start='0' data-id='([\w-]{11})'}
- or $content =~ m{src="https://www.youtube.com/embed/([\w-]{11})}) {
- system 'youtube-viewer', "--no-interactive", "--id=$1", ($opt{f} ? '-fs' : ());
- }
- elsif ( $content =~ /"file"\h*,\h*"(.*?)"/
- or $content =~ m{source type="video/mp4" src="(https://.*?)"}) {
- system('mpv', ($opt{f} ? '--fullscreen' : ()), $1);
- }
- else {
- warn "error: can't find any streaming URL for: $real_url\n";
- return;
- }
- return 1;
- }
- my @results;
- foreach my $url ("$BASE_URL/feed/?hot=1", "$BASE_URL/feed/") {
- my $hash_xml = xml2hash(encode_utf8($mech->get($url)->decoded_content));
- push @results, @{$hash_xml->{rss}{channel}{item}};
- }
- sub play_picked_videos {
- my (@list) = @_;
- $#list >= 0 or return;
- foreach my $num (@list) {
- play($results[$num - 1]->{link});
- }
- return 1;
- }
- sub play_random_video {
- play("$BASE_URL/random/");
- return 1;
- }
- sub parse_date {
- my ($date) = @_;
- # Turns "Mon, 06 Feb 2012 00:00:00 -0600" into "Feb 06"
- if ($date =~ /^\S+ (\d+) (\S+)/) {
- return "$2 $1";
- }
- return $date // '';
- }
- {
- print "\n";
- my $num = 0;
- foreach my $video (@results) {
- $video->{title} =~ s/\s*\[VIDEO\]//;
- printf "%s. %s [%s]\n", colored(sprintf("%2d", ++$num), 'bold'), $video->{title}, parse_date($video->{pubDate});
- }
- {
- my $line = $term->readline(colored("\n=>> Insert a number ('?' for help)", 'bold') . "\n> ");
- if ($line eq 'help' or $line eq '?') {
- print "\n", <<'STDIN_HELP';
- i : play the corresponding video
- all : play all the video results
- 3-8, 3..8 : same as 3 4 5 6 7 8
- /my?[regex]*$/ : play videos matched by a regex (/i)
- q, quit, exit : exit application
- STDIN_HELP
- redo;
- }
- elsif ($line =~ /^(?:q|quit|exit)\z/) {
- exit 0;
- }
- elsif ($line eq 'all') {
- play_picked_videos(1 .. @results);
- }
- elsif ($line =~ m{^/(.*?)/\h*$}) {
- my $match = eval { qr/$1/i };
- if ($@) {
- warn "\nError in regex: $@\n";
- redo;
- }
- play_picked_videos(grep { $results[$_ - 1]->{'title'} =~ /$match/ } 1 .. @results) || do {
- warn "\n(X_X) No video matched by the regex: /$match/\n";
- redo;
- };
- }
- elsif ($line =~ /\d/ and not $line =~ /(?>\s|^)[^\d-]/) {
- $line =~ s/(\d+)(?>-|\.\.)(\d+)/join q{ }, $1 .. $2;/eg; # '2..5' or '2-5' to '2 3 4 5'
- play_picked_videos(grep { $_ > 0 and $_ <= @results if /^\d+$/ } split(/[\s[:punct:]]+/, $line));
- }
- elsif ($line =~ /^(?:r|random)\z/) {
- play_random_video();
- }
- elsif ($line =~ m{^https?://.}) {
- play($_);
- }
- }
- redo;
- }
|