Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 186562 Details for
Bug 263804
media-sound/lastfm-ripper broken due to change in last-fm server structure
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
Adept to new last fm API
last.fm-ripper-2.0.1 (text/plain), 16.11 KB, created by
Markus Ehrnsperger
on 2009-03-28 15:56:56 UTC
(
hide
)
Description:
Adept to new last fm API
Filename:
MIME Type:
Creator:
Markus Ehrnsperger
Created:
2009-03-28 15:56:56 UTC
Size:
16.11 KB
patch
obsolete
>#!/usr/bin/perl > >eval 'exec /usr/bin/perl -S $0 ${1+"$@"}' > if 0; # not running under some shell > ># last.fm-ripper - (c) Copyright 2006 Jochen Schneider <scne59@googlemail.com> ># Update to new last fm API: Markus Ehrnsperger ># ># a simple last.fm to mp3-file ripper ># ># This program is free software; you can redistribute it and/or modify ># it under the same terms as Perl itself. > >$VERSION = 2.0.1; > >$version = '1.3.1.1'; # current version string of the offical last.fm player >$platform = guess_platform(); >$ws_host = 'ws.audioscrobbler.com'; # last.fm webservices hostname >$output_directory = '.'; # where to store mp3 files >$get_covers = 1 unless (system("wget --version > /dev/null")==-1); # retrieve covers if wget is available > ># check if all essential modules are in place >map >{ > my $module = $_; > unless (eval "use $module; 1") > { > print "Module \"$module\" is not availabe on your Perl installation\nEnter \"perl -MCPAN -e \"install $module\" to install it\n\n"; > exit(1); > } >} ('Getopt::Long','IO::Socket','FileHandle','Digest::MD5','IO::Select', 'XML::Simple', 'Data::Dumper', 'LWP::Simple'); > >$XML::Simple::PREFERRED_PARSER = "XML::SAX::PurePerl"; >#Global variable > >my $track_numer = 0; >my $track_list; >my $mp3_path; >my $download; >my $download_save; > ># can we tag the mp3 files? >if(eval "use MP3::Tag; 1") >{ > $tag_mp3s = 1; >} > >STDOUT->autoflush; >$SIG{INT} = sub { $bye_bye = 1; $download_save = $download; }; > >Getopt::Long::Configure("pass_through"); >GetOptions( 'help|?' => \$help, > 'debug|d' => \$debug, > 'no_covers|n' => \$no_covers, > 'artist|a=s' => \$artist, > 'username|u=s' => \$username, > 'password|p=s' => \$password, > 'output_dir|o=s' => \$output_directory, > 'aws_token|w=s' => \$aws_token); > ># let's see if params are correct and what our mission goals are >if($help) >{ > usage(); > exit; >} >if($no_covers) >{ > undef $get_covers; >} >if($username eq '') >{ > print "missing username\n"; > exit(1); >} >if(!-d $output_directory) >{ > print "output directory does not exist.\n"; > exit(1); >} ># will we listen to a supplied lastfm-url or will we roll our own for a similar-artist scheme >if ($ARGV[0]=~/lastfm\:\/\//) >{ > $url=$ARGV[0] >} >elsif ($artist) >{ > $artist=~s/\s/\%20/g; > $url="lastfm://artist/".$artist."/similarartists"; >} >else >{ > print "please supply an artist name or last.fm url\n"; > exit(1); >} > >if($password eq '') >{ > # we have to ask for a password > # and let Term::ReadPassword do the job if available > if (eval ("use Term::ReadPassword; 1")) > { > $password = read_password('password: '); > } > else > { > print "password: "; > $password = <STDIN>; > chomp($password); > } >} > >if($aws_token) >{ > # we have a amazon-webservices-token. Is Net::Amazon working? > map > { > my $module = $_; > if(!eval ("use $module; 1")) > { > die "could not initialize $module\n"; > } > } ('Net::Amazon', 'Net::Amazon::Request::Artist'); >} > ># last.fm uses a high-security password-obfuscation ;-) >$password_md5 = md5_password($password); > >debug("\nNow trying to play URL $url for user $username with pass $password - md5hash: $password_md5\n"); > >$sockets = IO::Select->new(); > >while (1) >{ > $buffer = ''; > if (!$handshake) > { > debug("\ntrying to log in\n"); > $handshake = IO::Socket::INET->new(PeerAddr => $ws_host, PeerPort => 80, Proto => "tcp") || die "could not initialize webservice socket\n"; > $handshake_url = "/radio/handshake.php?version=$version&platform=$platform&username=$username&passwordmd5=$password_md5&debug=0"; > $request = "GET $handshake_url HTTP/1.1\r\nhost: $ws_host\r\n\r\n"; > print $handshake $request; > $sockets->add($handshake); > } > elsif (!$tuned) > { > debug("\ntrying to tune station from $ws_host\n"); > $tune = IO::Socket::INET->new(PeerAddr => $ws_host, PeerPort => 80, Proto => "tcp") || die "could not initialize webservice socket\n"; > $tune_url = "/radio/adjust.php?session=$session&url=$url&debug=0"; > $request = "GET $tune_url HTTP/1.1\r\nhost: $ws_host\r\n\r\n"; > print $tune $request; > $sockets->add($tune); > } > elsif (!$xspf) > { > debug("\ntrying to get xspf playlist\n"); > $xspf = IO::Socket::INET->new(PeerAddr => $base_url, PeerPort => 80, Proto => "tcp") || die "could not initialize webservice socket for $base_url\n"; > $xspf_url = "$base_path/xspf.php?sk=$session&discovery=0&desktop=1.5.1"; > $request = "GET $xspf_url HTTP/1.1\r\nhost: $base_url\r\n\r\n"; > debug("\ndirekt nach lesen des Request, request = \n$request\nRequest Ende\n"); > > print $xspf $request; > $sockets->add($xspf); > } > else > { > $track = @{$track_list}[$track_number]; ># Data directly available in track info > my $location = $track->{location}->[0]; > my $creator = $track->{creator}->[0]; > my $duration = $track->{duration}->[0]; > my $image = $track->{image}->[0]; > my $album = $track->{album}->[0]; > my $title = $track->{title}->[0]; ># fill track info > $track_info{'artist'} = $creator; > $track_info{'album'} = $album; > $track_info{'track'} = $title; > > $track_number++ ; > @track_array = @{$track_list}; > $number_of_tracks_in_xspf = $#track_array; > if ($track_number > $number_of_tracks_in_xspf) { > $xspf = 0; > $track_number = 0; > } > debug("\n track_number = $track_number max. track: $number_of_tracks_in_xspf\n"); > > $dir_author = $output_directory."/".escape_filename($creator); > if(! -d $dir_author) { mkdir($dir_author,0755); } > if(! -d $dir_author) > { > print("\nCannot create directory \"$dir_author\", skip this author\n"); > } else > { > > $dir_album = $dir_author."/".escape_filename($album); > if(! -d $dir_album) > { > mkdir($dir_album,0755) || die("\n Cannot create directory \"$dir_album\"\n"); > } > > $mp3_path = $dir_album."/".escape_filename($title).".mp3"; > my $cover_file = $dir_album."/SmallCover.jpg"; > debug("\nset mp3_path = $mp3_path \n"); > debug("\nset cover_file = $cover_file \n"); > if( -f $mp3_path) > { > print "\n $mp3_path already exists, skip\n"; > } else > { > if ($get_covers) > { > # try to retrieve the largest available cover jpeg with wget > if (($image ne '') && !(-f $image)) > { > if(system("wget -O \"$cover_file\" $image > /dev/null 2>&1 &")>0){print "failed to retrieve cover art\n"}; > $image = ''; > } > } > > debug("\n download $mp3_path from $location\n"); > $download = 1; > getstore($location, $mp3_path) || print "\nfailed to download $mp3_path from $location\n"; > $download = 0; > debug("\n file \"$mp3_path\" written\n"); ># add meta data > > if ($aws_token) > { > my $aws_ua = Net::Amazon->new( token => $aws_token); > my $aws_request = Net::Amazon::Request::Artist->new(artist => $track_info{'artist'}); > my $aws_response = $aws_ua->request($aws_request); > if ($aws_response->is_success()) > { > my %albums; > map > { > my $album = $_; > if ($album->album() eq $track_info{'album'}) > { > $track_info{'year'} = $album->year(); > $track_info{'label'} = $album->label(); > my $track_index = 0; > map > { > my $title = $_; > chomp($title); > $track_index++; > if ($title eq $track_info{'track'}) > { > $track_info{'track_no'} = $track_index; > } > } $album->tracks(); > $track_info{'track_count'} = $track_index; > } > } $aws_response->properties(); > } > else > { > print "could not ask Amazon webservices for track-info\n"; > print $aws_response->message(); > exit(1); > } > } > if ($tag_mp3s) > { > my $mp3 = MP3::Tag->new($mp3_path); > my $mp3_tag = $mp3->new_tag("ID3v1"); > $mp3_tag->title($track_info{'track'}); > $mp3_tag->artist($track_info{'artist'}); > $mp3_tag->album($track_info{'album'}); > $mp3_tag->year($track_info{'year'}); > $mp3_tag->track($track_info{'track_no'}); > $mp3_tag->write_tag(); > my $mp3v2_tag = $mp3->new_tag("ID3v2"); > $mp3v2_tag->add_frame("TALB",$track_info{'album'}); > $mp3v2_tag->add_frame("TIT2",$track_info{'track'}); > $mp3v2_tag->add_frame("TPE1",$track_info{'artist'}); > $mp3v2_tag->add_frame("TLEN",$track_info{'trackduration'}); > $mp3v2_tag->add_frame("TRSN","last.fm"); > $mp3v2_tag->add_frame("TRCK",$track_info{'track_no'}); > $mp3v2_tag->add_frame("TYER",$track_info{'year'}); > > if ($get_covers) > { > open(COVER,"$cover_file"); > my $cover_data; > while(<COVER>){$cover_data.=$_}; > $mp3v2_tag->add_frame("APIC", chr(0x0), "image/jpeg", chr(0x0), "Cover Image", $cover_data); > } > $mp3v2_tag->write_tag; > $mp3->close(); > } > } > } > } > # handle sockets > map > { > my $sock = $_; ># debug("reading from socket\n"); > if ($sock eq $handshake) > { > debug("reading login response\n"); > $sock->recv($buffer,1024,0) || $sockets->remove($sock); > debug("\nbuffer \$buffer=\"$buffer\""); > > if($buffer =~ /session=([\w\d]+)/) > { > $session = $1; > debug("\nset \$session=\"$session\""); > } > if($buffer =~ /stream_url=(.+)\n/) > { > $stream_url = $1; > ($mp3_host=$1)=~s/http:\/\/([\.\w\d]+)[:\d]*\/.*/$1/; > debug("\nset \$mp3_host=\"$mp3_host\""); > debug("\nset \$stream_url=\"$stream_url\""); > } > if($buffer =~ /subscriber=(.+)\n/) > { > $subscriber = $1; > debug("\nset \$subscriber=\"$subscriber\""); > } > if($buffer =~ /framehack=(.+)\n/) > { > $framehack = $1; > debug("\nset \$framehack=\"$framehack\""); > } > if($buffer =~ /base_url=(.+)\n/) > { > $base_url = $1; > debug("\nset \$base_url=\"$base_url\""); > } > if($buffer =~ /base_path=(.+)\n/) > { > $base_path = $1; > debug("\nset \$base_path=\"$base_path\""); > } > if($buffer =~ /info_message=(.*)\n/) > { > $info_message = $1; > debug("\nset \$info_message=\"$info_message\""); > } > if($buffer =~ /fingerprint_upload_url=(.+)\012\n/) > { > $fingerprint_upload_url = $1; > debug("\nset \$fingerprint_upload_url=\"$fingerprint_upload_url\""); > } > if($session eq 'FAILED') > { > die "could not login\n"; > } > } > elsif ($sock eq $tune) > { > debug("reading tune response\n"); > $sock->recv($buffer,1024,0) || $sockets->remove($sock); > if($buffer =~ /HTTP\/1\.. 503/) > { > print "\nlast.fm service is temoprarily unavailable\n"; > exit(1); > } > if($buffer =~ /response=OK/) > { > $tuned = 1; > } > else > { > print "sorry, could not tune last.fm to play $url.\n"; > if ($artist) > { > print "maybe artist \"$artist\" is unkown to last.fm?\n"; > } > else > { > print "maybe url $url ist not valid?\n"; > } > exit(1); > } > } > elsif ($sock eq $xspf) > { > debug("reading xspf response\n"); > ># $sock->recv($buffer,4096,0) || $sockets->remove($sock); > my $xspf_out = ""; > while ($length = index($xspf_out,"</playlist>",0) == -1 ) > { > $sock->recv($buffer,4096,0) ; > if($buffer =~ /HTTP\/1\.. 503/) > { > print "\nlast.fm service is temoprarily unavailable while reading xspf\n"; > exit(1); > } > $xspf_out .= $buffer ; > } > $sockets->remove($sock); > > my ($header, $content) = split(/charset=utf-8\015\n/, $xspf_out, 2); > $content = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>$content"; > > debug("\nxspf content = \n$content\nEnd of xspf content\n"); > > my $xml_ref = XMLin($content, ForceArray => 1); > $track_list = $xml_ref->{trackList}->[0]->{track}; > > > if ($debug) { > print "\n list of tracks \n"; > my $i = 0; > map { > my $track_print = $_; > $i ++ ; > my $location = $track_print->{location}->[0]; > my $creator = $track_print->{creator}->[0]; > my $duration = $track_print->{duration}->[0]; > my $image = $track_print->{image}->[0]; > my $album = $track_print->{album}->[0]; > my $title = $track_print->{title}->[0]; > > print "\n track $i \n"; > print "location = $location\n"; > print "creator = $creator\n"; > print "duration = $duration\n"; > print "image = $image\n"; > print "album = $album\n"; > print "title = $title\n"; ># print Dumper($track_print); > } @{$track_list}; > print "\n Location [0]: @{$track_list}[0]->{location}->[0] \n"; > > } > if (scalar($track_list == 0)) { > print "\n Error getting tracks \n"; > exit (1); > } > > } > } $sockets->can_read(100); > map > { > my $sock = $_; > debug("writing to sockets\n"); > } $sockets->can_write(100); > if ($bye_bye){ > if($download_save) { unlink($mp3_path); print"\nDelete $mp3_path as it is not complete\n";} > print "\nbye!\n";exit(0);} >} > >sub debug >{ > if ($debug) > { > $|=1; > print @_; > } >} > >sub usage >{ > print <<EOF; >last.fm-ripper - $VERSION >(c) Copyright 2006 - Jochen Schneider - <scne59\@googlemail.com> > >usage: > >last.fm-ripper -u <username> [-p <password>] [-d] -[c] [-o <output-dir>] [-a <artist>] <lastfm-url> > > -u, --username last.fm username > -p, --password last.fm password > -a, --artist artist name (to find similar titles), obsolets last.fm url > -d, --debug enable debugging output > -o, --output_directory where to save mp3-files > -n, --nocovers disable cover download > -w, --aws_token amazon webservices developer token for advanced tagging (http://amazon.com/soap) > > >EOF >print "\n"; >} > >sub guess_platform >{ > my $platform = lc(`uname -s`); > chomp($platform); > if($platform eq ''){$platform="windows"}; #guess we are on win if uname does not work > return $platform; >} > >sub md5_password >{ > my $password = shift @_; > my $md5 = Digest::MD5->new(); > $md5->reset; > $md5->add($password); > return $md5->hexdigest; >} > >sub escape_filename >{ ># / \ * : ? " < > | not allowed in NTFS ># / not allowed in EXT3 > my $filename = shift @_; > $filename =~ s/\//%2F/g; > $filename =~ s/\\/%5C/g; > $filename =~ s/\*/%2A/g; ># $filename =~ s/\:/%3A/g; ># $filename =~ s/\?/%3F/g; > $filename =~ s/\"/%22/g; > $filename =~ s/\</%3C/g; > $filename =~ s/\>/%3E/g; > $filename =~ s/\|/%7C/g; > return $filename; >} > >=pod > >=head1 NAME > >last.fm-ripper - save last.fm radio to mp3 files > >=head1 SYNOPSIS > >last.fm-ripper -u <username> [-p <password>] [-d] -[c] [-o <output-dir>] [-a <artist>] <lastfm-url> > > -u, --username last.fm username > -p, --password last.fm password > -a, --artist artist name (to find similar titles), obsolets last.fm url > -d, --debug enable debugging output > -o, --output_directory where to save mp3-files > -n, --no_covers disable cover download > -w, --aws_token amazon webservices developer token for advanced tagging (http://amazon.com/soap) > >=head1 AUTHOR > >Jochen Schneider, <scne59@googlemail.com> >Markus Ehrnsperger, <markus_ehrnsperger [at] yahoo [dot] de > >=head1 DESCRIPTION > >last.fm-ripper is a small utility to save the last.fm program to individual mp3-files including >all availabel id3-tags and the cover art (requires MP3::Tag module). >Requires a valid last.fm login and password (http://www.last.fm/signup.php). >If you don't like to enter your password on the commandline last.fm-ripper asks for it >(requires Term::ReadPassword not to be echoed to the terminal). > >For advanced tagging (track-no., year) an amazon webservices developer token >is required (http://amazon.com/soap). > >=head1 COPYRIGHT > >Copyright (c) 2006 Jochen Schneider. All rights reserved. > 2009 Update to new last fm API: Markus Ehrnsperger > >This program is free software; you can redistribute it and/or >modify it under the terms of the Artistic License, distributed >with Perl. > >=cut
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 263804
: 186562