SHARE
TWEET

yandex music dowloader

a guest Sep 22nd, 2014 476 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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================================';
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top