Ver código fonte

Merge pull request #1422 from causefx/v2-develop

V2 develop
causefx 5 anos atrás
pai
commit
9fa7496a0f

+ 2 - 1
api/config/default.php

@@ -389,5 +389,6 @@ return array(
 	}',
 	}',
 	'githubMenuLink' => true,
 	'githubMenuLink' => true,
 	'organizrSupportMenuLink' => true,
 	'organizrSupportMenuLink' => true,
-	'organizrDocsMenuLink' => true
+	'organizrDocsMenuLink' => true,
+	'organizrSignoutMenuLink' => true
 );
 );

+ 1 - 1
api/functions/api-functions.php

@@ -1288,7 +1288,7 @@ function youtubeSearch($query)
 	if (!$query) {
 	if (!$query) {
 		return 'no query provided!';
 		return 'no query provided!';
 	}
 	}
-	$keys = array('AIzaSyBsdt8nLJRMTwOq5PY5A5GLZ2q7scgn01w', 'AIzaSyD-8SHutB60GCcSM8q_Fle38rJUV7ujd8k', 'AIzaSyBzOpVBT6VII-b-8gWD0MOEosGg4hyhCsQ');
+	$keys = array('AIzaSyBsdt8nLJRMTwOq5PY5A5GLZ2q7scgn01w', 'AIzaSyD-8SHutB60GCcSM8q_Fle38rJUV7ujd8k', 'AIzaSyBzOpVBT6VII-b-8gWD0MOEosGg4hyhCsQ', 'AIzaSyBKnRe1P8fpfBHgooJpmT0WOsrdUtZ4cpk');
 	$randomKeyIndex = array_rand($keys);
 	$randomKeyIndex = array_rand($keys);
 	$key = $keys[$randomKeyIndex];
 	$key = $keys[$randomKeyIndex];
 	$apikey = ($GLOBALS['youtubeAPI'] !== '') ? $GLOBALS['youtubeAPI'] : $key;
 	$apikey = ($GLOBALS['youtubeAPI'] !== '') ? $GLOBALS['youtubeAPI'] : $key;

+ 46 - 14
api/functions/auth-functions.php

@@ -337,32 +337,67 @@ function plugin_auth_emby_local($username, $password)
 	return false;
 	return false;
 }
 }
 
 
+// Pass credentials to JellyFin Backend
+function plugin_auth_jellyfin($username, $password)
+{
+	try {
+		$url = qualifyURL($GLOBALS['embyURL']) . '/Users/authenticatebyname';
+		$headers = array(
+			'X-Emby-Authorization' => 'MediaBrowser Client="Organizr Auth", Device="Organizr", DeviceId="orgv2", Version="2.0"',
+			'Content-Type' => 'application/json',
+		);
+		$data = array(
+			'Username' => $username,
+			'Pw' => $password
+		);
+		$response = Requests::post($url, $headers, json_encode($data));
+		if ($response->success) {
+			$json = json_decode($response->body, true);
+			if (is_array($json) && isset($json['SessionInfo']) && isset($json['User']) && $json['User']['HasPassword'] == true) {
+				writeLog('success', 'JellyFin Auth Function - Found User and Logged In', $username);
+				// Login Success - Now Logout JellyFin Session As We No Longer Need It
+				$headers = array(
+					'X-Emby-Authorization' => 'MediaBrowser Client="Organizr Auth", Device="Organizr", DeviceId="orgv2", Version="2.0", Token="' . $json['AccessToken'] . '"',
+					'Content-Type' => 'application/json',
+				);
+				$response = Requests::post(qualifyURL($GLOBALS['embyURL']) . '/Sessions/Logout', $headers, array());
+				if ($response->success) {
+					return true;
+				}
+			}
+		}
+		return false;
+	} catch (Requests_Exception $e) {
+		writeLog('error', 'JellyFin Auth Function - Error: ' . $e->getMessage(), $username);
+	}
+	return false;
+}
+
 // Authenticate against emby connect
 // Authenticate against emby connect
 function plugin_auth_emby_connect($username, $password)
 function plugin_auth_emby_connect($username, $password)
 {
 {
 	// Emby disabled EmbyConnect on their API
 	// Emby disabled EmbyConnect on their API
 	// https://github.com/MediaBrowser/Emby/issues/3553
 	// https://github.com/MediaBrowser/Emby/issues/3553
-	return plugin_auth_emby_local($username, $password);
-	/*
+	//return plugin_auth_emby_local($username, $password);
 	try {
 	try {
 		// Get A User
 		// Get A User
-		$connectId = '';
+		$connectUserName = '';
 		$url = qualifyURL($GLOBALS['embyURL']) . '/Users?api_key=' . $GLOBALS['embyToken'];
 		$url = qualifyURL($GLOBALS['embyURL']) . '/Users?api_key=' . $GLOBALS['embyToken'];
 		$response = Requests::get($url);
 		$response = Requests::get($url);
 		if ($response->success) {
 		if ($response->success) {
 			$json = json_decode($response->body, true);
 			$json = json_decode($response->body, true);
 			if (is_array($json)) {
 			if (is_array($json)) {
 				foreach ($json as $key => $value) { // Scan for this user
 				foreach ($json as $key => $value) { // Scan for this user
-					if (isset($value['ConnectUserName']) && isset($value['ConnectUserId'])) { // Qualify as connect account
-						if ($value['ConnectUserName'] == $username || $value['Name'] == $username) {
-							$connectId = $value['ConnectUserId'];
+					if (isset($value['ConnectUserName']) && isset($value['ConnectLinkType'])) { // Qualify as connect account
+						if (strtolower($value['ConnectUserName']) == $username || strtolower($value['Name']) == $username) {
+							$connectUserName = $value['ConnectUserName'];
 							writeLog('success', 'Emby Connect Auth Function - Found User', $username);
 							writeLog('success', 'Emby Connect Auth Function - Found User', $username);
 							break;
 							break;
 						}
 						}
 					}
 					}
 				}
 				}
-				if ($connectId) {
-					writeLog('success', 'Emby Connect Auth Function - Attempting to Login with Emby ID: ' . $connectId, $username);
+				if ($connectUserName) {
+					writeLog('success', 'Emby Connect Auth Function - Attempting to Login with Emby ID: ' . $connectUserName, $username);
 					$connectURL = 'https://connect.emby.media/service/user/authenticate';
 					$connectURL = 'https://connect.emby.media/service/user/authenticate';
 					$headers = array(
 					$headers = array(
 						'Accept' => 'application/json',
 						'Accept' => 'application/json',
@@ -375,10 +410,10 @@ function plugin_auth_emby_connect($username, $password)
 					$response = Requests::post($connectURL, $headers, $data);
 					$response = Requests::post($connectURL, $headers, $data);
 					if ($response->success) {
 					if ($response->success) {
 						$json = json_decode($response->body, true);
 						$json = json_decode($response->body, true);
-						if (is_array($json) && isset($json['AccessToken']) && isset($json['User']) && $json['User']['Id'] == $connectId) {
+						if (is_array($json) && isset($json['AccessToken']) && isset($json['User']) && $json['User']['Name'] == $connectUserName) {
 							return array(
 							return array(
 								'email' => $json['User']['Email'],
 								'email' => $json['User']['Email'],
-								'image' => $json['User']['ImageUrl'],
+								//'image' => $json['User']['ImageUrl'],
 							);
 							);
 						} else {
 						} else {
 							writeLog('error', 'Emby Connect Auth Function - Bad Response', $username);
 							writeLog('error', 'Emby Connect Auth Function - Bad Response', $username);
@@ -394,7 +429,6 @@ function plugin_auth_emby_connect($username, $password)
 		writeLog('error', 'Emby Connect Auth Function - Error: ' . $e->getMessage(), $username);
 		writeLog('error', 'Emby Connect Auth Function - Error: ' . $e->getMessage(), $username);
 		return false;
 		return false;
 	}
 	}
-	*/
 }
 }
 
 
 // Authenticate Against Emby Local (first) and Emby Connect
 // Authenticate Against Emby Local (first) and Emby Connect
@@ -403,12 +437,10 @@ function plugin_auth_emby_all($username, $password)
 	// Emby disabled EmbyConnect on their API
 	// Emby disabled EmbyConnect on their API
 	// https://github.com/MediaBrowser/Emby/issues/3553
 	// https://github.com/MediaBrowser/Emby/issues/3553
 	$localResult = plugin_auth_emby_local($username, $password);
 	$localResult = plugin_auth_emby_local($username, $password);
-	return $localResult;
-	/*
+	//return $localResult;
 	if ($localResult) {
 	if ($localResult) {
 		return $localResult;
 		return $localResult;
 	} else {
 	} else {
 		return plugin_auth_emby_connect($username, $password);
 		return plugin_auth_emby_connect($username, $password);
 	}
 	}
-	*/
 }
 }

+ 1 - 1
api/functions/homepage-connect-functions.php

@@ -795,7 +795,7 @@ function embyConnect($action, $key = 'Latest', $skip = false)
 				}
 				}
 				// Get A User
 				// Get A User
 				$userIds = $url . "/Users?api_key=" . $GLOBALS['embyToken'];
 				$userIds = $url . "/Users?api_key=" . $GLOBALS['embyToken'];
-				$showPlayed = true;
+				$showPlayed = false;
 				try {
 				try {
 					$options = (localURL($userIds)) ? array('verify' => false) : array();
 					$options = (localURL($userIds)) ? array('verify' => false) : array();
 					$response = Requests::get($userIds, array(), $options);
 					$response = Requests::get($userIds, array(), $options);

+ 1 - 1
api/functions/homepage-functions.php

@@ -3157,7 +3157,7 @@ function buildHomepageSettings()
 				break;
 				break;
 		}
 		}
 		$homepageList .= '
 		$homepageList .= '
-		<div class="col-md-3 col-xs-12 sort-homepage m-t-10 hvr-grow">
+		<div class="col-md-3 col-xs-12 sort-homepage m-t-10 hvr-grow clearfix">
 			<div class="homepage-drag fc-event ' . $class . ' lazyload"  data-src="' . $image . '">
 			<div class="homepage-drag fc-event ' . $class . ' lazyload"  data-src="' . $image . '">
 				<span class="ordinal-position text-uppercase badge bg-org homepage-number" data-link="' . $key . '" style="float:left;width: 30px;">' . $val . '</span>
 				<span class="ordinal-position text-uppercase badge bg-org homepage-number" data-link="' . $key . '" style="float:left;width: 30px;">' . $val . '</span>
 				<span class="homepage-text">&nbsp; ' . strtoupper(substr($key, 13)) . '</span>
 				<span class="homepage-text">&nbsp; ' . strtoupper(substr($key, 13)) . '</span>

+ 1 - 1
api/functions/netdata-functions.php

@@ -163,7 +163,7 @@ function netdataSettngsArray()
 			            </tr>
 			            </tr>
 			            <tr>
 			            <tr>
 			                <td>mutator</td>
 			                <td>mutator</td>
-			                <td>Used to perform simple mathematical operations on the result (+, -, /, *). For example: dividing the result by 1000 would be "1000". These operations can be chained together by putting them in a comma-seprated format.</td>
+			                <td>Used to perform simple mathematical operations on the result (+, -, /, *). For example: dividing the result by 1000 would be "/1000". These operations can be chained together by putting them in a comma-seprated format.</td>
 			                <td><i class="fa fa-times text-danger" aria-hidden="true"></i></td>
 			                <td><i class="fa fa-times text-danger" aria-hidden="true"></i></td>
 			            </tr>
 			            </tr>
 			            <tr>
 			            <tr>

+ 10 - 12
api/functions/normal-functions.php

@@ -77,7 +77,7 @@ function parseDomain($value, $force = false)
 }
 }
 
 
 // Cookie Custom Function
 // Cookie Custom Function
-function coookie($type, $name, $value = '', $days = -1, $http = true)
+function coookie($type, $name, $value = '', $days = -1, $http = true, $path = '/')
 {
 {
 	$days = ($days > 365) ? 365 : $days;
 	$days = ($days > 365) ? 365 : $days;
 	if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == "https") {
 	if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == "https") {
@@ -93,20 +93,19 @@ function coookie($type, $name, $value = '', $days = -1, $http = true)
 	if (!$http) {
 	if (!$http) {
 		$HTTPOnly = false;
 		$HTTPOnly = false;
 	}
 	}
-	$Path = '/';
 	$Domain = parseDomain($_SERVER['HTTP_HOST']);
 	$Domain = parseDomain($_SERVER['HTTP_HOST']);
 	$DomainTest = parseDomain($_SERVER['HTTP_HOST'], true);
 	$DomainTest = parseDomain($_SERVER['HTTP_HOST'], true);
 	if ($type == 'set') {
 	if ($type == 'set') {
 		$_COOKIE[$name] = $value;
 		$_COOKIE[$name] = $value;
 		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
 		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
 			. (empty($days) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() + (86400 * $days)) . ' GMT')
 			. (empty($days) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() + (86400 * $days)) . ' GMT')
-			. (empty($Path) ? '' : '; path=' . $Path)
+			. (empty($path) ? '' : '; path=' . $path)
 			. (empty($Domain) ? '' : '; domain=' . $Domain)
 			. (empty($Domain) ? '' : '; domain=' . $Domain)
 			. (!$Secure ? '' : '; SameSite=None; Secure')
 			. (!$Secure ? '' : '; SameSite=None; Secure')
 			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
 			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
 		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
 		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
 			. (empty($days) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() + (86400 * $days)) . ' GMT')
 			. (empty($days) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() + (86400 * $days)) . ' GMT')
-			. (empty($Path) ? '' : '; path=' . $Path)
+			. (empty($path) ? '' : '; path=' . $path)
 			. (empty($Domain) ? '' : '; domain=' . $DomainTest)
 			. (empty($Domain) ? '' : '; domain=' . $DomainTest)
 			. (!$Secure ? '' : '; SameSite=None; Secure')
 			. (!$Secure ? '' : '; SameSite=None; Secure')
 			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
 			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
@@ -114,20 +113,20 @@ function coookie($type, $name, $value = '', $days = -1, $http = true)
 		unset($_COOKIE[$name]);
 		unset($_COOKIE[$name]);
 		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
 		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
 			. (empty($days) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() - 3600) . ' GMT')
 			. (empty($days) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() - 3600) . ' GMT')
-			. (empty($Path) ? '' : '; path=' . $Path)
+			. (empty($path) ? '' : '; path=' . $path)
 			. (empty($Domain) ? '' : '; domain=' . $Domain)
 			. (empty($Domain) ? '' : '; domain=' . $Domain)
 			. (!$Secure ? '' : '; SameSite=None; Secure')
 			. (!$Secure ? '' : '; SameSite=None; Secure')
 			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
 			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
 		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
 		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
 			. (empty($days) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() - 3600) . ' GMT')
 			. (empty($days) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() - 3600) . ' GMT')
-			. (empty($Path) ? '' : '; path=' . $Path)
+			. (empty($path) ? '' : '; path=' . $path)
 			. (empty($Domain) ? '' : '; domain=' . $DomainTest)
 			. (empty($Domain) ? '' : '; domain=' . $DomainTest)
 			. (!$Secure ? '' : '; SameSite=None; Secure')
 			. (!$Secure ? '' : '; SameSite=None; Secure')
 			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
 			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
 	}
 	}
 }
 }
 
 
-function coookieSeconds($type, $name, $value = '', $ms, $http = true)
+function coookieSeconds($type, $name, $value = '', $ms, $http = true, $path = '/')
 {
 {
 	if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == "https") {
 	if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == "https") {
 		$Secure = true;
 		$Secure = true;
@@ -142,20 +141,19 @@ function coookieSeconds($type, $name, $value = '', $ms, $http = true)
 	if (!$http) {
 	if (!$http) {
 		$HTTPOnly = false;
 		$HTTPOnly = false;
 	}
 	}
-	$Path = '/';
 	$Domain = parseDomain($_SERVER['HTTP_HOST']);
 	$Domain = parseDomain($_SERVER['HTTP_HOST']);
 	$DomainTest = parseDomain($_SERVER['HTTP_HOST'], true);
 	$DomainTest = parseDomain($_SERVER['HTTP_HOST'], true);
 	if ($type == 'set') {
 	if ($type == 'set') {
 		$_COOKIE[$name] = $value;
 		$_COOKIE[$name] = $value;
 		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
 		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
 			. (empty($ms) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() + ($ms / 1000)) . ' GMT')
 			. (empty($ms) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() + ($ms / 1000)) . ' GMT')
-			. (empty($Path) ? '' : '; path=' . $Path)
+			. (empty($path) ? '' : '; path=' . $path)
 			. (empty($Domain) ? '' : '; domain=' . $Domain)
 			. (empty($Domain) ? '' : '; domain=' . $Domain)
 			. (!$Secure ? '' : '; SameSite=None; Secure')
 			. (!$Secure ? '' : '; SameSite=None; Secure')
 			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
 			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
 		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
 		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
 			. (empty($ms) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() + ($ms / 1000)) . ' GMT')
 			. (empty($ms) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() + ($ms / 1000)) . ' GMT')
-			. (empty($Path) ? '' : '; path=' . $Path)
+			. (empty($path) ? '' : '; path=' . $path)
 			. (empty($Domain) ? '' : '; domain=' . $DomainTest)
 			. (empty($Domain) ? '' : '; domain=' . $DomainTest)
 			. (!$Secure ? '' : '; SameSite=None; Secure')
 			. (!$Secure ? '' : '; SameSite=None; Secure')
 			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
 			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
@@ -163,13 +161,13 @@ function coookieSeconds($type, $name, $value = '', $ms, $http = true)
 		unset($_COOKIE[$name]);
 		unset($_COOKIE[$name]);
 		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
 		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
 			. (empty($ms) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() - 3600) . ' GMT')
 			. (empty($ms) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() - 3600) . ' GMT')
-			. (empty($Path) ? '' : '; path=' . $Path)
+			. (empty($path) ? '' : '; path=' . $path)
 			. (empty($Domain) ? '' : '; domain=' . $Domain)
 			. (empty($Domain) ? '' : '; domain=' . $Domain)
 			. (!$Secure ? '' : '; SameSite=None; Secure')
 			. (!$Secure ? '' : '; SameSite=None; Secure')
 			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
 			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
 		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
 		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
 			. (empty($ms) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() - 3600) . ' GMT')
 			. (empty($ms) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() - 3600) . ' GMT')
-			. (empty($Path) ? '' : '; path=' . $Path)
+			. (empty($path) ? '' : '; path=' . $path)
 			. (empty($Domain) ? '' : '; domain=' . $DomainTest)
 			. (empty($Domain) ? '' : '; domain=' . $DomainTest)
 			. (!$Secure ? '' : '; SameSite=None; Secure')
 			. (!$Secure ? '' : '; SameSite=None; Secure')
 			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
 			. (!$HTTPOnly ? '' : '; HttpOnly'), false);

+ 14 - 6
api/functions/organizr-functions.php

@@ -135,7 +135,8 @@ function organizrSpecialSettings()
 		'menuLink' => array(
 		'menuLink' => array(
 			'githubMenuLink' => $GLOBALS['githubMenuLink'],
 			'githubMenuLink' => $GLOBALS['githubMenuLink'],
 			'organizrSupportMenuLink' => $GLOBALS['organizrSupportMenuLink'],
 			'organizrSupportMenuLink' => $GLOBALS['organizrSupportMenuLink'],
-			'organizrDocsMenuLink' => $GLOBALS['organizrDocsMenuLink']
+			'organizrDocsMenuLink' => $GLOBALS['organizrDocsMenuLink'],
+			'organizrSignoutMenuLink' => $GLOBALS['organizrSignoutMenuLink']
 		)
 		)
 	);
 	);
 }
 }
@@ -165,6 +166,7 @@ function wizardConfig($array)
 		'organizrHash' => $hashKey,
 		'organizrHash' => $hashKey,
 		'organizrAPI' => $api,
 		'organizrAPI' => $api,
 		'registrationPassword' => $registrationPassword,
 		'registrationPassword' => $registrationPassword,
+		'uuid' => gen_uuid()
 	);
 	);
 	// Create Config
 	// Create Config
 	$GLOBALS['dbLocation'] = $location;
 	$GLOBALS['dbLocation'] = $location;
@@ -728,7 +730,7 @@ function getSettingsMain()
 				'type' => 'input',
 				'type' => 'input',
 				'name' => 'embyURL',
 				'name' => 'embyURL',
 				'class' => 'embyAuth switchAuth',
 				'class' => 'embyAuth switchAuth',
-				'label' => 'Emby URL',
+				'label' => 'Emby/Jellyfin URL',
 				'value' => $GLOBALS['embyURL'],
 				'value' => $GLOBALS['embyURL'],
 				'help' => 'Please make sure to use local IP address and port - You also may use local dns name too.',
 				'help' => 'Please make sure to use local IP address and port - You also may use local dns name too.',
 				'placeholder' => 'http(s)://hostname:port'
 				'placeholder' => 'http(s)://hostname:port'
@@ -737,7 +739,7 @@ function getSettingsMain()
 				'type' => 'password-alt',
 				'type' => 'password-alt',
 				'name' => 'embyToken',
 				'name' => 'embyToken',
 				'class' => 'embyAuth switchAuth',
 				'class' => 'embyAuth switchAuth',
-				'label' => 'Emby Token',
+				'label' => 'Emby/Jellyin Token',
 				'value' => $GLOBALS['embyToken'],
 				'value' => $GLOBALS['embyToken'],
 				'placeholder' => ''
 				'placeholder' => ''
 			),
 			),
@@ -1279,6 +1281,12 @@ function getCustomizeAppearance()
 					'label' => 'Show Organizr Docs Link',
 					'label' => 'Show Organizr Docs Link',
 					'value' => $GLOBALS['organizrDocsMenuLink']
 					'value' => $GLOBALS['organizrDocsMenuLink']
 				),
 				),
+				array(
+					'type' => 'switch',
+					'name' => 'organizrSignoutMenuLink',
+					'label' => 'Show Organizr Sign out & in Button on Sidebar',
+					'value' => $GLOBALS['organizrSignoutMenuLink']
+				),
 				array(
 				array(
 					'type' => 'select',
 					'type' => 'select',
 					'name' => 'unsortedTabs',
 					'name' => 'unsortedTabs',
@@ -1793,18 +1801,18 @@ function showLogin()
 
 
 function checkoAuth()
 function checkoAuth()
 {
 {
-	return ($GLOBALS['plexoAuth'] && $GLOBALS['authType'] !== 'internal') ? true : false;
+	return ($GLOBALS['plexoAuth'] && $GLOBALS['authBackend'] == 'plex' && $GLOBALS['authType'] !== 'internal') ? true : false;
 }
 }
 
 
 function checkoAuthOnly()
 function checkoAuthOnly()
 {
 {
-	return ($GLOBALS['plexoAuth'] && $GLOBALS['authType'] == 'external') ? true : false;
+	return ($GLOBALS['plexoAuth'] && $GLOBALS['authBackend'] == 'plex' && $GLOBALS['authType'] == 'external') ? true : false;
 }
 }
 
 
 function showoAuth()
 function showoAuth()
 {
 {
 	$buttons = '';
 	$buttons = '';
-	if ($GLOBALS['plexoAuth'] && $GLOBALS['authType'] !== 'internal') {
+	if ($GLOBALS['plexoAuth'] && $GLOBALS['authBackend'] == 'plex' && $GLOBALS['authType'] !== 'internal') {
 		$buttons .= '<a href="javascript:void(0)" onclick="oAuthStart(\'plex\')" class="btn btn-lg btn-block text-uppercase waves-effect waves-light bg-plex text-muted" data-toggle="tooltip" title="" data-original-title="Login with Plex"> <span>Login</span><i aria-hidden="true" class="mdi mdi-plex m-l-5"></i> </a>';
 		$buttons .= '<a href="javascript:void(0)" onclick="oAuthStart(\'plex\')" class="btn btn-lg btn-block text-uppercase waves-effect waves-light bg-plex text-muted" data-toggle="tooltip" title="" data-original-title="Login with Plex"> <span>Login</span><i aria-hidden="true" class="mdi mdi-plex m-l-5"></i> </a>';
 	}
 	}
 	return ($buttons) ? '
 	return ($buttons) ? '

+ 4 - 1
api/functions/sso-functions.php

@@ -15,7 +15,7 @@ function ssoCheck($username, $password, $token = null)
 		$tautulliToken = getTautulliToken($username, $password, $token);
 		$tautulliToken = getTautulliToken($username, $password, $token);
 		if ($tautulliToken) {
 		if ($tautulliToken) {
 			foreach ($tautulliToken as $key => $value) {
 			foreach ($tautulliToken as $key => $value) {
-				coookie('set', 'tautulli_token_' . $value['uuid'], $value['token'], $GLOBALS['rememberMeDays']);
+				coookie('set', 'tautulli_token_' . $value['uuid'], $value['token'], $GLOBALS['rememberMeDays'], true, $value['path']);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -74,8 +74,11 @@ function getTautulliToken($username, $password, $plexToken = null)
 				$options = (localURL($url)) ? array('verify' => false) : array();
 				$options = (localURL($url)) ? array('verify' => false) : array();
 				$response = Requests::post($url . '/auth/signin', $headers, $data, $options);
 				$response = Requests::post($url . '/auth/signin', $headers, $data, $options);
 				if ($response->success) {
 				if ($response->success) {
+					$qualifiedURL = qualifyURL($url, true);
+					$path = ($qualifiedURL['path']) ? $qualifiedURL['path'] : '/';
 					$token[$key]['token'] = json_decode($response->body, true)['token'];
 					$token[$key]['token'] = json_decode($response->body, true)['token'];
 					$token[$key]['uuid'] = json_decode($response->body, true)['uuid'];
 					$token[$key]['uuid'] = json_decode($response->body, true)['uuid'];
+					$token[$key]['path'] = $path;
 					writeLog('success', 'Tautulli Token Function - Grabbed token from: ' . $url, $username);
 					writeLog('success', 'Tautulli Token Function - Grabbed token from: ' . $url, $username);
 				} else {
 				} else {
 					writeLog('error', 'Tautulli Token Function - Error on URL: ' . $url, $username);
 					writeLog('error', 'Tautulli Token Function - Error on URL: ' . $url, $username);

+ 1 - 1
api/functions/static-globals.php

@@ -1,7 +1,7 @@
 <?php
 <?php
 // ===================================
 // ===================================
 // Organizr Version
 // Organizr Version
-$GLOBALS['installedVersion'] = '2.0.633';
+$GLOBALS['installedVersion'] = '2.0.650';
 // ===================================
 // ===================================
 // Quick php Version check
 // Quick php Version check
 $GLOBALS['minimumPHP'] = '7.1.3';
 $GLOBALS['minimumPHP'] = '7.1.3';

+ 1 - 1
api/pages/settings-tab-editor-homepage-order.php

@@ -3,7 +3,7 @@ if (file_exists('config' . DIRECTORY_SEPARATOR . 'config.php')) {
 	$pageSettingsTabEditorHomepageOrder = '
 	$pageSettingsTabEditorHomepageOrder = '
 <script>
 <script>
     $("#homepage-items-sort").sortable({
     $("#homepage-items-sort").sortable({
-	    placeholder:    "sort-placeholder col-md-3 col-xs-12 clearfix",
+	    placeholder:    "sort-placeholder col-md-3 col-xs-12 m-t-10 clearfix",
 	    forcePlaceholderSize: true,
 	    forcePlaceholderSize: true,
 	    start: function( e, ui ){
 	    start: function( e, ui ){
 	        ui.item.data( "start-pos", ui.item.index()+1 );
 	        ui.item.data( "start-pos", ui.item.index()+1 );

+ 2 - 2
api/pages/settings.php

@@ -8,7 +8,7 @@ if (file_exists('config' . DIRECTORY_SEPARATOR . 'config.php')) {
         sponsorLoad();
         sponsorLoad();
         newsLoad();
         newsLoad();
         checkCommitLoad();
         checkCommitLoad();
-        [].slice.call(document.querySelectorAll(\'.sttabs\')).forEach(function(el) {
+        [].slice.call(document.querySelectorAll(\'.sttabs-main-settings-div\')).forEach(function(el) {
             new CBPFWTabs(el);
             new CBPFWTabs(el);
         });
         });
     })();
     })();
@@ -30,7 +30,7 @@ if (file_exists('config' . DIRECTORY_SEPARATOR . 'config.php')) {
     <div class="row">
     <div class="row">
         <!-- Tab style start -->
         <!-- Tab style start -->
         <section class="">
         <section class="">
-            <div class="sttabs tabs-style-flip">
+            <div class="sttabs sttabs-main-settings-div tabs-style-flip">
                 <nav>
                 <nav>
                     <ul>
                     <ul>
                         <li onclick="changeSettingsMenu(\'Settings::Tab Editor\')" id="settings-main-tab-editor-anchor"><a href="#settings-main-tab-editor" class="sticon ti-layout-tab-v"><span lang="en">Tab Editor</span></a></li>
                         <li onclick="changeSettingsMenu(\'Settings::Tab Editor\')" id="settings-main-tab-editor-anchor"><a href="#settings-main-tab-editor" class="sticon ti-layout-tab-v"><span lang="en">Tab Editor</span></a></li>

+ 13 - 0
css/organizr.css

@@ -4399,3 +4399,16 @@ html {
     right: 20px;
     right: 20px;
     bottom: 20px;
     bottom: 20px;
 }
 }
+.sort-placeholder {
+    background-size: contain;
+    height: 60px;
+    border-radius: 10px;
+    border: 3px dotted whitesmoke;
+    opacity: .5;
+    font-size: 13px;
+    margin: 1px 0 -9px;
+    text-align: left;
+    background: #1f1f1f;
+    padding-right: 0px !important;
+    padding-left: 0px !important;
+}

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
css/organizr.min.css


+ 23 - 17
js/functions.js

@@ -2583,23 +2583,22 @@ function userMenu(user){
 function menuExtras(active){
 function menuExtras(active){
     var supportFrame = buildFrameContainer('Organizr Support','https://organizr.app/support',1);
     var supportFrame = buildFrameContainer('Organizr Support','https://organizr.app/support',1);
     var docsFrame = buildFrameContainer('Organizr Docs','https://docs.organizr.app',1);
     var docsFrame = buildFrameContainer('Organizr Docs','https://docs.organizr.app',1);
-    var adminMenu = (activeInfo.user.groupID <= 1 && activeInfo.settings.menuLink.githubMenuLink) ? buildMenuList('GitHub Repo','https://github.com/causefx/organizr',2,'fontawesome::github') : '';
+    var adminMenu = '<li class="devider"></li>';
+    adminMenu += (activeInfo.user.groupID <= 1 && activeInfo.settings.menuLink.githubMenuLink) ? buildMenuList('GitHub Repo','https://github.com/causefx/organizr',2,'fontawesome::github') : '';
     adminMenu += (activeInfo.user.groupID <= 1 && activeInfo.settings.menuLink.organizrSupportMenuLink) ? buildMenuList('Organizr Support','https://organizr.app/support',1,'fontawesome::life-ring') : '';
     adminMenu += (activeInfo.user.groupID <= 1 && activeInfo.settings.menuLink.organizrSupportMenuLink) ? buildMenuList('Organizr Support','https://organizr.app/support',1,'fontawesome::life-ring') : '';
     adminMenu += (activeInfo.user.groupID <= 1 && activeInfo.settings.menuLink.organizrDocsMenuLink) ? buildMenuList('Organizr Docs','https://docs.organizr.app',1,'simpleline::docs') : '';
     adminMenu += (activeInfo.user.groupID <= 1 && activeInfo.settings.menuLink.organizrDocsMenuLink) ? buildMenuList('Organizr Docs','https://docs.organizr.app',1,'simpleline::docs') : '';
-
     $(supportFrame).appendTo($('.iFrame-listing'));
     $(supportFrame).appendTo($('.iFrame-listing'));
     $(docsFrame).appendTo($('.iFrame-listing'));
     $(docsFrame).appendTo($('.iFrame-listing'));
 	if(active === true){
 	if(active === true){
-		return `
+		return (activeInfo.settings.menuLink.organizrSignoutMenuLink) ? `
 			<li class="devider"></li>
 			<li class="devider"></li>
 			<li id="sign-out"><a class="waves-effect" onclick="logout();"><i class="fa fa-sign-out fa-fw"></i> <span class="hide-menu" lang="en">Logout</span></a></li>
 			<li id="sign-out"><a class="waves-effect" onclick="logout();"><i class="fa fa-sign-out fa-fw"></i> <span class="hide-menu" lang="en">Logout</span></a></li>
-			<li class="devider"></li>
-		`+adminMenu;
+		` + adminMenu : '' + adminMenu;
 	}else{
 	}else{
-		return `
+		return (activeInfo.settings.menuLink.organizrSignoutMenuLink) ? `
 			<li class="devider"></li>
 			<li class="devider"></li>
 			<li id="menu-login"><a class="waves-effect show-login" href="javascript:void(0)"><i class="mdi mdi-login fa-fw"></i> <span class="hide-menu" lang="en">Login/Register</span></a></li>
 			<li id="menu-login"><a class="waves-effect show-login" href="javascript:void(0)"><i class="mdi mdi-login fa-fw"></i> <span class="hide-menu" lang="en">Login/Register</span></a></li>
-		`;
+		` : '';
 	}
 	}
 }
 }
 function categoryProcess(arrayItems){
 function categoryProcess(arrayItems){
@@ -7051,7 +7050,7 @@ var html = `
         <div class="white-box text-white p-0">
         <div class="white-box text-white p-0">
             <!-- Tabstyle start -->
             <!-- Tabstyle start -->
             <section class="">
             <section class="">
-                <div class="sttabs tabs-style-iconbox">
+                <div class="sttabs sttabs-main-weather-health-div tabs-style-iconbox">
                     <nav>
                     <nav>
                         <ul>${healthHeader}</ul>
                         <ul>${healthHeader}</ul>
                     </nav>
                     </nav>
@@ -7065,7 +7064,7 @@ var html = `
     </div>
     </div>
     <script>
     <script>
         (function() {
         (function() {
-            [].slice.call(document.querySelectorAll('.sttabs')).forEach(function(el) {
+            [].slice.call(document.querySelectorAll('.sttabs-main-weather-health-div')).forEach(function(el) {
                 new CBPFWTabs(el);
                 new CBPFWTabs(el);
             });
             });
         })();
         })();
@@ -7093,7 +7092,7 @@ function buildPollutant(array){
         <div class="white-box text-white p-0">
         <div class="white-box text-white p-0">
             <!-- Tabstyle start -->
             <!-- Tabstyle start -->
             <section class="">
             <section class="">
-                <div class="sttabs tabs-style-iconbox">
+                <div class="sttabs sttabs-main-weather-pollutant-div tabs-style-iconbox">
                     <nav>
                     <nav>
                         <ul>${pollutantHeader}</ul>
                         <ul>${pollutantHeader}</ul>
                     </nav>
                     </nav>
@@ -7107,7 +7106,7 @@ function buildPollutant(array){
     </div>
     </div>
     <script>
     <script>
         (function() {
         (function() {
-            [].slice.call(document.querySelectorAll('.sttabs')).forEach(function(el) {
+            [].slice.call(document.querySelectorAll('.sttabs-main-weather-pollutant-div')).forEach(function(el) {
                 new CBPFWTabs(el);
                 new CBPFWTabs(el);
             });
             });
         })();
         })();
@@ -8140,15 +8139,21 @@ function youtubeSearch(searchQuery) {
 function youtubeCheck(title,link){
 function youtubeCheck(title,link){
 	youtubeSearch(title).success(function(data) {
 	youtubeSearch(title).success(function(data) {
         var response = JSON.parse(data);
         var response = JSON.parse(data);
-		inlineLoad();
-		var id = response.data.items["0"].id.videoId;
-		var div = `
+        console.log(data)
+		if(response.data){
+			inlineLoad();
+			var id = response.data.items["0"].id.videoId;
+			var div = `
 		<div id="player-`+link+`" data-plyr-provider="youtube" data-plyr-embed-id="`+id+`"></div>
 		<div id="player-`+link+`" data-plyr-provider="youtube" data-plyr-embed-id="`+id+`"></div>
 		<div class="clearfix"></div>
 		<div class="clearfix"></div>
 		`;
 		`;
-		$('.youtube-div').html(div);
-		$('.'+link).trigger('click');
-		player = new Plyr('#player-'+link);
+			$('.youtube-div').html(div);
+			$('.'+link).trigger('click');
+			player = new Plyr('#player-'+link);
+		}else{
+			messageSingle('API Limit Reached','YouTube API Error',activeInfo.settings.notifications.position,'#FFF','error','5000');
+		}
+
 	}).fail(function(xhr) {
 	}).fail(function(xhr) {
 		console.error("Organizr Function: YouTube Connection Failed");
 		console.error("Organizr Function: YouTube Connection Failed");
 	});
 	});
@@ -8253,6 +8258,7 @@ function changeAuth(){
         case 'emby_local':
         case 'emby_local':
         case 'emby_connect':
         case 'emby_connect':
         case 'emby_all':
         case 'emby_all':
+	    case 'jellyfin':
             $('.switchAuth').parent().parent().parent().hide();
             $('.switchAuth').parent().parent().parent().hide();
             $('.backendAuth').parent().parent().parent().show();
             $('.backendAuth').parent().parent().parent().show();
             $('.embyAuth').parent().parent().parent().show();
             $('.embyAuth').parent().parent().parent().show();

+ 4 - 4
js/news.json

@@ -3,28 +3,28 @@
     "title": "Plex OAuth Patch",
     "title": "Plex OAuth Patch",
     "subTitle": "You server hostname will now be listed on OAuth box",
     "subTitle": "You server hostname will now be listed on OAuth box",
     "date": "2020-06-18 16:30",
     "date": "2020-06-18 16:30",
-    "body": "Plex has now fixed the 3 open CVE's pertaining to the ability for an attacker to phish for an Plex Admins token.  Please follow this link to read more about it.  <a href=\"https:\/\/www.bleepingcomputer.com\/news\/security\/plex-fixes-media-server-bugs-allowing-full-system-takeover\" target=\"_blank\">Plex Vulnerabilities Patched<\/a>",
+    "body": "Plex has now fixed the 3 open CVE's pertaining to the ability for an attacker to phish for an Plex Admins token.  Please follow this link to read more about it.  <a href=\"https:\/\/www.bleepingcomputer.com\/news\/security\/plex-fixes-media-server-bugs-allowing-full-system-takeover\/\" target=\"_blank\" rel=\"noopener noreferrer\">Plex Vulnerabilities Patched<\/a>",
     "author": "CauseFX"
     "author": "CauseFX"
   },
   },
   {
   {
     "title": "Tab Redirect Loops and SameSite Cookie Issues",
     "title": "Tab Redirect Loops and SameSite Cookie Issues",
     "subTitle": "New Browser Restrictions",
     "subTitle": "New Browser Restrictions",
     "date": "2020-04-01 19:30",
     "date": "2020-04-01 19:30",
-    "body": "It seems there are a lot of issues happening with redirect Loops and SameSite cookie issues.  If you are having issues, please read this document.  <a href=\"https:\/\/docs.organizr.app\/books\/troubleshooting\/page\/redirect-looping---samesite-errors\" target=\"_blank\">Organizr SameSite Docs<\/a>",
+    "body": "It seems there are a lot of issues happening with redirect Loops and SameSite cookie issues.  If you are having issues, please read this document.  <a href=\"https:\/\/docs.organizr.app\/books\/troubleshooting\/page\/redirect-looping---samesite-errors\" target=\"_blank\" rel=\"noopener noreferrer\">Organizr SameSite Docs<\/a>",
     "author": "CauseFX"
     "author": "CauseFX"
   },
   },
   {
   {
     "title": "Plex Oauth Issues - RESOLVED!",
     "title": "Plex Oauth Issues - RESOLVED!",
     "subTitle": "Let's make them bring back support correctly",
     "subTitle": "Let's make them bring back support correctly",
     "date": "2019-07-17 15:20",
     "date": "2019-07-17 15:20",
-    "body": "It seems like Plex has broken support for us using Oauth.  Currently there is a workaround but we would rather they fix the issue.  Please share your feedback in this thread: <a href=\"https:\/\/forums.plex.tv\/t\/plex-oauth-not-working-with-tautulli-ombi-etc\/433945\" target=\"_blank\">Plex Oauth Discussion<\/a>",
+    "body": "It seems like Plex has broken support for us using Oauth.  Currently there is a workaround but we would rather they fix the issue.  Please share your feedback in this thread: <a href=\"https:\/\/forums.plex.tv\/t\/plex-oauth-not-working-with-tautulli-ombi-etc\/433945\" target=\"_blank\" rel=\"noopener noreferrer\">Plex Oauth Discussion<\/a>",
     "author": "CauseFX"
     "author": "CauseFX"
   },
   },
   {
   {
     "title": "Emby Discontinued Support",
     "title": "Emby Discontinued Support",
     "subTitle": "Emby API - EmbyConnect Deprecated",
     "subTitle": "Emby API - EmbyConnect Deprecated",
     "date": "2019-05-14 19:15",
     "date": "2019-05-14 19:15",
-    "body": "Emby has discontinued support for matching users against Emby Connect via API.  Therefore, we will no longer be supporting this method of Authentication for Organizr.  If Emby decides to support this again, I will re-enable it once more.  You can find more information here: <a href=\"https:\/\/github.com\/MediaBrowser\/Emby\/issues\/3553\" target=\"_blank\">Emby API Discussion<\/a>",
+    "body": "Emby has discontinued support for matching users against Emby Connect via API.  Therefore, we will no longer be supporting this method of Authentication for Organizr.  If Emby decides to support this again, I will re-enable it once more.  You can find more information here: <a href=\"https:\/\/github.com\/MediaBrowser\/Emby\/issues\/3553\" target=\"_blank\" rel=\"noopener noreferrer\">Emby API Discussion<\/a>",
     "author": "CauseFX"
     "author": "CauseFX"
   },
   },
   {
   {

+ 7 - 0
js/version.json

@@ -264,5 +264,12 @@
     "new": "",
     "new": "",
     "fixed": "Fix heredoc error on php versions under 7.3",
     "fixed": "Fix heredoc error on php versions under 7.3",
     "notes": "Please report bugs in GitHub issues page"
     "notes": "Please report bugs in GitHub issues page"
+  },
+  "2.0.650": {
+    "date": "2020-07-03 20:55",
+    "title": "Weekly Updates",
+    "new": "Added Jellyfin Auth function to log into Organizr|Re-Enable EmbyConnect backend option|Option to disable logout/login button on sidebar",
+    "fixed": "Plex oAuth login enabled after switching to a different backend (#1416)|losing access to settings (#1418)|Youtube Error catch and added another API Key(#1419)|Update coookie function to include path|Update Tautulli cookie to include path|News.json fixes|homepage sort issue on right side|add uuid on wizard path",
+    "notes": "Please report bugs in GitHub issues page"
   }
   }
 }
 }

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff