mirror of
https://github.com/Yetangitu/ampache
synced 2025-10-03 01:39:28 +02:00
Add myPlex support
This commit is contained in:
parent
acc0f8029b
commit
6e5122302c
18 changed files with 1719 additions and 417 deletions
|
@ -25,6 +25,10 @@ class Artist extends database_object
|
|||
/* Variables from DB */
|
||||
public $id;
|
||||
public $name;
|
||||
public $summary;
|
||||
public $placeformed;
|
||||
public $yearformed;
|
||||
public $last_update;
|
||||
public $songs;
|
||||
public $albums;
|
||||
public $prefix;
|
||||
|
|
|
@ -535,7 +535,7 @@ abstract class Catalog extends database_object
|
|||
$sql_where = "WHERE `song`.`catalog` IN $catlist";
|
||||
}
|
||||
|
||||
$sql = "SELECT `artist`.id, `artist`.`name` FROM `song` LEFT JOIN `artist` ON `artist`.`id` = `song`.`artist` $sql_where GROUP BY `song`.artist ORDER BY `artist`.`name`";
|
||||
$sql = "SELECT `artist`.id, `artist`.`name`, `artist`.`summary` FROM `song` LEFT JOIN `artist` ON `artist`.`id` = `song`.`artist` $sql_where GROUP BY `song`.artist ORDER BY `artist`.`name`";
|
||||
|
||||
$results = array();
|
||||
$db_results = Dba::read($sql);
|
||||
|
|
|
@ -38,11 +38,138 @@ class Plex_Api
|
|||
{
|
||||
}
|
||||
|
||||
protected static function is_local()
|
||||
{
|
||||
$local = false;
|
||||
$local_auth = AmpConfig::get('plex_local_auth');
|
||||
if (!$local_auth) {
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
$lip = ip2long($ip);
|
||||
$rangs = array(
|
||||
array('127.0.0.1', '127.0.0.1'),
|
||||
array('10.0.0.1', '10.255.255.254 '),
|
||||
array('172.16.0.1', '172.31.255.254'),
|
||||
array('192.168.0.1', '192.168.255.254'),
|
||||
);
|
||||
|
||||
foreach ($rangs as $rang) {
|
||||
$ld = ip2long($rang[0]);
|
||||
$lu = ip2long($rang[1]);
|
||||
if ($lip <= $lu && $ld <= $lip) {
|
||||
debug_event('Access Control', 'Local client ip address (' . $ip . '), bypass authentication.', '3');
|
||||
$local = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $local;
|
||||
}
|
||||
|
||||
public static function auth_user()
|
||||
{
|
||||
$isLocal = self::is_local();
|
||||
if (!$isLocal) {
|
||||
$match_users = AmpConfig::get('plex_match_email');
|
||||
|
||||
$headers = apache_request_headers();
|
||||
$myplex_username = $headers['X-Plex-Username'];
|
||||
$myplex_token = $headers['X-Plex-Token'];
|
||||
if (empty($myplex_token)) {
|
||||
$myplex_token = $_REQUEST['X-Plex-Token'];
|
||||
}
|
||||
|
||||
if (empty($myplex_token)) {
|
||||
debug_event('Access Control', 'Authentication token is missing.', '3');
|
||||
self::createError(401);
|
||||
}
|
||||
|
||||
$createSession = false;
|
||||
Session::gc();
|
||||
$email = Session::read((string) $myplex_token);
|
||||
if (empty($email)) {
|
||||
$createSession = true;
|
||||
$xml = self::get_server_authtokens();
|
||||
$validToken = false;
|
||||
foreach ($xml->access_token as $tk) {
|
||||
if ((string) $tk['token'] == $myplex_token) {
|
||||
$username = (string) $tk['username'];
|
||||
// We should apply filter and access restriction to shared sections only, but that's not easily possible with current Ampache architecture
|
||||
$validToken = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$validToken) {
|
||||
debug_event('Access Control', 'Auth-Token ' . $myplex_token . ' invalid for this server.', '3');
|
||||
self::createError(401);
|
||||
}
|
||||
}
|
||||
|
||||
// Need to get a match between Plex and Ampache users
|
||||
if ($match_users) {
|
||||
if (!AmpConfig::get('access_control')) {
|
||||
debug_event('Access Control', 'Error Attempted to use Plex with Access Control turned off and plex/ampache link enabled.','3');
|
||||
self::createError(401);
|
||||
}
|
||||
|
||||
if (empty($email)) {
|
||||
$xml = self::get_users_account();
|
||||
if ((string) $xml->username == $username) {
|
||||
$email = (string) $xml->email;
|
||||
} else {
|
||||
$xml = self::get_server_friends();
|
||||
foreach ($xml->user as $xuser) {
|
||||
if ((string) $xml['username'] == $username) {
|
||||
$email = (string) $xml['email'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($email)) {
|
||||
$user = User::get_from_email($email);
|
||||
}
|
||||
if (!$user || !$user->id) {
|
||||
debug_event('Access Denied', 'Unable to get an Ampache user match for email ' . $email, '3');
|
||||
self::createError(401);
|
||||
}
|
||||
$username = $user->username;
|
||||
if (!Access::check_network('init-api', $username, 5)) {
|
||||
debug_event('Access Denied', 'Unauthorized access attempt to Plex [' . $_SERVER['REMOTE_ADDR'] . ']', '3');
|
||||
self::createError(401);
|
||||
}
|
||||
|
||||
$GLOBALS['user'] = $user;
|
||||
} else {
|
||||
$email = $username;
|
||||
$username = null;
|
||||
}
|
||||
|
||||
if ($createSession) {
|
||||
// Create an Ampache session from Plex authtoken
|
||||
Session::create(array(
|
||||
'type' => 'api',
|
||||
'sid' => $myplex_token,
|
||||
'username' => $username,
|
||||
'value' => $email
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static function check_access($level)
|
||||
{
|
||||
if (!self::is_local() && $GLOBALS['user']->access < $level) {
|
||||
debug_event('plex', 'User ' . $GLOBALS['user']->username . ' is unauthorized to complete the action.', '3');
|
||||
self::createError(401);
|
||||
}
|
||||
}
|
||||
|
||||
public static function setHeader($f)
|
||||
{
|
||||
header("HTTP/1.0 200 OK", true, 200);
|
||||
header("HTTP/1.1 200 OK", true, 200);
|
||||
header("Connection: close", true);
|
||||
header("X-Plex-Protocol: 1.0");
|
||||
|
||||
header_remove("x-powered-by");
|
||||
|
||||
|
@ -57,13 +184,46 @@ class Plex_Api
|
|||
}
|
||||
}
|
||||
|
||||
public static function setPlexHeader($reqheaders)
|
||||
{
|
||||
header("X-Plex-Protocol: 1.0");
|
||||
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
$acm = $reqheaders['Access-Control-Request-Method'];
|
||||
if ($acm) {
|
||||
header('Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT, HEAD');
|
||||
}
|
||||
$ach = $reqheaders['Access-Control-Request-Headers'];
|
||||
if ($ach) {
|
||||
$headers = self::getPlexHeaders(true, $acl);
|
||||
$headerkeys = array();
|
||||
foreach ($headers as $key => $value) {
|
||||
$headerkeys[] = strtolower($key);
|
||||
}
|
||||
header('Access-Control-Allow-Headers: ' . implode(',', $headerkeys));
|
||||
}
|
||||
|
||||
if ($acm || $ach) {
|
||||
header('Access-Control-Max-Age: 1209600');
|
||||
} else {
|
||||
header('Access-Control-Expose-Headers: Location');
|
||||
}
|
||||
}
|
||||
public static function apiOutput($string)
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] != 'OPTIONS') {
|
||||
ob_start('ob_gzhandler');
|
||||
echo $string;
|
||||
ob_end_flush();
|
||||
header("X-Plex-Compressed-Content-Length: " . ob_get_length());
|
||||
header("X-Plex-Original-Content-Length: " . strlen($string));
|
||||
$reqheaders = getallheaders();
|
||||
if ($reqheaders['Accept-Encoding']) {
|
||||
header("X-Plex-Content-Compressed-Length: " . ob_get_length(), true);
|
||||
header("X-Plex-Content-Original-Length: " . strlen($string), true);
|
||||
}
|
||||
} else {
|
||||
header("Content-type: text/plain", true);
|
||||
header("Content-length: 0", true);
|
||||
}
|
||||
}
|
||||
|
||||
public static function createError($code)
|
||||
|
@ -73,6 +233,10 @@ class Plex_Api
|
|||
case 404:
|
||||
$error = "Not Found";
|
||||
break;
|
||||
|
||||
case 401:
|
||||
$error = "Unauthorized";
|
||||
break;
|
||||
}
|
||||
header("Content-type: text/html", true);
|
||||
header("HTTP/1.0 ". $code . " " . $error, true, $code);
|
||||
|
@ -82,66 +246,166 @@ class Plex_Api
|
|||
exit();
|
||||
}
|
||||
|
||||
public static function validateMyPlex($myplex_username, $myplex_password, $clientUDID)
|
||||
public static function validateMyPlex($myplex_username, $myplex_password)
|
||||
{
|
||||
$options = array(
|
||||
CURLOPT_USERPWD => $myplex_username . ':' . $myplex_password,
|
||||
//CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
|
||||
CURLOPT_POST => true,
|
||||
);
|
||||
|
||||
$headers = array(
|
||||
'Content-Length: 0'
|
||||
);
|
||||
$action = 'users/sign_in.xml';
|
||||
|
||||
$req = array(
|
||||
'action' => 'users/sign_in.xml',
|
||||
'udid' => $clientUDID,
|
||||
);
|
||||
|
||||
$xml = self::myPlexRequest($req, $options, $headers);
|
||||
return $xml['authenticationToken'];
|
||||
$res = self::myPlexRequest($action, $options, $headers);;
|
||||
return $res['xml']['authenticationToken'];
|
||||
}
|
||||
|
||||
public static function registerMyPlex($clientUDID, $authtoken)
|
||||
public static function getPublicIp()
|
||||
{
|
||||
$action = 'pms/:/ip';
|
||||
|
||||
$res = self::myPlexRequest($action);
|
||||
return trim($res['raw']);
|
||||
}
|
||||
|
||||
public static function registerMyPlex($authtoken)
|
||||
{
|
||||
$headers = array (
|
||||
'Content-Type: text/xml'
|
||||
);
|
||||
$action = 'servers.xml?auth_token=' . $authtoken;
|
||||
|
||||
$r = Plex_XML_Data::createContainer();
|
||||
Plex_XML_Data::setServerInfo($r, Catalog::get_catalogs());
|
||||
Plex_XML_Data::setContainerSize($r);
|
||||
|
||||
$curlopts = array(
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => $r->asXML()
|
||||
);
|
||||
|
||||
$req = array(
|
||||
'action' => 'servers.xml?auth_token=' . $authtoken,
|
||||
'udid' => $clientUDID,
|
||||
);
|
||||
|
||||
$xml = self::myPlexRequest($req, array(), $headers, true);
|
||||
print_r($xml);
|
||||
exit;
|
||||
return self::myPlexRequest($action, $curlopts, $headers, true);
|
||||
}
|
||||
|
||||
protected static function myPlexRequest($req, $curlopts = array(), $headers = array(), $debug = false)
|
||||
public static function publishDeviceConnection($authtoken)
|
||||
{
|
||||
$server = 'http://' . $req['address'] . ':' . $req['port'];
|
||||
$allheaders = array(
|
||||
'X-Plex-Client-Identifier: ' . $req['udid'],
|
||||
'Content-length: 0',
|
||||
'X-Plex-Product: Plex Media Server',
|
||||
'X-Plex-Version: ' . Plex_XML_Data::getPlexVersion(),
|
||||
'X-Plex-Platform: ' . PHP_OS,
|
||||
'X-Plex-Client-Platform: ' . PHP_OS,
|
||||
'X-Plex-Protocol: 1.0',
|
||||
'X-Plex-Device: Ampache',
|
||||
'X-Plex-Provides: server',
|
||||
$headers = array ();
|
||||
$action = 'devices/' . Plex_XML_Data::getMachineIdentifier() . '?Connection[][uri]=' . Plex_XML_Data::getServerUri() . '&X-Plex-Token=' . $authtoken;
|
||||
$curlopts = array(
|
||||
CURLOPT_CUSTOMREQUEST => "PUT"
|
||||
);
|
||||
|
||||
return self::myPlexRequest($action, $curlopts, $headers);
|
||||
}
|
||||
|
||||
public static function unregisterMyPlex($authtoken)
|
||||
{
|
||||
$headers = array (
|
||||
'Content-Type: text/xml'
|
||||
);
|
||||
$action = 'servers/' . Plex_XML_Data::getMachineIdentifier() . '.xml?auth_token=' . $authtoken;
|
||||
$curlopts = array(
|
||||
CURLOPT_CUSTOMREQUEST => "DELETE"
|
||||
);
|
||||
|
||||
return self::myPlexRequest($action, $curlopts, $headers);
|
||||
}
|
||||
|
||||
protected static function get_server_authtokens()
|
||||
{
|
||||
$action = 'servers/' . Plex_XML_Data::getMachineIdentifier() . '/access_tokens.xml?auth_token=' . Plex_XML_Data::getMyPlexAuthToken();
|
||||
|
||||
$res = self::myPlexRequest($action);
|
||||
return $res['xml'];
|
||||
}
|
||||
|
||||
protected static function get_server_friends()
|
||||
{
|
||||
$action = 'pms/friends/all?auth_token=' . Plex_XML_Data::getMyPlexAuthToken();
|
||||
|
||||
$res = self::myPlexRequest($action);
|
||||
return $res['xml'];
|
||||
}
|
||||
|
||||
protected static function getPlexHeaders($private = false, $filters = null)
|
||||
{
|
||||
$headers = array(
|
||||
'X-Plex-Client-Identifier' => Plex_XML_Data::getClientIdentifier(),
|
||||
'X-Plex-Product' => 'Plex Media Server',
|
||||
'X-Plex-Version' => Plex_XML_Data::getPlexVersion(),
|
||||
'X-Plex-Platform' => Plex_XML_Data::getPlexPlatform(),
|
||||
'X-Plex-Platform-Version' => Plex_XML_Data::getPlexPlatformVersion(),
|
||||
'X-Plex-Client-Platform' => Plex_XML_Data::getPlexPlatform(),
|
||||
'X-Plex-Protocol' => 1.0,
|
||||
'X-Plex-Device' => 'Ampache Doped',
|
||||
'X-Plex-Device-Name' => 'Ampache Doped',
|
||||
'X-Plex-Provides' => 'server'
|
||||
);
|
||||
|
||||
if ($private) {
|
||||
if (Plex_XML_Data::getMyPlexUsername()) {
|
||||
$headers['X-Plex-Username'] = Plex_XML_Data::getMyPlexUsername();
|
||||
}
|
||||
if (Plex_XML_Data::getMyPlexUsername()) {
|
||||
$headers['X-Plex-Token'] = Plex_XML_Data::getMyPlexAuthToken();
|
||||
}
|
||||
}
|
||||
|
||||
if ($filters) {
|
||||
$fheaders = array();
|
||||
foreach ($headers as $key => $value) {
|
||||
if (array_search(strtolower($key), $filters)) {
|
||||
$fheaders[$key] = $value;
|
||||
}
|
||||
}
|
||||
$headers = $fheaders;
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
static $request_headers = array();
|
||||
public static function request_output_header($ch, $header)
|
||||
{
|
||||
self::$request_headers[] = $header;
|
||||
return strlen($header);
|
||||
}
|
||||
|
||||
public static function replay_header($ch, $header)
|
||||
{
|
||||
header($header);
|
||||
return strlen($header);
|
||||
}
|
||||
|
||||
protected static function myPlexRequest($action, $curlopts = array(), $headers = array(), $proxy = false)
|
||||
{
|
||||
$server = Plex_XML_Data::getServerUri();
|
||||
$allheaders = array();
|
||||
if (!$proxy) {
|
||||
$allheadersarr = self::getPlexHeaders();
|
||||
foreach ($allheadersarr as $key => $value) {
|
||||
$allheaders[] = $key . ': ' . $value;
|
||||
}
|
||||
$allheaders += array(
|
||||
'Origin: ' . $server,
|
||||
'Referer: ' . $server . '/web/index.html',
|
||||
);
|
||||
|
||||
if (!$curlopts[CURLOPT_POST]) {
|
||||
$allheaders[] = 'Content-length: 0';
|
||||
}
|
||||
}
|
||||
$allheaders = array_merge($allheaders, $headers);
|
||||
|
||||
$url = 'https://my.plexapp.com/' . $req['action'];
|
||||
$url = 'https://my.plexapp.com/' . $action;
|
||||
debug_event('plex', 'Calling ' . $url, '5');
|
||||
|
||||
$options = array(
|
||||
CURLOPT_HEADER => $debug,
|
||||
CURLOPT_HEADER => false,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HEADERFUNCTION => array('Plex_Api', 'request_output_header'),
|
||||
CURLOPT_SSL_VERIFYPEER => false,
|
||||
CURLOPT_SSL_VERIFYHOST => false,
|
||||
CURLOPT_HTTPHEADER => $allheaders,
|
||||
|
@ -151,9 +415,15 @@ class Plex_Api
|
|||
$ch = curl_init($url);
|
||||
curl_setopt_array($ch, $options);
|
||||
$r = curl_exec($ch);
|
||||
$res = array();
|
||||
$res['status'] = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
if ($debug) print_r($r);
|
||||
return simplexml_load_string($r);
|
||||
$res['headers'] = self::$request_headers;
|
||||
$res['raw'] = $r;
|
||||
try {
|
||||
$res['xml'] = simplexml_load_string($r);
|
||||
} catch (Exception $e) { }
|
||||
return $res;
|
||||
}
|
||||
|
||||
public static function root()
|
||||
|
@ -189,7 +459,7 @@ class Plex_Api
|
|||
|
||||
public static function channels($params)
|
||||
{
|
||||
$r = Plex_XML_Data::createContainer();
|
||||
$r = Plex_XML_Data::createPluginContainer();
|
||||
Plex_XML_Data::setContainerSize($r);
|
||||
self::apiOutput($r->asXML());
|
||||
}
|
||||
|
@ -287,6 +557,9 @@ class Plex_Api
|
|||
$id = Plex_XML_Data::getAmpacheId($key);
|
||||
|
||||
if ($n == 1) {
|
||||
// Should we check that files still exists here?
|
||||
$checkFiles = $_REQUEST['checkFiles'];
|
||||
|
||||
if (Plex_XML_Data::isArtist($key)) {
|
||||
$artist = new Artist($id);
|
||||
$artist->format();
|
||||
|
@ -295,6 +568,10 @@ class Plex_Api
|
|||
$album = new Album($id);
|
||||
$album->format();
|
||||
Plex_XML_Data::addAlbum($r, $album);
|
||||
} elseif (Plex_XML_Data::isTrack($key)) {
|
||||
$song = new Song($id);
|
||||
$song->format();
|
||||
Plex_XML_Data::addSong($r, $song);
|
||||
}
|
||||
} else {
|
||||
$subact = $params[1];
|
||||
|
@ -307,10 +584,6 @@ class Plex_Api
|
|||
$album = new Album($id);
|
||||
$album->format();
|
||||
Plex_XML_Data::setAlbumRoot($r, $album);
|
||||
} else if (Plex_XML_Data::isTrack($key)) {
|
||||
/*$song = new Song($id);
|
||||
$song->format();
|
||||
Plex_XML_Data::setSongRoot($r, $song);*/
|
||||
}
|
||||
} elseif ($subact == "thumb") {
|
||||
if ($n == 3) {
|
||||
|
@ -359,8 +632,20 @@ class Plex_Api
|
|||
$id = Plex_XML_Data::getAmpacheId($key);
|
||||
$song = new Song($id);
|
||||
if ($song->id) {
|
||||
$url = Song::play_url($id, '&client=Plex');
|
||||
header("Location: " . $url);
|
||||
$url = Song::play_url($id);
|
||||
|
||||
// header("Location: " . $url);
|
||||
$ch = curl_init($url);
|
||||
curl_setopt_array($ch, array(
|
||||
CURLOPT_HEADER => false,
|
||||
CURLOPT_RETURNTRANSFER => false,
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
CURLOPT_HEADERFUNCTION => array('Plex_Api', 'replay_header'),
|
||||
CURLOPT_SSL_VERIFYPEER => false,
|
||||
CURLOPT_SSL_VERIFYHOST => false
|
||||
));
|
||||
curl_exec($ch);
|
||||
curl_close($ch);
|
||||
} else {
|
||||
self::createError(404);
|
||||
}
|
||||
|
@ -394,4 +679,253 @@ class Plex_Api
|
|||
Plex_XML_Data::setContainerSize($r);
|
||||
self::apiOutput($r->asXML());
|
||||
}
|
||||
|
||||
public static function manage_frameworks_ekspinner_resources($params)
|
||||
{
|
||||
// Image file used to 'ping' the server
|
||||
if ($params[0] == "small_black_7.png") {
|
||||
header("Content-type: image/png", true);
|
||||
echo file_get_contents(AmpConfig::get('prefix') . '/plex/resources/small_black_7.png');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
public static function myplex_account($params)
|
||||
{
|
||||
$r = Plex_XML_Data::createMyPlexAccount();
|
||||
self::apiOutput($r->asXML());
|
||||
}
|
||||
|
||||
public static function system_agents($params)
|
||||
{
|
||||
$r = Plex_XML_Data::createSysContainer();
|
||||
$addcontributors = false;
|
||||
$mediaType = $_REQUEST['mediaType'];
|
||||
if (count($params) >= 3 && $params[1] == 'config') {
|
||||
$mediaType = $params[2];
|
||||
$addcontributors = true;
|
||||
}
|
||||
|
||||
if ($mediaType) {
|
||||
switch ($mediaType) {
|
||||
case '1':
|
||||
Plex_XML_Data::setSysMovieAgents($r);
|
||||
break;
|
||||
case '2':
|
||||
Plex_XML_Data::setSysTVShowAgents($r);
|
||||
break;
|
||||
case '13':
|
||||
Plex_XML_Data::setSysPhotoAgents($r);
|
||||
break;
|
||||
case '8':
|
||||
Plex_XML_Data::setSysMusicAgents($r);
|
||||
break;
|
||||
case '9':
|
||||
Plex_XML_Data::setSysMusicAgents($r, 'Albums');
|
||||
break;
|
||||
default:
|
||||
self::createError(404);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
Plex_XML_Data::setSysAgents($r);
|
||||
}
|
||||
if ($addcontributors) {
|
||||
Plex_XML_Data::setAgentsContributors($r, $mediaType, 'com.plexapp.agents.none');
|
||||
}
|
||||
Plex_XML_Data::setContainerSize($r);
|
||||
self::apiOutput($r->asXML());
|
||||
}
|
||||
|
||||
public static function system_agents_contributors($params)
|
||||
{
|
||||
$mediaType = $_REQUEST['mediaType'];
|
||||
$primaryAgent = $_REQUEST['primaryAgent'];
|
||||
|
||||
$r = Plex_XML_Data::createSysContainer();
|
||||
Plex_XML_Data::setAgentsContributors($r, $mediaType, $primaryAgent);
|
||||
Plex_XML_Data::setContainerSize($r);
|
||||
self::apiOutput($r->asXML());
|
||||
}
|
||||
|
||||
public static function system_agents_attribution($params)
|
||||
{
|
||||
$identifier = $_REQUEST['identifier'];
|
||||
|
||||
self::createError(404);
|
||||
}
|
||||
|
||||
public static function system_scanners($params)
|
||||
{
|
||||
if (count($params) > 0) {
|
||||
if ($params[0] == '8' || $params[0] == '9') {
|
||||
$r = Plex_XML_Data::createSysContainer();
|
||||
Plex_XML_Data::setMusicScanners($r);
|
||||
Plex_XML_Data::setContainerSize($r);
|
||||
self::apiOutput($r->asXML());
|
||||
}
|
||||
} else {
|
||||
self::createError(404);
|
||||
}
|
||||
}
|
||||
|
||||
public static function system_appstore($params)
|
||||
{
|
||||
$r = Plex_XML_Data::createAppStore();
|
||||
Plex_XML_Data::setContainerSize($r);
|
||||
self::apiOutput($r->asXML());
|
||||
}
|
||||
|
||||
public static function accounts($params)
|
||||
{
|
||||
$userid = '';
|
||||
if (isset($params[0])) {
|
||||
$userid = $params[0];
|
||||
}
|
||||
// Not supported yet
|
||||
if ($userid > 1) { self::createError(404); }
|
||||
|
||||
$r = Plex_XML_Data::createAccountContainer();
|
||||
Plex_XML_Data::setAccounts($r, $userid);
|
||||
Plex_XML_Data::setContainerSize($r);
|
||||
self::apiOutput($r->asXML());
|
||||
}
|
||||
|
||||
public static function status($params)
|
||||
{
|
||||
$r = Plex_XML_Data::createPluginContainer();
|
||||
Plex_XML_Data::setStatus($r);
|
||||
Plex_XML_Data::setContainerSize($r);
|
||||
self::apiOutput($r->asXML());
|
||||
}
|
||||
|
||||
public static function status_sessions($params)
|
||||
{
|
||||
self::createError(403);
|
||||
}
|
||||
|
||||
public static function prefs($params)
|
||||
{
|
||||
$r = Plex_XML_Data::createContainer();
|
||||
Plex_XML_Data::setPrefs($r);
|
||||
Plex_XML_Data::setContainerSize($r);
|
||||
self::apiOutput($r->asXML());
|
||||
}
|
||||
|
||||
public static function help($params)
|
||||
{
|
||||
$r = Plex_XML_Data::createPluginContainer();
|
||||
Plex_XML_Data::setContainerSize($r);
|
||||
self::apiOutput($r->asXML());
|
||||
}
|
||||
|
||||
public static function plexonline($params)
|
||||
{
|
||||
$r = Plex_XML_Data::createPluginContainer();
|
||||
Plex_XML_Data::setContainerSize($r);
|
||||
self::apiOutput($r->asXML());
|
||||
}
|
||||
|
||||
public static function plugins($params)
|
||||
{
|
||||
$r = Plex_XML_Data::createPluginContainer();
|
||||
Plex_XML_Data::setContainerSize($r);
|
||||
self::apiOutput($r->asXML());
|
||||
}
|
||||
|
||||
public static function services($params)
|
||||
{
|
||||
$r = Plex_XML_Data::createPluginContainer();
|
||||
Plex_XML_Data::setServices($r);
|
||||
Plex_XML_Data::setContainerSize($r);
|
||||
self::apiOutput($r->asXML());
|
||||
}
|
||||
|
||||
public static function services_browse($params)
|
||||
{
|
||||
self::check_access(75);
|
||||
|
||||
$r = Plex_XML_Data::createContainer();
|
||||
Plex_XML_Data::setBrowseService($r, $params[0]);
|
||||
Plex_XML_Data::setContainerSize($r);
|
||||
self::apiOutput($r->asXML());
|
||||
}
|
||||
|
||||
public static function timeline($params)
|
||||
{
|
||||
$ratingKey = $_REQUEST['ratingKey'];
|
||||
$key = $_REQUEST['key'];
|
||||
$state = $_REQUEST['state'];
|
||||
$time = $_REQUEST['time'];
|
||||
$duration = $_REQUEST['duration'];
|
||||
|
||||
// Not supported right now (maybe in a future for broadcast?)
|
||||
if ($_SERVER['REQUEST_METHOD'] != 'OPTIONS') {
|
||||
self::apiOutput('');
|
||||
} else {
|
||||
self::createError(400);
|
||||
}
|
||||
}
|
||||
|
||||
public static function rate($params)
|
||||
{
|
||||
$id = $_REQUEST['key'];
|
||||
$identifier = $_REQUEST['identifier'];
|
||||
$rating = $_REQUEST['rating'];
|
||||
|
||||
if ($identifier == 'com.plexapp.plugins.library') {
|
||||
if (Plex_XML_Data::isArtist($id)) {
|
||||
$robj = new Rating(Plex_XML_Data::getAmpacheId($id), "artist");
|
||||
} else if (Plex_XML_Data::isAlbum($id)) {
|
||||
$robj = new Rating(Plex_XML_Data::getAmpacheId($id), "album");
|
||||
} else if (Plex_XML_Data::isSong($id)) {
|
||||
$robj = new Rating(Plex_XML_Data::getAmpacheId($id), "song");
|
||||
}
|
||||
|
||||
if ($robj != null) {
|
||||
$robj->set_rating($rating / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Functions to emulate myPlex server and grant access to plexpass dynamically.
|
||||
Use it for testing purpose only, be fair!
|
||||
*/
|
||||
|
||||
public static function users($params)
|
||||
{
|
||||
if ($params[0] == 'sign_in.xml') {
|
||||
$curlopts = array();
|
||||
$headers = array();
|
||||
$res = self::myPlexRequest('users/sign_in.xml', $curlopts, $headers, true);
|
||||
|
||||
foreach ($res['headers'] as $header) {
|
||||
header($header);
|
||||
}
|
||||
|
||||
if ($res['status'] == '201') {
|
||||
Plex_XML_Data::injectMyPlexSubscription($res['xml']);
|
||||
self::apiOutput($res['xml']->asXML());
|
||||
} else { self::createError($res['status']); }
|
||||
}
|
||||
}
|
||||
|
||||
protected static function get_users_account($authtoken='')
|
||||
{
|
||||
if (empty($authtoken)) {
|
||||
$authtoken = Plex_XML_Data::getMyPlexAuthToken();
|
||||
}
|
||||
$action = 'users/account?auth_token=' . $authtoken;
|
||||
$res = self::myPlexRequest($action);
|
||||
return $res['xml'];
|
||||
}
|
||||
|
||||
public static function users_account($params)
|
||||
{
|
||||
$xml = self::get_users_account();
|
||||
Plex_XML_Data::injectMyPlexSubscription($xml);
|
||||
self::apiOutput($xml->asXML());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ class Plex_XML_Data
|
|||
|
||||
public static function getPlexVersion()
|
||||
{
|
||||
return "0.9.8.10.215-020456b";
|
||||
return "0.9.8.18.290-11b7fdd";
|
||||
}
|
||||
|
||||
public static function getServerAddress()
|
||||
|
@ -126,14 +126,47 @@ class Plex_XML_Data
|
|||
return $port?:'32400';
|
||||
}
|
||||
|
||||
public static function getServerKey()
|
||||
public static function getServerPublicAddress()
|
||||
{
|
||||
return self::getServerAddress();
|
||||
$address = AmpConfig::get('plex_public_address');
|
||||
if (!$address) {
|
||||
$address = self::getServerAddress();
|
||||
}
|
||||
return $address;
|
||||
}
|
||||
|
||||
public static function getServerPublicPort()
|
||||
{
|
||||
$port = AmpConfig::get('plex_public_port');
|
||||
if (!$port) {
|
||||
$port = self::getServerPort();
|
||||
}
|
||||
return $port;
|
||||
}
|
||||
|
||||
public static function getServerUri()
|
||||
{
|
||||
return 'http://' . self::getServerPublicAddress() . ':' . self::getServerPublicPort();
|
||||
}
|
||||
|
||||
public static function getServerName()
|
||||
{
|
||||
return "Ampache";
|
||||
return AmpConfig::get('plex_servername') ?: 'Ampache Doped';
|
||||
}
|
||||
|
||||
public static function getMyPlexUsername()
|
||||
{
|
||||
return AmpConfig::get('myplex_username');
|
||||
}
|
||||
|
||||
public static function getMyPlexAuthToken()
|
||||
{
|
||||
return AmpConfig::get('myplex_authtoken');
|
||||
}
|
||||
|
||||
public static function getMyPlexPublished()
|
||||
{
|
||||
return AmpConfig::get('myplex_published');
|
||||
}
|
||||
|
||||
public static function createFailedResponse($version = "")
|
||||
|
@ -181,6 +214,13 @@ class Plex_XML_Data
|
|||
return $response;
|
||||
}
|
||||
|
||||
public static function createAccountContainer()
|
||||
{
|
||||
$response = self::createContainer();
|
||||
$response->addAttribute('identifier', 'com.plexapp.system.accounts');
|
||||
return $response;
|
||||
}
|
||||
|
||||
public static function setContainerSize($container)
|
||||
{
|
||||
$container->addAttribute('size', $container->count());
|
||||
|
@ -216,18 +256,76 @@ class Plex_XML_Data
|
|||
return hash('sha1', $key);
|
||||
}
|
||||
|
||||
public static function uuidFromSubKey($key)
|
||||
{
|
||||
return self::uuidFromKey(self::getMachineIdentifier() . '-' . $key);
|
||||
}
|
||||
|
||||
public static function getMachineIdentifier()
|
||||
{
|
||||
$uniqid = AmpConfig::get('plex_uniqid');
|
||||
if (!$uniqid) {
|
||||
$uniqid = self::getServerAddress();
|
||||
}
|
||||
return self::uuidFromKey($uniqid);
|
||||
}
|
||||
|
||||
public static function getClientIdentifier()
|
||||
{
|
||||
return self::getMachineIdentifier();
|
||||
}
|
||||
|
||||
public static function getPlexPlatform()
|
||||
{
|
||||
if (PHP_OS == 'WINNT') {
|
||||
return 'Windows';
|
||||
} else {
|
||||
return "Linux";
|
||||
}
|
||||
}
|
||||
|
||||
public static function getPlexPlatformVersion()
|
||||
{
|
||||
if (PHP_OS == 'WINNT') {
|
||||
return '6.2 (Build 9200)';
|
||||
} else {
|
||||
return '(#1 SMP Debian 3.2.54-2)';
|
||||
}
|
||||
}
|
||||
|
||||
public static function setRootContent($xml, $catalogs)
|
||||
{
|
||||
$xml->addAttribute('friendlyName', self::getServerName());
|
||||
$xml->addAttribute('machineIdentifier', self::uuidFromKey(self::getServerKey()));
|
||||
$xml->addAttribute('machineIdentifier', self::getMachineIdentifier());
|
||||
|
||||
$myplex_username = self::getMyPlexUsername();
|
||||
$myplex_authtoken = self::getMyPlexAuthToken();
|
||||
$myplex_published = self::getMyPlexPublished();
|
||||
if ($myplex_username) {
|
||||
$xml->addAttribute('myPlex', '1');
|
||||
$xml->addAttribute('myPlexUsername', $myplex_username);
|
||||
if ($myplex_authtoken) {
|
||||
$xml->addAttribute('myPlexSigninState', 'ok');
|
||||
if ($myplex_published) {
|
||||
$xml->addAttribute('myPlexMappingState', 'mapped');
|
||||
} else {
|
||||
$xml->addAttribute('myPlexMappingState', 'unknown');
|
||||
}
|
||||
} else {
|
||||
$xml->addAttribute('myPlexSigninState', 'none');
|
||||
}
|
||||
} else {
|
||||
$xml->addAttribute('myPlex', '0');
|
||||
$xml->addAttribute('platform', PHP_OS);
|
||||
$xml->addAttribute('platformVersion', '');
|
||||
}
|
||||
|
||||
$xml->addAttribute('platform', self::getPlexPlatform());
|
||||
$xml->addAttribute('platformVersion', self::getPlexPlatformVersion());
|
||||
$xml->addAttribute('requestParametersInCookie', '1');
|
||||
$xml->addAttribute('sync', '1');
|
||||
$xml->addAttribute('transcoderActiveVideoSessions', '0');
|
||||
$xml->addAttribute('transcoderAudio', '0');
|
||||
$xml->addAttribute('transcoderVideo', '0');
|
||||
|
||||
$xml->addAttribute('updatedAt', self::getLastUpdate($catalogs));
|
||||
$xml->addAttribute('version', self::getPlexVersion());
|
||||
|
||||
|
@ -245,10 +343,18 @@ class Plex_XML_Data
|
|||
$dir->addAttribute('title', 'library');
|
||||
$dir = $xml->addChild('Directory');
|
||||
$dir->addAttribute('count', '1');
|
||||
$dir->addAttribute('key', 'music');
|
||||
$dir->addAttribute('title', 'music');
|
||||
$dir = $xml->addChild('Directory');
|
||||
$dir->addAttribute('count', '1');
|
||||
$dir->addAttribute('key', 'playQueues');
|
||||
$dir->addAttribute('title', 'playQueues');
|
||||
$dir = $xml->addChild('Directory');
|
||||
$dir->addAttribute('count', '1');
|
||||
$dir->addAttribute('key', 'player');
|
||||
$dir->addAttribute('title', 'player');
|
||||
$dir = $xml->addChild('Directory');
|
||||
$dir->addAttribute('count', '1');
|
||||
$dir->addAttribute('key', 'playlists');
|
||||
$dir->addAttribute('title', 'playlists');
|
||||
$dir = $xml->addChild('Directory');
|
||||
|
@ -267,6 +373,10 @@ class Plex_XML_Data
|
|||
$dir->addAttribute('count', '1');
|
||||
$dir->addAttribute('key', 'transcode');
|
||||
$dir->addAttribute('title', 'transcode');
|
||||
/*$dir = $xml->addChild('Directory');
|
||||
$dir->addAttribute('count', '1');
|
||||
$dir->addAttribute('key', 'video');
|
||||
$dir->addAttribute('title', 'video');*/
|
||||
}
|
||||
|
||||
public static function getLastUpdate($catalogs)
|
||||
|
@ -295,14 +405,14 @@ class Plex_XML_Data
|
|||
$catalog->format();
|
||||
|
||||
$dir = $xml->addChild('Directory');
|
||||
$key = self::getServerKey() . '-' . $id;
|
||||
$dir->addAttribute('key', base64_encode($key));
|
||||
$dir->addAttribute('uuid', self::uuidFromKey($id));
|
||||
$dir->addAttribute('name', $catalog->name);
|
||||
$key = base64_encode(self::getMachineIdentifier() . '-' . $id);
|
||||
$dir->addAttribute('type', 'music');
|
||||
$dir->addAttribute('key', $key);
|
||||
$dir->addAttribute('uuid', self::uuidFromSubKey($id));
|
||||
$dir->addAttribute('name', $catalog->name);
|
||||
$dir->addAttribute('unique', '1');
|
||||
$dir->addAttribute('serverVersion', self::getPlexVersion());
|
||||
$dir->addAttribute('machineIdentifier', self::uuidFromKey(self::getServerKey()));
|
||||
$dir->addAttribute('machineIdentifier', self::getMachineIdentifier());
|
||||
$dir->addAttribute('serverName', self::getServerName());
|
||||
$dir->addAttribute('path', self::getSectionUri($id));
|
||||
$ip = self::getServerAddress();
|
||||
|
@ -324,9 +434,10 @@ class Plex_XML_Data
|
|||
$dir->addAttribute('refreshing', '0');
|
||||
$dir->addAttribute('key', $id);
|
||||
$dir->addAttribute('type', 'artist');
|
||||
$dir->addAttribute('agent', 'com.plexapp.agents.none'); // com.plexapp.agents.lastfm
|
||||
$dir->addAttribute('scanner', 'Plex Music Scanner');
|
||||
$dir->addAttribute('language', 'en');
|
||||
$dir->addAttribute('uuid', self::uuidFromKey($id));
|
||||
$dir->addAttribute('uuid', self::uuidFromSubKey($id));
|
||||
$dir->addAttribute('updatedAt', self::getLastUpdate($catalogs));
|
||||
self::setSectionXContent($dir, $catalog, 'title');
|
||||
//$date = new DateTime("2013-01-01");
|
||||
|
@ -435,7 +546,7 @@ class Plex_XML_Data
|
|||
$xml->addAttribute('viewGroup', 'artist');
|
||||
$xml->addAttribute('viewMode', '65592');
|
||||
$xml->addAttribute('librarySectionID', $catalog->id);
|
||||
$xml->addAttribute('librarySectionUUID', self::uuidFromKey($catalog->id));
|
||||
$xml->addAttribute('librarySectionUUID', self::uuidFromSubKey($catalog->id));
|
||||
|
||||
foreach ($artists as $artist) {
|
||||
self::addArtist($xml, $artist);
|
||||
|
@ -471,7 +582,7 @@ class Plex_XML_Data
|
|||
$xml->addAttribute('viewGroup', 'album');
|
||||
$xml->addAttribute('viewMode', '65592');
|
||||
$xml->addAttribute('librarySectionID', $catalog->id);
|
||||
$xml->addAttribute('librarySectionUUID', self::uuidFromKey($catalog->id));
|
||||
$xml->addAttribute('librarySectionUUID', self::uuidFromSubKey($catalog->id));
|
||||
self::setSectionXContent($xml, $catalog);
|
||||
|
||||
$data = array();
|
||||
|
@ -507,16 +618,36 @@ class Plex_XML_Data
|
|||
}
|
||||
}
|
||||
|
||||
public static function setServerInfo($xml, $catalogs)
|
||||
{
|
||||
$server = $xml->addChild('Server');
|
||||
$server->addAttribute('name', self::getServerName());
|
||||
$server->addAttribute('host', self::getServerPublicAddress());
|
||||
$server->addAttribute('localAddresses', self::getServerAddress());
|
||||
$server->addAttribute('port', self::getServerPublicPort());
|
||||
$server->addAttribute('machineIdentifier', self::getMachineIdentifier());
|
||||
$server->addAttribute('version', self::getPlexVersion());
|
||||
|
||||
self::setSections($xml, $catalogs);
|
||||
}
|
||||
|
||||
public static function addArtist($xml, $artist)
|
||||
{
|
||||
$xdir = $xml->addChild('Directory');
|
||||
$id = self::getArtistId($artist->id);
|
||||
$xml->addAttribute('ratingKey', $id);
|
||||
$xdir->addAttribute('ratingKey', $id);
|
||||
$xdir->addAttribute('type', 'artist');
|
||||
$xdir->addAttribute('title', $artist->name);
|
||||
$xdir->addAttribute('index', '1');
|
||||
$xdir->addAttribute('addedAt', '');
|
||||
$xdir->addAttribute('updatedAt', '');
|
||||
|
||||
$rating = new Rating($artist->id, "artist");
|
||||
$rating_value = $rating->get_average_rating();
|
||||
if ($rating_value > 0) {
|
||||
$xdir->addAttribute('rating', intval($rating_value * 2));
|
||||
}
|
||||
|
||||
self::addArtistMeta($xdir, $artist);
|
||||
|
||||
$tags = Tag::get_top_tags('artist', $artist->id);
|
||||
|
@ -530,9 +661,22 @@ class Plex_XML_Data
|
|||
public static function addArtistMeta($xml, $artist)
|
||||
{
|
||||
$id = self::getArtistId($artist->id);
|
||||
if (!isset($xml['key'])) {
|
||||
$xml->addAttribute('key', self::getMetadataUri($id) . '/children');
|
||||
$xml->addAttribute('summary', '');
|
||||
$xml->addAttribute('thumb', '');
|
||||
}
|
||||
$xml->addAttribute('summary', $artist->summary);
|
||||
self::addArtistThumb($xml, $artist->id);
|
||||
}
|
||||
|
||||
protected static function addArtistThumb($xml, $artist_id, $attrthumb = 'thumb')
|
||||
{
|
||||
$id = self::getArtistId($artist_id);
|
||||
$art = new Art($artist_id, 'artist');
|
||||
$thumb = '';
|
||||
if ($art->get_db()) {
|
||||
$thumb = self::getMetadataUri($id) . '/thumb/' . $id;
|
||||
}
|
||||
$xml->addAttribute($attrthumb, $thumb);
|
||||
}
|
||||
|
||||
public static function addAlbum($xml, $album)
|
||||
|
@ -552,6 +696,12 @@ class Plex_XML_Data
|
|||
$xdir->addAttribute('year', $album->year);
|
||||
}
|
||||
|
||||
$rating = new Rating($album->id, "album");
|
||||
$rating_value = $rating->get_average_rating();
|
||||
if ($rating_value > 0) {
|
||||
$xdir->addAttribute('rating', intval($rating_value * 2));
|
||||
}
|
||||
|
||||
$tags = Tag::get_top_tags('album', $album->id);
|
||||
foreach ($tags as $tag_id=>$value) {
|
||||
$tag = new Tag($tag_id);
|
||||
|
@ -573,7 +723,9 @@ class Plex_XML_Data
|
|||
$xml->addAttribute('art', self::getMetadataUri($id) . '/thumb/' . $id);
|
||||
$xml->addAttribute('thumb', self::getMetadataUri($id) . '/thumb/' . $id);
|
||||
}
|
||||
$xml->addAttribute('parentThumb', '');
|
||||
if ($album->artist_id) {
|
||||
self::addArtistThumb($xml, $album->artist_id, 'parentThumb');
|
||||
}
|
||||
$xml->addAttribute('originallyAvailableAt', '');
|
||||
$xml->addAttribute('addedAt', '');
|
||||
$xml->addAttribute('updatedAt', '');
|
||||
|
@ -605,10 +757,14 @@ class Plex_XML_Data
|
|||
{
|
||||
$id = self::getAlbumId($album->id);
|
||||
self::addAlbumMeta($xml, $album);
|
||||
if (!isset($xml['key'])) {
|
||||
$xml->addAttribute('key', $id);
|
||||
}
|
||||
$xml->addAttribute('grandparentTitle', $album->f_artist);
|
||||
$xml->addAttribute('title1', $album->f_artist);
|
||||
if (!isset($xml['allowSync'])) {
|
||||
$xml->addAttribute('allowSync', '1');
|
||||
}
|
||||
$xml->addAttribute('nocache', '1');
|
||||
$xml->addAttribute('parentIndex', '1'); // ??
|
||||
$xml->addAttribute('parentTitle', $album->f_title);
|
||||
|
@ -637,17 +793,23 @@ class Plex_XML_Data
|
|||
$xdir->addAttribute('parentKey', self::getMetadataUri($albumid));
|
||||
$xdir->addAttribute('originalTitle', $album->f_artist_full);
|
||||
$xdir->addAttribute('summary', '');
|
||||
$xdir->addAttribute('index', '1');
|
||||
$xdir->addAttribute('index', $song->track);
|
||||
$xdir->addAttribute('duration', $time);
|
||||
$xdir->addAttribute('type', 'track');
|
||||
$xdir->addAttribute('addedAt', '');
|
||||
$xdir->addAttribute('updatedAt', '');
|
||||
|
||||
$rating = new Rating($song->id, "song");
|
||||
$rating_value = $rating->get_average_rating();
|
||||
if ($rating_value > 0) {
|
||||
$xdir->addAttribute('rating', intval($rating_value * 2));
|
||||
}
|
||||
|
||||
$xmedia = $xdir->addChild('Media');
|
||||
$mediaid = self::getMediaId($song->id);
|
||||
$xmedia->addAttribute('id', $mediaid);
|
||||
$xmedia->addAttribute('duration', $time);
|
||||
$xmedia->addAttribute('bitrate', $song->bitrate);
|
||||
$xmedia->addAttribute('bitrate', intval($song->bitrate / 1000));
|
||||
$xmedia->addAttribute('audioChannels', '');
|
||||
// Type != Codec != Container, but that's how Ampache works today...
|
||||
$xmedia->addAttribute('audioCodec', $song->type);
|
||||
|
@ -671,4 +833,304 @@ class Plex_XML_Data
|
|||
|
||||
return $xsong;
|
||||
}
|
||||
|
||||
public static function createMyPlexAccount()
|
||||
{
|
||||
$xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><MyPlex/>');
|
||||
$myplex_username = self::getMyPlexUsername();
|
||||
$myplex_authtoken = self::getMyPlexAuthToken();
|
||||
$myplex_published = self::getMyPlexPublished();
|
||||
if ($myplex_username) {
|
||||
$xml->addAttribute('myPlex', '1');
|
||||
$xml->addAttribute('username', $myplex_username);
|
||||
if ($myplex_authtoken) {
|
||||
$xml->addAttribute('authToken', $myplex_authtoken);
|
||||
$xml->addAttribute('signInState', 'ok');
|
||||
if ($myplex_published) {
|
||||
$xml->addAttribute('mappingState', 'mapped');
|
||||
} else {
|
||||
$xml->addAttribute('mappingState', 'unknown');
|
||||
}
|
||||
} else {
|
||||
$xml->addAttribute('signInState', 'none');
|
||||
}
|
||||
} else {
|
||||
$xml->addAttribute('signInState', 'none');
|
||||
}
|
||||
$xml->addAttribute('mappingError', '');
|
||||
$xml->addAttribute('mappingErrorMessage', '1');
|
||||
|
||||
$xml->addAttribute('publicAddress', '1');
|
||||
$xml->addAttribute('publicPort', self::getServerPublicPort());
|
||||
$xml->addAttribute('privateAddress', '1');
|
||||
$xml->addAttribute('privatePort', self::getServerPort());
|
||||
|
||||
$xml->addAttribute('subscriptionActive', '1');
|
||||
$xml->addAttribute('subscriptionFeatures', 'cloudsync,pass,sync');
|
||||
$xml->addAttribute('subscriptionState', 'Active');
|
||||
|
||||
return $xml;
|
||||
}
|
||||
|
||||
public static function setSysAgents($xml)
|
||||
{
|
||||
/*$agent = $xml->addChild('Agent');
|
||||
$agent->addAttribute('primary', '0');
|
||||
$agent->addAttribute('hasPrefs', '0');
|
||||
$agent->addAttribute('hasAttribution', '1');
|
||||
$agent->addAttribute('identifier', 'com.plexapp.agents.wikipedia');*/
|
||||
|
||||
$agent = $xml->addChild('Agent');
|
||||
$agent->addAttribute('primary', '1');
|
||||
$agent->addAttribute('hasPrefs', '0');
|
||||
$agent->addAttribute('hasAttribution', '0');
|
||||
$agent->addAttribute('identifier', 'com.plexapp.agents.none');
|
||||
self::addNoneAgentMediaType($agent, 'Personal Media Artists', '8');
|
||||
self::addNoneAgentMediaType($agent, 'Personal Media', '1');
|
||||
self::addNoneAgentMediaType($agent, 'Personal Media Shows', '2');
|
||||
self::addNoneAgentMediaType($agent, 'Photos', '13');
|
||||
self::addNoneAgentMediaType($agent, 'Personal Media Albums', '9');
|
||||
}
|
||||
|
||||
protected static function addNoneAgentMediaType($xml, $name, $type)
|
||||
{
|
||||
$media = $xml->addChild('MediaType');
|
||||
$media->addAttribute('name', $name);
|
||||
$media->addAttribute('mediaType', $type);
|
||||
self::addLanguages($media, 'xn');
|
||||
}
|
||||
|
||||
protected static function addLanguages($xml, $languages)
|
||||
{
|
||||
$langs = explode(',', $languages);
|
||||
foreach ($langs as $lang) {
|
||||
$lg = $xml->addChild('Language');
|
||||
$lg->addAttribute('code', $lang);
|
||||
}
|
||||
}
|
||||
|
||||
protected static function addNoneAgent($xml, $name)
|
||||
{
|
||||
self::addAgent($xml, $name, '0', 'com.plexapp.agents.none', true, 'xn');
|
||||
}
|
||||
|
||||
protected static function addAgent($xml, $name, $hasPrefs, $identifier, $enabled = false, $langs='')
|
||||
{
|
||||
$agent = $xml->addChild('Agent');
|
||||
$agent->addAttribute('name', $name);
|
||||
if ($enabled) {
|
||||
$agent->addAttribute('enabled', ($enabled) ? '1' : '0');
|
||||
}
|
||||
$agent->addAttribute('hasPrefs', $hasPrefs);
|
||||
$agent->addAttribute('identifier', $identifier);
|
||||
if (!empty($langs)) {
|
||||
self::addLanguages($agent, $langs);
|
||||
}
|
||||
return $agent;
|
||||
}
|
||||
|
||||
public static function setSysMovieAgents($xml)
|
||||
{
|
||||
self::addNoneAgent($xml, 'Personal Media');
|
||||
}
|
||||
|
||||
public static function setSysTVShowAgents($xml)
|
||||
{
|
||||
self::addNoneAgent($xml, 'Personal Media Shows');
|
||||
}
|
||||
|
||||
public static function setSysPhotoAgents($xml)
|
||||
{
|
||||
self::addNoneAgent($xml, 'Photos');
|
||||
}
|
||||
|
||||
public static function setSysMusicAgents($xml, $category = 'Artists')
|
||||
{
|
||||
self::addNoneAgent($xml, 'Personal Media ' . $category);
|
||||
//self::addAgent($xml, 'Last.fm', '1', 'com.plexapp.agents.lastfm', 'true', 'en,sv,fr,es,de,pl,it,pt,ja,tr,ru,zh');
|
||||
}
|
||||
|
||||
public static function setAgentsContributors($xml, $mediaType, $primaryAgent)
|
||||
{
|
||||
if ($primaryAgent == 'com.plexapp.agents.none') {
|
||||
$type = '';
|
||||
switch ($mediaType) {
|
||||
case '1':
|
||||
$type = 'Movies';
|
||||
break;
|
||||
case '2':
|
||||
$type = 'TV';
|
||||
break;
|
||||
case '13':
|
||||
$type = 'Photos';
|
||||
break;
|
||||
case '8':
|
||||
$type = 'Artists';
|
||||
break;
|
||||
case '9':
|
||||
$type = 'Albums';
|
||||
break;
|
||||
}
|
||||
|
||||
self::addAgent($xml, 'Local Media Assets (' . $type . ')', '0', 'com.plexapp.agents.localmedia', true);
|
||||
}
|
||||
}
|
||||
|
||||
public static function setAccounts($xml, $userid)
|
||||
{
|
||||
// Not sure how to handle Plex accounts vs Ampache accounts, return only 1 for now.
|
||||
|
||||
$account = $xml->addChild('Account');
|
||||
$account->addAttribute('key', '/accounts/1');
|
||||
$account->addAttribute('name', 'Administrator');
|
||||
$account->addAttribute('defaultAudioLanguage', 'en');
|
||||
$account->addAttribute('autoSelectAudio', '1');
|
||||
$account->addAttribute('defaultSubtitleLanguage', 'en');
|
||||
$account->addAttribute('subtitleMode', '0');
|
||||
}
|
||||
|
||||
public static function setStatus($xml)
|
||||
{
|
||||
$dir = $xml->addChild('Directory');
|
||||
$dir->addAttribute('key', 'sessions');
|
||||
$dir->addAttribute('title', 'sessions');
|
||||
}
|
||||
|
||||
public static function setPrefs($xml)
|
||||
{
|
||||
self::addSettings($xml, 'AcceptedEULA', 'Has the user accepted the EULA', 'false', '', 'bool', 'true', '1', '0', '');
|
||||
//self::addSettings($xml, 'ApertureLibraryXmlPath', 'Aperture library XML path', '', '', 'text', '', '0', '1', 'channels');
|
||||
//self::addSettings($xml, 'ApertureSharingEnabled', 'Enable Aperture sharing', 'true', '', 'bool', 'true', '0', '0', 'channels');
|
||||
//self::addSettings($xml, 'AppCastUrl', 'AppCast URL', 'https://www.plexapp.com/appcast/mac/pms.xml', '', 'text', 'https://www.plexapp.com/appcast/mac/pms.xml', '0', '1', 'network');
|
||||
self::addSettings($xml, 'ConfigurationUrl', 'Web Manager URL', 'http://127.0.0.1:32400/web', '', 'text', self::getServerUri() . '/web', '1', '0', 'network');
|
||||
//self::addSettings($xml, 'DisableHlsAuthorization', 'Disable HLS authorization', 'false', '', 'bool', 'false', '1', '0', '');
|
||||
//self::addSettings($xml, 'DlnaAnnouncementLeaseTime', 'DLNA server announcement lease time', '1800', 'Duration of DLNA Server SSDP announcement lease time, in seconds', 'int', '1800', '0', '1', 'dlna');
|
||||
self::addSettings($xml, 'FirstRun', 'First run of PMS on this machine', 'true', '', 'bool', 'false', '1', '0', '');
|
||||
self::addSettings($xml, 'ForceSecureAccess', 'Force secure access', 'false', 'Disallow access on the local network except to authorized users', 'bool', 'false', '1', '0', 'general');
|
||||
self::addSettings($xml, 'FriendlyName', 'Friendly name', '', 'This name will be used to identify this media server to other computers on your network. If you leave it blank, your computer\'s name will be used instead.', 'text', self::getServerName(), '0', '0', 'general');
|
||||
self::addSettings($xml, 'LogVerbose', 'Plex Media Server verbose logging', 'false', 'Enable Plex Media Server verbose logging', 'bool', AmpConfig::get('debug_level') == '5', '0', '1', 'general');
|
||||
self::addSettings($xml, 'MachineIdentifier', 'A unique identifier for the machine', '', '', 'text', self::getMachineIdentifier(), '1', '0', '');
|
||||
self::addSettings($xml, 'ManualPortMappingMode', 'Disable Automatic Port Mapping', 'false', 'When enabled, PMS is not trying to set-up a port mapping through your Router automatically', 'bool', 'false', '1', '0', '');
|
||||
self::addSettings($xml, 'ManualPortMappingPort', 'External Port', '32400', 'When Automatic Port Mapping is disabled, you need to specify the external port that is mapped to this machine.', 'int', self::getServerPublicPort(), '1', '0', '');
|
||||
self::addSettings($xml, 'PlexOnlineMail', 'myPlex email', '', 'The email address you use to login to myPlex.', 'text', self::getMyPlexUsername(), '1', '0', '');
|
||||
self::addSettings($xml, 'PlexOnlineUrl', 'myPlex service URL', 'https://my.plexapp.com', 'The URL of the myPlex service', 'text', 'https://my.plexapp.com', '1', '0', '');
|
||||
self::addSettings($xml, 'allowMediaDeletion', 'Allow clients to delete media', 'false', 'Clients will be able to delete media', 'bool', 'false', '0', '1', 'library');
|
||||
self::addSettings($xml, 'logDebug', 'Plex Media Server debug logging', 'false', 'Enable Plex Media Server debug logging', 'bool', AmpConfig::get('debug'), '0', '1', 'general');
|
||||
}
|
||||
|
||||
protected static function addSettings($xml, $id, $label, $default, $summary, $type, $value, $hidden, $advanced, $group)
|
||||
{
|
||||
$setting = $xml->addChild('Setting');
|
||||
$setting->addAttribute('id', $id);
|
||||
$setting->addAttribute('label', $label);
|
||||
$setting->addAttribute('default', $default);
|
||||
$setting->addAttribute('summary', $summary);
|
||||
$setting->addAttribute('type', $type);
|
||||
$setting->addAttribute('value', $value);
|
||||
$setting->addAttribute('hidden', $hidden);
|
||||
$setting->addAttribute('advanced', $advanced);
|
||||
$setting->addAttribute('group', $group);
|
||||
}
|
||||
|
||||
public static function setMusicScanners($xml)
|
||||
{
|
||||
$scanner = $xml->addChild('Scanner');
|
||||
$scanner->addAttribute('name', 'Plex Music Scanner');
|
||||
}
|
||||
|
||||
public static function createAppStore()
|
||||
{
|
||||
// Maybe we can setup our own store here? Ignore for now.
|
||||
$xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><ASContainer/>');
|
||||
$xml->addAttribute('art', self::getResourceUri('store-art.png'));
|
||||
$xml->addAttribute('noCache', '1');
|
||||
$xml->addAttribute('noHistory', '0');
|
||||
$xml->addAttribute('title1', 'Channel Directory');
|
||||
$xml->addAttribute('replaceParent', '0');
|
||||
$xml->addAttribute('identifier', 'com.plexapp.system');
|
||||
|
||||
return $xml;
|
||||
}
|
||||
|
||||
public static function setMyPlexSubscription($xml)
|
||||
{
|
||||
$subscription = $xml->addChild('subscription');
|
||||
$subscription->addAttribute('active', '1');
|
||||
$subscription->addAttribute('status', 'Active');
|
||||
$subscription->addAttribute('plan', 'lifetime');
|
||||
$features = array('cloudsync', 'pass', 'sync');
|
||||
foreach ($features as $feature) {
|
||||
$fxml = $subscription->addChild('feature');
|
||||
$fxml->addAttribute('id', $feature);
|
||||
}
|
||||
}
|
||||
|
||||
public static function setServices($xml)
|
||||
{
|
||||
$dir = $xml->addChild('Directory');
|
||||
$dir->addAttribute('key', 'browse');
|
||||
$dir->addAttribute('title', 'browse');
|
||||
}
|
||||
|
||||
protected static function getPathDelimiter()
|
||||
{
|
||||
if (strpos(PHP_OS, 'WIN') === 0)
|
||||
return '\\';
|
||||
else
|
||||
return '/';
|
||||
}
|
||||
|
||||
public static function setBrowseService($xml, $path)
|
||||
{
|
||||
$delim = self::getPathDelimiter();
|
||||
if (!empty($path)) {
|
||||
$dir = base64_decode($path);
|
||||
debug_event('plex', 'Dir: ' . $dir, '5');
|
||||
} else {
|
||||
self::addDirPath($xml, AmpConfig::get('prefix') . $delim . 'plex', 'plex', true);
|
||||
|
||||
if ($delim == '/') {
|
||||
$dir = '/';
|
||||
} else {
|
||||
$dir = '';
|
||||
// TODO: found a better way to list Windows drive
|
||||
$letters = str_split("CDEFGHIJ");
|
||||
foreach ($letters as $letter) {
|
||||
self::addDirPath($xml, $letter . ':');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($dir)) {
|
||||
$dh = opendir($dir);
|
||||
if (is_resource($dh)) {
|
||||
while (false !== ($filename = readdir($dh))) {
|
||||
$path = $dir . $delim . $filename;
|
||||
if ($filename != '.' && $filename != '..' && is_dir($path)) {
|
||||
self::addDirPath($xml, $path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function addDirPath($xml, $path, $title='', $isHome=false)
|
||||
{
|
||||
$delim = self::getPathDelimiter();
|
||||
$dir = $xml->addChild('Path');
|
||||
if ($isHome) {
|
||||
$dir->addAttribute('isHome', '1');
|
||||
}
|
||||
if (empty($title)) {
|
||||
$pp = explode($delim, $path);
|
||||
$title = $pp[count($pp)-1];
|
||||
if (empty($title)) {
|
||||
$title = $path;
|
||||
}
|
||||
}
|
||||
$key = '/services/browse/' . base64_encode($path);
|
||||
$dir->addAttribute('key', $key);
|
||||
$dir->addAttribute('title', $title);
|
||||
$dir->addAttribute('path', $path);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ class Session
|
|||
*
|
||||
* This function is randomly called and it cleans up the spoo
|
||||
*/
|
||||
public static function gc($maxlifetime)
|
||||
public static function gc()
|
||||
{
|
||||
$sql = 'DELETE FROM `session` WHERE `expire` < ?';
|
||||
$db_results = Dba::write($sql, array(time()));
|
||||
|
|
|
@ -70,6 +70,12 @@ if (!empty($results['force_ssl'])) {
|
|||
$http_type = 'https://';
|
||||
}
|
||||
|
||||
if ($ow_config) {
|
||||
foreach ($ow_config as $key => $value) {
|
||||
$results[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$results['raw_web_path'] = $results['web_path'];
|
||||
if (empty($results['http_host'])) {
|
||||
$results['http_host'] = $_SERVER['HTTP_HOST'];
|
||||
|
@ -86,7 +92,7 @@ if (isset($results['user_ip_cardinality']) && !$results['user_ip_cardinality'])
|
|||
|
||||
/* Variables needed for Auth class */
|
||||
$results['cookie_path'] = $results['raw_web_path'];
|
||||
$results['cookie_domain'] = $_SERVER['SERVER_NAME'];
|
||||
$results['cookie_domain'] = $results['http_port'];
|
||||
$results['cookie_life'] = $results['session_cookielife'];
|
||||
$results['cookie_secure'] = $results['session_cookiesecure'];
|
||||
|
||||
|
|
190
lib/login.php
Normal file
190
lib/login.php
Normal file
|
@ -0,0 +1,190 @@
|
|||
<?php
|
||||
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
|
||||
/**
|
||||
*
|
||||
* LICENSE: GNU General Public License, version 2 (GPLv2)
|
||||
* Copyright 2001 - 2013 Ampache.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License v2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* We have to create a cookie here because IIS
|
||||
* can't handle Cookie + Redirect
|
||||
*/
|
||||
Session::create_cookie();
|
||||
Preference::init();
|
||||
|
||||
/**
|
||||
* If Access Control is turned on then we don't
|
||||
* even want them to be able to get to the login
|
||||
* page if they aren't in the ACL
|
||||
*/
|
||||
if (AmpConfig::get('access_control')) {
|
||||
if (!Access::check_network('interface', '', '5')) {
|
||||
debug_event('UI::access_denied', 'Access Denied:' . $_SERVER['REMOTE_ADDR'] . ' is not in the Interface Access list', '3');
|
||||
UI::access_denied();
|
||||
exit();
|
||||
}
|
||||
} // access_control is enabled
|
||||
|
||||
/* Clean Auth values */
|
||||
unset($auth);
|
||||
|
||||
if (empty($_REQUEST['step'])) {
|
||||
/* Check for posted username and password, or appropriate environment variable if using HTTP auth */
|
||||
if (($_POST['username']) ||
|
||||
(in_array('http', AmpConfig::get('auth_methods')) &&
|
||||
($_SERVER['REMOTE_USER'] || $_SERVER['HTTP_REMOTE_USER']))) {
|
||||
|
||||
if ($_POST['rememberme']) {
|
||||
Session::create_remember_cookie();
|
||||
}
|
||||
|
||||
/* If we are in demo mode let's force auth success */
|
||||
if (AmpConfig::get('demo_mode')) {
|
||||
$auth['success'] = true;
|
||||
$auth['info']['username'] = 'Admin - DEMO';
|
||||
$auth['info']['fullname'] = 'Administrative User';
|
||||
$auth['info']['offset_limit'] = 25;
|
||||
} else {
|
||||
if ($_POST['username']) {
|
||||
$username = scrub_in($_POST['username']);
|
||||
$password = $_POST['password'];
|
||||
} else {
|
||||
if ($_SERVER['REMOTE_USER']) {
|
||||
$username = $_SERVER['REMOTE_USER'];
|
||||
} elseif ($_SERVER['HTTP_REMOTE_USER']) {
|
||||
$username = $_SERVER['HTTP_REMOTE_USER'];
|
||||
}
|
||||
$password = '';
|
||||
}
|
||||
|
||||
$auth = Auth::login($username, $password, true);
|
||||
if ($auth['success']) {
|
||||
$username = $auth['username'];
|
||||
} elseif ($auth['ui_required']) {
|
||||
echo $auth['ui_required'];
|
||||
exit();
|
||||
} else {
|
||||
debug_event('Login', scrub_out($username) . ' attempted to login and failed', '1');
|
||||
Error::add('general', T_('Error Username or Password incorrect, please try again'));
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ($_REQUEST['step'] == '2') {
|
||||
$auth_mod = $_REQUEST['auth_mod'];
|
||||
$auth = Auth::login_step2($auth_mod);
|
||||
if ($auth['success']) {
|
||||
$username = $auth['username'];
|
||||
} else {
|
||||
debug_event('Login', 'Second step authentication failed', '1');
|
||||
Error::add('general', $auth['error']);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($username)) {
|
||||
$user = User::get_from_username($username);
|
||||
|
||||
if ($user->disabled) {
|
||||
$auth['success'] = false;
|
||||
Error::add('general', T_('User Disabled please contact Admin'));
|
||||
debug_event('Login', scrub_out($username) . ' is disabled and attempted to login', '1');
|
||||
} // if user disabled
|
||||
elseif (AmpConfig::get('prevent_multiple_logins')) {
|
||||
$session_ip = $user->is_logged_in();
|
||||
$current_ip = inet_pton($_SERVER['REMOTE_ADDR']);
|
||||
if ($current_ip && ($current_ip != $session_ip)) {
|
||||
$auth['success'] = false;
|
||||
Error::add('general', T_('User Already Logged in'));
|
||||
debug_event('Login', scrub_out($username) . ' is already logged in from ' . $session_ip . ' and attempted to login from ' . $current_ip, '1');
|
||||
} // if logged in multiple times
|
||||
} // if prevent multiple logins
|
||||
elseif (AmpConfig::get('auto_create') && $auth['success'] &&
|
||||
! $user->username) {
|
||||
/* This is run if we want to autocreate users who don't
|
||||
exist (useful for non-mysql auth) */
|
||||
$access = AmpConfig::get('auto_user')
|
||||
? User::access_name_to_level(AmpConfig::get('auto_user'))
|
||||
: '5';
|
||||
$name = $auth['name'];
|
||||
$email = $auth['email'];
|
||||
$website = $auth['website'];
|
||||
|
||||
/* Attempt to create the user */
|
||||
if (User::create($username, $name, $email, $website,
|
||||
hash('sha256', mt_rand()), $access)) {
|
||||
$user = User::get_from_username($username);
|
||||
} else {
|
||||
$auth['success'] = false;
|
||||
Error::add('general', T_('Unable to create local account'));
|
||||
}
|
||||
} // End if auto_create
|
||||
|
||||
// This allows stealing passwords validated by external means
|
||||
// such as LDAP
|
||||
if (AmpConfig::get('auth_password_save') && $auth['success'] && $password) {
|
||||
$user->update_password($password);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the authentication was a success */
|
||||
if ($auth['success']) {
|
||||
// $auth->info are the fields specified in the config file
|
||||
// to retrieve for each user
|
||||
Session::create($auth);
|
||||
|
||||
// Not sure if it was me or php tripping out,
|
||||
// but naming this 'user' didn't work at all
|
||||
$_SESSION['userdata'] = $auth;
|
||||
|
||||
// Record the IP of this person!
|
||||
if (AmpConfig::get('track_user_ip')) {
|
||||
$user->insert_ip_history();
|
||||
}
|
||||
|
||||
// Update data from this auth if ours are empty
|
||||
if (empty($user->fullname) && !empty($auth['name'])) {
|
||||
$user->update_fullname($auth['name']);
|
||||
}
|
||||
if (empty($user->email) && !empty($auth['email'])) {
|
||||
$user->update_email($auth['email']);
|
||||
}
|
||||
if (empty($user->website) && !empty($auth['website'])) {
|
||||
$user->update_website($auth['website']);
|
||||
}
|
||||
|
||||
// If an admin, check for update
|
||||
if (AmpConfig::get('autoupdate') && Access::check('interface','100')) {
|
||||
AutoUpdate::is_update_available(true);
|
||||
}
|
||||
|
||||
/* Make sure they are actually trying to get to this site and don't try
|
||||
* to redirect them back into an admin section
|
||||
*/
|
||||
$web_path = AmpConfig::get('web_path');
|
||||
if ((substr($_POST['referrer'], 0, strlen($web_path)) == $web_path) &&
|
||||
strpos($_POST['referrer'], 'install.php') === false &&
|
||||
strpos($_POST['referrer'], 'login.php') === false &&
|
||||
strpos($_POST['referrer'], 'logout.php') === false &&
|
||||
strpos($_POST['referrer'], 'update.php') === false &&
|
||||
strpos($_POST['referrer'], 'activate.php') === false &&
|
||||
strpos($_POST['referrer'], 'admin') === false ) {
|
||||
|
||||
header('Location: ' . $_POST['referrer']);
|
||||
exit();
|
||||
} // if we've got a referrer
|
||||
header('Location: ' . AmpConfig::get('web_path') . '/index.php');
|
||||
exit();
|
||||
} // auth success
|
|
@ -563,7 +563,7 @@ function print_bool($value)
|
|||
*/
|
||||
function show_now_playing()
|
||||
{
|
||||
Session::gc(null);
|
||||
Session::gc();
|
||||
Stream::gc_now_playing();
|
||||
|
||||
$web_path = AmpConfig::get('web_path');
|
||||
|
|
170
login.php
170
login.php
|
@ -22,174 +22,6 @@
|
|||
|
||||
define('NO_SESSION', '1');
|
||||
require_once 'lib/init.php';
|
||||
|
||||
/* We have to create a cookie here because IIS
|
||||
* can't handle Cookie + Redirect
|
||||
*/
|
||||
Session::create_cookie();
|
||||
Preference::init();
|
||||
|
||||
/**
|
||||
* If Access Control is turned on then we don't
|
||||
* even want them to be able to get to the login
|
||||
* page if they aren't in the ACL
|
||||
*/
|
||||
if (AmpConfig::get('access_control')) {
|
||||
if (!Access::check_network('interface', '', '5')) {
|
||||
debug_event('UI::access_denied', 'Access Denied:' . $_SERVER['REMOTE_ADDR'] . ' is not in the Interface Access list', '3');
|
||||
UI::access_denied();
|
||||
exit();
|
||||
}
|
||||
} // access_control is enabled
|
||||
|
||||
/* Clean Auth values */
|
||||
unset($auth);
|
||||
|
||||
if (empty($_REQUEST['step'])) {
|
||||
/* Check for posted username and password, or appropriate environment variable if using HTTP auth */
|
||||
if (($_POST['username']) ||
|
||||
(in_array('http', AmpConfig::get('auth_methods')) &&
|
||||
($_SERVER['REMOTE_USER'] || $_SERVER['HTTP_REMOTE_USER']))) {
|
||||
|
||||
if ($_POST['rememberme']) {
|
||||
Session::create_remember_cookie();
|
||||
}
|
||||
|
||||
/* If we are in demo mode let's force auth success */
|
||||
if (AmpConfig::get('demo_mode')) {
|
||||
$auth['success'] = true;
|
||||
$auth['info']['username'] = 'Admin - DEMO';
|
||||
$auth['info']['fullname'] = 'Administrative User';
|
||||
$auth['info']['offset_limit'] = 25;
|
||||
} else {
|
||||
if ($_POST['username']) {
|
||||
$username = scrub_in($_POST['username']);
|
||||
$password = $_POST['password'];
|
||||
} else {
|
||||
if ($_SERVER['REMOTE_USER']) {
|
||||
$username = $_SERVER['REMOTE_USER'];
|
||||
} elseif ($_SERVER['HTTP_REMOTE_USER']) {
|
||||
$username = $_SERVER['HTTP_REMOTE_USER'];
|
||||
}
|
||||
$password = '';
|
||||
}
|
||||
|
||||
$auth = Auth::login($username, $password, true);
|
||||
if ($auth['success']) {
|
||||
$username = $auth['username'];
|
||||
} elseif ($auth['ui_required']) {
|
||||
echo $auth['ui_required'];
|
||||
exit();
|
||||
} else {
|
||||
debug_event('Login', scrub_out($username) . ' attempted to login and failed', '1');
|
||||
Error::add('general', T_('Error Username or Password incorrect, please try again'));
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ($_REQUEST['step'] == '2') {
|
||||
$auth_mod = $_REQUEST['auth_mod'];
|
||||
$auth = Auth::login_step2($auth_mod);
|
||||
if ($auth['success']) {
|
||||
$username = $auth['username'];
|
||||
} else {
|
||||
debug_event('Login', 'Second step authentication failed', '1');
|
||||
Error::add('general', $auth['error']);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($username)) {
|
||||
$user = User::get_from_username($username);
|
||||
|
||||
if ($user->disabled) {
|
||||
$auth['success'] = false;
|
||||
Error::add('general', T_('User Disabled please contact Admin'));
|
||||
debug_event('Login', scrub_out($username) . ' is disabled and attempted to login', '1');
|
||||
} // if user disabled
|
||||
elseif (AmpConfig::get('prevent_multiple_logins')) {
|
||||
$session_ip = $user->is_logged_in();
|
||||
$current_ip = inet_pton($_SERVER['REMOTE_ADDR']);
|
||||
if ($current_ip && ($current_ip != $session_ip)) {
|
||||
$auth['success'] = false;
|
||||
Error::add('general', T_('User Already Logged in'));
|
||||
debug_event('Login', scrub_out($username) . ' is already logged in from ' . $session_ip . ' and attempted to login from ' . $current_ip, '1');
|
||||
} // if logged in multiple times
|
||||
} // if prevent multiple logins
|
||||
elseif (AmpConfig::get('auto_create') && $auth['success'] &&
|
||||
! $user->username) {
|
||||
/* This is run if we want to autocreate users who don't
|
||||
exist (useful for non-mysql auth) */
|
||||
$access = AmpConfig::get('auto_user')
|
||||
? User::access_name_to_level(AmpConfig::get('auto_user'))
|
||||
: '5';
|
||||
$name = $auth['name'];
|
||||
$email = $auth['email'];
|
||||
$website = $auth['website'];
|
||||
|
||||
/* Attempt to create the user */
|
||||
if (User::create($username, $name, $email, $website,
|
||||
hash('sha256', mt_rand()), $access)) {
|
||||
$user = User::get_from_username($username);
|
||||
} else {
|
||||
$auth['success'] = false;
|
||||
Error::add('general', T_('Unable to create local account'));
|
||||
}
|
||||
} // End if auto_create
|
||||
|
||||
// This allows stealing passwords validated by external means
|
||||
// such as LDAP
|
||||
if (AmpConfig::get('auth_password_save') && $auth['success'] && $password) {
|
||||
$user->update_password($password);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the authentication was a success */
|
||||
if ($auth['success']) {
|
||||
// $auth->info are the fields specified in the config file
|
||||
// to retrieve for each user
|
||||
Session::create($auth);
|
||||
|
||||
// Not sure if it was me or php tripping out,
|
||||
// but naming this 'user' didn't work at all
|
||||
$_SESSION['userdata'] = $auth;
|
||||
|
||||
// Record the IP of this person!
|
||||
if (AmpConfig::get('track_user_ip')) {
|
||||
$user->insert_ip_history();
|
||||
}
|
||||
|
||||
// Update data from this auth if ours are empty
|
||||
if (empty($user->fullname) && !empty($auth['name'])) {
|
||||
$user->update_fullname($auth['name']);
|
||||
}
|
||||
if (empty($user->email) && !empty($auth['email'])) {
|
||||
$user->update_email($auth['email']);
|
||||
}
|
||||
if (empty($user->website) && !empty($auth['website'])) {
|
||||
$user->update_website($auth['website']);
|
||||
}
|
||||
|
||||
// If an admin, check for update
|
||||
if (AmpConfig::get('autoupdate') && Access::check('interface','100')) {
|
||||
AutoUpdate::is_update_available(true);
|
||||
}
|
||||
|
||||
/* Make sure they are actually trying to get to this site and don't try
|
||||
* to redirect them back into an admin section
|
||||
*/
|
||||
$web_path = AmpConfig::get('web_path');
|
||||
if ((substr($_POST['referrer'], 0, strlen($web_path)) == $web_path) &&
|
||||
strpos($_POST['referrer'], 'install.php') === false &&
|
||||
strpos($_POST['referrer'], 'login.php') === false &&
|
||||
strpos($_POST['referrer'], 'logout.php') === false &&
|
||||
strpos($_POST['referrer'], 'update.php') === false &&
|
||||
strpos($_POST['referrer'], 'activate.php') === false &&
|
||||
strpos($_POST['referrer'], 'admin') === false ) {
|
||||
|
||||
header('Location: ' . $_POST['referrer']);
|
||||
exit();
|
||||
} // if we've got a referrer
|
||||
header('Location: ' . AmpConfig::get('web_path') . '/index.php');
|
||||
exit();
|
||||
} // auth success
|
||||
require_once 'lib/login.php';
|
||||
|
||||
require AmpConfig::get('prefix') . '/templates/show_login_form.inc.php';
|
||||
|
|
176
plex/index.php
176
plex/index.php
|
@ -28,189 +28,40 @@ if (!AmpConfig::get('plex_backend')) {
|
|||
exit;
|
||||
}
|
||||
|
||||
$action = strtolower($_GET['action']);
|
||||
$action = $_GET['action'];
|
||||
|
||||
$headers = apache_request_headers();
|
||||
$client = $headers['User-Agent'];
|
||||
/*$deviceName = $headers['X-Plex-Device-Name'];
|
||||
$clientPlatform = $headers['X-Plex-Client-Platform'];
|
||||
$version = $headers['X-Plex-Version'];
|
||||
$language = $headers['X-Plex-Language'];
|
||||
$clientFeatures = $headers['X-Plex-Client-Capabilities'];
|
||||
|
||||
// User probably get here with a browser, we show specific content
|
||||
if (empty($version) && empty($action)) {
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<title>Ampache/Plex Configuration</title>
|
||||
<style>
|
||||
body {
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
#main {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#content {
|
||||
margin-top: 10%;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info {
|
||||
font-weight: bold;
|
||||
color: #8d8d8d;
|
||||
}
|
||||
|
||||
.error {
|
||||
font-weight: bold;
|
||||
color: #801010;
|
||||
}
|
||||
|
||||
.configform {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
|
||||
border-color: #777777;
|
||||
width: auto;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.field {
|
||||
margin: 20px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.field_label {
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
margin-right: 15px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.field_value {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.formbuttons {
|
||||
text-align: right;
|
||||
margin-right: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="main">
|
||||
<div id="content">
|
||||
<img src="/images/plex-icon-256.png" />
|
||||
<?php
|
||||
$username = $_POST['username'];
|
||||
$password = $_POST['password'];
|
||||
|
||||
$authadmin = false;
|
||||
if(!empty($username) && !empty($password)) {
|
||||
$auth = Auth::login($username, $password);
|
||||
if ($auth['success']) {
|
||||
$GLOBALS['user'] = User::get_from_username($username);
|
||||
if (Access::check('interface', '100')) {
|
||||
$authadmin = true;
|
||||
|
||||
$plexact = $_POST['plexact'];
|
||||
if (empty($plexact)) {
|
||||
?>
|
||||
<p class="info">Configure your Plex server settings bellow.</p>
|
||||
<div class="configform">
|
||||
<form action="/" method="POST" enctype="multipart/form-data">
|
||||
<input type="hidden" name="plexact" value="save" />
|
||||
<input type="hidden" name="username" value="<?php echo $username; ?>" />
|
||||
<input type="hidden" name="password" value="<?php echo $password; ?>" />
|
||||
<div class="field">
|
||||
<div class="field_label">myPlex Username (optional):</div>
|
||||
<div class="field_value"><input type="text" name="myplex_username" /></div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="field_label">myPlex Password (optional):</div>
|
||||
<div class="field_value"><input type="password" name="myplex_password" /></div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="field_label">Server Name:</div>
|
||||
<div class="field_value"><input type="text" name="plex_servername" /></div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="field_label">Server UUID:</div>
|
||||
<div class="field_value"><input type="text" name="plex_uuid" /></div>
|
||||
</div>
|
||||
<div class="formbuttons">
|
||||
<input type="submit" value="Save" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
} elseif ($plexact == "save") {
|
||||
$myplex_username = $_POST['myplex_username'];
|
||||
$myplex_password = $_POST['myplex_password'];
|
||||
$plex_servername = $_POST['plex_servername'];
|
||||
$plex_uuid = $_POST['plex_uuid'];
|
||||
|
||||
if (!empty($myplex_username)) {
|
||||
// Register the server on myPlex and get auth token
|
||||
$authtoken = Plex_Api::validateMyPlex($myplex_username, $myplex_password, $plex_uuid);
|
||||
echo "Authentication token: " . $authtoken . "<br />\r\n";
|
||||
Plex_Api::registerMyPlex($plex_uuid, $authtoken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$authadmin) {
|
||||
?>
|
||||
<p class="error">Ampache authentication required.</p>
|
||||
<div class="configform">
|
||||
<form action="/" method="POST" enctype="multipart/form-data">
|
||||
<div class="field">
|
||||
<div class="field_label">Username:</div>
|
||||
<div class="field_value"><input type="text" name="username" /></div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="field_label">Password:</div>
|
||||
<div class="field_value"><input type="password" name="password" /></div>
|
||||
</div>
|
||||
<div class="formbuttons">
|
||||
<input type="submit" value="Log-on" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
|
||||
exit;
|
||||
}
|
||||
$clientFeatures = $headers['X-Plex-Client-Capabilities'];*/
|
||||
debug_event('plex', 'Request headers: '. print_r($headers, true), '5');
|
||||
|
||||
// Get the list of possible methods for the Plex API
|
||||
$methods = get_class_methods('plex_api');
|
||||
// Define list of internal functions that should be skipped
|
||||
$internal_functions = array('setHeader', 'root', 'apiOutput', 'createError', 'validateMyPlex');
|
||||
$internal_functions = array('setHeader', 'root', 'apiOutput', 'createError', 'validateMyPlex', 'getPublicIp', 'registerMyPlex', 'publishDeviceConnection', 'unregisterMyPlex');
|
||||
|
||||
$params = array_filter(explode('/', $action), 'strlen');
|
||||
if (count($params) > 0) {
|
||||
// Recurse through them and see if we're calling one of them
|
||||
for ($i = count($params); $i > 0; $i--) {
|
||||
$act = implode('_', array_slice($params, 0, $i));
|
||||
$act = strtolower(implode('_', array_slice($params, 0, $i)));
|
||||
foreach ($methods as $method) {
|
||||
if (in_array($method, $internal_functions)) { continue; }
|
||||
|
||||
// If the method is the same as the action being called
|
||||
// Then let's call this function!
|
||||
if ($act == $method) {
|
||||
|
||||
if ($act != 'users' && $act != 'users_account' && $act != 'manage_frameworks_ekspinner_resources') {
|
||||
Plex_Api::auth_user();
|
||||
}
|
||||
|
||||
Plex_Api::setHeader('xml');
|
||||
Plex_Api::setPlexHeader($headers);
|
||||
call_user_func(array('plex_api', $method), array_slice($params, $i, count($params) - $i));
|
||||
// We only allow a single function to be called, and we assume it's cleaned up!
|
||||
exit();
|
||||
|
@ -219,10 +70,11 @@ if (count($params) > 0) {
|
|||
} // end foreach methods in API
|
||||
}
|
||||
} else {
|
||||
Plex_Api::auth_user();
|
||||
Plex_Api::setHeader('xml');
|
||||
Plex_Api::setPlexHeader($headers);
|
||||
Plex_Api::root();
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
Plex_Api::createError(404);
|
||||
|
|
BIN
plex/resources/small_black_7.png
Normal file
BIN
plex/resources/small_black_7.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 67 B |
BIN
plex/resources/store-art.png
Normal file
BIN
plex/resources/store-art.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2 MiB |
4
plex/web/footer.inc.php
Normal file
4
plex/web/footer.inc.php
Normal file
|
@ -0,0 +1,4 @@
|
|||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
plex/web/header.inc.php
Normal file
9
plex/web/header.inc.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Ampache/Plex Configuration</title>
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="main">
|
||||
<div id="maincontainer">
|
||||
<img src="/images/plex-icon-256.png" />
|
207
plex/web/index.php
Normal file
207
plex/web/index.php
Normal file
|
@ -0,0 +1,207 @@
|
|||
<?php
|
||||
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
|
||||
/**
|
||||
*
|
||||
* LICENSE: GNU General Public License, version 2 (GPLv2)
|
||||
* Copyright 2001 - 2013 Ampache.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License v2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
require_once 'init.php';
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<title>Ampache/Plex Configuration</title>
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
<script>
|
||||
function changeUniqid()
|
||||
{
|
||||
if (confirm("<?php echo T_('Changing the server UUID could break clients connectivity. Do you confirm?'); ?>")) {
|
||||
document.location='/web/?plexact=change_uniqid';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="main">
|
||||
<div id="maincontainer">
|
||||
<img src="/images/plex-icon-256.png" /><br />
|
||||
<?php
|
||||
|
||||
function init_db()
|
||||
{
|
||||
if (!Preference::exists('myplex_username')) {
|
||||
Preference::insert('myplex_username','myPlex Username','','25','string','internal');
|
||||
Preference::insert('myplex_authtoken','myPlex Auth Token','','25','string','internal');
|
||||
Preference::insert('myplex_published','Plex Server is published to myPlex','0','25','boolean','internal');
|
||||
Preference::insert('plex_uniqid','Plex Server Unique Id', uniqid(),'25','string','internal');
|
||||
Preference::insert('plex_servername','Plex Server Name','Ampache Doped','25','string','internal');
|
||||
Preference::insert('plex_public_address','Plex Public Address','','25','string','internal');
|
||||
Preference::insert('plex_public_port','Plex Public Port','32400','25','string','internal');
|
||||
Preference::insert('plex_local_auth','myPlex authentication required on local network','0','25','boolean','internal');
|
||||
Preference::insert('plex_match_email','Link myPlex users to Ampache based on e-mail address','1','25','boolean','internal');
|
||||
|
||||
User::rebuild_all_preferences();
|
||||
}
|
||||
}
|
||||
|
||||
init_db();
|
||||
$myplex_username = Plex_XML_Data::getMyPlexUsername();
|
||||
$myplex_authtoken = Plex_XML_Data::getMyPlexAuthToken();
|
||||
$myplex_published = Plex_XML_Data::getMyPlexPublished();
|
||||
$plex_servername = Plex_XML_Data::getServerName();
|
||||
$plex_public_address = Plex_XML_Data::getServerPublicAddress();
|
||||
$plex_public_port = Plex_XML_Data::getServerPublicPort();
|
||||
$plex_local_auth = AmpConfig::get('plex_local_auth');
|
||||
$plex_match_email = AmpConfig::get('plex_match_email');
|
||||
|
||||
$plexact = $_REQUEST['plexact'];
|
||||
switch ($plexact) {
|
||||
case 'auth_myplex':
|
||||
$myplex_username = $_POST['myplex_username'];
|
||||
$myplex_password = $_POST['myplex_password'];
|
||||
$plex_public_port = $_POST['plex_public_port'];
|
||||
|
||||
|
||||
if (!empty($myplex_username)) {
|
||||
// Register the server on myPlex and get auth token
|
||||
$myplex_authtoken = Plex_Api::validateMyPlex($myplex_username, $myplex_password);
|
||||
if (!empty($myplex_authtoken)) {
|
||||
echo T_('myPlex authentication completed.') . "<br />\r\n";
|
||||
|
||||
Preference::update('myplex_username', -1, $myplex_username, true, true);
|
||||
Preference::update('myplex_authtoken', -1, $myplex_authtoken, true, true);
|
||||
Preference::update('plex_public_port', -1, $plex_public_port, true, true);
|
||||
|
||||
$plex_public_address = Plex_Api::getPublicIp();
|
||||
Preference::update('plex_public_address', -1, $plex_public_address, true, true);
|
||||
|
||||
$ret = Plex_Api::registerMyPlex($myplex_authtoken);
|
||||
if ($ret['status'] == '201') {
|
||||
Plex_Api::publishDeviceConnection($myplex_authtoken);
|
||||
$myplex_published = true;
|
||||
echo T_('Server registration completed.') . "<br />\r\n";
|
||||
} else {
|
||||
$myplex_published = false;
|
||||
echo "<p class='error'>" . T_('Cannot register the server on myPlex.') . "</p>";
|
||||
}
|
||||
Preference::update('myplex_published', -1, $myplex_published, true, true);
|
||||
} else {
|
||||
$myplex_authtoken = '';
|
||||
$myplex_published = false;
|
||||
echo "<p class='error'>" . T_('Cannot authenticate on myPlex.') . "</p>";
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'unauth_myplex':
|
||||
Plex_Api::unregisterMyPlex($myplex_authtoken);
|
||||
|
||||
$myplex_username = '';
|
||||
$myplex_authtoken = '';
|
||||
$myplex_published = false;
|
||||
Preference::update('myplex_username', -1, $myplex_username, true, true);
|
||||
Preference::update('myplex_authtoken', -1, $myplex_authtoken, true, true);
|
||||
Preference::update('myplex_published', -1, $myplex_published, true, true);
|
||||
break;
|
||||
|
||||
case 'save':
|
||||
$plex_servername = $_POST['plex_servername'];
|
||||
$plex_local_auth = $_POST['plex_local_auth'] ?: '0';
|
||||
$plex_match_email = $_POST['plex_match_email'] ?: '0';
|
||||
|
||||
Preference::update('plex_servername', -1, $plex_servername, true, true);
|
||||
Preference::update('plex_local_auth', -1, $plex_local_auth, true, true);
|
||||
Preference::update('plex_match_email', -1, $plex_match_email, true, true);
|
||||
break;
|
||||
|
||||
case 'change_uniqid':
|
||||
Preference::update('plex_uniqid', -1,uniqid(), true, true);
|
||||
echo T_('Server UUID changed.') . "<br />\r\n";
|
||||
break;
|
||||
}
|
||||
?>
|
||||
<p class="info">Configure your Plex server settings bellow.</p>
|
||||
|
||||
<div class="configform">
|
||||
<h3>Server Settings</h3>
|
||||
<form action="" method="POST" enctype="multipart/form-data">
|
||||
<input type="hidden" name="plexact" value="save" />
|
||||
<div class="field">
|
||||
<label for="plex_servername">Server Name:</label>
|
||||
<input id="plex_servername" class="field_value" type="text" name="plex_servername" value="<?php echo $plex_servername; ?>" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="plex_local_auth">myPlex authentication required on local network</label>
|
||||
<input type="checkbox" id="plex_local_auth" name="plex_local_auth" value="1" <?php if ($plex_local_auth) { echo "checked"; } ?>>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="plex_match_email">Link myPlex users to Ampache based on e-mail address</label>
|
||||
<input type="checkbox" id="plex_match_email" name="plex_match_email" value="1" <?php if ($plex_match_email) { echo "checked"; } ?>>
|
||||
</div>
|
||||
<div class="formbuttons">
|
||||
<input type="submit" value="Save" />
|
||||
</div>
|
||||
</form>
|
||||
</div><br />
|
||||
|
||||
<?php if (empty($myplex_authtoken)) { ?>
|
||||
<div class="configform">
|
||||
<h3>myPlex authentication / server publish</h3>
|
||||
<form action="" method="POST" enctype="multipart/form-data">
|
||||
<input type="hidden" name="plexact" value="auth_myplex" />
|
||||
<div class="field">
|
||||
<label for="myplex_username">myPlex Username:</label>
|
||||
<input type="text" id="myplex_username" class="field_value" name="myplex_username" value="<?php echo $myplex_username; ?>" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="myplex_password">myPlex Password:</label>
|
||||
<input id="myplex_password" type="password" class="field_value" name="myplex_password" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="plex_public_port">Public Server Port (optional):</label>
|
||||
<input type="text" id="plex_public_port" class="field_value" name="plex_public_port" value="<?php echo $plex_public_port; ?>" />
|
||||
</div>
|
||||
<div class="formbuttons">
|
||||
<input type="submit" value="Auth/Publish" />
|
||||
</div>
|
||||
</form>
|
||||
</div><br />
|
||||
<?php } else { ?>
|
||||
<div class="configform">
|
||||
<h3>myPlex authentication / server publish</h3>
|
||||
<form action="" method="POST" enctype="multipart/form-data">
|
||||
<label>myPlex user: <b><?php echo $myplex_username; ?></b></label><br />
|
||||
<label>Public server address: <b><?php echo $plex_public_address; ?>:<?php echo $plex_public_port; ?></b></label>
|
||||
<input type="hidden" name="plexact" value="unauth_myplex" />
|
||||
<div class="formbuttons">
|
||||
<input type="submit" value="Unregister" />
|
||||
</div>
|
||||
</form>
|
||||
</div><br />
|
||||
<?php } ?>
|
||||
|
||||
<br />
|
||||
<div class="configform">
|
||||
<h3>Tools</h3><form>
|
||||
<div class="formbuttons">
|
||||
<input type="button" value="Change Server UUID" onclick="changeUniqid();" />
|
||||
</div></form>
|
||||
</div><br />
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
40
plex/web/init.php
Normal file
40
plex/web/init.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
|
||||
/**
|
||||
*
|
||||
* LICENSE: GNU General Public License, version 2 (GPLv2)
|
||||
* Copyright 2001 - 2013 Ampache.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License v2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
require_once('../../lib/class/plex_xml_data.class.php');
|
||||
|
||||
$ow_config = array(
|
||||
'http_host' => Plex_XML_Data::getServerAddress() . ':' . Plex_XML_Data::getServerPort(),
|
||||
'web_path' => '/web'
|
||||
);
|
||||
|
||||
require_once '../../lib/init.php';
|
||||
|
||||
if (!AmpConfig::get('plex_backend')) {
|
||||
echo "Disabled.";
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!defined('NO_SESSION') && !Access::check('interface', '100')) {
|
||||
Error::add('general', T_('Unauthorized.'));
|
||||
exit();
|
||||
}
|
47
plex/web/login.php
Normal file
47
plex/web/login.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
|
||||
/**
|
||||
*
|
||||
* LICENSE: GNU General Public License, version 2 (GPLv2)
|
||||
* Copyright 2001 - 2013 Ampache.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License v2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
define('NO_SESSION','1');
|
||||
require_once 'init.php';
|
||||
require_once '../../lib/login.php';
|
||||
|
||||
require_once('header.inc.php');
|
||||
?>
|
||||
<p class="error">Ampache authentication required.</p>
|
||||
<div class="configform">
|
||||
<form action="" method="POST" enctype="multipart/form-data">
|
||||
<div class="field">
|
||||
<div class="field_label">Username:</div>
|
||||
<div class="field_value"><input type="text" name="username" /></div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="field_label">Password:</div>
|
||||
<div class="field_value"><input type="password" name="password" /></div>
|
||||
</div>
|
||||
<div class="formbuttons">
|
||||
<input type="submit" value="Login" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
require_once('footer.inc.php');
|
||||
?>
|
115
plex/web/style.css
Normal file
115
plex/web/style.css
Normal file
|
@ -0,0 +1,115 @@
|
|||
body {
|
||||
background-color: #222;
|
||||
height: 90%;
|
||||
font-family: "DejaVuSansCondensed",Helvetica,Arial,sans-serif;
|
||||
font-weight: normal;
|
||||
font-size: 16px;
|
||||
line-height: 1.5em;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
#main {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#maincontainer {
|
||||
min-width: 800px;
|
||||
margin-top: 10%;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
border-radius: 2px;
|
||||
border: 2px solid rgba(0, 0, 0, 0.15);
|
||||
box-shadow: 0px 0px 5px rgba(255, 255, 255, 0.05);
|
||||
-moz-box-sizing: border-box;
|
||||
}
|
||||
|
||||
#maincontainer form {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
#maincontainer input {
|
||||
margin-left: 0px;
|
||||
width: 100%;
|
||||
min-height: 28px;
|
||||
-moz-box-sizing: border-box;
|
||||
border-radius: 7px;
|
||||
height: 32px;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
#maincontainer input:focus {
|
||||
float: none;
|
||||
outline: medium none;
|
||||
border-color: #F1B720;
|
||||
box-shadow: 0px 0px 10px #9ECAED;
|
||||
}
|
||||
|
||||
.configform {
|
||||
width: 500px;
|
||||
margin: 40px auto 20px;
|
||||
}
|
||||
|
||||
.info {
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
color: #8d8d8d;
|
||||
}
|
||||
|
||||
.error {
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
color: #801010;
|
||||
}
|
||||
|
||||
.field {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
font-size: 18px;
|
||||
text-shadow: 0px 1px 0px #000;
|
||||
text-rendering: auto;
|
||||
line-height: 1.5em;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.field_value {
|
||||
|
||||
}
|
||||
|
||||
.formbuttons {
|
||||
text-align: right;
|
||||
margin-top: 30px;
|
||||
float: right !important;
|
||||
}
|
||||
|
||||
.formbuttons input {
|
||||
color: #FFF;
|
||||
border: medium none;
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
#maincontainer input[type=checkbox] {
|
||||
float: left;
|
||||
width: auto;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
#maincontainer input[type=button], input[type=submit] {
|
||||
background-image: -moz-linear-gradient(center top , #FF9D00, #CC6200);
|
||||
background-repeat: repeat-x;
|
||||
position: relative;
|
||||
padding: 5px 12px 4px;
|
||||
font-size: 18px;
|
||||
line-height: normal;
|
||||
border-radius: 2px !important;
|
||||
}
|
||||
|
||||
#maincontainer input[type=button]:hover, input[type=button]:focus, input[type=submit]:hover, input[type=submit]:focus {
|
||||
background-position: 0px -10px;
|
||||
background-color: #CC6200;
|
||||
transition: background-position 0.1s linear 0s;
|
||||
text-shadow: 0px -1px 0px rgba(0, 0, 0, 0.5);
|
||||
text-decoration: none;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue