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