package YTMusicAPI::Helpers; use strict; use warnings; use Exporter 'import'; use POSIX qw(strftime locale_h); use LWP::UserAgent; use JSON; use HTTP::Cookies; use Digest::SHA qw(sha1_hex); use Time::HiRes qw(time); use Unicode::Normalize; use Encode 'encode_utf8', 'is_utf8'; use locale; use YTMusicAPI::Constants qw(YTM_DOMAIN USER_AGENT); sub initialize_headers { return { 'user-agent' => USER_AGENT, 'accept' => '*/*', 'accept-encoding' => 'gzip, deflate', 'content-type' => 'application/json', 'content-encoding' => 'gzip', 'origin' => YTM_DOMAIN, }; } sub initialize_context { return { 'context' => { 'client' => { 'clientName' => "WEB_REMIX", 'clientVersion' => "1." . strftime( "%Y%m%d", gmtime ) . ".01.00", }, 'user' => {}, } }; } sub get_visitor_id { my ($response) = @_; my @matches = $response->decoded_content =~ /ytcfg\.set\s*\(\s*({.+?})\s*\)\s*;/g; my $visitor_id = ""; if (@matches) { my $encoded_match = is_utf8( $matches[0] ) ? encode_utf8( $matches[0] ) : $matches[0]; my $ytcfg = decode_json($encoded_match); $visitor_id = $ytcfg->{"VISITOR_DATA"} // ""; } return $visitor_id; } sub sapisid_from_cookie { my ($raw_cookie) = @_; my $cookie_jar = HTTP::Cookies->new(); $raw_cookie =~ s/\"//g; # Replace double quotes $cookie_jar->parse_headers( { 'set-cookie' => $raw_cookie } ); my $sapisid = $cookie_jar->get_cookie("__Secure-3PAPISID"); return $sapisid; } sub get_authorization { my ($auth) = @_; my $unix_timestamp = int(time); my $digest = sha1_hex( $unix_timestamp . " " . $auth ); return "SAPISIDHASH " . $unix_timestamp . "_" . $digest; } sub to_int { my ($string) = @_; $string = NFKD($string); my $number_string = $string =~ s/\D//gr; setlocale( LC_ALL, "en_US.UTF-8" ); my $int_value; eval { $int_value = atoi($number_string); }; if ($@) { $number_string =~ s/,//g; $int_value = int($number_string); } return $int_value; } sub sum_total_duration { my ($item) = @_; return 0 unless exists $item->{"tracks"}; my $total_duration = 0; foreach my $track ( @{ $item->{"tracks"} } ) { $total_duration += exists $track->{"duration_seconds"} ? $track->{"duration_seconds"} : 0; } return $total_duration; } sub array_index { my ( $list, $value ) = @_; my $index = 0; my $found_index = -1; foreach my $type (@$list) { if ( $type eq $value ) { $found_index = $index; last; } $index++; } return $found_index; } our @EXPORT = qw( initialize_headers initialize_context get_visitor_id sapisid_from_cookie get_authorization to_int sum_total_duration array_index ); 1;