]>
Commit | Line | Data |
---|---|---|
964dd0bc JW |
1 | <?php |
2 | /* | |
3 | Pitchfork Music Player Daemon Client | |
4 | Copyright (C) 2007 Roger Bystrøm | |
5 | ||
6 | This program is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; version 2 of the License. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License along | |
16 | with this program; if not, write to the Free Software Foundation, Inc., | |
17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 | */ | |
19 | ob_start(); | |
20 | ||
21 | /* how much time must pass before we try searching for cover art again */ | |
22 | $COVER_SEARCH_AGAIN = 86400; | |
23 | ||
6f0e4e7c | 24 | include("aws_signed_request.php"); |
964dd0bc JW |
25 | require_once("../inc/base.php"); |
26 | require_once("metadata_cover.php"); | |
27 | ||
6f0e4e7c JW |
28 | function amazonlink($params) |
29 | { | |
30 | $params["SubscriptionId"] = "15BH771NY941TX2NKC02"; | |
31 | $res = aws_signed_request("com", $params, "Access Key ID", "Secret Access Key"); | |
32 | ||
33 | return $res; | |
34 | } | |
35 | ||
964dd0bc JW |
36 | /* metadata should not require locking of session */ |
37 | session_write_close(); | |
38 | ||
39 | $missing_metadata_dir = false; | |
40 | ||
41 | if(!file_exists($metadata_dir)) { | |
42 | if(!mkdir($metadata_dir, 0755)) { | |
43 | $missing_metadata_dir = true; | |
44 | } | |
45 | } | |
46 | if(!is_writeable($metadata_dir)) { | |
47 | $missing_metadata_dir = true; | |
48 | } | |
49 | ||
50 | if($missing_metadata_dir) { | |
51 | $xml = array_to_xml(array("result" => "nocachedir")); | |
52 | echo $xml->asXML(); | |
53 | exit(); | |
54 | } | |
55 | ||
56 | function escape_name($name) { | |
57 | return str_replace(DIRECTORY_SEPARATOR, "_", $name); | |
58 | } | |
59 | ||
60 | function get_cover_base_name($artist, $album) { | |
61 | global $cover_dir; | |
62 | return $cover_dir . escape_name($artist) . " - " . escape_name($album); | |
63 | } | |
64 | ||
65 | function get_album_info_name($artist, $album) { | |
66 | return get_cover_base_name($artist, $album) . ".txt"; | |
67 | } | |
68 | function get_lyric_filename($artist, $title) { | |
69 | global $cover_dir; | |
70 | return $cover_dir . escape_name($artist) . " - ". escape_name($title) . ".lyric"; | |
71 | } | |
72 | ||
73 | function find_lyrics($arr) { | |
74 | foreach($arr as $val) { | |
75 | if(!is_array($val)) | |
76 | continue; | |
77 | if(isset($val['name'])&&$val['name']=="RETURN") { | |
78 | return $val['children']; | |
79 | } | |
80 | else if(is_array($val)) { | |
81 | $ret = find_lyrics($val); | |
82 | if($ret) | |
83 | return $ret; | |
84 | } | |
85 | } | |
86 | return false; | |
87 | } | |
88 | ||
89 | function fp_get_contents($fp) { | |
90 | $ret = ""; | |
91 | $tmp = false; | |
92 | while($tmp = fgets($fp)) | |
93 | $ret .= $tmp; | |
94 | fseek($fp, 0); | |
95 | if(strlen($ret)==0) | |
96 | return false; | |
97 | return $ret; | |
98 | } | |
99 | ||
100 | /* Queries amazon with the specified url, strict serach first and then a more careless one, | |
101 | * will urlencode artist and albumname | |
102 | * returns xml document or false upon failure */ | |
6f0e4e7c | 103 | function amazon_album_query($params) { |
964dd0bc JW |
104 | $stype = array("Title", "Keywords"); |
105 | $artist = urlencode($artist); | |
106 | $album = urlencode($album); | |
107 | foreach($stype as $st) { | |
108 | if(!amazon_wait()) | |
109 | return false; | |
6f0e4e7c | 110 | $xml = amazonlink($params); |
964dd0bc JW |
111 | if($xml&&isset($xml->Items[0])&&isset($xml->Items[0]->Item[0])) |
112 | return $xml; | |
113 | } | |
114 | return false; | |
115 | } | |
116 | ||
117 | /* returns file pointer or false */ | |
118 | function get_album_lock($artist, $album) { | |
119 | $file_name = get_album_info_name($artist, $album); | |
120 | $exists = file_exists($file_name); | |
121 | $fp = false; | |
122 | ||
123 | if($exists) | |
124 | $fp = @fopen($file_name, "r+"); | |
125 | else $fp = @fopen($file_name, "w+"); | |
126 | if($fp && flock($fp, LOCK_EX)) | |
127 | return $fp; | |
128 | ||
129 | trigger_error("Can't lock album-file: $file_name", E_USER_WARNING); | |
130 | return false; | |
131 | } | |
132 | ||
133 | /* waits for appropriate amazon time, have to be called before making any amazon requests | |
134 | returns true if ok to continue otherwise false */ | |
135 | function amazon_wait() { | |
136 | global $metadata_dir; | |
137 | ||
138 | /* rationale behind this: | |
139 | * amazon requires that we don't make more than one request pr. second pr. ip */ | |
140 | ||
141 | $file_name = $metadata_dir . "amazon_time"; | |
142 | if(file_exists($file_name)) | |
143 | $fp = @fopen($file_name, "r+"); | |
144 | else $fp = @fopen($file_name, "w+"); | |
145 | ||
146 | if(!$fp) { | |
147 | trigger_error("Can't open amazon_time", E_USER_WARNING); | |
148 | return false; | |
149 | } | |
150 | if(!flock($fp, LOCK_EX)) { | |
151 | @fclose($fp); | |
152 | trigger_error("Can't lock amazon_time", E_USER_WARNING); | |
153 | return false; | |
154 | } | |
155 | ||
156 | $last = fp_get_contents($fp); | |
157 | if($last) { | |
158 | $stime = 1000; | |
159 | if(is_numeric($last)) { | |
160 | $stime = current_time_millis() - $last; | |
161 | } | |
162 | $stime = abs($stime); | |
163 | if($stime<1000) | |
164 | usleep($stime*1000); // micro seconds | |
165 | } | |
166 | ||
167 | if(@fwrite($fp, current_time_millis())===false) { | |
168 | @fclose($fp); | |
169 | trigger_error("Can't write to amazon_time", E_USER_WARNING); | |
170 | return false; | |
171 | } | |
172 | else { | |
173 | @fclose($fp); | |
174 | return true; | |
175 | } | |
176 | } | |
177 | ||
178 | /* returns artist and album info and get's album lock or dies */ | |
179 | /* return value: array($fp, $artist, $album) */ | |
180 | function init_album_artist_or_die() { | |
181 | ob_end_clean(); | |
182 | header("Content-Type: text/xml; charset=UTF-8"); | |
183 | ||
184 | $album = ""; | |
185 | $artist = ""; | |
186 | if(isset($_GET['artist'])&&isset($_GET['album']) && | |
187 | strlen(trim($_GET['artist']))>0&&strlen(trim($_GET['album']))>0) { | |
188 | $album = trim($_GET['album']); | |
189 | $artist = trim($_GET['artist']); | |
190 | } | |
191 | else { | |
192 | $xml = array_to_xml(array("result" => "missingparam")); | |
193 | echo $xml->asXML(); | |
194 | exit(); | |
195 | } | |
196 | ||
197 | $fp = get_album_lock($artist, $album); | |
198 | ||
199 | if(!$fp) { | |
200 | $xml = array_to_xml(array("result" => "failed")); | |
201 | echo $xml->asXML(); | |
202 | exit(); | |
203 | } | |
204 | return array($fp, $artist, $album); | |
205 | } | |
206 | ||
207 | /* returns array(artist, album, filename) or false */ | |
208 | function get_current_info() { | |
209 | try { | |
210 | $pl = get_playback(); | |
211 | if($pl) { | |
212 | $info = $pl->getCurrentSong(); | |
213 | if(isset($info['Artist'])&&isset($info['Title'])) { | |
214 | $artist = trim($info['Artist']); | |
215 | $title = trim($info['Title']); | |
216 | $file_name = $info['file']; | |
217 | return array($artist, $title, $file_name); | |
218 | } | |
219 | } | |
220 | $pl->disconnect(); | |
221 | } | |
222 | catch(PEARException $e) { | |
223 | } | |
224 | return false; | |
225 | } | |
226 | ||
227 | ||
228 | function get_cover() { | |
6f0e4e7c | 229 | global $COVER_SEARCH_AGAIN, $cover_providers; |
964dd0bc JW |
230 | |
231 | list($fp, $artist, $album) = init_album_artist_or_die(); | |
232 | ||
233 | $xml = fp_get_contents($fp); | |
234 | if($xml) { | |
235 | $xml = @simplexml_load_string($xml); | |
236 | if($xml) { | |
237 | $use_cache = true; | |
238 | if(isset($xml->notfound)&&is_numeric((string)$xml->notfound[0])) { | |
239 | $time = @intval((string)$xml->notfound[0]); | |
240 | if($time+$COVER_SEARCH_AGAIN<time()) | |
241 | $use_cache = false; | |
242 | } | |
243 | else if(!isset($xml->image[0])&&!isset($xml->thumbnail[0])) { | |
244 | $use_cache = false; | |
245 | } | |
246 | ||
247 | if($use_cache) { | |
248 | $xml->addChild("cached", "true"); | |
249 | echo $xml->asXML(); | |
250 | exit(); | |
251 | } | |
252 | } | |
253 | } | |
254 | ||
255 | ||
256 | $res = false; | |
257 | ||
258 | foreach($cover_providers as $cp) { | |
259 | $res = $cp($artist, $album); | |
260 | if($res&&is_array($res)) | |
261 | break; | |
262 | } | |
263 | ||
264 | if($xml) { | |
265 | if($res&&is_array($res)) { | |
266 | foreach($res as $key => $val) { | |
267 | if(!isset($xml->$key)) | |
268 | $xml->$key = (string)$val; | |
269 | } | |
270 | } | |
271 | else { | |
272 | $xml->notfound = time(); | |
273 | } | |
274 | } | |
275 | else { | |
276 | if($res&&is_array($res)) { | |
277 | $res['time'] = time(); | |
278 | $xml = array_to_xml($res); | |
279 | } | |
280 | else { | |
281 | $xml = array("notfound" => time()); | |
282 | $xml = array_to_xml($xml); | |
283 | } | |
284 | } | |
285 | ||
286 | @fwrite($fp, $xml->asXML()); | |
287 | ||
288 | @fclose($fp); | |
289 | echo $xml->asXML(); | |
290 | exit(); | |
291 | } | |
292 | ||
293 | function get_review() { | |
6f0e4e7c | 294 | global $COVER_SEARCH_AGAIN; |
964dd0bc JW |
295 | |
296 | list($fp, $artist, $album) = init_album_artist_or_die(); | |
297 | ||
298 | $xml = fp_get_contents($fp); | |
299 | $asin = ""; | |
300 | $desc = false; | |
301 | $review = false; | |
302 | $review_src = false; | |
303 | $no_search = false; | |
304 | $failed = false; | |
305 | $changed = false; | |
306 | ||
307 | ||
308 | if($xml) { | |
309 | $xml = @simplexml_load_string($xml); | |
310 | if($xml) { | |
311 | if(isset($xml->rnotfound)&&is_numeric((string)$xml->rnotfound[0])) { | |
312 | $time = @intval((string)$xml->rnotfound[0]); | |
313 | if($time+$COVER_SEARCH_AGAIN>time()) | |
314 | $no_search = true; | |
315 | } | |
316 | } | |
317 | } | |
318 | ||
319 | if(!$xml||(!(isset($xml->review[0])||isset($xml->desc[0]))&&!$no_search)) { | |
320 | $res = false; | |
321 | if(!amazon_wait()) { | |
322 | echo array_to_xml(array("result" => "failed"))->asXML(); | |
323 | exit(); | |
324 | } | |
325 | ||
326 | if($xml&&isset($xml->asin[0])) { | |
6f0e4e7c | 327 | $res = amazonlink(array("Operation"=>"ItemLookup", "IdType"=>"ASIN", "ItemId"=>"urlencode($xml->asin[0])")); |
964dd0bc JW |
328 | $asin = false; |
329 | } | |
330 | else { | |
6f0e4e7c | 331 | $res = @amazon_album_query(array("Operation"=>"ItemSearch", "SearchIndex"=>"Music", "Artist"=>"$artist", "Album"=>"$album")); |
964dd0bc JW |
332 | } |
333 | if($res) { | |
334 | if($res&&isset($res->Items[0])&&isset($res->Items[0]->Item[0])) { | |
335 | $p = $res->Items[0]->Item[0]; | |
336 | $asin = (string) $p->ASIN; | |
337 | if(isset($p->EditorialReviews[0])) { | |
338 | $p = $p->EditorialReviews[0]; | |
339 | foreach($p->EditorialReview as $er) { | |
340 | if(!$desc&&"Album Description" == (string)$er->Source) { | |
341 | $desc = (string) $er->Content; | |
342 | } | |
343 | else if(!$review) { | |
344 | $review_src = (string) $er->Source; | |
345 | $review = (string) $er->Content; | |
346 | } | |
347 | } | |
348 | } | |
349 | /* set info in xml-file... */ | |
350 | if($xml) { | |
351 | if($review) { | |
352 | $xml->review_src = htmlspecialchars($review_src); | |
353 | $xml->review = htmlspecialchars($review); | |
354 | } | |
355 | if($desc) { | |
356 | $xml->desc = htmlspecialchars($desc); | |
357 | } | |
358 | if(!isset($xml->asin[0])) { | |
359 | $xml->addChild("asin", $asin); | |
360 | $changed = true; | |
361 | } | |
362 | if(!$review&&!$desc) { | |
363 | $failed = true; | |
364 | } | |
365 | else { | |
366 | $changed = true; | |
367 | } | |
368 | } | |
369 | else { | |
370 | $xml = array(); | |
371 | $xml['asin'] = $asin; | |
372 | if($desc) | |
373 | $xml['desc'] = $desc; | |
374 | if($review) { | |
375 | $xml['review_src'] = $review_src; | |
376 | $xml['review'] = $review; | |
377 | } | |
378 | if(!$review&&!$desc) | |
379 | $failed = true; | |
380 | $xml = array_to_xml($xml); | |
381 | $changed = true; | |
382 | } | |
383 | } | |
384 | else { | |
385 | $failed = true; | |
386 | } | |
387 | } | |
388 | else { | |
389 | $failed = true; | |
390 | } | |
391 | } | |
392 | else { | |
393 | $xml->addChild("cached", "true"); | |
394 | } | |
395 | ||
396 | if($xml) { | |
397 | if($failed) { | |
398 | if(isset($xml->rnotfound)) { | |
399 | $xml->rnotfound = time(); | |
400 | } | |
401 | else { | |
402 | $xml->addChild("rnotfound", time()); | |
403 | } | |
404 | @fwrite($fp, $xml->asXML()); | |
405 | } | |
406 | else if($changed) { | |
407 | @fwrite($fp, $xml->asXML()); | |
408 | } | |
409 | } | |
410 | else { | |
411 | $xml = array_to_xml(array("rnotfound" => time())); | |
412 | @fwrite($fp, $xml->asXML()); | |
413 | } | |
414 | @fclose($fp); | |
415 | echo $xml->asXML(); | |
416 | exit(); | |
417 | } | |
418 | ||
419 | /* artist, title and song file name in system */ | |
420 | function _get_lyric_lyricwiki($artist, $title, $file_name) { | |
421 | $file = get_lyric_filename($artist, $title); | |
422 | $fp = fsockopen("lyricwiki.org", 80); | |
423 | if(!$fp) { | |
424 | $xml = array_to_xml(array("result"=>"connectionfailed")); | |
425 | return $xml->asXML(); | |
426 | } | |
427 | ||
428 | $out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"; | |
429 | $out .= "<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" "; | |
430 | $out .= "xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" "; | |
431 | $out .= "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "; | |
432 | $out .= "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "; | |
433 | $out .= "xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" "; | |
434 | $out .= "xmlns:tns=\"urn:LyricWiki\">"; | |
435 | $out .= "<SOAP-ENV:Body><tns:getSong xmlns:tns=\"urn:LyricWiki\">"; | |
436 | $out .= "<artist xsi:type=\"xsd:string\">"; | |
437 | $out .= htmlspecialchars($artist); | |
438 | $out .= "</artist>"; | |
439 | $out .= "<song xsi:type=\"xsd:string\">"; | |
440 | $out .= htmlspecialchars($title); | |
441 | $out .= "</song>"; | |
442 | $out .= "</tns:getSong></SOAP-ENV:Body></SOAP-ENV:Envelope>\r\n"; | |
443 | ||
444 | $head = "POST /server.php HTTP/1.1\r\n"; | |
445 | $head .= "Host: lyricwiki.org\r\n"; | |
446 | $head .= "SOAPAction: urn:LyricWiki#getSong\r\n"; | |
447 | $head .= "Content-Type: text/xml; charset=UTF-8\r\n"; | |
448 | $head .= "User-Agent: RemissPitchfork/0.1\r\n"; | |
449 | $head .= "Content-Length: " . str_byte_count($out) . "\r\n"; | |
450 | $head .= "Connection: Close\r\n\r\n"; | |
451 | ||
452 | fwrite($fp, $head . $out); | |
453 | ||
454 | $responseHeader = ""; | |
455 | /* assume everything is dandy */ | |
456 | do { | |
457 | $responseHeader.= fread($fp, 1); | |
458 | } | |
459 | while (!preg_match('/\\r\\n\\r\\n$/', $responseHeader)); | |
460 | ||
461 | $ret = ""; | |
462 | while(!feof($fp)) { | |
463 | $ret .= fgets($fp, 128); | |
464 | } | |
465 | fclose($fp); | |
466 | /* stupid hack to get around wrong xml declearation */ | |
467 | $qmark = "?"; | |
468 | if(strpos($ret, "<". $qmark . "xml version=\"1.0\" encoding=\"ISO-8859-1\"".$qmark.">")===0) | |
469 | $ret = str_replace("<". $qmark . "xml version=\"1.0\" encoding=\"ISO-8859-1\"".$qmark.">", | |
470 | "<". $qmark . "xml version=\"1.0\" encoding=\"UTF-8\"".$qmark.">", | |
471 | $ret); | |
472 | ||
473 | /*echo $ret; | |
474 | exit();*/ | |
475 | $parser = new xml2array(); | |
476 | $parser->parse($ret); | |
477 | $data = find_lyrics($parser->arrOutput); | |
478 | // check that data is ok and lyrics exist | |
479 | if($data&&isset($data[2]['tagData'])) { | |
480 | $res = array(); | |
481 | foreach($data as $d) { | |
482 | if($d['name']=="ARTIST") | |
483 | $res['artist'] = $d['tagData']; | |
484 | else if($d['name']=="SONG") | |
485 | $res['title'] = $d['tagData']; | |
486 | else if($d['name']=="LYRICS") | |
487 | $res['lyric'] = $d['tagData']; | |
488 | else if($d['name']=="URL") | |
489 | $res['url'] = $d['tagData']; | |
490 | } | |
491 | $res['from'] = "lyricwiki.org"; | |
492 | $res['time'] = time(); | |
493 | /* this caching thing will have to be extracted if we | |
494 | * put in another lyrics source */ | |
495 | if(trim($res['lyric'])&&trim($res['lyric'])!="Not found") { | |
496 | $xml = array_to_xml(array("result" => $res)); | |
497 | $xml->addChild("file", htmlspecialchars($file_name)); | |
498 | $res = $xml->asXML(); | |
499 | @file_put_contents($file, $res); | |
500 | } | |
501 | else { | |
502 | $out = array("result" => "notfound"); | |
503 | if(isset($res['url'])) | |
504 | $out['url'] = $res['url']; | |
505 | $res = array_to_xml($out); | |
506 | $res = $res->asXML(); | |
507 | } | |
508 | return $res; | |
509 | } | |
510 | return false; | |
511 | } | |
512 | ||
513 | /* $file: filename of cached version | |
514 | * $file_name: file name of song */ | |
515 | function _get_lyric_cache($file, $file_name) { | |
516 | $xml = @simplexml_load_file($file); | |
517 | if($xml) { | |
518 | $add_file = true; | |
519 | if(isset($xml->file)) { | |
520 | foreach($xml->file as $f) { | |
521 | if(((string)$f)==$file_name) | |
522 | $add_file = false; | |
523 | } | |
524 | } | |
525 | if($add_file) { | |
526 | $xml->addChild("file", htmlspecialchars($file_name)); | |
527 | @file_put_contents($file, $xml->asXML()); | |
528 | } | |
529 | $xml->addChild("cached", "true"); | |
530 | return $xml->asXML(); | |
531 | } | |
532 | return false; | |
533 | } | |
534 | ||
535 | function get_lyric($info = null) { | |
536 | header("Content-Type: text/xml; charset=UTF-8"); | |
537 | ob_end_clean(); | |
538 | if(is_null($info)) | |
539 | $info = get_current_info(); | |
540 | if(!$info) { | |
541 | $xml = array_to_xml(array("result"=>"failed")); | |
542 | echo $xml->asXML(); | |
543 | exit(); | |
544 | } | |
545 | $artist = $info[0]; | |
546 | $title = $info[1]; | |
547 | $file_name = $info[2]; | |
548 | ||
549 | $file = get_lyric_filename($artist, $title); | |
550 | if(file_exists($file)&&!isset($_GET['force'])) { | |
551 | $xml = _get_lyric_cache($file, $file_name); | |
552 | if($xml) { | |
553 | echo $xml; | |
554 | exit(); | |
555 | } | |
556 | } | |
557 | ||
558 | $xml = _get_lyric_lyricwiki($artist, $title, $file_name); | |
559 | if($xml) { | |
560 | echo $xml; | |
561 | } | |
562 | else { | |
563 | echo array_to_xml(array("result" => "failed"))->asXML(); | |
564 | } | |
565 | exit(); | |
566 | } | |
567 | ||
568 | function get_pic() { | |
569 | ||
570 | global $cover_dir; | |
571 | $b_name = basename(trim($_GET['pic'])); | |
572 | $name = $cover_dir . $b_name; | |
573 | if(file_exists($name)&&is_readable($name)) { | |
574 | if(function_exists("finfo_open")&&function_exists("finfo_file")) { | |
575 | $f = finfo_open(FILEINFO_MIME); | |
576 | header("Content-Type: " . finfo_file($f, $name)); | |
577 | } | |
578 | else if(function_exists("mime_content_type")) { | |
579 | header("Content-Type: " . mime_content_type($name)); | |
580 | } | |
581 | else { | |
582 | header("Content-Type: image/jpeg"); | |
583 | } | |
584 | $c = "Content-Disposition: inline; filename=\""; | |
585 | $c .= rawurlencode($b_name) . "\""; | |
586 | header($c); | |
587 | echo @file_get_contents($name); | |
588 | ob_end_flush(); | |
589 | exit(); | |
590 | } | |
591 | else { | |
592 | echo "File does not exist\n"; | |
593 | trigger_error("Did not find albumart althought it was requested", E_USER_WARNING); | |
594 | exit(); | |
595 | } | |
596 | } | |
597 | ||
598 | function get_recommendations_from_playlist() { | |
599 | require_once("../player/openstrands.php"); | |
600 | $pl = get_playlist(); | |
601 | $list = $pl->getPlaylistInfo(); | |
602 | $artist = array(); | |
603 | foreach($list as $song) { | |
604 | if(isset($song['Artist'])&&$song['Artist']) | |
605 | $artist[$song['Artist']] = true; | |
606 | } | |
607 | $artist = array_keys(array_change_key_case($artist)); | |
608 | $pl->disconnect(); | |
609 | ||
610 | header("Content-Type: text/xml; charset=UTF-8"); | |
611 | ||
612 | $ret = strands_get_recommendations($artist); | |
613 | $res = array(); | |
614 | if(!$ret || ! count($ret)) { | |
615 | $res['result'] = is_array($ret)?"notfound":"failed"; | |
616 | echo array_to_xml($res)->asXML(); | |
617 | exit(); | |
618 | } | |
619 | $db = get_database(); | |
620 | foreach($ret as $a) { | |
621 | $tmp = array(); | |
622 | $tmp['name'] = $a; | |
623 | $tmp['album'] = $db->getMetadata("Album", "Artist", $a); | |
624 | $res[] = $tmp; | |
625 | } | |
626 | $out = array("result" => $res); | |
627 | $db->disconnect(); | |
628 | echo array_to_xml($out)->asXML(); | |
629 | } | |
630 | ||
631 | function do_houseclean() { | |
632 | /* this is a *very* inefficient method, but it's needed... */ | |
633 | //header("Content-Type: text/xml; charset=UTF-8"); | |
634 | header("Content-type: multipart/x-mixed-replace;boundary=--ThisRandomString"); | |
635 | ||
636 | global $metadata_dir; | |
637 | ||
638 | echo "--ThisRandomString\n"; | |
639 | $out = "Content-type: text/html\n\n". | |
640 | "<html><head><title>Housecleaning</title></head><body>\n". | |
641 | "<p>Performing housecleaning, please wait...</p>\n"; | |
642 | ||
643 | echo "$out--ThisRandomString\n"; | |
644 | ob_end_flush(); | |
645 | flush(); | |
646 | set_time_limit(300); // this might take a while, but | |
647 | // shouldn't be more than 5 mins even on slow machines | |
648 | $db = get_database(); | |
649 | $res = "failed"; | |
650 | try { | |
651 | $time = current_time_millis(); | |
652 | $list = $db->getAll(); | |
653 | if(!isset($list['file'])) | |
654 | return; | |
655 | $files = $list['file']; | |
656 | $db->disconnect(); | |
657 | $list = scandir($metadata_dir); | |
658 | $total = count($list); | |
659 | $fixed = 0; | |
660 | $errors = 0; | |
661 | $fcount = 0; | |
662 | $fcount_inv = 0; | |
663 | $tcount = 0; | |
664 | foreach($list as $f) { | |
665 | $r = strrpos($f, ".lyric"); | |
666 | $tcount++; | |
667 | if($r!==false&&$r+6==strlen($f)) { | |
668 | $xml = @simplexml_load_file($metadata_dir . $f); | |
669 | $fcount++; | |
670 | if($fcount%100 == 0) { | |
671 | echo $out; | |
672 | echo "<p>Processed $fcount (".(int)($tcount*100/$total)."%)..</p>\n"; | |
673 | echo "--ThisRandomString\n"; | |
674 | flush(); | |
675 | ||
676 | } | |
677 | if($xml) { | |
678 | $x_files = array(); | |
679 | foreach($xml->file as $v) { | |
680 | $x_files[] = (string)$v; | |
681 | } | |
682 | $dis = array_intersect($x_files, $files); | |
683 | if(count($dis)!=count($x_files)) { | |
684 | $dom = @dom_import_simplexml($xml); | |
685 | if($dom===false) { | |
686 | $errors++; | |
687 | continue; | |
688 | } | |
689 | ||
690 | while($elem = $dom->getElementsByTagName("file")->item(0)) { | |
691 | $dom->removeChild($elem); | |
692 | } | |
693 | ||
694 | $xml = simplexml_import_dom($dom); | |
695 | array_to_xml($dis, $xml, "file"); | |
696 | @$xml->asXML($metadata_dir . $f); | |
697 | $fixed++; | |
698 | } | |
699 | } | |
700 | else { | |
701 | $fcount_inv++; | |
702 | } | |
703 | } | |
704 | } | |
705 | $result = array("time" => intval(current_time_millis() - $time), "fixed" => $fixed, "errors" => $errors); | |
706 | } | |
707 | catch(PEAR_Exception $e) { | |
708 | } | |
709 | echo "Content-type: text/html\n\n"; | |
710 | echo "<p>"; | |
711 | if(is_array($result)) { | |
712 | echo "Result of cleaning:<br/>\n"; | |
713 | echo "$fcount files checked in " . $result['time'] . "ms of which $fcount_inv was invalid<br/>"; | |
714 | echo "Fixed: " . $result['fixed'] . "<br/>"; | |
715 | echo "Errors: " . $result['errors'] . "<br/>\n"; | |
716 | ||
717 | } | |
718 | else if($result=="failed") { | |
719 | echo "It appears housecleaning failed, check your MPD settings"; | |
720 | } | |
721 | else { | |
722 | echo "hmm.. somethings wrong, try again"; | |
723 | } | |
724 | echo "</p><p><a href='config.php'>Back to configuration</a></p></body></html>\n"; | |
725 | echo "\n--ThisRandomString\n"; | |
726 | } | |
727 | ||
728 | ||
729 | if(!isset($iamincluded)) { | |
730 | if(isset($_GET['cover'])) get_cover(); | |
731 | else if(isset($_GET['review'])) get_review(); | |
732 | else if(isset($_GET['lyric'])) get_lyric(); | |
733 | else if(isset($_GET['pic'])) get_pic(); | |
734 | else if(isset($_GET['housecleaning'])) do_houseclean(); | |
735 | else if(isset($_GET['plrecommend'])) get_recommendations_from_playlist(); | |
736 | else { | |
737 | header("Content-Type: text/xml; charset=UTF-8"); | |
738 | $xml = array_to_xml(array("result"=>"what do you want?")); | |
739 | echo $xml->asXML(); | |
740 | exit(); | |
741 | } | |
742 | } | |
743 | ||
744 | ||
745 | class xml2Array { | |
746 | ||
747 | var $arrOutput = array(); | |
748 | var $resParser; | |
749 | var $strXmlData; | |
750 | ||
751 | /* parse to utf-8 */ | |
752 | function parse($strInputXML) { | |
753 | ||
754 | $this->resParser = xml_parser_create("UTF-8"); | |
755 | ||
756 | xml_set_object($this->resParser,$this); | |
757 | xml_set_element_handler($this->resParser, "tagOpen", "tagClosed"); | |
758 | xml_parser_set_option($this->resParser, XML_OPTION_TARGET_ENCODING, "UTF-8"); | |
759 | ||
760 | xml_set_character_data_handler($this->resParser, "tagData"); | |
761 | ||
762 | $this->strXmlData = xml_parse($this->resParser,$strInputXML ); | |
763 | if(!$this->strXmlData) { | |
764 | die(sprintf("XML error: %s at line %d", | |
765 | xml_error_string(xml_get_error_code($this->resParser)), | |
766 | xml_get_current_line_number($this->resParser))); | |
767 | } | |
768 | ||
769 | xml_parser_free($this->resParser); | |
770 | ||
771 | return $this->arrOutput; | |
772 | } | |
773 | function tagOpen($parser, $name, $attrs) { | |
774 | $tag=array("name"=>$name,"attrs"=>$attrs); | |
775 | array_push($this->arrOutput,$tag); | |
776 | } | |
777 | ||
778 | function tagData($parser, $tagData) { | |
779 | if(isset($this->arrOutput[count($this->arrOutput)-1]['tagData'])) | |
780 | $this->arrOutput[count($this->arrOutput)-1]['tagData'] .= $tagData; | |
781 | else | |
782 | $this->arrOutput[count($this->arrOutput)-1]['tagData'] = $tagData; | |
783 | } | |
784 | ||
785 | function tagClosed($parser, $name) { | |
786 | $this->arrOutput[count($this->arrOutput)-2]['children'][] = $this->arrOutput[count($this->arrOutput)-1]; | |
787 | array_pop($this->arrOutput); | |
788 | } | |
789 | } | |
790 | ||
791 | ?> |