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