add youtube search script
This commit is contained in:
parent
b49131d8ea
commit
1c79066fe7
2
README
2
README
|
@ -2,3 +2,5 @@ unweb er min samling af forskellige scripts til at undgå at bruge webapps.
|
|||
|
||||
tv2east.dk/getlive.sh
|
||||
Udtræk HLS playlist til Livestream af TV2Øst.
|
||||
youtube.com/search.pl
|
||||
Søg på youtube.
|
||||
|
|
21
youtube.com/README
Normal file
21
youtube.com/README
Normal file
|
@ -0,0 +1,21 @@
|
|||
Search youtube.
|
||||
|
||||
The script can only show the first page of results.
|
||||
|
||||
Usage: ./search.pl [--sort][--uploaded][--type][--duration][--features] QUERY
|
||||
|
||||
Options:
|
||||
--sort upload|views|rating|relevance
|
||||
--uploaded hour|day|week|month|year
|
||||
--type video|channel|playlist|movie
|
||||
--duration short|long
|
||||
--features live|4k|hd|sub|cc|360|vr180|3d|hdr|location|purchased
|
||||
|
||||
Dependencies:
|
||||
use Encode;
|
||||
use JSON::XS;
|
||||
use HTML::TreeBuilder 5 -weak;
|
||||
use LWP;
|
||||
use LWP::UserAgent;
|
||||
use MIME::Base64;
|
||||
use Getopt::Long;
|
243
youtube.com/search.pl
Executable file
243
youtube.com/search.pl
Executable file
|
@ -0,0 +1,243 @@
|
|||
#!/usr/bin/perl
|
||||
# Copyright (c) 2021 smpl <smpl@slamkode.ml>
|
||||
# SPDX-Identifier: Zlib
|
||||
|
||||
use Encode;
|
||||
use JSON::XS;
|
||||
use HTML::TreeBuilder 5 -weak;
|
||||
use LWP;
|
||||
use LWP::UserAgent;
|
||||
use MIME::Base64;
|
||||
use Getopt::Long;
|
||||
use strict;
|
||||
|
||||
sub print_help {
|
||||
print "Usage: " . $0 . " [--sort][--uploaded][--type][--duration][--features] QUERY\n" .
|
||||
"--sort upload|views|rating|relevance\n" .
|
||||
"--uploaded hour|day|week|month|year\n" .
|
||||
"--type video|channel|playlist|movie\n" .
|
||||
"--duration short|long\n" .
|
||||
"--features live|4k|hd|sub|cc|360|vr180|3d|hdr|location|purchased\n\n";
|
||||
}
|
||||
|
||||
sub parse_cli {
|
||||
my %options = (
|
||||
"sort" => {
|
||||
"upload" => "\x08\x02",
|
||||
"views" => "\x08\x03",
|
||||
"rating" => "\x08\x01",
|
||||
"relevance" => "\x08\x00"
|
||||
},
|
||||
"uploaded" => {
|
||||
"hour" => "\x08\x01",
|
||||
"day" => "\x08\x02",
|
||||
"week" => "\x08\x03",
|
||||
"month" => "\x08\x04",
|
||||
"year" => "\x08\x05"
|
||||
},
|
||||
"type" => {
|
||||
"video" => "\x10\x01",
|
||||
"channel" => "\x10\x02",
|
||||
"playlist" => "\x10\x03",
|
||||
"movie" => "\x10\x04"
|
||||
},
|
||||
"duration" => {
|
||||
"short" => "\x18\x01",
|
||||
"long" => "\x18\x02"
|
||||
},
|
||||
"features" => {
|
||||
"live" => "\x40\x01",
|
||||
"4k" => "\x70\x01",
|
||||
"hd" => "\x20\x01",
|
||||
"sub" => "\x28\x01",
|
||||
"cc" => "\x30\x01",
|
||||
"360" => "\x78\x01",
|
||||
"vr180" => "\xd0\x01\x01",
|
||||
"3d" => "\x38\x01",
|
||||
"hdr" => "\xc8\x01\x01",
|
||||
"location" => "\xb8\x01\x01",
|
||||
"purchased" => "\x48\x01"
|
||||
}
|
||||
);
|
||||
|
||||
my ($sp, $sp_raw);
|
||||
my ($sort, $uploaded, $type, $duration, $features);
|
||||
my $filter_bytes = 0;
|
||||
my $filter = "";
|
||||
|
||||
GetOptions(
|
||||
"sort:s" => \$sort,
|
||||
"uploaded:s" => \$uploaded,
|
||||
"type:s" => \$type,
|
||||
"duration:s" => \$duration,
|
||||
"features:s" => \$features
|
||||
) or die("Error in command line arguments\n");
|
||||
|
||||
if($sort && defined($options{"sort"}{$sort})) {
|
||||
$sp_raw = $options{"sort"}{$sort};
|
||||
}
|
||||
|
||||
if($type ne "video" && $type ne "movie") {
|
||||
if($duration && defined($options{"duration"}{$duration})) {
|
||||
print "\n--duration can only be combined with type video or movie.\n\n";
|
||||
print_help;
|
||||
exit 1;
|
||||
}
|
||||
if($features && defined($options{"features"}{$features})) {
|
||||
print "\n--features can only be combined with type video or movie.\n\n";
|
||||
print_help;
|
||||
exit 1;
|
||||
}
|
||||
if($uploaded && defined($options{"uploaded"}{$uploaded})) {
|
||||
print "\n--uploaded can only be combined with type video or movie.\n\n";
|
||||
print_help;
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
|
||||
if($uploaded && defined($options{"uploaded"}{$uploaded})) {
|
||||
$filter_bytes += bytes::length($options{"uploaded"}{$uploaded});
|
||||
$filter .= $options{"uploaded"}{$uploaded};
|
||||
}
|
||||
if($type && defined($options{"type"}{$type})) {
|
||||
$filter_bytes += bytes::length($options{"type"}{$type});
|
||||
$filter .= $options{"type"}{$type};
|
||||
}
|
||||
if($duration && defined($options{"duration"}{$duration})) {
|
||||
$filter_bytes += bytes::length($options{"duration"}{$duration});
|
||||
$filter .= $options{"duration"}{$duration};
|
||||
}
|
||||
if($features && defined($options{"features"}{$features})) {
|
||||
$filter_bytes += bytes::length($options{"features"}{$features});
|
||||
$filter .= $options{"features"}{$features};
|
||||
}
|
||||
|
||||
if($filter_bytes > 0) {
|
||||
$sp = encode_base64($sp_raw . "\x12" . chr($filter_bytes) . $filter);
|
||||
} else {
|
||||
$sp = encode_base64($sp_raw);
|
||||
}
|
||||
|
||||
$sp =~ s/([+\/=])/sprintf("%%25%02X", ord($1))/eg;
|
||||
|
||||
return $sp;
|
||||
}
|
||||
|
||||
my $sp = "";
|
||||
|
||||
if($#ARGV != 0) {
|
||||
if($#ARGV < 0) {
|
||||
print_help;
|
||||
exit;
|
||||
}
|
||||
|
||||
$sp = parse_cli;
|
||||
|
||||
if($#ARGV != 0) {
|
||||
print_help;
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
my $params = $ARGV[0];
|
||||
if(bytes::length($sp) > 0) {
|
||||
$params .= "&sp=".$sp;
|
||||
}
|
||||
|
||||
my $ua = LWP::UserAgent->new;
|
||||
$ua->agent("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0");
|
||||
$ua->cookie_jar( {} );
|
||||
$ua->cookie_jar()->set_cookie(0, 'CONSENT', 'YES+cb.20210530-19-p0.en+FX+027', '/', '.youtube.com');
|
||||
my $response = $ua->get('https://www.youtube.com/results?search_query='.$params);
|
||||
|
||||
my $jsonobject;
|
||||
my $coder = JSON::XS->new->pretty->allow_nonref;
|
||||
my $tree = HTML::TreeBuilder->new;
|
||||
|
||||
$tree->parse_content($response->content);
|
||||
|
||||
my $body = $tree->find_by_tag_name('body');
|
||||
|
||||
my $ytInitialData_tag = $body->look_down(
|
||||
_tag => "script",
|
||||
sub { $_[0]->as_HTML =~ /ytInitialData/ }
|
||||
);
|
||||
|
||||
$ytInitialData_tag->as_HTML =~ /.*ytInitialData[^=]*= (.*});.*/;
|
||||
my $ytInitialData = $1;
|
||||
|
||||
$jsonobject = $coder->decode($ytInitialData);
|
||||
my $utf8_encoded_json_text = $coder->encode($jsonobject);
|
||||
|
||||
my @results = @{$jsonobject->{"contents"}->{'twoColumnSearchResultsRenderer'}->{'primaryContents'}->{'sectionListRenderer'}->{'contents'}->[0]->{'itemSectionRenderer'}->{'contents'}};
|
||||
|
||||
sub get_textarray
|
||||
{
|
||||
my $aref = shift @_;
|
||||
my $text = "";
|
||||
foreach my $line (@{$aref}) {
|
||||
$text .= $line->{'text'};
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
sub print_video
|
||||
{
|
||||
my $video = shift @_;
|
||||
print "Title: " . $video->{'videoRenderer'}->{'title'}->{'runs'}->[0]->{'text'} . "\n";
|
||||
print "Length: " . $video->{'videoRenderer'}->{'lengthText'}->{'simpleText'} . "\n";
|
||||
print "Published: " . $video->{'videoRenderer'}->{'publishedTimeText'}->{'simpleText'} . "\n";
|
||||
print "Views: " . $video->{'videoRenderer'}->{'viewCountText'}->{'simpleText'} . "\n";
|
||||
print "By: " . $video->{'videoRenderer'}->{'ownerText'}->{'runs'}->[0]->{'text'} . "\n";
|
||||
print "Feed: ";
|
||||
my $feeduri = $video->{'videoRenderer'}->{'ownerText'}->{'runs'}->[0]->{'navigationEndpoint'}->{'commandMetadata'}->{'webCommandMetadata'}->{'url'};
|
||||
if($feeduri =~ m{^/user/}) {
|
||||
print 'https://www.youtube.com/feeds/videos.xml?user=' . $feeduri =~ s!^/user/!!r;
|
||||
} else {
|
||||
print 'http://www.youtube.com/feeds/videos.xml?channel_id=' . $feeduri =~ s!^/channel/!!r;
|
||||
}
|
||||
print "\n";
|
||||
print "Url: https://www.youtube.com/watch?v=" . $video->{'videoRenderer'}->{'videoId'} . "\n\n";
|
||||
}
|
||||
|
||||
sub print_playlist
|
||||
{
|
||||
my $playlist = shift @_;
|
||||
print "Title: " . $playlist->{'playlistRenderer'}->{'title'}->{'simpleText'} . "\n";
|
||||
print "Videos: " . $playlist->{'playlistRenderer'}->{'videoCount'} . "\n";
|
||||
print "Url: https://www.youtube.com/playlist?list=" . $playlist->{'playlistRenderer'}->{'playlistId'} . "\n";
|
||||
print "Feed: https://www.youtube.com/feeds/videos.xml?playlist_id=" . $playlist->{'playlistRenderer'}->{'playlistId'} . "\n\n";
|
||||
}
|
||||
|
||||
sub print_channel
|
||||
{
|
||||
my $channel = shift @_;
|
||||
print "Title: " . $channel->{'channelRenderer'}->{'title'}->{'simpleText'} . "\n";
|
||||
if($channel->{'channelRenderer'}->{'descriptionSnippet'}) {
|
||||
print "Description: " . get_textarray($channel->{'channelRenderer'}->{'descriptionSnippet'}->{'runs'}) . "\n";
|
||||
}
|
||||
if($channel->{'channelRenderer'}->{'subscriberCountText'}) {
|
||||
print "Subscribers: " . $channel->{'channelRenderer'}->{'subscriberCountText'}->{'simpleText'} . "\n";
|
||||
}
|
||||
print "Videos: " . get_textarray($channel->{'channelRenderer'}->{'videoCountText'}->{'runs'}) . "\n";
|
||||
print "Url: https://www.youtube.com/channel/" . $channel->{'channelRenderer'}->{'channelId'} . "\n";
|
||||
print "Feed: http://www.youtube.com/feeds/videos.xml?channel_id=" . $channel->{'channelRenderer'}->{'channelId'} . "\n\n";
|
||||
}
|
||||
|
||||
foreach my $item (@results) {
|
||||
my ($key, $title, $length, $date, $views, $id);
|
||||
foreach my $k (keys %{$item}) {
|
||||
$key = $k;
|
||||
}
|
||||
|
||||
if($key eq 'videoRenderer') {
|
||||
print "[video]\n";
|
||||
print_video($item);
|
||||
} elsif($key eq 'playlistRenderer') {
|
||||
print "[playlist]\n";
|
||||
print_playlist($item);
|
||||
} elsif($key eq 'channelRenderer') {
|
||||
print "[channel]\n";
|
||||
print_channel($item);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue