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