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