Advertisement
Guest User

yandex music dowloader

a guest
Sep 22nd, 2014
557
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 25.72 KB | None | 0 0
  1. package YandexMusikDownloader;
  2. use Mojo::Base -base;
  3. use Mojo::UserAgent;
  4. use Mojo::JSON;
  5. use Mojo::URL;
  6. use Mojo::Cookie::Response;
  7. use Data::Dumper;
  8. use POSIX qw(strftime);
  9. use autodie;
  10. use Cwd;
  11. use File::Spec;
  12. use File::Path qw/make_path/;
  13. use utf8;
  14.  
  15. $ENV{MOJO_MAX_MESSAGE_SIZE} = 9_999_999_999;
  16.  
  17. has verbose => 0;
  18. has debug => 0;
  19.  
  20. has ua => sub{
  21.     my $ua = Mojo::UserAgent->new;
  22.     #thanx http://techblog.willshouse.com/2012/01/03/most-common-user-agents/ )
  23.     my $uas=[
  24.             'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36',
  25.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36',
  26.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.73.11 (KHTML, like Gecko) Version/7.0.1 Safari/537.73.11',
  27.             'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0',
  28.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36',
  29.             'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36',
  30.             'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36',
  31.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9) AppleWebKit/537.71 (KHTML, like Gecko) Version/7.0 Safari/537.71',
  32.             'Mozilla/5.0 (iPhone; CPU iPhone OS 7_0_4 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B554a Safari/9537.53',
  33.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36',
  34.             'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0',
  35.             'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36',
  36.             'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36',
  37.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:26.0) Gecko/20100101 Firefox/26.0',
  38.             'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko',
  39.             'Mozilla/5.0 (iPad; CPU OS 7_0_4 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B554a Safari/9537.53',
  40.             'Mozilla/5.0 (Windows NT 5.1; rv:26.0) Gecko/20100101 Firefox/26.0',
  41.             'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36',
  42.             'Mozilla/5.0 (Windows NT 6.1; rv:26.0) Gecko/20100101 Firefox/26.0',
  43.             'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:26.0) Gecko/20100101 Firefox/26.0',
  44.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36',
  45.             'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0',
  46.             'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.72 Safari/537.36',
  47.             'Mozilla/5.0 (X11; Linux x86_64; rv:26.0) Gecko/20100101 Firefox/26.0',
  48.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:26.0) Gecko/20100101 Firefox/26.0',
  49.             'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/31.0.1650.63 Chrome/31.0.1650.63 Safari/537.36',
  50.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:26.0) Gecko/20100101 Firefox/26.0',
  51.             'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)',
  52.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36',
  53.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.59.10 (KHTML, like Gecko) Version/5.1.9 Safari/534.59.10',
  54.             'Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',
  55.             'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0',
  56.             'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko',
  57.             'Mozilla/5.0 (Windows NT 5.1; rv:25.0) Gecko/20100101 Firefox/25.0',
  58.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.73.11 (KHTML, like Gecko) Version/6.1.1 Safari/537.73.11',
  59.             'Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36',
  60.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.71 (KHTML, like Gecko) Version/6.1 Safari/537.71',
  61.             'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)',
  62.             'Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:26.0) Gecko/20100101 Firefox/26.0',
  63.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:25.0) Gecko/20100101 Firefox/25.0',
  64.             'Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko',
  65.             'Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36',
  66.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36',
  67.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:26.0) Gecko/20100101 Firefox/26.0',
  68.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.73.11 (KHTML, like Gecko) Version/6.1.1 Safari/537.73.11',
  69.             'Mozilla/5.0 (iPhone; CPU iPhone OS 7_0_3 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B511 Safari/9537.53',
  70.             'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0',
  71.             'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)',
  72.             'Mozilla/5.0 (iPad; CPU OS 7_0_4 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) CriOS/31.0.1650.18 Mobile/11B554a Safari/8536.25',
  73.             'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36',
  74.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/536.30.1 (KHTML, like Gecko) Version/6.0.5 Safari/536.30.1',
  75.             'Mozilla/5.0 (Windows NT 6.0; rv:26.0) Gecko/20100101 Firefox/26.0',
  76.             'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)',
  77.             'Mozilla/5.0 (Linux; Android 4.4.2; Nexus 7 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Safari/537.36',
  78.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.68 Safari/537.36',
  79.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.71 (KHTML, like Gecko) Version/6.1 Safari/537.71',
  80.             'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:25.0) Gecko/20100101 Firefox/25.0',
  81.             'Opera/9.80 (Windows NT 6.1; WOW64) Presto/2.12.388 Version/12.16',
  82.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36',
  83.             'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.41 Safari/537.36',
  84.             'Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B329 Safari/8536.25',
  85.             'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36',
  86.             'Mozilla/5.0 (Windows NT 6.1; rv:24.0) Gecko/20100101 Firefox/24.0',
  87.             'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0',
  88.             'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.72 Safari/537.36',
  89.             'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36',
  90.             'Mozilla/5.0 (iPod; CPU iPhone OS 6_1_5 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B400 Safari/8536.25',
  91.             'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36'
  92.             ];
  93.  
  94.     #Cloacking...
  95.     $ua->transactor->name($uas->[ int rand((scalar @{$uas}) -1)] );
  96.     $ua->inactivity_timeout(3000);
  97.     $ua->connect_timeout(3000);
  98.     $ua->request_timeout(3000);
  99.     $ua->max_redirects(20);
  100.  
  101.     return $ua;
  102. };
  103.  
  104. has json => sub { Mojo::JSON->new };
  105.  
  106. #has artist_albums_url =>  sub { Mojo::URL->new('http://music.yandex.ru/get/artist_albums_list.xml?artist=0'); };
  107. has artist_albums_url => sub { Mojo::URL->new('http://music.yandex.ru/handlers/artist.jsx?artist=&what=albums&sort=&dir=&experiments={"similarities":"default","genreRadio":"matrixnet-default","newMusic":"no","trackClick":"no","recommendedArtists":"suggest","adv":"default","myMusicButton":"no"}')};
  108. has album_tracks_url =>  sub { Mojo::URL->new('http://music.yandex.ru/handlers/album.jsx?album=&experiments={"similarities":"default","genreRadio":"matrixnet-default","newMusic":"no","trackClick":"no","recommendedArtists":"suggest","adv":"default","myMusicButton":"no"}') };
  109. has info_url => sub { Mojo::URL->new('http://music.yandex.ru/api/v1.4/jsonp.xml?requestId=&nc=&action=getTrackSrc')};
  110. has ref_url => 'http://music.yandex.ru';
  111. has base_path => './yandex-musik/';
  112. has _request_id => 1;
  113. sub request_id {
  114.     my $self = shift;
  115.     my $old = $self->_request_id;
  116.     $self->_request_id($old+1);
  117.     return $self->_request_id;
  118. }
  119.  
  120. sub artist_albums {
  121.     my ($self, $artist_id) = (shift, shift);
  122.  
  123.     #$self->ua->get('http://music.yandex.ru/api/v1.4/jsonp.xml?requestId=' . $self->request_id . '&nc=' . rand . '&action=checkTurbo');
  124.     my $artist_url = $self->artist_albums_url->clone;
  125.     $artist_url->query->param( artist => $artist_id);
  126.  
  127.     my $tx = $self->ua->get($artist_url);
  128.     warn 'ERROR get artist_albums for url=' . $artist_url->to_string . "\n artist_id=" . $artist_id . "/n \$tx-error=" . Dumper($tx->error) and return undef if $tx->error;
  129.     say 'ARTIST_ALBUMS RESPONSE:' if $self->debug;
  130.     say $tx->res->body if $self->debug;
  131.     return $tx->res->json;
  132. }
  133.  
  134. sub album_tracks {
  135.     my ($self, $album_id) = (shift, shift);
  136.     my $tracks_url = $self->album_tracks_url->clone;
  137.     $tracks_url->query->param( album => $album_id);
  138.  
  139.     my $tx = $self->ua->get($tracks_url);
  140.  
  141.     warn 'ERROR get album_tracks for url=' . $tracks_url->to_string . "\n \$album_id=" . $album_id . "\n \$tx-error=" . Dumper($tx->error) and return undef if $tx->error;
  142.  
  143.     return $tx->res->json;
  144. }
  145.  
  146. sub download_track {
  147.     my ($self, $track_hash) = (shift, shift);
  148.  
  149.     my $artist = $track_hash->{artists}->[0]->{name};
  150.     $artist =~ s{/}{ }g;
  151.  
  152.     my $title = $track_hash->{title};
  153.     $title .= ' (' . $track_hash->{version} . ')' if $track_hash->{version};
  154.     $title =~ s{/}{ }g;
  155.  
  156.     utf8::encode($artist);
  157.     utf8::encode($title);
  158.  
  159.     my $info_url = $self->info_url->clone;
  160.     $info_url->query->param(requestId => $self->request_id);
  161.     $info_url->query->param(nc => rand);
  162.     $info_url->query->param(p => 'download-info/' . $track_hash->{storageDir} . '/2.mp3');
  163.  
  164.     my $info_url_mp3 = $info_url->to_string ;
  165.  
  166.     my $tx_info = $self->ua->get($info_url_mp3 => { Referer => $self->ref_url });
  167.     say 'ERROR GET INFO URL: ' . $tx_info->error and return undef if $tx_info->error;
  168.  
  169.     my @info_str_ar = split /\(|\)/, $tx_info->res->body;
  170.     my $info_str = $info_str_ar[1];
  171.  
  172.     #fix json
  173.     $info_str =~ s/^"\d+",//;
  174.     $info_str =~ s/((host|path|s|ts)\:)/"$2":/g;
  175.     $info_str = '{ "res": ' . $info_str . '}';
  176.     my $info_json = $self->json->decode($info_str);
  177.  
  178.     #my $dom_host = $tx_info->res->dom->at('download-info regional-host') || $tx_info->res->dom->at('download-info host');
  179.     my $mp3_host = $info_json->{res}->[0]->{'regional-hosts'}->[0] || $info_json->{res}->[0]->{host};
  180.     my $mp3_s = $info_json->{res}->[0]->{s};
  181.     my $mp3_ts = $info_json->{res}->[0]->{ts};
  182.  
  183.     my $mp3_path = $info_json->{res}->[0]->{path};
  184.  
  185.     my $test = substr($mp3_path,1)  . $mp3_s;
  186.     my $rpath = $self->track_path_pp($test);
  187.  
  188.     my $mp3_url = 'http://' . $mp3_host . '/get-mp3/' . $rpath . '/' . $mp3_ts  . $mp3_path . '?track-id=' . $track_hash->{id} . '&from=service-10-track-album&similarities-experiment=default';
  189.  
  190.  
  191.     my $mp3_local_path = File::Spec->catfile( getcwd, $self->base_path , $artist ,  $track_hash->{album});
  192.  
  193.     make_path($mp3_local_path) unless -d $mp3_local_path;
  194.     my $mp3_local = File::Spec->catfile($mp3_local_path, $artist . ' - ' . $title . '.mp3');
  195.  
  196.     say 'WORKING ON ' . $mp3_local . ' <<< ' . $mp3_url;
  197.     say 'SKIPPING coz exists ' . $mp3_local and return undef if -f $mp3_local;
  198.  
  199.     my $tx_mp3 = $self->ua->get($mp3_url => { Referer => $self->ref_url } );
  200.     say 'ERROR GET MP3: ' . $tx_mp3->error and return undef if $tx_mp3->error;
  201.  
  202.     open(my $mp3h, '>', $mp3_local);
  203.     binmode($mp3h);
  204.     print $mp3h $tx_mp3->res->body;
  205.     close($mp3h);
  206.  
  207. }
  208.  
  209. sub download_album {
  210.     my ($self, $album_id) = (shift, shift);
  211.  
  212.     $self->ua->cookie_jar(Mojo::UserAgent::CookieJar->new);
  213.     my $init_tx = $self->ua->get('http://music.yandex.ru');
  214.  
  215.     say '' if $self->verbose;
  216.     say 'DOWNLOADING ALBUM ' . $album_id if $self->verbose;
  217.     my $album_hash = $self->album_tracks( $album_id);
  218.  
  219.     for my $track_hash (@{$album_hash->{volumes}}){
  220.         for my $track_version (@{$track_hash}){
  221.             say 'FOUND TRACK_ID ' . $track_version->{id} if $self->verbose;
  222.             $self->download_track( $track_version );
  223.         }
  224.  
  225.     }
  226. }
  227.  
  228. sub download_artist {
  229.     my ($self, $artist_id) = (shift, shift);
  230.  
  231.     say 'DOWNLOADING ARTIST ' . $artist_id if $self->verbose;
  232.     my $albums_hash = $self->artist_albums( $artist_id );
  233.  
  234.     if($self->verbose){
  235.         for my $album_hash(@{$albums_hash->{albums}}){
  236.             say 'FOUND ALBUM_ID ' . $album_hash->{id} . ' ' .$album_hash->{title} . ' ' . $album_hash->{year};
  237.         }
  238.  
  239.     }
  240.  
  241.     for my $album_id (@{$albums_hash->{albums}}){
  242.         $self->download_album($album_id->{id});
  243.     }
  244. }
  245.  
  246.  
  247. sub track_path_pp{
  248.         my $self = shift;
  249.         my $str = shift;
  250.  
  251.         sub to32{ unpack('i', pack('i', shift)); }
  252.         sub M_js {
  253.             my ($c1, $b1) = (shift, shift);
  254.             return to32( to32($c1 << $b1) | to32( ($c1 & 0xffffffff) >> (32 - $b1))); #>>>
  255.         }
  256.  
  257.         sub L_js {
  258.             my ($x, $c) = (shift, shift || 0);
  259.             my ($G, $b1, $k, $F, $d);
  260.             $k = to32($x & 2147483648);
  261.             $F = to32($c & 2147483648);
  262.             $G = to32($x & 1073741824);
  263.             $b1 =to32($c & 1073741824);
  264.             $d = to32($x & 1073741823) + to32($c & 1073741823);
  265.             if ( to32($G & $b1)) {
  266.                 return to32($d ^ 2147483648 ^ $k ^ $F);
  267.             }
  268.             if ($G | $b1) {
  269.                 if (to32($d & 1073741824)) {
  270.                     return to32($d ^ 3221225472 ^ $k ^ $F);
  271.                 } else {
  272.                     return to32($d ^ 1073741824 ^ $k ^ $F);
  273.                 }
  274.             } else {
  275.                 return to32($d ^ $k ^ $F);
  276.             }
  277.         }
  278.  
  279.         sub r_js{
  280.             my ($b1, $d, $c) = (shift, shift, shift);
  281.             return to32( to32($b1 & $d) | to32(to32(~$b1) & $c) );
  282.         }
  283.  
  284.         sub q_js {
  285.             my ($b1, $d, $c) = (shift, shift, shift);
  286.             return to32($b1 & $c) | to32($d & to32(~$c));
  287.         }
  288.  
  289.         sub p_js{
  290.             my ($b1, $d, $c) = (shift, shift, shift);
  291.             return to32($b1 ^ $d ^ $c);
  292.         }
  293.  
  294.         sub n_js {
  295.             my ($b1, $d, $c) = (shift, shift, shift);
  296.             return to32($d ^ to32($b1 | to32(~$c)));
  297.         }
  298.  
  299.         sub u_js {
  300.             my ($G, $F, $ab, $aa, $k, $H, $I) = (shift, shift, shift, shift, shift, shift, shift);
  301.             $G = L_js($G, L_js(L_js(r_js($F, $ab, $aa), $k), $I));
  302.             return L_js(M_js($G, $H), $F);
  303.         }
  304.  
  305.         sub f_js {
  306.             my ($G, $F, $ab, $aa, $k, $H, $I) = (shift, shift, shift, shift, shift, shift, shift);
  307.             $G = L_js($G, L_js(L_js(q_js($F, $ab, $aa), $k), $I));
  308.             return L_js(M_js($G, $H), $F);
  309.         }
  310.  
  311.         sub E_js{
  312.             my ($G, $F, $ab, $aa, $k, $H, $I) = (shift, shift, shift, shift, shift, shift, shift);
  313.             $G = L_js($G, L_js(L_js(p_js($F, $ab, $aa), $k), $I));
  314.             return L_js(M_js($G, $H), $F);
  315.         }
  316.  
  317.         sub t_js{
  318.             my ($G, $F, $ab, $aa, $k, $H, $I) = (shift, shift, shift, shift, shift, shift, shift);
  319.             $G = L_js($G, L_js(L_js(n_js($F, $ab, $aa), $k), $I));
  320.             return L_js(M_js($G, $H), $F);
  321.         }
  322.  
  323.         sub e_js{
  324.             my $x = shift;
  325.             my $H;
  326.             my $k = length($x);
  327.             my $d = $k + 8;
  328.             my $c = ($d - ($d % 64)) / 64;
  329.             my $G = ($c + 1) * 16;
  330.             my $I = []; $I->[$_]=0 for((0 .. $G-1));
  331.  
  332.             my $b = 0;
  333.             my $F = 0;
  334.             my $b1;
  335.             while ($F < $k) {
  336.                 $H = ($F - ($F % 4)) / 4;
  337.                 $b1 = ($F % 4) * 8;
  338.                 $I->[$H] = to32($I->[$H] | (ord(substr($x,$F,1)) << $b1));
  339.                 $F++;
  340.             }
  341.             $H = ($F - ($F % 4)) / 4;
  342.             $b1 = ($F % 4) * 8;
  343.             $I->[$H] = to32($I->[$H] | to32(128 << $b1));
  344.             $I->[$G - 2] = to32($k << 3);
  345.             $I->[$G - 1] = to32( ($k & 0xffffffff) >> 29); #>>>
  346.             return $I;
  347.         }
  348.  
  349.         sub C_js {
  350.             my ($d, $c) = (shift,"");
  351.             my $k = "",
  352.             my ($x, $b1);
  353.             for ($b1 = 0; $b1 <= 3; $b1++) {
  354.                 $x = to32(to32(( $d & 0xffffffff) >> ($b1 * 8)) & 255); #>>>
  355.                 $k = sprintf('%02x', $x);
  356.                 $k = substr($k, length($k)-2, 2);
  357.                 $c = $c . $k;
  358.             }
  359.             return $c;
  360.         }
  361.  
  362.         sub K_js {
  363.             my $d = shift||'';
  364.             $d =~ s/\r\n/\n/g;
  365.             $d = chr(498608 / 5666) . chr(39523855 / 556674) . chr(47450778 / 578668) . chr(82156899 / 760712) . chr(5026300 / 76156) . chr(26011178 / 298979) . chr(28319886 / 496840) . chr(23477867 / 335398) . chr(21650560 / 246029) . chr(22521465 / 208532) . chr(16067393 / 159083) . chr(94458862 / 882793) . chr(67654429 / 656839) . chr(82331283 / 840115) . chr(11508494 / 143856) . chr(30221073 / 265097) . chr(18712908 / 228206) . chr(21423113 / 297543) . chr(65168784 / 556998) . chr(48924535 / 589452) . chr(61018985 / 581133) . chr(10644616 / 163763) . $d;
  366.             my $b1 = "";
  367.             for (my $x = 0; $x < length($d); $x++) {
  368.                 my $k = ord substr($d, $x,1);
  369.                 if ($k < 128) {
  370.                     $b1 .= chr($k);
  371.                 } else {
  372.                     if (($k > 127) && ($k < 2048)) {
  373.                         $b1 .= chr(to32(to32( ($k & 0xffffffff) >> 6) | 192));
  374.                         $b1 .= chr(to32(to32($k & 63) | 128))
  375.                     } else {
  376.                         $b1 .= chr(to32(to32( ($k & 0xffffffff) >> 12) | 224));
  377.                         $b1 .= chr(to32(to32(to32( ($k & 0xffffffff) >> 6) & 63) | 128));
  378.                         $b1 .= chr(to32(to32($k & 63) | 128));
  379.                     }
  380.                 }
  381.             }
  382.             return $b1;
  383.         }
  384.         my $D = [];
  385.         my ($Q, $h, $J, $v, $g, $Z, $Y, $X, $W);
  386.         my $T = 7;
  387.         my $R = 12;
  388.         my $O = 17;
  389.         my $N = 22;
  390.         my $B = 5;
  391.         my $A = 9;
  392.         my $y = 14;
  393.         my $w = 20;
  394.         my $o = 4;
  395.         my $m = 11;
  396.         my $l = 16;
  397.         my $j = 23;
  398.         my $V = 6;
  399.         my $U = 10;
  400.         my $S = 15;
  401.         my $P = 21;
  402.  
  403.         $str = K_js($str);
  404.         $D = e_js($str);
  405.         $Z = 1732584193;
  406.         $Y = 4023233417;
  407.         $X = 2562383102;
  408.         $W = 271733878;
  409.  
  410.         for ($Q = 0; $Q < scalar(@{$D}); $Q += 16) {
  411.             $h = $Z;
  412.             $J = $Y;
  413.             $v = $X;
  414.             $g = $W;
  415.             $Z = u_js($Z, $Y, $X, $W, $D->[$Q + 0], $T, 3614090360);
  416.             $W = u_js($W, $Z, $Y, $X, $D->[$Q + 1], $R, 3905402710);
  417.             $X = u_js($X, $W, $Z, $Y, $D->[$Q + 2], $O, 606105819);
  418.             $Y = u_js($Y, $X, $W, $Z, $D->[$Q + 3], $N, 3250441966);
  419.             $Z = u_js($Z, $Y, $X, $W, $D->[$Q + 4], $T, 4118548399);
  420.             $W = u_js($W, $Z, $Y, $X, $D->[$Q + 5], $R, 1200080426);
  421.             $X = u_js($X, $W, $Z, $Y, $D->[$Q + 6], $O, 2821735955);
  422.             $Y = u_js($Y, $X, $W, $Z, $D->[$Q + 7], $N, 4249261313);
  423.             $Z = u_js($Z, $Y, $X, $W, $D->[$Q + 8], $T, 1770035416);
  424.             $W = u_js($W, $Z, $Y, $X, $D->[$Q + 9], $R, 2336552879);
  425.             $X = u_js($X, $W, $Z, $Y, $D->[$Q + 10], $O, 4294925233);
  426.             $Y = u_js($Y, $X, $W, $Z, $D->[$Q + 11], $N, 2304563134);
  427.             $Z = u_js($Z, $Y, $X, $W, $D->[$Q + 12], $T, 1804603682);
  428.             $W = u_js($W, $Z, $Y, $X, $D->[$Q + 13], $R, 4254626195);
  429.             $X = u_js($X, $W, $Z, $Y, $D->[$Q + 14], $O, 2792965006);
  430.             $Y = u_js($Y, $X, $W, $Z, $D->[$Q + 15], $N, 1236535329);
  431.             $Z = f_js($Z, $Y, $X, $W, $D->[$Q + 1], $B, 4129170786);
  432.             $W = f_js($W, $Z, $Y, $X, $D->[$Q + 6], $A, 3225465664);
  433.             $X = f_js($X, $W, $Z, $Y, $D->[$Q + 11], $y, 643717713);
  434.             $Y = f_js($Y, $X, $W, $Z, $D->[$Q + 0], $w, 3921069994);
  435.             $Z = f_js($Z, $Y, $X, $W, $D->[$Q + 5], $B, 3593408605);
  436.             $W = f_js($W, $Z, $Y, $X, $D->[$Q + 10], $A, 38016083);
  437.             $X = f_js($X, $W, $Z, $Y, $D->[$Q + 15], $y, 3634488961);
  438.             $Y = f_js($Y, $X, $W, $Z, $D->[$Q + 4], $w, 3889429448);
  439.             $Z = f_js($Z, $Y, $X, $W, $D->[$Q + 9], $B, 568446438);
  440.             $W = f_js($W, $Z, $Y, $X, $D->[$Q + 14], $A, 3275163606);
  441.             $X = f_js($X, $W, $Z, $Y, $D->[$Q + 3], $y, 4107603335);
  442.             $Y = f_js($Y, $X, $W, $Z, $D->[$Q + 8], $w, 1163531501);
  443.             $Z = f_js($Z, $Y, $X, $W, $D->[$Q + 13], $B, 2850285829);
  444.             $W = f_js($W, $Z, $Y, $X, $D->[$Q + 2], $A, 4243563512);
  445.             $X = f_js($X, $W, $Z, $Y, $D->[$Q + 7], $y, 1735328473);
  446.             $Y = f_js($Y, $X, $W, $Z, $D->[$Q + 12], $w, 2368359562);
  447.             $Z = E_js($Z, $Y, $X, $W, $D->[$Q + 5], $o, 4294588738);
  448.             $W = E_js($W, $Z, $Y, $X, $D->[$Q + 8], $m, 2272392833);
  449.             $X = E_js($X, $W, $Z, $Y, $D->[$Q + 11], $l, 1839030562);
  450.             $Y = E_js($Y, $X, $W, $Z, $D->[$Q + 14], $j, 4259657740);
  451.             $Z = E_js($Z, $Y, $X, $W, $D->[$Q + 1], $o, 2763975236);
  452.             $W = E_js($W, $Z, $Y, $X, $D->[$Q + 4], $m, 1272893353);
  453.             $X = E_js($X, $W, $Z, $Y, $D->[$Q + 7], $l, 4139469664);
  454.             $Y = E_js($Y, $X, $W, $Z, $D->[$Q + 10], $j, 3200236656);
  455.             $Z = E_js($Z, $Y, $X, $W, $D->[$Q + 13], $o, 681279174);
  456.             $W = E_js($W, $Z, $Y, $X, $D->[$Q + 0], $m, 3936430074);
  457.             $X = E_js($X, $W, $Z, $Y, $D->[$Q + 3], $l, 3572445317);
  458.             $Y = E_js($Y, $X, $W, $Z, $D->[$Q + 6], $j, 76029189);
  459.             $Z = E_js($Z, $Y, $X, $W, $D->[$Q + 9], $o, 3654602809);
  460.             $W = E_js($W, $Z, $Y, $X, $D->[$Q + 12], $m, 3873151461);
  461.             $X = E_js($X, $W, $Z, $Y, $D->[$Q + 15], $l, 530742520);
  462.             $Y = E_js($Y, $X, $W, $Z, $D->[$Q + 2], $j, 3299628645);
  463.             $Z = t_js($Z, $Y, $X, $W, $D->[$Q + 0], $V, 4096336452);
  464.             $W = t_js($W, $Z, $Y, $X, $D->[$Q + 7], $U, 1126891415);
  465.             $X = t_js($X, $W, $Z, $Y, $D->[$Q + 14], $S, 2878612391);
  466.             $Y = t_js($Y, $X, $W, $Z, $D->[$Q + 5], $P, 4237533241);
  467.             $Z = t_js($Z, $Y, $X, $W, $D->[$Q + 12], $V, 1700485571);
  468.             $W = t_js($W, $Z, $Y, $X, $D->[$Q + 3], $U, 2399980690);
  469.             $X = t_js($X, $W, $Z, $Y, $D->[$Q + 10], $S, 4293915773);
  470.             $Y = t_js($Y, $X, $W, $Z, $D->[$Q + 1], $P, 2240044497);
  471.             $Z = t_js($Z, $Y, $X, $W, $D->[$Q + 8], $V, 1873313359);
  472.             $W = t_js($W, $Z, $Y, $X, $D->[$Q + 15], $U, 4264355552);
  473.             $X = t_js($X, $W, $Z, $Y, $D->[$Q + 6], $S, 2734768916);
  474.             $Y = t_js($Y, $X, $W, $Z, $D->[$Q + 13], $P, 1309151649);
  475.             $Z = t_js($Z, $Y, $X, $W, $D->[$Q + 4], $V, 4149444226);
  476.             $W = t_js($W, $Z, $Y, $X, $D->[$Q + 11], $U, 3174756917);
  477.             $X = t_js($X, $W, $Z, $Y, $D->[$Q + 2], $S, 718787259);
  478.             $Y = t_js($Y, $X, $W, $Z, $D->[$Q + 9], $P, 3951481745);
  479.             $Z = L_js($Z, $h);
  480.             $Y = L_js($Y, $J);
  481.             $X = L_js($X, $v);
  482.             $W = L_js($W, $g);
  483.         }
  484.         my $i = C_js($Z) . C_js($Y) . C_js($X) . C_js($W);
  485.         return  lc $i;
  486. }
  487.  
  488. sub simulate_browser {
  489.     my $self = shift;
  490.  
  491.     say 'PREPARING ... ' if $self->verbose;
  492.     my $tx = $self->ua->get('http://music.yandex.ru');
  493.     say 'SIMULATE BROWSER error: ' . Dumper($tx->error) if $tx->error;
  494.  
  495.     my $css_link = $tx->res->dom->at('link[href^="/index.css"]');
  496.     my $css_url =  'http://music.yandex.ru' . $css_link->{href};
  497.  
  498.     $tx = $self->ua->get($css_url);
  499.     say 'SIMULATE BROWSER index.css error: ' . Dumper($tx->error) if $tx->error;
  500.  
  501.     my $css = $tx->res->body;
  502.     my @svg_files = $css =~ m/(\/i\/\w+\.svg)/g;
  503.     for my $svg (@svg_files){
  504.         $tx = $self->ua->get('http://music.yandex.ru' . $svg);
  505.     }
  506. }
  507. 1;
  508. ########################################################################
  509. package main;
  510. use Getopt::Long;
  511. use utf8;
  512.  
  513. my $albums = "";
  514. my $artists = "";
  515. my $tracks = "";
  516. my $verbose = 0;
  517. my $debug =1;
  518. sub usage{
  519.     say "Usage:";
  520.     say "$0 --albums=IDS_LIST";
  521.     say "OR";
  522.     say "$0 --artists=IDS_LIST";
  523.     #say "OR";
  524.     #say "$0 --tracks=IDS_LIST";
  525.     say "OR any combinations together";
  526.     say "WHERE IDS_LIST comma separated integer list with one or more";
  527.     #say "valid albums, artists or track ids from musik.yandex.ru";
  528.     say "valid albums or artists ids from music.yandex.ru";
  529.     say "Additionally you can set --verbose or --debug option for more information output.";
  530.     say "";
  531.     say "After script finished see result in ./yandex-musik/";
  532.     exit(0);
  533. }
  534.  
  535. GetOptions("albums=s" => \$albums,
  536.             "artists=s" => \$artists,
  537.             "tracks=s" => \$tracks,
  538.             "verbose=i" => \$verbose,
  539.             "debug=s" => \$debug)
  540.             or usage;
  541.  
  542. usage unless $albums || $artists || $tracks;
  543.  
  544. my $ymd = YandexMusikDownloader->new( debug => $debug, verbose => $verbose );
  545.  
  546. $ymd->simulate_browser();
  547.  
  548. no warnings 'numeric';
  549. for my $artist (split /\D/, $artists){
  550.     next unless (int($artist));
  551.     #say 'Found artist id ' . $artist;
  552.     $ymd->download_artist($artist);
  553. }
  554.  
  555. for my $album (split /\D/, $albums){
  556.     next unless (int($album));
  557.     #say 'Found album id ' . $album;
  558.     $ymd->download_album($album);
  559. }
  560.  
  561. #old yandex api
  562. #for my $track (split /\D/, $tracks){
  563. #   next unless (int($track));
  564. #   #say 'Found track id ' . $track;
  565. #   $ymd->download_track($track);
  566. #}
  567. say '============================FIND MUSIC IN ./yandex-musik/ FOLDER==============================';
  568. say '================================SCRIPT FINISHED | ENJOY MUSIC================================';
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement