]> git.sesse.net Git - shamaz/blob - lookup.pl
Initial commit.
[shamaz] / lookup.pl
1 #! /usr/bin/perl
2 use LWP::UserAgent;
3 use HTTP::Request;
4 use IPC::Open2;
5 use XML::DOM;
6 use POSIX;
7
8 my $ua = LWP::UserAgent->new;
9 push(@LWP::Protocol::http::EXTRA_SOCK_OPTS, SendTE => 0);
10 $ua->agent('Dalvik/1.2.0 (Linux; U; Android Froyo Build/MASTER)');
11
12 my $requestid = recognize($ua, $ARGV[0]);
13 lookup($ua, $requestid);
14
15 sub recognize {
16         my ($ua, $filename) = @_;
17         my $amr;
18         {
19                 local $/ = undef;
20                 $amr = `cat $filename`;
21         }
22
23         my @parts = (
24                 language => make_part('en_US'),
25                 service => make_part('cn=CH,cn=V3,cn=SmartClub,cn=ShazamiD,cn=services'),
26                 applicationIdentifier => make_encrypted_string('ShazamId_SmartPhone_Gamma__1.2'),
27                 deviceId => make_encrypted_string('1234567812345678'),
28                 deviceModel => make_encrypted_string('Nexus_One'),
29                 userAgent => make_encrypted_string('Mozilla/5.0_(Linux;_U;_Android_1.0;_en-us;_generic)_AppleWebKit/525.10+_(KHTML,_like_Gecko)_Version/3.0.4_Mobile_Safari/523.12.2'),
30                 tagDate => make_encrypted_string(POSIX::strftime("%Y-%m-%dT%H:%M:%S", localtime)),
31                 cryptToken => make_encrypted_string('A220B36F'),
32                 sample => make_encrypted_part($amr, 'janet.3gp.amr', 'application/octet-stream'),
33         );
34
35         my $res = $ua->post(
36                 'http://goog.shazamid.com/orbit/DoRecognition1',
37                 \@parts,
38                 'content-language' => 'en_US',
39                 'Content_Type' => 'multipart/form-data; boundary=A3r_ISAAC_eQeY2Bh');
40          
41         if (!$res->is_success) {
42                 die $res->status_line;
43         }
44
45         my $parser = XML::DOM::Parser->new;
46         my $doc = $parser->parse($res->content);
47         my $ids = $doc->getElementsByTagName("requestId");
48         if ($ids->getLength == 0) {
49                 print "Didn't recognize song\n";
50                 exit;
51         }
52         return $ids->item(0)->getAttribute('id');
53 }
54
55 sub lookup {
56         my ($ua, $requestid) = @_;
57
58         my @parts = (
59                 language => make_part('en_US'),
60                 service => make_part('cn=CH,cn=V3,cn=SmartClub,cn=ShazamiD,cn=services'),
61                 applicationIdentifier => make_encrypted_string('ShazamId_SmartPhone_Gamma__1.2'),
62                 deviceId => make_encrypted_string('1234567812345678'),
63                 deviceModel => make_encrypted_string('Nexus_One'),
64                 userAgent => make_encrypted_string('Mozilla/5.0_(Linux;_U;_Android_1.0;_en-us;_generic)_AppleWebKit/525.10+_(KHTML,_like_Gecko)_Version/3.0.4_Mobile_Safari/523.12.2'),
65                 requestId => make_encrypted_string($requestid),
66                 coverartSize => make_encrypted_string('304'),
67                 artistartX => make_encrypted_string('81'),
68                 artistartY => make_encrypted_string('0'),
69                 cryptToken => make_encrypted_string('A220B36F'),
70         );
71
72         my $res = $ua->post(
73                 'http://goog.shazamid.com/orbit/RequestResults1',
74                 \@parts,
75                 'content-language' => 'en_US',
76                 'Content_Type' => 'multipart/form-data; boundary=A3r_ISAAC_eQeY2Bh');
77          
78         if (!$res->is_success) {
79                 die $res->status_line;
80         }
81
82         my $parser = XML::DOM::Parser->new;
83         my $doc = $parser->parse($res->content);
84         my $tracks = $doc->getElementsByTagName("track");
85         if ($tracks->getLength == 0) {
86                 print "Didn't recognize song\n";
87                 exit;
88         }
89         my $track = $tracks->item(0);
90         my $title = $track->getElementsByTagName("ttitle")->item(0)->getFirstChild->getData;
91         my $artist = $track->getElementsByTagName("tartist")->item(0)->getFirstChild->getData;
92
93         print "$title,$artist\n";
94 }
95
96 sub make_part {
97         my ($content, $filename, $mime_type) = @_;
98         if (defined($mime_type)) {
99                 return [ undef, $filename, 'Content' => $content, 'Content-Type' => $mime_type ];
100         } else {
101                 return [ undef, $filename, 'Content' => $content ];
102         }
103 }
104
105 sub make_encrypted_string {
106         my ($content, $filename, $mime_type) = @_;
107         if (length($content) % 8 == 0) {
108                 $content .= "\0\0\0\0\0\0\0\0";
109         }
110         my $enc = '#0x' . join("", map { sprintf "%02X", $_ } (unpack("W*", encrypt($content))));
111         return make_part($enc, $filename, $mime_type);
112 }
113
114 sub make_encrypted_part {
115         my ($content, $filename, $mime_type) = @_;
116         my $enc = encrypt($content);
117         return make_part($enc, $filename, $mime_type);
118 }
119         
120 sub encrypt {
121         my $content = shift;
122         my $blocks = (length($content) + 7) / 8;
123         my $ret = "";
124         local $/ = undef;
125
126         $pid = open2(\*CHLD_OUT, \*CHLD_IN, './encrypt-ice');
127         for my $i (0..($blocks-1)) {
128                 my $block = substr($content, 8*$i, 8);
129                 print CHLD_IN $block;
130         }
131
132         close CHLD_IN;
133         $ret = <CHLD_OUT>;
134         close CHLD_OUT;
135         return $ret;
136 }