332 lines
13 KiB
PHP
332 lines
13 KiB
PHP
<?php
|
|
|
|
// Automatic Collection Updates can be performed using cURL:
|
|
// curl -b "currenthost=Default;player_backend=mpd" http://localhost/rompr/albums.php?rebuild > /dev/null
|
|
// where currenthost is the name of one of the Players defined in the Configuration menu
|
|
// and player_backend MUST be mpd or mopidy, depending on what your player is.
|
|
// You can also use eg -b "debug_enabled=8;currenthost=MPD;player_backend=mpd"
|
|
// to get more debug info in the webserver error log.
|
|
|
|
require_once ("includes/vars.php");
|
|
require_once ("includes/functions.php");
|
|
require_once ("utils/imagefunctions.php");
|
|
require_once ("international.php");
|
|
require_once ("backends/sql/backend.php");
|
|
$error = 0;
|
|
|
|
logger::trace("TIMINGS", "======================================================================");
|
|
$initmem = memory_get_usage();
|
|
logger::trace("COLLECTION", "Memory Used is ".$initmem);
|
|
$now2 = time();
|
|
|
|
switch (true) {
|
|
|
|
case array_key_exists('item', $_REQUEST):
|
|
logit('item');
|
|
// Populate a dropdown in the collection or search results
|
|
dumpAlbums($_REQUEST['item']);
|
|
break;
|
|
|
|
case array_key_exists('mpdsearch', $_REQUEST):
|
|
logit('mpdsearch');
|
|
// Handle an mpd-style search request
|
|
require_once ("player/".$prefs['player_backend']."/player.php");
|
|
require_once ("collection/collection.php");
|
|
$trackbytrack = true;
|
|
$doing_search = true;
|
|
mpd_search();
|
|
break;
|
|
|
|
case array_key_exists('browsealbum', $_REQUEST):
|
|
logit('browsealbum');
|
|
// Populate a spotify album in mopidy's search results - as spotify doesn't return all tracks
|
|
require_once ("player/".$prefs['player_backend']."/player.php");
|
|
require_once ("collection/collection.php");
|
|
$trackbytrack = true;
|
|
$doing_search = true;
|
|
browse_album();
|
|
break;
|
|
|
|
case array_key_exists("rawterms", $_REQUEST):
|
|
logit('rawterms');
|
|
// Handle an mpd-style search request requiring tl_track format results
|
|
// Note that raw_search uses the collection models but not the database
|
|
// hence $trackbytrack must be false
|
|
logger::log("MPD SEARCH", "Doing RAW search");
|
|
require_once ("player/".$prefs['player_backend']."/player.php");
|
|
require_once ("collection/collection.php");
|
|
require_once ("collection/dbsearch.php");
|
|
$doing_search = true;
|
|
raw_search();
|
|
break;
|
|
|
|
case array_key_exists('terms', $_REQUEST):
|
|
logit('terms');
|
|
// SQL database search request
|
|
require_once ("player/".$prefs['player_backend']."/player.php");
|
|
require_once ("collection/collection.php");
|
|
require_once ("collection/dbsearch.php");
|
|
$doing_search = true;
|
|
database_search();
|
|
break;
|
|
|
|
case array_key_exists('rebuild', $_REQUEST):
|
|
logit('rebuild');
|
|
// This is a request to rebuild the music collection
|
|
require_once ("player/".$prefs['player_backend']."/player.php");
|
|
require_once ("collection/collection.php");
|
|
$trackbytrack = true;
|
|
update_collection();
|
|
break;
|
|
|
|
default:
|
|
logger::fail("ALBUMS", "Couldn't figure out what to do!");
|
|
break;
|
|
|
|
}
|
|
|
|
logger::trace("TIMINGS", "== Collection Update And Send took ".format_time(time() - $now2));
|
|
$peakmem = memory_get_peak_usage();
|
|
$ourmem = $peakmem - $initmem;
|
|
logger::trace("TIMINGS", "Peak Memory Used Was ".number_format($peakmem)." bytes - meaning we used ".number_format($ourmem)." bytes.");
|
|
logger::trace("TIMINGS", "======================================================================");
|
|
|
|
function logit($key) {
|
|
logger::log("COLLECTION", "Request is",$key,"=",$_REQUEST[$key]);
|
|
}
|
|
|
|
function checkDomains($d) {
|
|
if (array_key_exists('domains', $d)) {
|
|
return $d['domains'];
|
|
}
|
|
logger::debug("SEARCH", "No search domains in use");
|
|
return false;
|
|
}
|
|
|
|
function mpd_search() {
|
|
global $dbterms, $skin, $PLAYER_TYPE;
|
|
// If we're searching for tags or ratings it would seem sensible to only search the database
|
|
// HOWEVER - we could be searching for genre or performer or composer - which will not match in the database
|
|
// For those cases ONLY, controller.js will call into this instead of database_search, and we set $dbterms
|
|
// to make the collection check everything it finds against the database
|
|
$cmd = $_REQUEST['command'];
|
|
$domains = checkDomains($_REQUEST);
|
|
foreach ($_REQUEST['mpdsearch'] as $key => $term) {
|
|
switch ($key) {
|
|
case 'tag':
|
|
case 'rating':
|
|
$dbterms[$key] = $term;
|
|
break;
|
|
|
|
case 'any':
|
|
// This makes a search term of 'Madness My Girl' into
|
|
// search any Madness any My any Girl
|
|
// which seems to produce better results with Spotify. But probably doesn't with Google Play, which
|
|
// only uses the first term. Soundcloud concatenates them all back into one term again. What does MPD do?
|
|
foreach ($term as $t) {
|
|
$terms = explode(' ',$t);
|
|
foreach ($terms as $tom) {
|
|
$cmd .= " ".$key.' "'.format_for_mpd(html_entity_decode(trim($tom))).'"';
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
foreach ($term as $t) {
|
|
$cmd .= " ".$key.' "'.format_for_mpd(html_entity_decode(trim($t))).'"';
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
logger::log("MPD SEARCH", "Search command : ".$cmd);
|
|
if ($_REQUEST['resultstype'] == "tree") {
|
|
require_once ("player/mpd/filetree.php");
|
|
require_once ("skins/".$skin."/ui_elements.php");
|
|
$player = new fileCollector();
|
|
$player->doFileSearch($cmd, $domains);
|
|
} else {
|
|
cleanSearchTables();
|
|
prepareCollectionUpdate();
|
|
$collection = new musicCollection();
|
|
$player = new $PLAYER_TYPE();
|
|
$player->populate_collection($cmd, $domains, $collection);
|
|
$collection->tracks_to_database();
|
|
close_transaction();
|
|
dumpAlbums($_REQUEST['dump']);
|
|
remove_findtracks();
|
|
}
|
|
}
|
|
|
|
function browse_album() {
|
|
global $PLAYER_TYPE, $skin;
|
|
$a = preg_match('/(a|b)(.*?)(\d+|root)/', $_REQUEST['browsealbum'], $matches);
|
|
if (!$a) {
|
|
print '<h3>'.get_int_text("label_general_error").'</h3>';
|
|
logger::error("DUMPALBUMS", "Browse Album Failed - regexp failed to match", $_REQUEST['browsealbum']);
|
|
return false;
|
|
}
|
|
$why = $matches[1];
|
|
$what = $matches[2];
|
|
$who = $matches[3];
|
|
$albumlink = get_albumlink($who);
|
|
if (substr($albumlink, 0, 8) == 'podcast+') {
|
|
require_once ('includes/podcastfunctions.php');
|
|
logger::log("ALBUMS", "Browsing For Podcast ".substr($albumlink, 9));
|
|
$podid = getNewPodcast(substr($albumlink, 8), 0, false);
|
|
logger::trace("ALBUMS", "Ouputting Podcast ID ".$podid);
|
|
outputPodcast($podid, false);
|
|
} else {
|
|
if (preg_match('/^.+?:artist:/', $albumlink)) {
|
|
remove_album_from_database($who);
|
|
}
|
|
$player = new $PLAYER_TYPE();
|
|
$collection = new musicCollection();
|
|
$cmd = 'find file "'.$albumlink.'"';
|
|
logger::log("MPD", "Doing Album Browse : ".$cmd);
|
|
prepareCollectionUpdate();
|
|
$player->populate_collection($cmd, false, $collection);
|
|
$collection->tracks_to_database(true);
|
|
close_transaction();
|
|
remove_findtracks();
|
|
if (preg_match('/^.+?:album:/', $albumlink)) {
|
|
// Just occasionally, the spotify album originally returned by search has an incorrect AlbumArtist
|
|
// When we browse the album the new tracks therefore get added to a new album, while the original tracks
|
|
// remain attached to the old one. This is where we use do_tracks_from_database with an array of albumids
|
|
// which joins them together into a virtual album, with the track ordering correct
|
|
print do_tracks_from_database($why, $what, find_justadded_albums(), true);
|
|
} else {
|
|
$artistarray = find_justadded_artists();
|
|
$do_controlheader = true;
|
|
foreach ($artistarray as $artistid) {
|
|
do_albums_from_database($why, 'album', $artistid, false, false, true, $do_controlheader);
|
|
$do_controlheader = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function raw_search() {
|
|
global $PLAYER_TYPE, $doing_search;
|
|
$domains = checkDomains($_REQUEST);
|
|
$collection = new musicCollection();
|
|
$found = 0;
|
|
logger::trace("MPD SEARCH", "checkdb is ".$_REQUEST['checkdb']);
|
|
if ($_REQUEST['checkdb'] !== 'false') {
|
|
logger::trace("MPD SEARCH", " ... checking database first ");
|
|
$found = doDbCollection($_REQUEST['rawterms'], $domains, "RAW", $collection);
|
|
if ($found > 0) {
|
|
logger::log("MPD SEARCH", " ... found ".$found." matches in database");
|
|
}
|
|
}
|
|
if ($found == 0) {
|
|
$cmd = $_REQUEST['command'];
|
|
foreach ($_REQUEST['rawterms'] as $key => $term) {
|
|
$cmd .= " ".$key.' "'.format_for_mpd(html_entity_decode($term[0])).'"';
|
|
}
|
|
logger::log("MPD SEARCH", "Search command : ".$cmd);
|
|
$doing_search = true;
|
|
$player = new $PLAYER_TYPE();
|
|
$player->populate_collection($cmd, $domains, $collection);
|
|
|
|
// For backends that don't support multiple parameters (Google Play)
|
|
// This'll return nothing for Spotify, so it's OK. It might help SoundCloud too.
|
|
|
|
$cmd = $_REQUEST['command'].' any ';
|
|
$parms = array();
|
|
if (array_key_exists('artist', $_REQUEST['rawterms'])) {
|
|
$parms[] = format_for_mpd(html_entity_decode($_REQUEST['rawterms']['artist'][0]));
|
|
}
|
|
if (array_key_exists('title', $_REQUEST['rawterms'])) {
|
|
$parms[] = format_for_mpd(html_entity_decode($_REQUEST['rawterms']['title'][0]));
|
|
}
|
|
if (count($parms) > 0) {
|
|
$cmd .= '"'.implode(' ',$parms).'"';
|
|
logger::log("MPD SEARCH", "Search command : ".$cmd);
|
|
$doing_search = true;
|
|
$collection->filter_duplicate_tracks();
|
|
$player->populate_collection($cmd, $domains, $collection);
|
|
}
|
|
|
|
}
|
|
print json_encode($collection->tracks_as_array());
|
|
}
|
|
|
|
function database_search() {
|
|
$tree = null;
|
|
$domains = checkDomains($_REQUEST);
|
|
if ($_REQUEST['resultstype'] == "tree") {
|
|
$tree = new mpdlistthing(null);
|
|
} else {
|
|
cleanSearchTables();
|
|
open_transaction();
|
|
}
|
|
$fcount = doDbCollection($_REQUEST['terms'], $domains, $_REQUEST['resultstype'], $tree);
|
|
if ($_REQUEST['resultstype'] == "tree") {
|
|
printFileSearch($tree, $fcount);
|
|
} else {
|
|
close_transaction();
|
|
dumpAlbums($_REQUEST['dump']);
|
|
}
|
|
}
|
|
|
|
function update_collection() {
|
|
global $PLAYER_TYPE;
|
|
|
|
// Check that an update is not currently in progress
|
|
// and create the update lock if not
|
|
if (collectionUpdateRunning()) {
|
|
header('HTTP/1.1 500 Internal Server Error');
|
|
print get_int_text('error_nocol');
|
|
exit(0);
|
|
}
|
|
|
|
if (file_exists('prefs/monitor')) {
|
|
unlink('prefs/monitor');
|
|
}
|
|
// Send some dummy data back to the browser, then close the connection
|
|
// so that the browser doesn't time out and retry
|
|
$sapi_type = php_sapi_name();
|
|
logger::log('COLLECTION','SAPI Name is',$sapi_type);
|
|
if (preg_match('/fpm/', $sapi_type) || preg_match('/fcgi/', $sapi_type)) {
|
|
logger::mark('COLLECTION', 'Closing Request The FastCGI Way');
|
|
print('<html></html>');
|
|
fastcgi_finish_request();
|
|
} else {
|
|
logger::mark('COLLECTION', 'Closing Request The Apache Way');
|
|
ob_end_clean();
|
|
ignore_user_abort(true); // just to be safe
|
|
ob_start();
|
|
print('<html></html>');
|
|
$size = ob_get_length();
|
|
header("Content-Length: $size");
|
|
header("Content-Encoding: none");
|
|
header("Connection: close");
|
|
ob_end_flush();
|
|
ob_flush();
|
|
flush();
|
|
if (ob_get_contents()) {
|
|
ob_end_clean();
|
|
}
|
|
}
|
|
|
|
if (session_id()) {
|
|
session_write_close();
|
|
}
|
|
|
|
// Browser is now happy. Now we can do our work in peace.
|
|
cleanSearchTables();
|
|
prepareCollectionUpdate();
|
|
$player = new $PLAYER_TYPE();
|
|
$player->musicCollectionUpdate();
|
|
tidy_database();
|
|
remove_findtracks();
|
|
// Add a marker to the monitor file to say we've finished
|
|
$player->collectionUpdateDone();
|
|
// Clear the update lock
|
|
clearUpdateLock();
|
|
|
|
}
|
|
|
|
?>
|