606 lines
18 KiB
PHP
606 lines
18 KiB
PHP
<?php
|
|
|
|
$dtz = ini_get('date.timezone');
|
|
if (!$dtz) {
|
|
date_default_timezone_set('UTC');
|
|
}
|
|
|
|
define('ROMPR_MAX_TRACKS_PER_TRANSACTION', 500);
|
|
define('ROMPR_COLLECTION_VERSION', 3);
|
|
define('ROMPR_IMAGE_VERSION', 4);
|
|
define('ROMPR_SCHEMA_VERSION', 56);
|
|
define('ROMPR_VERSION', '1.32');
|
|
define('ROMPR_IDSTRING', 'RompR Music Player '.ROMPR_VERSION);
|
|
define('ROMPR_MOPIDY_MIN_VERSION', 1.1);
|
|
define('ROMPR_UNKNOWN_STREAM', "Unknown Internet Stream");
|
|
|
|
define('REFRESHOPTION_NEVER', 0);
|
|
define('REFRESHOPTION_HOURLY', 1);
|
|
define('REFRESHOPTION_DAILY', 2);
|
|
define('REFRESHOPTION_WEEKLY', 3);
|
|
define('REFRESHOPTION_MONTHLY', 4);
|
|
|
|
define('SORTMODE_NEWESTFIRST', 0);
|
|
define('SORTMODE_OLDESTFIRST', 1);
|
|
|
|
define('DISPLAYMODE_ALL', 0);
|
|
define('DISPLAYMODE_NEW', 1);
|
|
define('DISPLAYMODE_UNLISTENED', 2);
|
|
define('DISPLAYMODE_DOWNLOADEDNEW', 3);
|
|
define('DISPLAYMODE_DOWNLOADED', 4);
|
|
|
|
define('ROMPR_PODCAST_TABLE_VERSION', 4);
|
|
|
|
define('ADDED_ALL_TIME', 0);
|
|
define('ADDED_TODAY', 1);
|
|
define('ADDED_THIS_WEEK', 2);
|
|
define('ADDED_THIS_MONTH', 3);
|
|
define('ADDED_THIS_YEAR', 4);
|
|
|
|
// Safe definitions for setups that do not have a full set of image support built in,
|
|
// Otherwise we spam the server logs with udefined constant errors.
|
|
// These are the MIME types that make it compatible with imagemagick
|
|
if (!defined('IMAGETYPE_JPEG')) {
|
|
define('IMAGETYPE_JPEG', 'image/jpeg');
|
|
}
|
|
if (!defined('IMAGETYPE_GIF')) {
|
|
define('IMAGETYPE_GIF', 'image/gif');
|
|
}
|
|
if (!defined('IMAGETYPE_PNG')) {
|
|
define('IMAGETYPE_PNG', 'image/png');
|
|
}
|
|
if (!defined('IMAGETYPE_WBMP')) {
|
|
define('IMAGETYPE_WBMP', 'image/wbmp');
|
|
}
|
|
if (!defined('IMAGETYPE_XBM')) {
|
|
define('IMAGETYPE_XBM', 'image/xbm');
|
|
}
|
|
if (!defined('IMAGETYPE_WEBP')) {
|
|
define('IMAGETYPE_WEBP', 'image/webp');
|
|
}
|
|
if (!defined('IMAGETYPE_BMP')) {
|
|
define('IMAGETYPE_BMP', 'image/bmp');
|
|
}
|
|
if (!defined('IMAGETYPE_SVG')) {
|
|
define('IMAGETYPE_SVG', 'image/svg+xml');
|
|
}
|
|
|
|
define('ORIENTATION_PORTRAIT', 0);
|
|
define('ORIENTATION_LANDSCAPE', 1);
|
|
|
|
define('MPD_FILE_MODEL', array (
|
|
'file' => null,
|
|
'domain' => 'local',
|
|
'type' => 'local',
|
|
'station' => null,
|
|
'stream' => null,
|
|
'folder' => null,
|
|
'Title' => null,
|
|
'Album' => null,
|
|
'Artist' => null,
|
|
'Track' => 0,
|
|
'Name' => null,
|
|
'AlbumArtist' => null,
|
|
'Time' => 0,
|
|
'X-AlbumUri' => null,
|
|
'playlist' => '',
|
|
'X-AlbumImage' => null,
|
|
'Date' => null,
|
|
'Last-Modified' => '0',
|
|
'Disc' => null,
|
|
'Composer' => null,
|
|
'Performer' => null,
|
|
'Genre' => null,
|
|
'ImgKey' => null,
|
|
'StreamIndex' => null,
|
|
'Searched' => 0,
|
|
'Playcount' => 0,
|
|
'Comment' => '',
|
|
// Never send null in any musicbrainz id as it prevents plugins from
|
|
// waiting on lastfm to find one
|
|
'MUSICBRAINZ_ALBUMID' => '',
|
|
'MUSICBRAINZ_ARTISTID' => array(''),
|
|
'MUSICBRAINZ_ALBUMARTISTID' => '',
|
|
'MUSICBRAINZ_TRACKID' => '',
|
|
'Id' => null,
|
|
'Pos' => null,
|
|
'ttindex' => null,
|
|
'trackartist_index' => null,
|
|
'albumartist_index' => null,
|
|
'album_index' => null,
|
|
'searchflag' => 0,
|
|
'hidden' => 0,
|
|
'isaudiobook' => 0
|
|
)
|
|
);
|
|
|
|
define('MPD_ARRAY_PARAMS', array(
|
|
"Artist",
|
|
"AlbumArtist",
|
|
"Composer",
|
|
"Performer",
|
|
"MUSICBRAINZ_ARTISTID",
|
|
)
|
|
);
|
|
|
|
// Rompr's internal file model used in the Javascript side is a merge of the MPD_FILE_MODEL and ROMPR_FILE_MODEL
|
|
// it is created in class playlistCollection
|
|
|
|
define('ROMPR_FILE_MODEL', array(
|
|
"progress" => 0,
|
|
"year" => null,
|
|
"albumartist" => '',
|
|
"trackartist" => '',
|
|
"images" => '',
|
|
"metadata" => array(
|
|
"iscomposer" => 'false',
|
|
"artists" => array(),
|
|
"album" => array(
|
|
"name" => '',
|
|
"artist" => '',
|
|
"musicbrainz_id" => '',
|
|
"uri" => null
|
|
),
|
|
"track" => array(
|
|
"name" => '',
|
|
"musicbrainz_id" => '',
|
|
),
|
|
)
|
|
)
|
|
);
|
|
|
|
$mysqlc = null;
|
|
|
|
$prefs = array(
|
|
// Things that only make sense as backend options, not per-user options
|
|
"music_directory_albumart" => "",
|
|
"mysql_host" => "localhost",
|
|
"mysql_database" => "romprdb",
|
|
"mysql_user" => "rompr",
|
|
"mysql_password" => "romprdbpass",
|
|
"mysql_port" => "3306",
|
|
"proxy_host" => "",
|
|
"proxy_user" => "",
|
|
"proxy_password" => "",
|
|
"sortbycomposer" => false,
|
|
"composergenre" => false,
|
|
"composergenrename" => array("Classical"),
|
|
"preferlocalfiles" => false,
|
|
"mopidy_collection_folders" => array("Spotify Playlists","Local media","SoundCloud/Liked"),
|
|
"lastfm_country_code" => "GB",
|
|
"country_userset" => false,
|
|
"debug_enabled" => 0,
|
|
"custom_logfile" => "",
|
|
"cleanalbumimages" => true,
|
|
"do_not_show_prefs" => false,
|
|
// This option for plugin debugging ONLY
|
|
"load_plugins_at_loadtime" => false,
|
|
"beets_server_location" => "",
|
|
"multihosts" => (object) array (
|
|
'Default' => (object) array(
|
|
'host' => 'localhost',
|
|
'port' => '6600',
|
|
'password' => '',
|
|
'socket' => '',
|
|
'mopidy_slave' => false,
|
|
'radioparams' => (object) array (
|
|
"radiomode" => "",
|
|
"radioparam" => "",
|
|
"radiomaster" => "",
|
|
"radioconsume" => 0
|
|
)
|
|
)
|
|
),
|
|
'dev_mode' => false,
|
|
'live_mode' => false,
|
|
'collection_load_timeout' => 3600000,
|
|
"smartradio_chunksize" => 5,
|
|
"linkchecker_nextrun" => 0,
|
|
"linkchecker_isrunning" => false,
|
|
"linkchecker_frequency" => 604800000,
|
|
"linkchecker_polltime" => 5000,
|
|
"audiobook_directory" => '',
|
|
"collection_player" => null,
|
|
"snapcast_server" => '',
|
|
"snapcast_port" => '1705',
|
|
|
|
// Things that could be set on a per-user basis but need to be known by the backend
|
|
"displaycomposer" => true,
|
|
"artistsatstart" => array("Various Artists","Soundtracks"),
|
|
"nosortprefixes" => array("The"),
|
|
"sortcollectionby" => "artist",
|
|
"showartistbanners" => true,
|
|
"google_api_key" => '',
|
|
"google_search_engine_id" => '',
|
|
"sync_lastfm_playcounts" => false,
|
|
"sync_lastfm_at_start" => false,
|
|
"last_lastfm_synctime" => time(),
|
|
"lfm_importer_start_offset" => 0,
|
|
"lfm_importer_last_import" => 0,
|
|
|
|
// Things that are set as Cookies
|
|
"sortbydate" => false,
|
|
"notvabydate" => false,
|
|
"currenthost" => 'Default',
|
|
"player_backend" => "none",
|
|
"collectionrange" => ADDED_ALL_TIME,
|
|
|
|
// These are currently saved in the backend, as the most likely scenario is one user
|
|
// with multiple browsers. But what if it's multiple users?
|
|
"lastfm_user" => "",
|
|
"lastfm_session_key" => "",
|
|
"autotagname" => "",
|
|
|
|
// All of these are saved in the browser, so these are only defaults
|
|
"tradsearch" => false,
|
|
"lastfm_scrobbling" => false,
|
|
"lastfm_autocorrect" => false,
|
|
"sourceshidden" => false,
|
|
"playlisthidden" => false,
|
|
"infosource" => "lastfm",
|
|
"playlistcontrolsvisible" => false,
|
|
"sourceswidthpercent" => 25,
|
|
"playlistwidthpercent" => 25,
|
|
"downloadart" => true,
|
|
"clickmode" => "double",
|
|
"chooser" => "albumlist",
|
|
"hide_albumlist" => false,
|
|
"hide_filelist" => false,
|
|
"hide_radiolist" => false,
|
|
"hide_podcastslist" => false,
|
|
"hide_playlistslist" => false,
|
|
"hide_audiobooklist" => false,
|
|
"hide_searcher" => false,
|
|
"hidebrowser" => false,
|
|
"shownupdatewindow" => '',
|
|
"scrolltocurrent" => false,
|
|
"alarm_ramptime" => 30,
|
|
"alarm_snoozetime" => 8,
|
|
"lastfmlang" => "default",
|
|
"user_lang" => "en",
|
|
"synctags" => false,
|
|
"synclove" => false,
|
|
"synclovevalue" => "5",
|
|
"theme" => "Numismatist.css",
|
|
"icontheme" => "Modern-Dark",
|
|
"coversize" => "40-Large.css",
|
|
"fontsize" => "04-Grande.css",
|
|
"fontfamily" => "Nunito.css",
|
|
"collectioncontrolsvisible" => false,
|
|
"displayresultsas" => "collection",
|
|
'crossfade_duration' => 5,
|
|
"newradiocountry" => "countries/GB",
|
|
"search_limit_limitsearch" => false,
|
|
"scrobblepercent" => 50,
|
|
"updateeverytime" => false,
|
|
"fullbiobydefault" => true,
|
|
"mopidy_search_domains" => array("local", "spotify"),
|
|
"mopidy_radio_domains" => array("local", "spotify"),
|
|
"outputsvisible" => false,
|
|
"wheelscrollspeed" => "150",
|
|
"searchcollectiononly" => false,
|
|
"displayremainingtime" => true,
|
|
"cdplayermode" => false,
|
|
"auto_discovembobulate" => false,
|
|
"ratman_sortby" => 'Rating',
|
|
"ratman_showletters" => false,
|
|
"sleeptime" => 30,
|
|
"sleepon" => false,
|
|
"advanced_search_open" => false,
|
|
"sortwishlistby" => 'artist',
|
|
"player_in_titlebar" => false,
|
|
"communityradiocountry" => 'united kingdom',
|
|
"communityradiolanguage" => '',
|
|
"communityradiotag" => '',
|
|
"communityradiolistby" => 'country',
|
|
"communityradioorderby" => 'name',
|
|
"browser_id" => null,
|
|
"playlistswipe" => true,
|
|
"podcastcontrolsvisible" => true,
|
|
"default_podcast_display_mode" => DISPLAYMODE_ALL,
|
|
"default_podcast_refresh_mode" => REFRESHOPTION_MONTHLY,
|
|
"default_podcast_sort_mode" => SORTMODE_NEWESTFIRST,
|
|
"podcast_mark_new_as_unlistened" => false,
|
|
"use_albumart_in_playlist" => true,
|
|
"podcast_sort_levels" => 4,
|
|
"podcast_sort_0" => 'Title',
|
|
"podcast_sort_1" => 'Artist',
|
|
"podcast_sort_2" => 'Category',
|
|
"podcast_sort_3" => 'new',
|
|
"bgimgparms" => (object) array('dummy' => 'baby'),
|
|
"alarms" => array( )
|
|
);
|
|
|
|
// Prefs that should not be exposed to the browser for security reasons
|
|
// lastfm_session_key should really be one of these, but it is needed by the frontend
|
|
$private_prefs = array(
|
|
'mysql_database',
|
|
'mysql_host',
|
|
'mysql_password',
|
|
'mysql_port',
|
|
'mysql_user',
|
|
'proxy_host',
|
|
'proxy_password',
|
|
'proxy_user',
|
|
'spotify_token',
|
|
'spotify_token_expires'
|
|
);
|
|
|
|
// ====================================================================
|
|
// Load Saved Preferences
|
|
loadPrefs();
|
|
|
|
if (defined('ROMPR_IS_LOADING')) {
|
|
logger::log("INIT", "******++++++======------******------======++++++******");
|
|
}
|
|
|
|
if (array_key_exists('REQUEST_URI', $_SERVER)) {
|
|
logger::debug("REQUEST", $_SERVER['REQUEST_URI']);
|
|
}
|
|
|
|
if (!property_exists($prefs['multihosts'], $prefs['currenthost'])) {
|
|
logger::warn("INIT", $prefs['currenthost'],"is not defined in the hosts defs");
|
|
foreach ($prefs['multihosts'] as $key => $obj) {
|
|
logger::log("INIT", " Using host ".$key);
|
|
$prefs['currenthost'] = $key;
|
|
setcookie('currenthost',$prefs['currenthost'],time()+365*24*60*60*10,'/');
|
|
break;
|
|
}
|
|
}
|
|
|
|
logger::debug("INIT", "Using MPD Host ".$prefs['currenthost']);
|
|
|
|
if (!array_key_exists('currenthost', $_COOKIE)) {
|
|
setcookie('currenthost',$prefs['currenthost'],time()+365*24*60*60*10,'/');
|
|
}
|
|
|
|
// NOTE. skin is NOT saved as a preference on the backend. It is set as a Cookie only.
|
|
// This is because saving it once as a preference would change the default for ALL new devices
|
|
// and we want to allow devices to intelligently select a default skin using checkwindowsize.php
|
|
$skin = null;
|
|
if(array_key_exists('skin', $_REQUEST)) {
|
|
$skin = $_REQUEST['skin'];
|
|
logger::log("INIT", "Request asked for skin: ".$skin);
|
|
} else if (array_key_exists('skin', $_COOKIE)) {
|
|
$skin = $_COOKIE['skin'];
|
|
logger::debug("INIT", "Using skin as set by Cookie: ".$skin);
|
|
}
|
|
if ($skin !== null) {
|
|
$skin = trim($skin);
|
|
}
|
|
|
|
$romonitor_hack = true;
|
|
// ====================================================================
|
|
|
|
function savePrefs() {
|
|
|
|
global $prefs;
|
|
$sp = $prefs;
|
|
$ps = serialize($sp);
|
|
$r = file_put_contents('prefs/prefs.var', $ps, LOCK_EX);
|
|
if ($r === false) {
|
|
error_log("ERROR! : COULD NOT SAVE PREFS");
|
|
}
|
|
}
|
|
|
|
function loadPrefs() {
|
|
global $prefs;
|
|
if (file_exists('prefs/prefs.var')) {
|
|
$fp = fopen('prefs/prefs.var', 'r');
|
|
if($fp) {
|
|
if (flock($fp, LOCK_SH)) {
|
|
$sp = unserialize(fread($fp, 32768));
|
|
flock($fp, LOCK_UN);
|
|
fclose($fp);
|
|
if ($sp === false) {
|
|
print '<h1>Fatal Error - Could not open the preferences file</h1>';
|
|
error_log("ERROR! : COULD NOT LOAD PREFS");
|
|
exit(1);
|
|
}
|
|
$prefs = array_replace($prefs, $sp);
|
|
$prefs['player_backend'] = 'none';
|
|
logger::setLevel($prefs['debug_enabled']);
|
|
logger::setOutfile($prefs['custom_logfile']);
|
|
|
|
foreach ($_COOKIE as $a => $v) {
|
|
if (array_key_exists($a, $prefs)) {
|
|
if ($v === 'false') { $v = false; }
|
|
if ($v === 'true') { $v = true; }
|
|
$prefs[$a] = $v;
|
|
logger::debug('COOKIEPREFS',"Pref",$a,"is set by Cookie - Value :",$v);
|
|
}
|
|
}
|
|
} else {
|
|
print '<h1>Fatal Error - Could not open the preferences file</h1>';
|
|
error_log("ERROR! : COULD NOT GET READ FILE LOCK ON PREFS FILE");
|
|
exit(1);
|
|
}
|
|
} else {
|
|
print '<h1>Fatal Error - Could not open the preferences file</h1>';
|
|
error_log("ERROR! : COULD NOT GET HANDLE FOR PREFS FILE");
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
function set_music_directory($dir) {
|
|
$prefs['music_directory_albumart'] = rtrim($dir, '/');
|
|
logger::log("SAVEPREFS", "Creating Album Art SymLink to ".$dir);
|
|
if (is_link("prefs/MusicFolders")) {
|
|
system ("unlink prefs/MusicFolders");
|
|
}
|
|
system ('ln -s "'.$dir.'" prefs/MusicFolders');
|
|
}
|
|
|
|
class logger {
|
|
|
|
private static $outfile;
|
|
private static $loglevel = 8;
|
|
private static $debug_colours = array(
|
|
# light red
|
|
0 => 91,
|
|
# red
|
|
1 => 31,
|
|
# yellow
|
|
2 => 33,
|
|
# magenta
|
|
3 => 35,
|
|
# cyan
|
|
4 => 36,
|
|
# lihgt grey
|
|
5 => 37,
|
|
# light yellow
|
|
6 => 93,
|
|
# green
|
|
7 => 32,
|
|
# white
|
|
8 => 97,
|
|
# light blue
|
|
9 => 94
|
|
);
|
|
|
|
private static $debug_names = array(
|
|
1 => 'ERROR',
|
|
2 => 'WARN ',
|
|
3 => 'FAIL ',
|
|
4 => 'BLURT',
|
|
5 => 'SHOUT',
|
|
6 => 'MARK ',
|
|
7 => 'LOG ',
|
|
8 => 'TRACE',
|
|
9 => 'DEBUG'
|
|
);
|
|
|
|
public static function setLevel($level) {
|
|
self::$loglevel = intval($level);
|
|
}
|
|
|
|
public static function setOutfile($file) {
|
|
self::$outfile = $file;
|
|
}
|
|
|
|
private static function dothelogging($level, $parms) {
|
|
if ($level > self::$loglevel || $level < 1) return;
|
|
$module = array_shift($parms);
|
|
if (strlen($module) > 18) {
|
|
$in = ' ';
|
|
} else {
|
|
$in = str_repeat(" ", 18 - strlen($module));
|
|
}
|
|
$pid = getmypid();
|
|
array_walk($parms, 'logger::un_array');
|
|
$out = implode(' ', $parms);
|
|
if (self::$outfile != "") {
|
|
// Two options here - either colour by level
|
|
// $col = self::$debug_colours[$level];
|
|
// or attempt to have different processes in different colours.
|
|
// This helps to keep track of things when multiple concurrent things are happening at once.
|
|
$col = self::$debug_colours[$pid % 10];
|
|
error_log("\033[90m".strftime('%T').' : '.self::$debug_names[$level]." : \033[".$col."m".$module.$in.$out."\033[0m\n",3,self::$outfile);
|
|
} else {
|
|
error_log(self::$debug_names[$level].' : '.$module.$in.": ".$out,0);
|
|
}
|
|
}
|
|
|
|
public static function un_array(&$a, $i) {
|
|
if (is_array($a)) {
|
|
$a = multi_implode($a);
|
|
}
|
|
}
|
|
|
|
// Level 9
|
|
public static function debug() {
|
|
$parms = func_get_args();
|
|
logger::dothelogging(9, $parms);
|
|
}
|
|
|
|
// Level 8
|
|
public static function trace() {
|
|
$parms = func_get_args();
|
|
logger::dothelogging(8, $parms);
|
|
}
|
|
|
|
// Level 7
|
|
public static function log() {
|
|
$parms = func_get_args();
|
|
logger::dothelogging(7, $parms);
|
|
}
|
|
|
|
// Level 6
|
|
public static function mark() {
|
|
$parms = func_get_args();
|
|
logger::dothelogging(6, $parms);
|
|
}
|
|
|
|
// Level 5
|
|
public static function shout() {
|
|
$parms = func_get_args();
|
|
logger::dothelogging(5, $parms);
|
|
}
|
|
|
|
// Level 4
|
|
public static function blurt() {
|
|
$parms = func_get_args();
|
|
logger::dothelogging(4, $parms);
|
|
}
|
|
|
|
// Level 3
|
|
public static function fail() {
|
|
$parms = func_get_args();
|
|
logger::dothelogging(3, $parms);
|
|
}
|
|
|
|
// Level 2
|
|
public static function warn() {
|
|
$parms = func_get_args();
|
|
logger::dothelogging(2, $parms);
|
|
}
|
|
|
|
// Level 1
|
|
public static function error() {
|
|
$parms = func_get_args();
|
|
logger::dothelogging(1, $parms);
|
|
}
|
|
|
|
}
|
|
|
|
function upgrade_host_defs($ver) {
|
|
global $prefs;
|
|
foreach ($prefs['multihosts'] as $key => $value) {
|
|
switch ($ver) {
|
|
case 45:
|
|
$prefs['multihosts']->{$key}->mopidy_slave = false;
|
|
break;
|
|
|
|
case 49:
|
|
$prefs['multihosts']->{$key}->radioparams = (object) array (
|
|
"radiomode" => "",
|
|
"radioparam" => "",
|
|
"radiomaster" => "",
|
|
"radioconsume" => 0
|
|
);
|
|
break;
|
|
|
|
}
|
|
}
|
|
savePrefs();
|
|
}
|
|
|
|
function multi_implode($array, $glue = ', ') {
|
|
if (!is_array($array)) {
|
|
return $array;
|
|
}
|
|
$ret = '';
|
|
foreach ($array as $key => $item) {
|
|
if (is_array($item)) {
|
|
$ret .= $key . '=[' . multi_implode($item, $glue) . ']' . $glue;
|
|
} else {
|
|
$ret .= $key . '=' . $item . $glue;
|
|
}
|
|
}
|
|
$ret = substr($ret, 0, 0-strlen($glue));
|
|
return $ret;
|
|
}
|
|
|
|
?>
|