Procházet zdrojové kódy

Merge pull request #519 from causefx/develop

Develop
causefx před 8 roky
rodič
revize
45ed642fb1
26 změnil soubory, kde provedl 1749 přidání a 746 odebrání
  1. 15 3
      ajax.php
  2. 5 5
      auth.php
  3. 0 0
      bower_components/bootstrap/dist/css/bootstrap.min.css
  4. 1 1
      chat.php
  5. 8 7
      check.php
  6. 5 0
      config/configDefaults.php
  7. 4 4
      css/style.css
  8. 0 7
      error.php
  9. 747 159
      functions.php
  10. 413 159
      homepage.php
  11. binární
      images/ellipsis.png
  12. binární
      images/guacamole.png
  13. binární
      images/livetv.png
  14. binární
      images/pf-blue.png
  15. binární
      images/pfsense.png
  16. 24 16
      index.php
  17. 0 3
      js/custom.js
  18. 55 27
      lang/de.ini
  19. 31 3
      lang/en.ini
  20. 31 3
      lang/es.ini
  21. 31 3
      lang/fr.ini
  22. 31 3
      lang/it.ini
  23. 31 3
      lang/nl.ini
  24. 31 3
      lang/pl.ini
  25. 245 18
      settings.php
  26. 41 319
      user.php

+ 15 - 3
ajax.php

@@ -67,6 +67,12 @@ switch ($_SERVER['REQUEST_METHOD']) {
 				echo nzbgetConnect($_GET['list'] ? $_GET['list'] : die('Error!'));
 				die();
 				break;
+			case 'show-image':
+				qualifyUser(NZBGETHOMEAUTH, true);
+				header('Content-type: image/jpeg');
+				echo file_get_contents($_GET['image']);
+				die();
+				break;
 			default:
 				sendNotification(false, 'Unsupported Action!');
 		}
@@ -74,7 +80,10 @@ switch ($_SERVER['REQUEST_METHOD']) {
 	case 'POST':
         // Check if the user is an admin and is allowed to commit values
         switch ($action) {
-            case 'search-plex':
+            case 'tvdb-get':
+			 	$response = tvdbGet($_POST['id']);
+			 	break;
+			case 'search-plex':
 			 	$response = searchPlex($_POST['searchtitle']);
 			 	break;
 			case 'validate-invite':
@@ -96,11 +105,14 @@ switch ($_SERVER['REQUEST_METHOD']) {
             default: // Stuff that you need admin for
                 qualifyUser('admin', true);
                 switch ($action) {
-                    case 'check-url':
+                    case 'test-email':
+                        sendResult(sendTestEmail($_POST['emailto'], $_POST['emailsenderemail'], $_POST['emailhost'], $_POST['emailauth'], $_POST['emailusername'], $_POST['emailpassword'], $_POST['emailtype'], $_POST['emailport'], $_POST['emailsendername']), "flask", "E-Mail TEST", "SUCCESS", "ERROR");
+                        break;
+					case 'check-url':
                         sendResult(frameTest($_POST['checkurl']), "flask", $_POST['checkurl'], "IFRAME_CAN_BE_FRAMED", "IFRAME_CANNOT_BE_FRAMED");
                         break;
                     case 'upload-images':
-                        uploadFiles('images/', array('jpg', 'png', 'svg', 'jpeg', 'bmp'));
+                        uploadFiles('images/', array('jpg', 'png', 'svg', 'jpeg', 'bmp', 'gif'));
                         sendNotification(true);
                         break;
                     case 'remove-images':

+ 5 - 5
auth.php

@@ -16,16 +16,16 @@ if ($whitelist) {
 }
 if (isset($_GET['admin'])) {
     if($USER->authenticated && $USER->role == "admin" && !in_array(strtoupper($USER->username), getBannedUsers($ban))) {
-        !$debug ? exit(http_response_code(200)) : die("$USER->username Authorized At Admin Level");
+        !$debug ? exit(http_response_code(200)) : die("$USER->username on $currentIP Authorized At Admin Level");
 	} else {
-        !$debug ? exit(http_response_code(401)) : die("$USER->username Not Authorized At Admin Level");
+        !$debug ? exit(http_response_code(401)) : die("$USER->username on $currentIP Not Authorized At Admin Level");
     }
 }
 if (isset($_GET['user'])) {
     if($USER->authenticated && !in_array(strtoupper($USER->username), getBannedUsers($ban))) {
-        !$debug ? exit(http_response_code(200)) : die("$USER->username Authorized At User Level");
+        !$debug ? exit(http_response_code(200)) : die("$USER->username on $currentIP Authorized At User Level");
 	} else {
-        !$debug ? exit(http_response_code(401)) : die("$USER->username Not Authorized At User Level");
+        !$debug ? exit(http_response_code(401)) : die("$USER->username on $currentIP Not Authorized At User Level");
 	}
 }
 if (!isset($_GET['user']) && !isset($_GET['admin']) && !isset($_GET['whitelist'])) {
@@ -33,7 +33,7 @@ if (!isset($_GET['user']) && !isset($_GET['admin']) && !isset($_GET['whitelist']
 }
 
 if ($skipped) {
-	!$debug ? exit(http_response_code(401)) : die("$USER->username on $currentIP $skipped Not Authorized Nor On Whitelist");
+	!$debug ? exit(http_response_code(401)) : die("$USER->username on $currentIP Not Authorized Nor On Whitelist");
 }
 
 ?>

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 0
bower_components/bootstrap/dist/css/bootstrap.min.css


+ 1 - 1
chat.php

@@ -136,7 +136,7 @@ endif;
                 echo '<h3 class="panel-title">SQLITE3</h3>';
                 echo '</div>';
                 echo '<div style="color: gray" class="panel-body">';
-                echo 'SQLITE3 is NOT loaded!  Please install it before proceeding';
+				echo getError(getOS(),'sqlite3');
 
                 echo '</div></div></div>';
                 die();

+ 8 - 7
check.php

@@ -1,6 +1,9 @@
 <?php
-
-require_once("user.php");
+if (file_exists('config/config.php')) {
+    require_once("user.php");
+    $db = DATABASE_LOCATION.'users.db';
+    $folder = USER_HOME;
+}
 
 function check($extension) {
     
@@ -25,7 +28,7 @@ function check($extension) {
         
         if($extension == "PDO_SQLITE") :
             
-            echo '<br/> If you are on Windows, please uncomment this line in php.ini: ;extension=php_pdo_sqlite.dll';
+            echo '<br/> If you are on Windows, please uncomment this line in php.ini: ;extension=php_pdo_sqlite.dll<br/>If you are on Ununtu, please install php5.3-sqlite or php7-sqlite depending on your version of PHP, then restart PHP service';
         
         endif;
     
@@ -116,9 +119,6 @@ function getFilePermission($file) {
     endif;
 }
 
-$db = DATABASE_LOCATION.'users.db';
-$folder = USER_HOME;
-
 ?>
 
 <!DOCTYPE html>
@@ -164,10 +164,11 @@ $folder = USER_HOME;
                 check("PDO");
                 check("SQLITE3");
                 check("Zip");
+                check("cURL");
                 check("openssl");
                 check("session");
                 check("simplexml");
-                checkFunction("MAIL");
+                //checkFunction("MAIL");
                 checkFunction("fopen");
 
                 @getFilePermission($db);

+ 5 - 0
config/configDefaults.php

@@ -13,6 +13,7 @@ return array(
 	"plexHomeAuth" => false,
 	"plexSearch" => false,
 	"plexRecentItems" => "20",
+	"plexPlaylists" => "false",
 	"plexTabName" => "",
 	"embyURL" => "",
 	"embyToken" => "",
@@ -85,4 +86,8 @@ return array(
 	"homepageNoticeType" => "success",
 	"homepageNoticeAuth" => "false",
 	"homepageNoticeLayout" => "elegant",
+	"ipInfoToken" => "ddd0c072ad5021",
+	"historyRefresh" => "120000",
+	"downloadRefresh" => "30000",
+	"organizrAPI" => "",
 );

+ 4 - 4
css/style.css

@@ -3763,8 +3763,8 @@ ul.inbox-pagination li {
 .ns-effect-exploader.ns-show {
   -webkit-animation-name: animLoad;
           animation-name: animLoad;
-  -webkit-animation-duration: 2.5s;
-          animation-duration: 2.5s;
+  -webkit-animation-duration: 1.0s;
+          animation-duration: 1.0s;
 }
 
 @-webkit-keyframes animLoad {
@@ -3836,8 +3836,8 @@ ul.inbox-pagination li {
 
 .ns-effect-exploader.ns-show .ns-box-inner,
 .ns-effect-exploader.ns-show .ns-close {
-  -webkit-animation-delay: 2.4s;
-          animation-delay: 2.4s;
+  -webkit-animation-delay: .9s;
+          animation-delay: .9s;
   -webkit-animation-duration: 0.3s;
           animation-duration: 0.3s;
   -webkit-animation-fill-mode: both;

+ 0 - 7
error.php

@@ -20,19 +20,12 @@ $file_db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 ini_set("display_errors", 1);
 ini_set("error_reporting", E_ALL | E_STRICT);
 
-// Load User List
-$gotUsers = $file_db->query('SELECT * FROM users');
-
-// Load Colours/Appearance
 foreach(loadAppearance() as $key => $value) {
 	$$key = $value;
 }
 
-
 $requested = (isset($_SERVER['HTTPS']) ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
-
 $status = (isset($_GET['error'])?$_GET['error']:404);
-
 $codes = array(  
        400 => array('Bad Request', 'The server cannot or will not process the request due to an apparent client error.', 'sowwy'),
        401 => array('Unauthorized', 'You do not have access to this page.', 'sowwy'),

+ 747 - 159
functions.php

@@ -2,13 +2,15 @@
 
 // ===================================
 // Define Version
- define('INSTALLEDVERSION', '1.40');
+ define('INSTALLEDVERSION', '1.42');
 // ===================================
 
 // Debugging output functions
 function debug_out($variable, $die = false) {
 	$trace = debug_backtrace()[0];
-	echo '<pre style="background-color: #f2f2f2; border: 2px solid black; border-radius: 5px; padding: 5px; margin: 5px;">'.$trace['file'].':'.$trace['line']."\n\n".print_r($variable, true).'</pre>';
+	echo "<center><img height='200px' src='images/confused.png'></center>";
+	echo "<center>Look's like something happened, here are the errors and perhaps how to fix them:</center>";
+	echo '<pre style="white-space: pre-line; background-color: #f2f2f2; border: 2px solid black; border-radius: 5px; padding: 5px; margin: 5px;">'.$trace['file'].':'.$trace['line']."\n\n".print_r($variable, true).'</pre>';
 	if ($die) { http_response_code(503); die(); }
 }
 
@@ -225,7 +227,7 @@ if (function_exists('curl_version')) :
 					}
 				}
 			}else{
-				writeLog("error", "$username is not an authorized user or entered invalid password");
+				writeLog("error", "$username is not an authorized PLEX user or entered invalid password");
 			}
 		}else{
   			writeLog("error", "error occured logging into plex might want to check curl.cainfo=/path/to/downloaded/cacert.pem in php.ini");   
@@ -640,7 +642,7 @@ function resolveEmbyItem($address, $token, $item, $nowPlaying = false, $showName
 		$itemDetails['Overview'] = '';
 	}
     
-if (file_exists('images/cache/'.$key.'.jpg')){ $image_url = 'images/cache/'.$key.'.jpg'; }
+	if (file_exists('images/cache/'.$key.'.jpg')){ $image_url = 'images/cache/'.$key.'.jpg'; }
     if (file_exists('images/cache/'.$key.'.jpg') && (time() - 604800) > filemtime('images/cache/'.$key.'.jpg') || !file_exists('images/cache/'.$key.'.jpg')) {
         $image_url = 'ajax.php?a=emby-image&type='.$imageType.'&img='.$imageId.'&height='.$height.'&width='.$width.'&key='.$key.'';        
     }
@@ -655,12 +657,12 @@ if (file_exists('images/cache/'.$key.'.jpg')){ $image_url = 'images/cache/'.$key
     if(isset($useImage)){ $image_url = $useImage; }
 	
 	// Assemble Item And Cache Into Array     
-if($nowPlaying){
-    //prettyPrint($itemDetails);
-    return '<div class="col-sm-6 col-md-3"><div class="thumbnail ultra-widget"><div style="display: none;" np="'.$id.'" class="overlay content-box small-box gray-bg">'.$streamInfo.'</div><span class="w-refresh w-p-icon gray" link="'.$id.'"><span class="fa-stack fa-lg" style="font-size: .5em"><i class="fa fa-square fa-stack-2x"></i><i class="fa fa-info-circle fa-stack-1x fa-inverse"></i></span></span><a href="'.$URL.'" target="_blank"><img style="width: 500px; display:inherit;" src="'.$image_url.'" alt="'.$itemDetails['Name'].'"></a><div class="progress progress-bar-sm zero-m"><div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="'.$watched.'" aria-valuemin="0" aria-valuemax="100" style="width: '.$watched.'%"></div><div class="progress-bar palette-Grey-500 bg" style="width: 0%"></div></div><div class="caption"><i style="float:left" class="fa fa-'.$state.'"></i>'.$topTitle.''.$bottomTitle.'</div></div></div>';
+	if($nowPlaying){
+    	//prettyPrint($itemDetails);
+    	return '<div class="col-sm-6 col-md-3"><div class="thumbnail ultra-widget"><div style="display: none;" np="'.$id.'" class="overlay content-box small-box gray-bg">'.$streamInfo.'</div><span class="w-refresh w-p-icon gray" link="'.$id.'"><span class="fa-stack fa-lg" style="font-size: .5em"><i class="fa fa-square fa-stack-2x"></i><i class="fa fa-info-circle fa-stack-1x fa-inverse"></i></span></span><a href="'.$URL.'" target="_blank"><img style="width: 500px; display:inherit;" src="'.$image_url.'" alt="'.$itemDetails['Name'].'"></a><div class="progress progress-bar-sm zero-m"><div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="'.$watched.'" aria-valuemin="0" aria-valuemax="100" style="width: '.$watched.'%"></div><div class="progress-bar palette-Grey-500 bg" style="width: 0%"></div></div><div class="caption"><i style="float:left" class="fa fa-'.$state.'"></i>'.$topTitle.''.$bottomTitle.'</div></div></div>';
     }else{
- return '<div class="item-'.$itemDetails['Type'].'"><a href="'.$URL.'" target="_blank"><img alt="'.$itemDetails['Name'].'" class="'.$image.'" data-lazy="'.$image_url.'"></a><small style="margin-right: 13px" class="elip">'.$title.'</small></div>';
-}
+		 return '<div class="item-'.$itemDetails['Type'].'"><a href="'.$URL.'" target="_blank"><img alt="'.$itemDetails['Name'].'" class="'.$image.'" data-lazy="'.$image_url.'"></a><small style="margin-right: 13px" class="elip">'.$title.'</small></div>';
+	}
 }
 
 // Format item from Plex for Carousel
@@ -707,7 +709,7 @@ function resolvePlexItem($server, $token, $item, $nowPlaying = false, $showNames
             $image = 'slick-image-tall';
             $style = '';
             if(!$nowPlaying){ 
-                $thumb = $item['parentThumb'];
+                $thumb = ($item['parentThumb'] ? $item['parentThumb'] : $item['grandparentThumb']);
                 $key = $item['ratingKey'] . "-list";
             }else { 
                 $height = 281;
@@ -731,7 +733,7 @@ function resolvePlexItem($server, $token, $item, $nowPlaying = false, $showNames
                 $state = (($item->Player['state'] == "paused") ? "pause" : "play");
                 $topTitle = '<h5 class="text-center zero-m elip">'.$title.' - '.$item['title'].'</h5>';
                 $bottomTitle = '<small class="zero-m">S'.$item['parentIndex'].' · E'.$item['index'].'</small>';
-                if($showNames == "true"){ $bottomTitle .= '</small><small class="zero-m pull-right">'.$user.'</small>'; }
+                if($showNames == "true"){ $bottomTitle .= '<small class="zero-m pull-right">'.$user.'</small>'; }
             }
             break;
         case 'clip':
@@ -747,7 +749,8 @@ function resolvePlexItem($server, $token, $item, $nowPlaying = false, $showNames
                 $height = 281;
                 $width = 500;
                 $thumb = $item['art'];
-                $key = $item['ratingKey'] . "-np";
+                $key = isset($item['ratingKey']) ? $item['ratingKey'] . "-np" : (isset($item['live']) ? "livetv.png" : ":)");
+				$useImage = (isset($item['live']) ? "images/livetv.png" : null);
 				$extraInfo = isset($item['extraType']) ? "Trailer" : (isset($item['live']) ? "Live TV" : ":)");
                 $elapsed = $item['viewOffset'];
                 $duration = $item['duration'];
@@ -839,7 +842,7 @@ function resolvePlexItem($server, $token, $item, $nowPlaying = false, $showNames
             }
 		}
 	
-		if (substr_count(PLEXURL, ':') == 2) {
+		if (substr_count(PLEXURL, '.') != 2) {
 			$address = "https://app.plex.tv/web/app#!/server/$server/details?key=/library/metadata/".$item['ratingKey'];
 		}else{
 			$address = PLEXURL."/web/index.html#!/server/$server/details?key=/library/metadata/".$item['ratingKey'];
@@ -852,7 +855,12 @@ function resolvePlexItem($server, $token, $item, $nowPlaying = false, $showNames
     if (file_exists('images/cache/'.$key.'.jpg') && (time() - 604800) > filemtime('images/cache/'.$key.'.jpg') || !file_exists('images/cache/'.$key.'.jpg')) {
         $image_url = 'ajax.php?a=plex-image&img='.$thumb.'&height='.$height.'&width='.$width.'&key='.$key.'';        
     }
-    if(!$thumb){ $image_url = "images/no-np.png"; $key = "no-np"; }
+    if($nowPlaying){
+        if(!$thumb){ $image_url = "images/no-np.png"; $key = "no-np"; }
+    }else{
+        if(!$thumb){ $image_url = "images/no-list.png"; $key = "no-list"; }
+    }
+	if(isset($useImage)){ $image_url = $useImage; }
 	$openTab = (PLEXTABNAME) ? "true" : "false";
     // Assemble Item And Cache Into Array 
     if($nowPlaying){
@@ -864,22 +872,23 @@ function resolvePlexItem($server, $token, $item, $nowPlaying = false, $showNames
 
 //Recent Added
 function outputRecentAdded($header, $items, $script = false, $array) {
-    $hideMenu = '<div class="pull-right"><div class="btn-group" role="group"><button type="button" class="btn waves btn-default btn-sm dropdown-toggle waves-effect waves-float" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Filter<span class="caret"></span></button><ul style="right:0; left: auto" class="dropdown-menu">';
+    $hideMenu = '<div class="pull-right"><div class="btn-group" role="group"><button type="button" class="btn waves btn-default btn-sm dropdown-toggle waves-effect waves-float" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Filter<span class="caret"></span></button><ul style="right:0; left: auto" class="dropdown-menu filter-recent-event">';
     if($array["movie"] == "true"){
-        $hideMenu .= '<li><a class="js-filter-movie" href="javascript:void(0)">Hide Movies</a></li>';
+        $hideMenu .= '<li data-filter="item-movie" data-filter-on="false"><a class="js-filter-movie" href="javascript:void(0)">Movies</a></li>';
     }
     if($array["season"] == "true"){
-        $hideMenu .= '<li><a class="js-filter-season" href="javascript:void(0)">Hide Show</a></li>';
+        $hideMenu .= '<li data-filter="item-season" data-filter-on="false"><a class="js-filter-season" href="javascript:void(0)">Shows</a></li>';
     }
     if($array["album"] == "true"){
-        $hideMenu .= '<li><a class="js-filter-album" href="javascript:void(0)">Hide Music</a></li>';
+        $hideMenu .= '<li data-filter="item-album" data-filter-on="false"><a class="js-filter-album" href="javascript:void(0)">Music</a></li>';
     }
     $hideMenu .= '</ul></div></div>';
     // If None Populate Empty Item
     if (!count($items)) {
-        return '<div id=recentMedia><h5 class="text-center">'.$header.'</h5><p class="text-center">No Media Found</p></div>';
+        return '<div id="recentMedia" class="content-box box-shadow big-box"><h5 class="text-center">'.$header.'</h5><p class="text-center">No Media Found</p></div>';
     }else{
-        return '<div id=recentMedia><h5 style="margin-bottom: -20px" class="text-center">'.$header.'</h5><div class="recentHeader inbox-pagination">'.$hideMenu.'</div><br/><div class="recentItems">'.implode('',$items).'</div></div>'.($script?'<script>'.$script.'</script>':'');
+		$className = str_replace(' ', '', $header);
+        return '<div id="recentMedia" class="content-box box-shadow big-box"><h5 style="margin-bottom: -20px" class="text-center">'.$header.'</h5><div class="recentHeader inbox-pagination '.$className.'">'.$hideMenu.'</div><br/><div class="recentItems" data-name="'.$className.'">'.implode('',$items).'</div></div>'.($script?'<script>'.$script.'</script>':'');
     }
     
 }
@@ -890,7 +899,7 @@ function outputNowPlaying($header, $size, $type, $items, $script = false) {
 	if (!count($items)) {
 		return '<div id=streamz></div>'.($script?'<script>'.$script.'</script>':'');
 	}else{
-	   return '<div id=streamz><h5 class="text-center">'.$header.'</h5>'.implode('',$items).'</div>'.($script?'<script>'.$script.'</script>':'');
+	   return '<div id=streamz><h5 class="zero-m big-box"><strong>'.$header.'</strong></h5>'.implode('',$items).'</div>'.($script?'<script>'.$script.'</script>':'');
  }
     
 }
@@ -928,27 +937,35 @@ function getPlexStreams($size, $showNames, $role){
 	// Perform API requests
     $api = @curl_get($address."/status/sessions?X-Plex-Token=".PLEXTOKEN);
     $api = simplexml_load_string($api);
-    $getServer = simplexml_load_string(@curl_get($address."/?X-Plex-Token=".PLEXTOKEN));
-    if (!$getServer) { return 'Could not load!'; }
-	
-	// Identify the local machine
-    $gotServer = $getServer['machineIdentifier'];
-	
-	$items = array();
-	foreach($api AS $child) {
-		$items[] = resolvePlexItem($gotServer, PLEXTOKEN, $child, true, $showNames, $role);
+	if (is_array($api) || is_object($api)){
+		if (!$api->head->title){
+			$getServer = simplexml_load_string(@curl_get($address."/?X-Plex-Token=".PLEXTOKEN));
+			if (!$getServer) { return 'Could not load!'; }
+
+			// Identify the local machine
+			$gotServer = $getServer['machineIdentifier'];
+
+			$items = array();
+			foreach($api AS $child) {
+				$items[] = resolvePlexItem($gotServer, PLEXTOKEN, $child, true, $showNames, $role);
+			}
+
+			return outputNowPlaying(translate('PLAYING_NOW_ON_PLEX')." ( ".count($items)." Streams )", $size, 'streams-plex', $items, "
+				setInterval(function() {
+					$('<div></div>').load('ajax.php?a=plex-streams',function() {
+						var element = $(this).find('[id]');
+						var loadedID = 	element.attr('id');
+						$('#'+loadedID).replaceWith(element);
+						console.log('Loaded updated: '+loadedID);
+					});
+				}, 15000);
+			");
+		}else{
+			writeLog("error", "PLEX STREAM ERROR: could not connect - check token - if HTTPS, is cert valid");
+		}
+	}else{
+		writeLog("error", "PLEX STREAM ERROR: could not connect - check URL - if HTTPS, is cert valid");
 	}
-	
-	return outputNowPlaying(translate('PLAYING_NOW_ON_PLEX'), $size, 'streams-plex', $items, "
-		setInterval(function() {
-			$('<div></div>').load('ajax.php?a=plex-streams',function() {
-				var element = $(this).find('[id]');
-				var loadedID = 	element.attr('id');
-				$('#'+loadedID).replaceWith(element);
-				console.log('Loaded updated: '+loadedID);
-			});
-		}, 15000);
-	");
 }
 
 // Get Recent Content From Emby
@@ -1008,21 +1025,29 @@ function getPlexRecent($array){
 	// Perform Requests
     $api = @curl_get($address."/library/recentlyAdded?limit=".PLEXRECENTITEMS."&X-Plex-Token=".PLEXTOKEN);
     $api = simplexml_load_string($api);
-    $getServer = simplexml_load_string(@curl_get($address."/?X-Plex-Token=".PLEXTOKEN));
-	if (!$getServer) { return 'Could not load!'; }
-	
-	// Identify the local machine
-    $gotServer = $getServer['machineIdentifier'];
-	
-	$items = array();
-	foreach($api AS $child) {
-     $type = (string) $child['type'];
-		if($array[$type] == "true"){
-			$items[] = resolvePlexItem($gotServer, PLEXTOKEN, $child, false, false, false);
+	if (is_array($api) || is_object($api)){
+		if (!$api->head->title){
+			$getServer = simplexml_load_string(@curl_get($address."/?X-Plex-Token=".PLEXTOKEN));
+			if (!$getServer) { return 'Could not load!'; }
+
+			// Identify the local machine
+			$gotServer = $getServer['machineIdentifier'];
+
+			$items = array();
+			foreach($api AS $child) {
+			 $type = (string) $child['type'];
+				if($array[$type] == "true"){
+					$items[] = resolvePlexItem($gotServer, PLEXTOKEN, $child, false, false, false);
+				}
+			}
+
+			return outputRecentAdded($header, $items, "", $array);
+		}else{
+			writeLog("error", "PLEX STREAM ERROR: could not connect - check token - if HTTPS, is cert valid");
 		}
+	}else{
+		writeLog("error", "PLEX STREAM ERROR: could not connect - check URL - if HTTPS, is cert valid");
 	}
-	
-	return outputRecentAdded($header, $items, "", $array);
 }
 
 // Get Image From Emby
@@ -1044,7 +1069,7 @@ function getEmbyImage() {
     $cachefile = 'images/cache/'.$key.'.jpg';
     $cachetime = 604800;
     // Serve from the cache if it is younger than $cachetime
-    if (file_exists($cachefile) && time() - $cachetime > filemtime($cachefile)) {
+    if (file_exists($cachefile) && time() - $cachetime < filemtime($cachefile)) {
         header("Content-type: image/jpeg");
         @readfile($cachefile);
         exit;
@@ -1080,7 +1105,7 @@ function getPlexImage() {
         $cachefile = 'images/cache/'.$key.'.jpg';
         $cachetime = 604800;
         // Serve from the cache if it is younger than $cachetime
-        if (file_exists($cachefile) && time() - $cachetime > filemtime($cachefile)) {
+        if (file_exists($cachefile) && time() - $cachetime < filemtime($cachefile)) {
             header("Content-type: image/jpeg");
             @readfile($cachefile);
             exit;
@@ -1423,13 +1448,53 @@ function upgradeCheck() {
 	return true;
 }
 
+// Get OS from server
+function getOS(){
+	if(PHP_SHLIB_SUFFIX == "dll"){
+		return "win";
+	}else{
+		return "nix";
+	}
+}
+
+//Get Error by Server OS
+function getError($os, $error){
+	$ini = (!empty(php_ini_loaded_file()) ? php_ini_loaded_file() : "php.ini");
+	$ext = (!empty(ini_get('extension_dir')) ? "uncomment ;extension_dir = and make sure it says -> extension_dir = '".ini_get('extension_dir')."'" : "uncomment ;extension_dir = and add path to 'ext' to make it like extension_dir = 'C:\nginx\php\ext'");
+	$errors = array(
+		'pdo_sqlite' => array(
+			'win' => '<b>PDO:SQLite</b> not enabled, uncomment ;extension=php_pdo_sqlite.dll in the file php.ini | '.$ext,
+			'nix' => '<b>PDO:SQLite</b> not enabled, PHP7 -> run sudo apt-get install php7.0-sqlite | PHP5 -> run sudo apt-get install php5-sqlite',
+		),
+		'sqlite3' => array(
+			'win' => '<b>SQLite3</b> not enabled, uncomment ;extension=php_sqlite3.dll in the file php.ini | uncomment ;sqlite3.extension_dir = and add "ext" to make it sqlite3.extension_dir = ext',
+			'nix' => '<b>SQLite3</b> not enabled, run sudo apt-get install php-sqlite3',
+		),
+		'curl' => array(
+			'win' => '<b>cURL</b> not enabled, uncomment ;extension=php_curl.dll in the file php.ini | '.$ext,
+			'nix' => '<b>cURL</b> not enabled, PHP7 -> sudo apt-get install php-curl | PHP5 -> run sudo apt-get install php5.6-curl',
+		),
+		'zip' => array(
+			'win' => '<b>PHP Zip</b> not enabled, uncomment ;extension=php_zip.dll in the file php.ini, if that doesn\'t work remove that line',
+			'nix' => '<b>PHP Zip</b> not enabled, PHP7 -> run sudo apt-get install php7.0-zip | PHP5 -> run sudo apt-get install php5.6-zip',
+		),
+		
+	);
+	return (isset($errors[$error][$os]) ? $errors[$error][$os] : 'No Error Info Found');
+}
+
 // Check if all software dependancies are met
 function dependCheck() {
 	$output = array();
-	if (!extension_loaded('pdo_sqlite')) { $output[] = 'PDO:SQLite not enabled, please add "extension = php_pdo_sqlite.dll" to php.ini'; }
-	//if (!extension_loaded('sqlite3')) { $output[] = 'SQLite3 not enabled, please add "extension = php_sqlite3.dll" to php.ini'; }
+	$i = 1;
+	if (!extension_loaded('pdo_sqlite')) { $output["Step $i"] = getError(getOS(),'pdo_sqlite'); $i++; }
+	if (!extension_loaded('curl')) { $output["Step $i"] = getError(getOS(),'curl'); $i++; }
+	if (!extension_loaded('zip')) { $output["Step $i"] = getError(getOS(),'zip'); $i++; }
+	//if (!extension_loaded('sqlite3')) { $output[] = getError(getOS(),'sqlite3'); }
 	
 	if ($output) {
+		$output["Step $i"] = "<b>Restart PHP and/or Webserver to apply changes</b>"; $i++; 
+		$output["Step $i"] = "<b>Please visit here to also check status of necessary components after you fix them: <a href='check.php'>check.php<a/></b>"; $i++; 
 		debug_out($output,1);
 	}
 	return true;
@@ -1953,7 +2018,7 @@ function timezoneOptions() {
 // Build Database
 function createSQLiteDB($path = false) {
 	if ($path === false) {
-		if (defined('DATABASE_LOCATION')) {
+		if (DATABASE_LOCATION){
 			$path = DATABASE_LOCATION;
 		} else {
 			debug_out('No Path Specified!');
@@ -2149,11 +2214,6 @@ function sendNotification($success, $message = false, $send = true) {
 
 // Load colours from the database
 function loadAppearance() {
-	if (!isset($GLOBALS['file_db'])) {
-		$GLOBALS['file_db'] = new PDO('sqlite:'.DATABASE_LOCATION.'users.db');
-		$GLOBALS['file_db']->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
-	}
-	
 	// Defaults
 	$defaults = array(
 		'title' => 'Organizr',
@@ -2170,19 +2230,27 @@ function loadAppearance() {
 		'loading' => '#66D9EF',
 		'hovertext' => '#000000',
 	);
-	
-	// Database Lookup
-	$options = $GLOBALS['file_db']->query('SELECT * FROM options');
-	
-	// Replace defaults with filled options
-	foreach($options as $row) {
-		foreach($defaults as $key => $value) {
-			if (isset($row[$key]) && $row[$key]) {
-				$defaults[$key] = $row[$key];
+
+	if (DATABASE_LOCATION) {
+		if(is_file(DATABASE_LOCATION.'users.db') && filesize(DATABASE_LOCATION.'users.db') > 0){
+			if (!isset($GLOBALS['file_db'])) {
+				$GLOBALS['file_db'] = new PDO('sqlite:'.DATABASE_LOCATION.'users.db');
+				$GLOBALS['file_db']->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+			}
+			
+			// Database Lookup
+			$options = $GLOBALS['file_db']->query('SELECT * FROM options');
+			// Replace defaults with filled options
+			foreach($options as $row) {
+				foreach($defaults as $key => $value) {
+					if (isset($row[$key]) && $row[$key]) {
+						$defaults[$key] = $row[$key];
+					}
+				}
 			}
 		}
 	}
-	
+
 	// Return the Results
 	return $defaults;
 }
@@ -2306,42 +2374,44 @@ function nzbgetConnect($list = 'listgroups') {
     
     $api = curl_get($url.'/'.NZBGETUSERNAME.':'.NZBGETPASSWORD.'/jsonrpc/'.$list);          
     $api = json_decode($api, true);
-    
     $gotNZB = array();
-    
-    foreach ($api['result'] AS $child) {
-        $downloadName = htmlentities($child['NZBName'], ENT_QUOTES);
-        $downloadStatus = $child['Status'];
-        $downloadCategory = $child['Category'];
-        if($list == "history"){ $downloadPercent = "100"; $progressBar = ""; }
-        if($list == "listgroups"){ $downloadPercent = (($child['FileSizeMB'] - $child['RemainingSizeMB']) / $child['FileSizeMB']) * 100; $progressBar = "progress-bar-striped active"; }
-        if($child['Health'] <= "750"){ 
-            $downloadHealth = "danger"; 
-        }elseif($child['Health'] <= "900"){ 
-            $downloadHealth = "warning"; 
-        }elseif($child['Health'] <= "1000"){ 
-            $downloadHealth = "success"; 
-        }
-        
-        $gotNZB[] = '<tr>
-                        <td class="col-xs-7 nzbtable-file-row">'.$downloadName.'</td>
-                        <td class="col-xs-2 nzbtable nzbtable-row">'.$downloadStatus.'</td>
-                        <td class="col-xs-1 nzbtable nzbtable-row">'.$downloadCategory.'</td>
-                        <td class="col-xs-2 nzbtable nzbtable-row">
-                            <div class="progress">
-                                <div class="progress-bar progress-bar-'.$downloadHealth.' '.$progressBar.'" role="progressbar" aria-valuenow="'.$downloadPercent.'" aria-valuemin="0" aria-valuemax="100" style="width: '.$downloadPercent.'%">
-                                    <p class="text-center">'.round($downloadPercent).'%</p>
-                                    <span class="sr-only">'.$downloadPercent.'% Complete</span>
-                                </div>
-                            </div>
-                        </td>
-                    </tr>';
-    }
-    
-	if ($gotNZB) {
-		return implode('',$gotNZB);
-	} else {
-		return '<tr><td colspan="4"><p class="text-center">No Results</p></td></tr>';
+    if (is_array($api) || is_object($api)){
+		foreach ($api['result'] AS $child) {
+			$downloadName = htmlentities($child['NZBName'], ENT_QUOTES);
+			$downloadStatus = $child['Status'];
+			$downloadCategory = $child['Category'];
+			if($list == "history"){ $downloadPercent = "100"; $progressBar = ""; }
+			if($list == "listgroups"){ $downloadPercent = (($child['FileSizeMB'] - $child['RemainingSizeMB']) / $child['FileSizeMB']) * 100; $progressBar = "progress-bar-striped active"; }
+			if($child['Health'] <= "750"){ 
+				$downloadHealth = "danger"; 
+			}elseif($child['Health'] <= "900"){ 
+				$downloadHealth = "warning"; 
+			}elseif($child['Health'] <= "1000"){ 
+				$downloadHealth = "success"; 
+			}
+
+			$gotNZB[] = '<tr>
+							<td class="col-xs-7 nzbtable-file-row">'.$downloadName.'</td>
+							<td class="col-xs-2 nzbtable nzbtable-row">'.$downloadStatus.'</td>
+							<td class="col-xs-1 nzbtable nzbtable-row">'.$downloadCategory.'</td>
+							<td class="col-xs-2 nzbtable nzbtable-row">
+								<div class="progress">
+									<div class="progress-bar progress-bar-'.$downloadHealth.' '.$progressBar.'" role="progressbar" aria-valuenow="'.$downloadPercent.'" aria-valuemin="0" aria-valuemax="100" style="width: '.$downloadPercent.'%">
+										<p class="text-center">'.round($downloadPercent).'%</p>
+										<span class="sr-only">'.$downloadPercent.'% Complete</span>
+									</div>
+								</div>
+							</td>
+						</tr>';
+		}
+
+		if ($gotNZB) {
+			return implode('',$gotNZB);
+		} else {
+			return '<tr><td colspan="4"><p class="text-center">No Results</p></td></tr>';
+		}
+	}else{
+		writeLog("error", "NZBGET ERROR: could not connect - check URL and/or check token and/or Usernamd and Password - if HTTPS, is cert valid");
 	}
 }
 
@@ -2616,19 +2686,30 @@ function explosion($string, $position){
 }
 
 function getServerPath() {
-    
-    if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') { 
-        
+	if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == "https"){
+		$protocol = "https://";
+	}elseif (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') { 
         $protocol = "https://"; 
-    
     } else {  
-        
         $protocol = "http://"; 
-    
     }
-    
-    return $protocol . $_SERVER['SERVER_NAME'] . dirname($_SERVER['REQUEST_URI']);
-      
+	$domain = '';
+    if (isset($_SERVER['SERVER_NAME']) && strpos($_SERVER['SERVER_NAME'], '.') !== false){
+        $domain = $_SERVER['SERVER_NAME'];
+	}elseif(isset($_SERVER['HTTP_HOST'])){
+		if (strpos($_SERVER['HTTP_HOST'], ':') !== false) {
+			$domain = explode(':', $_SERVER['HTTP_HOST'])[0];
+			$port = explode(':', $_SERVER['HTTP_HOST'])[1];
+			if ($port == "80" || $port == "443"){
+				$domain = $domain;
+			}else{
+				$domain = $_SERVER['HTTP_HOST'];
+			}
+		}else{
+        	$domain = $_SERVER['HTTP_HOST'];
+		}
+	}
+    return $protocol . $domain . dirname($_SERVER['REQUEST_URI']);
 }
 
 function get_browser_name() {
@@ -2665,7 +2746,7 @@ function getSickrageCalendarWanted($array){
             if (new DateTime() < new DateTime($episodeAirDate)) { $unaired = true; }
             $downloaded = "0";
             if($downloaded == "0" && isset($unaired)){ $downloaded = "indigo-bg"; }elseif($downloaded == "1"){ $downloaded = "green-bg";}else{ $downloaded = "red-bg"; }
-            $gotCalendar .= "{ title: \"$seriesName\", start: \"$episodeAirDate\", className: \"$downloaded\", imagetype: \"tv\", url: \"https://thetvdb.com/?tab=series&id=$episodeID\" }, \n";
+            $gotCalendar .= "{ title: \"$seriesName\", start: \"$episodeAirDate\", className: \"$downloaded tvID--$episodeID\", imagetype: \"tv\" }, \n";
         
     }
     
@@ -2682,7 +2763,7 @@ function getSickrageCalendarWanted($array){
             if (new DateTime() < new DateTime($episodeAirDate)) { $unaired = true; }
             $downloaded = "0";
             if($downloaded == "0" && isset($unaired)){ $downloaded = "indigo-bg"; }elseif($downloaded == "1"){ $downloaded = "green-bg";}else{ $downloaded = "red-bg"; }
-            $gotCalendar .= "{ title: \"$seriesName\", start: \"$episodeAirDate\", className: \"$downloaded\", imagetype: \"tv\", url: \"https://thetvdb.com/?tab=series&id=$episodeID\" }, \n";
+            $gotCalendar .= "{ title: \"$seriesName\", start: \"$episodeAirDate\", className: \"$downloaded tvID--$episodeID\", imagetype: \"tv\" }, \n";
         
     }
     
@@ -2699,7 +2780,7 @@ function getSickrageCalendarWanted($array){
             if (new DateTime() < new DateTime($episodeAirDate)) { $unaired = true; }
             $downloaded = "0";
             if($downloaded == "0" && isset($unaired)){ $downloaded = "indigo-bg"; }elseif($downloaded == "1"){ $downloaded = "green-bg";}else{ $downloaded = "red-bg"; }
-            $gotCalendar .= "{ title: \"$seriesName\", start: \"$episodeAirDate\", className: \"$downloaded\", imagetype: \"tv\", url: \"https://thetvdb.com/?tab=series&id=$episodeID\" }, \n";
+            $gotCalendar .= "{ title: \"$seriesName\", start: \"$episodeAirDate\", className: \"$downloaded tvID--$episodeID\", imagetype: \"tv\" }, \n";
         
     }
     
@@ -2716,7 +2797,7 @@ function getSickrageCalendarWanted($array){
             if (new DateTime() < new DateTime($episodeAirDate)) { $unaired = true; }
             $downloaded = "0";
             if($downloaded == "0" && isset($unaired)){ $downloaded = "indigo-bg"; }elseif($downloaded == "1"){ $downloaded = "green-bg";}else{ $downloaded = "red-bg"; }
-            $gotCalendar .= "{ title: \"$seriesName\", start: \"$episodeAirDate\", className: \"$downloaded\", imagetype: \"tv\", url: \"https://thetvdb.com/?tab=series&id=$episodeID\" }, \n";
+            $gotCalendar .= "{ title: \"$seriesName\", start: \"$episodeAirDate\", className: \"$downloaded tvID--$episodeID\", imagetype: \"tv\" }, \n";
         
     }
 
@@ -2737,7 +2818,7 @@ function getSickrageCalendarHistory($array){
             $episodeID = $child['tvdbid'];
             $episodeAirDate = $child['date'];
             $downloaded = "green-bg";
-            $gotCalendar .= "{ title: \"$seriesName\", start: \"$episodeAirDate\", className: \"$downloaded\", imagetype: \"tv\", url: \"https://thetvdb.com/?tab=series&id=$episodeID\" }, \n";
+            $gotCalendar .= "{ title: \"$seriesName\", start: \"$episodeAirDate\", className: \"$downloaded tvID--$episodeID\", imagetype: \"tv\" }, \n";
         
     }
 
@@ -2767,7 +2848,7 @@ function getSonarrCalendar($array){
         $downloaded = $child['hasFile'];
         if($downloaded == "0" && isset($unaired) && $episodePremier == "true"){ $downloaded = "light-blue-bg"; }elseif($downloaded == "0" && isset($unaired)){ $downloaded = "indigo-bg"; }elseif($downloaded == "1"){ $downloaded = "green-bg";}else{ $downloaded = "red-bg"; }
         
-        $gotCalendar .= "{ title: \"$seriesName\", start: \"$episodeAirDate\", className: \"$downloaded\", imagetype: \"tv\", url: \"https://thetvdb.com/?tab=series&id=$episodeID\" }, \n";
+        $gotCalendar .= "{ title: \"$seriesName\", start: \"$episodeAirDate\", className: \"$downloaded tvID--$episodeID\", imagetype: \"tv\" }, \n";
         
     }
 
@@ -2807,7 +2888,7 @@ function getRadarrCalendar($array){
             
             }
                         
-            $gotCalendar .= "{ title: \"$movieName\", start: \"$physicalRelease\", className: \"$downloaded\", imagetype: \"film\", url: \"https://www.themoviedb.org/movie/$movieID\" }, \n";
+            $gotCalendar .= "{ title: \"$movieName\", start: \"$physicalRelease\", className: \"$downloaded movieID--$movieID\", imagetype: \"film\" }, \n";
         }
         
     }
@@ -2817,41 +2898,46 @@ function getRadarrCalendar($array){
 }
 
 function getHeadphonesCalendar($url, $key, $list){
-	$url = qualifyURL(HEADPHONESURL);
-    
+	$url = qualifyURL(HEADPHONESURL);    
     $api = curl_get($url."/api?apikey=".$key."&cmd=$list");
-    
     $api = json_decode($api, true);
-    
     $i = 0;
-    
     $gotCalendar = "";
-	
-    foreach($api AS $child) {
-
-        if($child['Status'] == "Wanted"){
-        
-            $i++;
-            $albumName = addslashes($child['AlbumTitle']);
-            $albumArtist = htmlentities($child['ArtistName'], ENT_QUOTES);
-            $albumDate = $child['ReleaseDate'];
-            $albumID = $child['AlbumID'];
-            $albumDate = strtotime($albumDate);
-            $albumDate = date("Y-m-d", $albumDate);
-            $albumStatus = $child['Status'];
-            
-            if (new DateTime() < new DateTime($albumDate)) {  $notReleased = "true"; }else{ $notReleased = "false"; }
-
-            if($albumStatus == "Wanted" && $notReleased == "true"){ $albumStatusColor = "indigo-bg"; }elseif($albumStatus == "Downloaded"){ $albumStatusColor = "green-bg"; }else{ $albumStatusColor = "red-bg"; }
-
-            $gotCalendar .= "{ title: \"$albumArtist - $albumName\", start: \"$albumDate\", className: \"$albumStatusColor\", imagetype: \"music\", url: \"https://musicbrainz.org/release-group/$albumID\" }, \n";
-            
-        }
-        
-    }
-
-    if ($i != 0){ return $gotCalendar; }
-
+	if (is_array($api) || is_object($api)){
+		foreach($api AS $child) {
+			if($child['Status'] == "Wanted" && $list == "getWanted"){
+				$i++;
+				$albumName = addslashes($child['AlbumTitle']);
+				$albumArtist = htmlentities($child['ArtistName'], ENT_QUOTES);
+				$albumDate = $child['ReleaseDate'];
+				$albumID = $child['AlbumID'];
+				$albumDate = strtotime($albumDate);
+				$albumDate = date("Y-m-d", $albumDate);
+				$albumStatus = $child['Status'];
+
+				if (new DateTime() < new DateTime($albumDate)) {  $notReleased = "true"; }else{ $notReleased = "false"; }
+
+				if($albumStatus == "Wanted" && $notReleased == "true"){ $albumStatusColor = "indigo-bg"; }elseif($albumStatus == "Downloaded"){ $albumStatusColor = "green-bg"; }else{ $albumStatusColor = "red-bg"; }
+
+				$gotCalendar .= "{ title: \"$albumArtist - $albumName\", start: \"$albumDate\", className: \"$albumStatusColor\", imagetype: \"music\", url: \"https://musicbrainz.org/release-group/$albumID\" }, \n";
+			}
+			if($child['Status'] == "Processed" && $list == "getHistory"){
+				$i++;
+				$albumName = addslashes($child['Title']);
+				$albumDate = $child['DateAdded'];
+				$albumID = $child['AlbumID'];
+				$albumDate = strtotime($albumDate);
+				$albumDate = date("Y-m-d", $albumDate);
+				$albumStatusColor = "green-bg";
+				if (new DateTime() < new DateTime($albumDate)) {  $notReleased = "true"; }else{ $notReleased = "false"; }
+
+				$gotCalendar .= "{ title: \"$albumName\", start: \"$albumDate\", className: \"$albumStatusColor\", imagetype: \"music\", url: \"https://musicbrainz.org/release-group/$albumID\" }, \n";
+			}
+		}
+    	if ($i != 0){ return $gotCalendar; }
+	}else{
+		writeLog("error", "HEADPHONES $list ERROR: could not connect - check URL and/or check API key - if HTTPS, is cert valid");
+	}
 }
 
 function checkRootPath($string){
@@ -2862,6 +2948,10 @@ function checkRootPath($string){
     }
 }
 
+function strip($string){
+	return str_replace(array("\r","\n","\t"),"",$string);
+}
+
 function writeLog($type, $message){
     $message = date("Y-m-d H:i:s")."|".$type."|".$message."\n";
     file_put_contents("org.log", $message, FILE_APPEND | LOCK_EX);
@@ -2924,12 +3014,13 @@ function getPlatform($platform){
         "Emby Classic" => "emby.png",
         "Safari" => "safari.png",
         "Android" => "android.png",
+        "AndroidTv" => "android.png",
         "Chromecast" => "chromecast.png",
         "Dashboard" => "emby.png",
         "Dlna" => "dlna.png",
         "Windows Phone" => "wp.png",
         "Windows RT" => "win8.png",
-        "Kodi" => "koid.png",
+        "Kodi" => "kodi.png",
     );
     if (array_key_exists($platform, $allPlatforms)) {
         return $allPlatforms[$platform];
@@ -3151,7 +3242,7 @@ function searchPlex($query){
     		}
     		if(!$results['image']){ $image_url = "images/no-search.png"; $key = "no-search"; }
 			
-			if (substr_count(PLEXURL, ':') == 2) {
+			if (substr_count(PLEXURL, '.') != 2) {
 				$link = "https://app.plex.tv/web/app#!/server/$server/details?key=/library/metadata/".$results['ratingkey'];
 			}else{
 				$link = PLEXURL."/web/index.html#!/server/$server/details?key=/library/metadata/".$results['ratingkey'];
@@ -3248,6 +3339,34 @@ function sendEmail($email, $username = "Organizr User", $subject, $body, $cc = n
 
 }
 
+//EMAIL SHIT
+function sendTestEmail($to, $from, $host, $auth, $username, $password, $type, $port, $sendername){
+
+	$mail = new PHPMailer;
+	$mail->isSMTP();
+	$mail->Host = $host;
+	$mail->SMTPAuth = $auth;
+	$mail->Username = $username;
+	$mail->Password = $password;
+	$mail->SMTPSecure = $type;
+	$mail->Port = $port;
+	$mail->setFrom($from, $sendername);
+	$mail->addReplyTo($from, $sendername);
+	$mail->isHTML(true);
+	$mail->addAddress($to, "Organizr Admin");
+	$mail->Subject = "Organizr Test E-Mail";
+	$mail->Body    = "This was just a test!";
+	//$mail->send();
+	if(!$mail->send()) {
+		writeLog("error", "EMAIL TEST: mail failed to send - Error:".$mail->ErrorInfo);
+		return false;
+	} else {
+		writeLog("success", "EMAIL TEST: mail has been sent successfully");
+		return true;
+	}
+
+}
+
 function libraryList(){
     $address = qualifyURL(PLEXURL);
 	$headers = array(
@@ -3265,7 +3384,9 @@ function libraryList(){
 	foreach($api->SharedServer AS $child) {
 		if(!empty($child['username'])){
 			$username = (string)strtolower($child['username']);
+			$email = (string)strtolower($child['email']);
 			$libraryList['users'][$username] = (string)$child['id'];
+			$libraryList['emails'][$email] = (string)$child['id'];
 		}
     }
     return (!empty($libraryList) ? array_change_key_case($libraryList,CASE_LOWER) : null );
@@ -3320,7 +3441,7 @@ function plexUserDelete($username){
 	);
 	$getServer = simplexml_load_string(@curl_get($address."/?X-Plex-Token=".PLEXTOKEN));
     if (!$getServer) { return 'Could not load!'; }else { $gotServer = $getServer['machineIdentifier']; }
-	$id = convertPlexName($username, "id");
+	$id = (is_numeric($username) ? $id : convertPlexName($username, "id"));
 	
 	$api = curl_delete("https://plex.tv/api/servers/$gotServer/shared_servers/$id", $headers);
 	
@@ -3491,5 +3612,472 @@ function customCSS(){
 	}
 }
 
+function tvdbToken(){
+	$headers = array(
+		"Accept" => "application/json", 
+		"Content-Type" => "application/json"
+	);
+	$json = array(
+		"apikey" => "FBE7B62621F4CAD7",
+         "userkey" => "328BB46EB1E9A0F5",
+         "username" => "causefx"
+	);
+	$api = curl_post("https://api.thetvdb.com/login", $json, $headers);
+    return json_decode($api['content'], true)['token'];
+}
+
+function tvdbGet($id){
+	$headers = array(
+		"Accept" => "application/json", 
+		"Authorization" => "Bearer ".tvdbToken(),
+		"trakt-api-key" => "4502cfdf8f7282fe454878ff8583f5636392cdc5fcac30d0cc4565f7173bf443",
+		"trakt-api-version" => "2"
+	);
+
+	$trakt = curl_get("https://api.trakt.tv/search/tvdb/$id?type=show", $headers);
+	@$api['trakt'] = json_decode($trakt, true)[0]['show']['ids'];
+	
+	if(empty($api['trakt'])){
+		$series = curl_get("https://api.thetvdb.com/series/$id", $headers);
+		$poster = curl_get("https://api.thetvdb.com/series/$id/images/query?keyType=poster", $headers);
+		$backdrop = curl_get("https://api.thetvdb.com/series/$id/images/query?keyType=fanart", $headers);
+		$api['series'] = json_decode($series, true)['data'];
+		$api['poster'] = json_decode($poster, true)['data'];
+		$api['backdrop'] = json_decode($backdrop, true)['data'];
+	}
+	return $api;
+}
+
+function getPlexPlaylists(){
+    $address = qualifyURL(PLEXURL);
+    
+	// Perform API requests
+    $api = @curl_get($address."/playlists?X-Plex-Token=".PLEXTOKEN);
+    $api = simplexml_load_string($api);
+	if (is_array($api) || is_object($api)){
+		if (!$api->head->title){
+			$getServer = simplexml_load_string(@curl_get($address."/?X-Plex-Token=".PLEXTOKEN));
+			if (!$getServer) { return 'Could not load!'; }
+			// Identify the local machine
+			$gotServer = $getServer['machineIdentifier'];
+			$output = "";
+			foreach($api AS $child) {
+				$items = "";
+				if ($child['playlistType'] == "video" && strpos(strtolower($child['title']) , 'private') === false){
+					$api = @curl_get($address.$child['key']."?X-Plex-Token=".PLEXTOKEN);
+					$api = simplexml_load_string($api);
+					if (is_array($api) || is_object($api)){
+						if (!$api->head->title){
+							foreach($api->Video AS $child){
+								$items[] = resolvePlexItem($gotServer, PLEXTOKEN, $child, false, false,false);
+							}
+							if (count($items)) {
+								$className = preg_replace("/(\W)+/", "", $api['title']);
+								$output .= '<div id="playlist-'.$className.'" class="content-box box-shadow big-box"><h5 style="margin-bottom: -20px" class="text-center">'.$api['title'].'</h5><div class="recentHeader inbox-pagination '.$className.'"></div><br/><div class="recentItems" data-name="'.$className.'">'.implode('',$items).'</div></div>';
+							}							
+						}
+					}
+				}
+			}
+			return $output;
+		}else{
+			writeLog("error", "PLEX PLAYLIST ERROR: could not connect - check token - if HTTPS, is cert valid");
+		}
+	}else{
+		writeLog("error", "PLEX PLAYLIST ERROR: could not connect - check URL - if HTTPS, is cert valid");
+	}
+}
+
+function orgEmail($header = "Message From Admin", $title = "Important Message", $user = "Organizr User", $mainMessage = "", $button = null, $buttonURL = null, $subTitle = "", $subMessage = ""){
+	$path = getServerPath();
+	return '
+	<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
+<head>
+    <!--[if gte mso 9]><xml>
+<o:OfficeDocumentSettings>
+<o:AllowPNG/>
+<o:PixelsPerInch>96</o:PixelsPerInch>
+</o:OfficeDocumentSettings>
+</xml><![endif]-->
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+    <meta name="viewport" content="width=device-width">
+    <!--[if !mso]><!-->
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <!--<![endif]-->
+    <title></title>
+    <!--[if !mso]><!-- -->
+    <link href="https://fonts.googleapis.com/css?family=Ubuntu" rel="stylesheet" type="text/css">
+    <link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet" type="text/css">
+    <!--<![endif]-->
+    <style type="text/css" id="media-query">
+        body {
+            margin: 0;
+            padding: 0;
+        }
+        table,
+        tr,
+        td {
+            vertical-align: top;
+            border-collapse: collapse;
+        }
+        .ie-browser table,
+        .mso-container table {
+            table-layout: fixed;
+        }
+        * {
+            line-height: inherit;
+        }
+        a[x-apple-data-detectors=true] {
+            color: inherit !important;
+            text-decoration: none !important;
+        }
+        [owa] .img-container div,
+        [owa] .img-container button {
+            display: block !important;
+        }
+        [owa] .fullwidth button {
+            width: 100% !important;
+        }
+        [owa] .block-grid .col {
+            display: table-cell;
+            float: none !important;
+            vertical-align: top;
+        }
+        .ie-browser .num12,
+        .ie-browser .block-grid,
+        [owa] .num12,
+        [owa] .block-grid {
+            width: 615px !important;
+        }
+        .ExternalClass,
+        .ExternalClass p,
+        .ExternalClass span,
+        .ExternalClass font,
+        .ExternalClass td,
+        .ExternalClass div {
+            line-height: 100%;
+        }
+        .ie-browser .mixed-two-up .num4,
+        [owa] .mixed-two-up .num4 {
+            width: 204px !important;
+        }
+        .ie-browser .mixed-two-up .num8,
+        [owa] .mixed-two-up .num8 {
+            width: 408px !important;
+        }
+        .ie-browser .block-grid.two-up .col,
+        [owa] .block-grid.two-up .col {
+            width: 307px !important;
+        }
+        .ie-browser .block-grid.three-up .col,
+        [owa] .block-grid.three-up .col {
+            width: 205px !important;
+        }
+        .ie-browser .block-grid.four-up .col,
+        [owa] .block-grid.four-up .col {
+            width: 153px !important;
+        }
+        .ie-browser .block-grid.five-up .col,
+        [owa] .block-grid.five-up .col {
+            width: 123px !important;
+        }
+        .ie-browser .block-grid.six-up .col,
+        [owa] .block-grid.six-up .col {
+            width: 102px !important;
+        }
+        .ie-browser .block-grid.seven-up .col,
+        [owa] .block-grid.seven-up .col {
+            width: 87px !important;
+        }
+        .ie-browser .block-grid.eight-up .col,
+        [owa] .block-grid.eight-up .col {
+            width: 76px !important;
+        }
+        .ie-browser .block-grid.nine-up .col,
+        [owa] .block-grid.nine-up .col {
+            width: 68px !important;
+        }
+        .ie-browser .block-grid.ten-up .col,
+        [owa] .block-grid.ten-up .col {
+            width: 61px !important;
+        }
+        .ie-browser .block-grid.eleven-up .col,
+        [owa] .block-grid.eleven-up .col {
+            width: 55px !important;
+        }
+        .ie-browser .block-grid.twelve-up .col,
+        [owa] .block-grid.twelve-up .col {
+            width: 51px !important;
+        }
+        @media only screen and (min-width: 635px) {
+            .block-grid {
+                width: 615px !important;
+            }
+            .block-grid .col {
+                display: table-cell;
+                Float: none !important;
+                vertical-align: top;
+            }
+            .block-grid .col.num12 {
+                width: 615px !important;
+            }
+            .block-grid.mixed-two-up .col.num4 {
+                width: 204px !important;
+            }
+            .block-grid.mixed-two-up .col.num8 {
+                width: 408px !important;
+            }
+            .block-grid.two-up .col {
+                width: 307px !important;
+            }
+            .block-grid.three-up .col {
+                width: 205px !important;
+            }
+            .block-grid.four-up .col {
+                width: 153px !important;
+            }
+            .block-grid.five-up .col {
+                width: 123px !important;
+            }
+            .block-grid.six-up .col {
+                width: 102px !important;
+            }
+            .block-grid.seven-up .col {
+                width: 87px !important;
+            }
+            .block-grid.eight-up .col {
+                width: 76px !important;
+            }
+            .block-grid.nine-up .col {
+                width: 68px !important;
+            }
+            .block-grid.ten-up .col {
+                width: 61px !important;
+            }
+            .block-grid.eleven-up .col {
+                width: 55px !important;
+            }
+            .block-grid.twelve-up .col {
+                width: 51px !important;
+            }
+        }
+        @media (max-width: 635px) {
+            .block-grid,
+            .col {
+                min-width: 320px !important;
+                max-width: 100% !important;
+            }
+            .block-grid {
+                width: calc(100% - 40px) !important;
+            }
+            .col {
+                width: 100% !important;
+            }
+            .col>div {
+                margin: 0 auto;
+            }
+            img.fullwidth {
+                max-width: 100% !important;
+            }
+        }
+    </style>
+</head>
+<body class="clean-body" style="margin: 0;padding: 0;-webkit-text-size-adjust: 100%;background-color: #FFFFFF">
+    <!--[if IE]><div class="ie-browser"><![endif]-->
+    <!--[if mso]><div class="mso-container"><![endif]-->
+    <div class="nl-container" style="min-width: 320px;Margin: 0 auto;background-color: #FFFFFF">
+        <!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td align="center" style="background-color: #FFFFFF;"><![endif]-->
+        <div style="background-color:#333333;">
+            <div style="Margin: 0 auto;min-width: 320px;max-width: 615px;width: 615px;width: calc(30500% - 193060px);overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;background-color: transparent;"
+                class="block-grid ">
+                <div style="border-collapse: collapse;display: table;width: 100%;">
+                    <!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="background-color:#333333;" align="center"><table cellpadding="0" cellspacing="0" border="0" style="width: 615px;"><tr class="layout-full-width" style="background-color:transparent;"><![endif]-->
+                    <!--[if (mso)|(IE)]><td align="center" width="615" style=" width:615px; padding-right: 0px; padding-left: 0px; padding-top:0px; padding-bottom:0px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><![endif]-->
+                    <div class="col num12" style="min-width: 320px;max-width: 615px;width: 615px;width: calc(29500% - 180810px);background-color: transparent;">
+                        <div style="background-color: transparent; width: 100% !important;">
+                            <!--[if (!mso)&(!IE)]><!-->
+                            <div style="border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent; padding-top:0px; padding-bottom:0px; padding-right: 0px; padding-left: 0px;">
+                                <!--<![endif]-->
+                                <div align="left" class="img-container left fullwidth" style="padding-right: 30px;	padding-left: 30px;">
+                                    <!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 30px; padding-left: 30px;" align="left"><![endif]-->
+                                    <img class="left fullwidth" align="left" border="0" src="'.$path.'images/organizr-logo-h.png" alt="Image" title="Image"
+                                        style="outline: none;text-decoration: none;-ms-interpolation-mode: bicubic;clear: both;display: block !important;border: 0;height: auto;float: none;width: 100%;max-width: 555px"
+                                        width="555">
+                                    <!--[if mso]></td></tr></table><![endif]-->
+                                </div>
+                                <!--[if (!mso)&(!IE)]><!-->
+                            </div>
+                            <!--<![endif]-->
+                        </div>
+                    </div>
+                    <!--[if (mso)|(IE)]></td></tr></table></td></tr></table><![endif]-->
+                </div>
+            </div>
+        </div>
+        <div style="background-color:#333333;">
+            <div style="Margin: 0 auto;min-width: 320px;max-width: 615px;width: 615px;width: calc(30500% - 193060px);overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;background-color: transparent;"
+                class="block-grid ">
+                <div style="border-collapse: collapse;display: table;width: 100%;">
+                    <!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="background-color:#333333;" align="center"><table cellpadding="0" cellspacing="0" border="0" style="width: 615px;"><tr class="layout-full-width" style="background-color:transparent;"><![endif]-->
+                    <!--[if (mso)|(IE)]><td align="center" width="615" style=" width:615px; padding-right: 0px; padding-left: 0px; padding-top:0px; padding-bottom:0px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><![endif]-->
+                    <div class="col num12" style="min-width: 320px;max-width: 615px;width: 615px;width: calc(29500% - 180810px);background-color: transparent;">
+                        <div style="background-color: transparent; width: 100% !important;">
+                            <!--[if (!mso)&(!IE)]><!-->
+                            <div style="border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent; padding-top:0px; padding-bottom:0px; padding-right: 0px; padding-left: 0px;">
+                                <!--<![endif]-->
+                                <!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 0px; padding-left: 0px; padding-top: 0px; padding-bottom: 0px;"><![endif]-->
+                                <div style="font-family:\'Lato\', Tahoma, Verdana, Segoe, sans-serif;line-height:120%;color:#FFFFFF; padding-right: 0px; padding-left: 0px; padding-top: 0px; padding-bottom: 0px;">
+                                    <div style="font-size:12px;line-height:14px;color:#FFFFFF;font-family:\'Lato\', Tahoma, Verdana, Segoe, sans-serif;text-align:left;">
+                                        <p style="margin: 0;font-size: 12px;line-height: 14px;text-align: center"><span style="font-size: 16px; line-height: 19px;"><strong><span style="line-height: 19px; font-size: 16px;">'.$header.'</span></strong>
+                                            </span>
+                                        </p>
+                                    </div>
+                                </div>
+                                <!--[if mso]></td></tr></table><![endif]-->
+                                <!--[if (!mso)&(!IE)]><!-->
+                            </div>
+                            <!--<![endif]-->
+                        </div>
+                    </div>
+                    <!--[if (mso)|(IE)]></td></tr></table></td></tr></table><![endif]-->
+                </div>
+            </div>
+        </div>
+        <div style="background-color:#393939;">
+            <div style="Margin: 0 auto;min-width: 320px;max-width: 615px;width: 615px;width: calc(30500% - 193060px);overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;background-color: transparent;"
+                class="block-grid ">
+                <div style="border-collapse: collapse;display: table;width: 100%;">
+                    <!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="background-color:#393939;" align="center"><table cellpadding="0" cellspacing="0" border="0" style="width: 615px;"><tr class="layout-full-width" style="background-color:transparent;"><![endif]-->
+                    <!--[if (mso)|(IE)]><td align="center" width="615" style=" width:615px; padding-right: 0px; padding-left: 0px; padding-top:5px; padding-bottom:5px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><![endif]-->
+                    <div class="col num12" style="min-width: 320px;max-width: 615px;width: 615px;width: calc(29500% - 180810px);background-color: transparent;">
+                        <div style="background-color: transparent; width: 100% !important;">
+                            <!--[if (!mso)&(!IE)]><!-->
+                            <div style="border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent; padding-top:5px; padding-bottom:5px; padding-right: 0px; padding-left: 0px;">
+                                <!--<![endif]-->
+                                <!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 30px; padding-left: 30px; padding-top: 0px; padding-bottom: 0px;"><![endif]-->
+                                <div style="font-family:\'Ubuntu\', Tahoma, Verdana, Segoe, sans-serif;line-height:120%;color:#FFFFFF; padding-right: 30px; padding-left: 30px; padding-top: 0px; padding-bottom: 0px;">
+                                    <div style="font-family:Ubuntu, Tahoma, Verdana, Segoe, sans-serif;font-size:12px;line-height:14px;color:#FFFFFF;text-align:left;">
+                                        <p style="margin: 0;font-size: 12px;line-height: 14px;text-align: center"><span style="font-size: 16px; line-height: 19px;"><strong>'.$title.'</strong></span></p>
+                                    </div>
+                                </div>
+                                <!--[if mso]></td></tr></table><![endif]-->
+                                <div style="padding-right: 5px; padding-left: 5px; padding-top: 5px; padding-bottom: 5px;">
+                                    <!--[if (mso)]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 5px;padding-left: 5px; padding-top: 5px; padding-bottom: 5px;"><table width="55%" align="center" cellpadding="0" cellspacing="0" border="0"><tr><td><![endif]-->
+                                    <div align="center">
+                                        <div style="border-top: 2px solid #66D9EF; width:55%; line-height:2px; height:2px; font-size:2px;">&#160;</div>
+                                    </div>
+                                    <!--[if (mso)]></td></tr></table></td></tr></table><![endif]-->
+                                </div>
+                                <!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 30px; padding-left: 30px; padding-top: 15px; padding-bottom: 10px;"><![endif]-->
+                                <div style="font-family:\'Lato\', Tahoma, Verdana, Segoe, sans-serif;line-height:120%;color:#FFFFFF; padding-right: 30px; padding-left: 30px; padding-top: 15px; padding-bottom: 10px;">
+                                    <div style="font-family:\'Lato\',Tahoma,Verdana,Segoe,sans-serif;font-size:12px;line-height:14px;color:#FFFFFF;text-align:left;">
+                                        <p style="margin: 0;font-size: 12px;line-height: 14px"><span style="font-size: 28px; line-height: 33px;">Hey '.$user.',</span></p>
+                                    </div>
+                                </div>
+                                <!--[if mso]></td></tr></table><![endif]-->
+                                <!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 15px; padding-left: 30px; padding-top: 10px; padding-bottom: 25px;"><![endif]-->
+                                <div style="font-family:\'Lato\', Tahoma, Verdana, Segoe, sans-serif;line-height:180%;color:#FFFFFF; padding-right: 15px; padding-left: 30px; padding-top: 10px; padding-bottom: 25px;">
+                                    <div style="font-size:12px;line-height:22px;font-family:\'Lato\',Tahoma,Verdana,Segoe,sans-serif;color:#FFFFFF;text-align:left;">
+                                        <p style="margin: 0;font-size: 14px;line-height: 25px"><span style="font-size: 18px; line-height: 32px;"><em><span style="line-height: 32px; font-size: 18px;">'.$mainMessage.'</span></em>
+                                            </span>
+                                        </p>
+                                    </div>
+                                </div>
+                                <!--[if mso]></td></tr></table><![endif]-->
+                                <div align="center" class="button-container center" style="padding-right: 30px; padding-left: 30px; padding-top:15px; padding-bottom:15px;">
+                                    <!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0" style="border-spacing: 0; border-collapse: collapse; mso-table-lspace:0pt; mso-table-rspace:0pt;"><tr><td style="padding-right: 30px; padding-left: 30px; padding-top:15px; padding-bottom:15px;" align="center"><v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="'.$path.'" style="height:48px; v-text-anchor:middle; width:194px;" arcsize="53%" strokecolor="" fillcolor="#66D9EF"><w:anchorlock/><center style="color:#000; font-family:\'Lato\', Tahoma, Verdana, Segoe, sans-serif; font-size:18px;"><![endif]-->
+                                    <a href="'.$buttonURL.'" target="_blank" style="display: inline-block;text-decoration: none;-webkit-text-size-adjust: none;text-align: center;color: #000; background-color: #66D9EF; border-radius: 25px; -webkit-border-radius: 25px; -moz-border-radius: 25px; max-width: 180px; width: 114px; width: auto; border-top: 3px solid transparent; border-right: 3px solid transparent; border-bottom: 3px solid transparent; border-left: 3px solid transparent; padding-top: 5px; padding-right: 30px; padding-bottom: 5px; padding-left: 30px; font-family: \'Lato\', Tahoma, Verdana, Segoe, sans-serif;mso-border-alt: none">
+<span style="font-size:12px;line-height:21px;"><span style="font-size: 18px; line-height: 32px;" data-mce-style="font-size: 18px; line-height: 44px;">'.$button.'</span></span></a>
+                                    <!--[if mso]></center></v:roundrect></td></tr></table><![endif]-->
+                                </div>
+                                <!--[if mso]></center></v:roundrect></td></tr></table><![endif]-->
+                            </div>
+                            <!--[if (!mso)&(!IE)]><!-->
+                        </div>
+                        <!--<![endif]-->
+                    </div>
+                </div>
+                <!--[if (mso)|(IE)]></td></tr></table></td></tr></table><![endif]-->
+            </div>
+        </div>
+    </div>
+    <div style="background-color:#ffffff;">
+        <div style="Margin: 0 auto;min-width: 320px;max-width: 615px;width: 615px;width: calc(30500% - 193060px);overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;background-color: transparent;"
+            class="block-grid ">
+            <div style="border-collapse: collapse;display: table;width: 100%;">
+                <!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="background-color:#ffffff;" align="center"><table cellpadding="0" cellspacing="0" border="0" style="width: 615px;"><tr class="layout-full-width" style="background-color:transparent;"><![endif]-->
+                <!--[if (mso)|(IE)]><td align="center" width="615" style=" width:615px; padding-right: 0px; padding-left: 0px; padding-top:5px; padding-bottom:30px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><![endif]-->
+                <div class="col num12" style="min-width: 320px;max-width: 615px;width: 615px;width: calc(29500% - 180810px);background-color: transparent;">
+                    <div style="background-color: transparent; width: 100% !important;">
+                        <!--[if (!mso)&(!IE)]><!-->
+                        <div style="border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent; padding-top:5px; padding-bottom:30px; padding-right: 0px; padding-left: 0px;">
+                            <!--<![endif]-->
+                            <!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 10px; padding-left: 10px; padding-top: 0px; padding-bottom: 10px;"><![endif]-->
+                            <div style="font-family:\'Lato\', Tahoma, Verdana, Segoe, sans-serif;line-height:120%;color:#555555; padding-right: 10px; padding-left: 10px; padding-top: 0px; padding-bottom: 10px;">
+                                <div style="font-size:12px;line-height:14px;color:#555555;font-family:\'Lato\', Tahoma, Verdana, Segoe, sans-serif;text-align:left;">
+                                    <p style="margin: 0;font-size: 14px;line-height: 17px;text-align: center"><strong><span style="font-size: 26px; line-height: 31px;">'.$subTitle.'<br></span></strong></p>
+                                </div>
+                            </div>
+                            <!--[if mso]></td></tr></table><![endif]-->
+                            <div style="padding-right: 20px; padding-left: 20px; padding-top: 15px; padding-bottom: 20px;">
+                                <!--[if (mso)]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 20px;padding-left: 20px; padding-top: 15px; padding-bottom: 20px;"><table width="40%" align="center" cellpadding="0" cellspacing="0" border="0"><tr><td><![endif]-->
+                                <div align="center">
+                                    <div style="border-top: 3px solid #66D9EF; width:40%; line-height:3px; height:3px; font-size:3px;">&#160;</div>
+                                </div>
+                                <!--[if (mso)]></td></tr></table></td></tr></table><![endif]-->
+                            </div>
+                            <!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 10px; padding-left: 10px; padding-top: 0px; padding-bottom: 0px;"><![endif]-->
+                            <div style="font-family:\'Lato\', Tahoma, Verdana, Segoe, sans-serif;line-height:180%;color:#7E7D7D; padding-right: 10px; padding-left: 10px; padding-top: 0px; padding-bottom: 0px;">
+                                <div style="font-size:12px;line-height:22px;color:#7E7D7D;font-family:\'Lato\', Tahoma, Verdana, Segoe, sans-serif;text-align:left;">
+                                    <p style="margin: 0;font-size: 14px;line-height: 25px;text-align: center"><em><span style="font-size: 18px; line-height: 32px;">'.$subMessage.'</span></em></p>
+                                </div>
+                            </div>
+                            <!--[if mso]></td></tr></table><![endif]-->
+                            <!--[if (!mso)&(!IE)]><!-->
+                        </div>
+                        <!--<![endif]-->
+                    </div>
+                </div>
+                <!--[if (mso)|(IE)]></td></tr></table></td></tr></table><![endif]-->
+            </div>
+        </div>
+    </div>
+    <div style="background-color:#333333;">
+        <div style="Margin: 0 auto;min-width: 320px;max-width: 615px;width: 615px;width: calc(30500% - 193060px);overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;background-color: transparent;"
+            class="block-grid ">
+            <div style="border-collapse: collapse;display: table;width: 100%;">
+                <!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="background-color:#333333;" align="center"><table cellpadding="0" cellspacing="0" border="0" style="width: 615px;"><tr class="layout-full-width" style="background-color:transparent;"><![endif]-->
+                <!--[if (mso)|(IE)]><td align="center" width="615" style=" width:615px; padding-right: 0px; padding-left: 0px; padding-top:5px; padding-bottom:5px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><![endif]-->
+                <div class="col num12" style="min-width: 320px;max-width: 615px;width: 615px;width: calc(29500% - 180810px);background-color: transparent;">
+                    <div style="background-color: transparent; width: 100% !important;">
+                        <!--[if (!mso)&(!IE)]><!-->
+                        <div style="border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent; padding-top:5px; padding-bottom:5px; padding-right: 0px; padding-left: 0px;">
+                            <!--<![endif]-->
+                            <!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 10px; padding-left: 10px; padding-top: 10px; padding-bottom: 10px;"><![endif]-->
+                            <div style="font-family:\'Lato\', Tahoma, Verdana, Segoe, sans-serif;line-height:120%;color:#959595; padding-right: 10px; padding-left: 10px; padding-top: 10px; padding-bottom: 10px;">
+                                <div style="font-size:12px;line-height:14px;color:#959595;font-family:\'Lato\', Tahoma, Verdana, Segoe, sans-serif;text-align:left;">
+                                    <p style="margin: 0;font-size: 14px;line-height: 17px;text-align: center">This&#160;email was sent by <a style="color:#AD80FD;text-decoration: underline;" title="Organizr"
+                                            href="https://github.com/causefx/Organizr" target="_blank" rel="noopener noreferrer">Organizr</a><strong><br></strong></p>
+                                </div>
+                            </div>
+                            <!--[if mso]></td></tr></table><![endif]-->
+                            <!--[if (!mso)&(!IE)]><!-->
+                        </div>
+                        <!--<![endif]-->
+                    </div>
+                </div>
+                <!--[if (mso)|(IE)]></td></tr></table></td></tr></table><![endif]-->
+            </div>
+        </div>
+    </div>
+    <!--[if (mso)|(IE)]></td></tr></table><![endif]-->
+    </div>
+    <!--[if (mso)|(IE)]></div><![endif]-->
+</body>
+</html>
+	';
+}
+
 // Always run this
 dependCheck();

+ 413 - 159
homepage.php

@@ -17,63 +17,10 @@ $USER = new User("registration_callback");
 // Check if connection to homepage is allowed
 qualifyUser(HOMEPAGEAUTHNEEDED, true);
 
-$dbfile = DATABASE_LOCATION.'users.db';
-
-$file_db = new PDO("sqlite:" . $dbfile);
-$file_db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
-
-$dbOptions = $file_db->query('SELECT name FROM sqlite_master WHERE type="table" AND name="options"');
-
-$hasOptions = "No";
-
-foreach($dbOptions as $row) :
-
-    if (in_array("options", $row)) :
-        $hasOptions = "Yes";
-    endif;
-
-endforeach;
-
-if($hasOptions == "No") :
-
-    $title = "Organizr";
-    $topbar = "#333333"; 
-    $topbartext = "#66D9EF";
-    $bottombar = "#333333";
-    $sidebar = "#393939";
-    $hoverbg = "#AD80FD";
-    $activetabBG = "#F92671";
-    $activetabicon = "#FFFFFF";
-    $activetabtext = "#FFFFFF";
-    $inactiveicon = "#66D9EF";
-    $inactivetext = "#66D9EF";
-    $loading = "#66D9EF";
-    $hovertext = "#000000";
-
-endif;
-
-if($hasOptions == "Yes") :
-
-    $resulto = $file_db->query('SELECT * FROM options'); 
-    foreach($resulto as $row) : 
-
-        $title = isset($row['title']) ? $row['title'] : "Organizr";
-        $topbartext = isset($row['topbartext']) ? $row['topbartext'] : "#66D9EF";
-        $topbar = isset($row['topbar']) ? $row['topbar'] : "#333333";
-        $bottombar = isset($row['bottombar']) ? $row['bottombar'] : "#333333";
-        $sidebar = isset($row['sidebar']) ? $row['sidebar'] : "#393939";
-        $hoverbg = isset($row['hoverbg']) ? $row['hoverbg'] : "#AD80FD";
-        $activetabBG = isset($row['activetabBG']) ? $row['activetabBG'] : "#F92671";
-        $activetabicon = isset($row['activetabicon']) ? $row['activetabicon'] : "#FFFFFF";
-        $activetabtext = isset($row['activetabtext']) ? $row['activetabtext'] : "#FFFFFF";
-        $inactiveicon = isset($row['inactiveicon']) ? $row['inactiveicon'] : "#66D9EF";
-        $inactivetext = isset($row['inactivetext']) ? $row['inactivetext'] : "#66D9EF";
-        $loading = isset($row['loading']) ? $row['loading'] : "#66D9EF";
-        $hovertext = isset($row['hovertext']) ? $row['hovertext'] : "#000000";
-
-    endforeach;
-
-endif;
+// Load Colours/Appearance
+foreach(loadAppearance() as $key => $value) {
+	${$key} = $value;
+}
 
 $startDate = date('Y-m-d',strtotime("-".CALENDARSTARTDAY." days"));
 $endDate = date('Y-m-d',strtotime("+".CALENDARENDDAY." days")); 
@@ -121,7 +68,7 @@ $endDate = date('Y-m-d',strtotime("+".CALENDARENDDAY." days"));
         <script src="bower_components/slick/slick.js?v=<?php echo INSTALLEDVERSION; ?>"></script>
 
         <script src="js/jqueri_ui_custom/jquery-ui.min.js"></script>
-	       <script src="js/jquery.mousewheel.min.js" type="text/javascript"></script>
+	    <script src="js/jquery.mousewheel.min.js" type="text/javascript"></script>
 		
 		<!--Other-->
 		<script src="js/ajax.js?v=<?php echo INSTALLEDVERSION; ?>"></script>
@@ -131,6 +78,9 @@ $endDate = date('Y-m-d',strtotime("+".CALENDARENDDAY." days"));
         <script src="bower_components/respondJs/dest/respond.min.js"></script>
         <![endif]-->
         <style>
+            .fc-day-grid-event{
+                cursor: pointer;
+            }
             .recentItems {
                 padding-top: 10px;
                 margin: 5px 0;
@@ -494,7 +444,17 @@ $endDate = date('Y-m-d',strtotime("+".CALENDARENDDAY." days"));
                     ?>
                     </div>
                 </div>
-				<?php } ?>
+                <div id="plexPlaylists" class="row">
+                    <div class="col-lg-12">
+                    <?php
+                    if(PLEXPLAYLISTS == "true"){  
+                        echo getPlexPlaylists($plexArray);
+                    } 
+                    ?>
+                    </div>
+                </div>
+                <?php } ?>
+    
 				<?php if (qualifyUser(EMBYHOMEAUTH) && EMBYTOKEN) { ?>
                 <div id="embyRowNowPlaying" class="row">
                     <?php if(EMBYPLAYINGNOW == "true"){ echo getEmbyStreams(12, EMBYSHOWNAMES, $USER->role); } ?>
@@ -528,6 +488,18 @@ $endDate = date('Y-m-d',strtotime("+".CALENDARENDDAY." days"));
                             <span class="label indigo-bg well-sm">Unreleased</span>
                             <span class="label light-blue-bg well-sm">Premier</span>
                         </div>
+                        <!--
+                        <div class="pull-right">
+                            <div class="btn-group" role="group">
+                            <button type="button" class="btn waves btn-default btn-sm dropdown-toggle waves-effect waves-float" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">View All<span class="caret"></span></button>
+                            <ul style="right:0; left: auto" class="dropdown-menu">
+                                <li><a class="" href="javascript:void(0)">Movies</a></li>
+                                <li><a class="" href="javascript:void(0)">TV Shows</a></li>
+                                <li><a class="" href="javascript:void(0)">Music</a></li>
+                            </ul>
+                            </div>
+                        </div>-->
+
                     </div>
                 </div>
                 <div id="calendarRow" class="row">
@@ -545,6 +517,7 @@ $endDate = date('Y-m-d',strtotime("+".CALENDARENDDAY." days"));
         });
 		$('#clearSearch').click(function(e){
             $('#searchInput').val("");
+            $('#resultshere').html("");
             $('#searchInput').focus();
             e.preventDefault();
         });
@@ -574,6 +547,14 @@ $endDate = date('Y-m-d',strtotime("+".CALENDARENDDAY." days"));
 		
         $( document ).ready(function() {
             $('#plexSearchForm').on('submit', function () {
+                var refreshBox = $(this).closest('div.content-box');
+                $("<div class='refresh-preloader'><div class='la-timer la-dark'><div></div></div></div>").appendTo(refreshBox).fadeIn(300);
+                setTimeout(function(){
+                    var refreshPreloader = refreshBox.find('.refresh-preloader'),
+                    deletedRefreshBox = refreshPreloader.fadeOut(300, function(){
+                        refreshPreloader.remove();
+                    });
+                },1000);
                 ajax_request('POST', 'search-plex', {
                     searchtitle: $('#plexSearchForm [name=search-title]').val(),
                 }).done(function(data){ $('#resultshere').html(data);});
@@ -593,93 +574,148 @@ $endDate = date('Y-m-d',strtotime("+".CALENDARENDDAY." days"));
                 var id = $(this).attr("link");
                 $("div[np^='"+id+"']").toggle();
             });
-     
-            $('.recentItems').slick({
-              
-                slidesToShow: 13,
-                slidesToScroll: 13,
-                infinite: true,
-                lazyLoad: 'ondemand',
-                prevArrow: '<a class="zero-m pull-left prev-mail btn btn-default waves waves-button btn-sm waves-effect waves-float"><i class="fa fa-angle-left"></i></a>',
-                nextArrow: '<a class="pull-left next-mail btn btn-default waves waves-button btn-sm waves-effect waves-float"><i class="fa fa-angle-right"></i></a>',
-                appendArrows: '.recentHeader',
-                responsive: [
-                {
-                  breakpoint: 1750,
-                  settings: {
-                    slidesToShow: 12,
-                    slidesToScroll: 12,
-                  }
-                },
-                {
-                  breakpoint: 1600,
-                  settings: {
-                    slidesToShow: 11,
-                    slidesToScroll: 11,
-                  }
-                },
-                {
-                  breakpoint: 1450,
-                  settings: {
-                    slidesToShow: 10,
-                    slidesToScroll: 10,
-                  }
-                },
-                {
-                  breakpoint: 1300,
-                  settings: {
-                    slidesToShow: 9,
-                    slidesToScroll: 9,
-                  }
-                },
-                {
-                  breakpoint: 1150,
-                  settings: {
-                    slidesToShow: 8,
-                    slidesToScroll: 8,
-                  }
-                },
-                {
-                  breakpoint: 1000,
-                  settings: {
-                    slidesToShow: 7,
-                    slidesToScroll: 7,
-                  }
-                },
-                {
-                  breakpoint: 850,
-                  settings: {
-                    slidesToShow: 6,
-                    slidesToScroll: 6,
-                  }
-                },
-                {
-                  breakpoint: 700,
-                  settings: {
-                    slidesToShow: 5,
-                    slidesToScroll: 5,
-                  }
-                },
-                {
-                  breakpoint: 675,
-                  settings: {
-                    slidesToShow: 4,
-                    slidesToScroll: 4
-                  }
-                },
-                {
-                  breakpoint: 480,
-                  settings: {
-                    slidesToShow: 3,
-                    slidesToScroll: 3
-                  }
+
+            $('.recentItems').each(function() {
+                var name = $(this).attr("data-name");
+                console.log(name);
+                $(this).slick({
+                
+                    slidesToShow: 13,
+                    slidesToScroll: 13,
+                    infinite: true,
+                    lazyLoad: 'ondemand',
+                    prevArrow: '<a class="zero-m pull-left prev-mail btn btn-default waves waves-button btn-sm waves-effect waves-float"><i class="fa fa-angle-left"></i></a>',
+                    nextArrow: '<a class="pull-left next-mail btn btn-default waves waves-button btn-sm waves-effect waves-float"><i class="fa fa-angle-right"></i></a>',
+                    appendArrows: $('.'+name),
+                    arrows: true,
+                    responsive: [
+                    {
+                    breakpoint: 1750,
+                    settings: {
+                        slidesToShow: 12,
+                        slidesToScroll: 12,
+                    }
+                    },
+                    {
+                    breakpoint: 1600,
+                    settings: {
+                        slidesToShow: 11,
+                        slidesToScroll: 11,
+                    }
+                    },
+                    {
+                    breakpoint: 1450,
+                    settings: {
+                        slidesToShow: 10,
+                        slidesToScroll: 10,
+                    }
+                    },
+                    {
+                    breakpoint: 1300,
+                    settings: {
+                        slidesToShow: 9,
+                        slidesToScroll: 9,
+                    }
+                    },
+                    {
+                    breakpoint: 1150,
+                    settings: {
+                        slidesToShow: 8,
+                        slidesToScroll: 8,
+                    }
+                    },
+                    {
+                    breakpoint: 1000,
+                    settings: {
+                        slidesToShow: 7,
+                        slidesToScroll: 7,
+                    }
+                    },
+                    {
+                    breakpoint: 850,
+                    settings: {
+                        slidesToShow: 6,
+                        slidesToScroll: 6,
+                    }
+                    },
+                    {
+                    breakpoint: 700,
+                    settings: {
+                        slidesToShow: 5,
+                        slidesToScroll: 5,
+                    }
+                    },
+                    {
+                    breakpoint: 675,
+                    settings: {
+                        slidesToShow: 4,
+                        slidesToScroll: 4
+                    }
+                    },
+                    {
+                    breakpoint: 480,
+                    settings: {
+                        slidesToShow: 3,
+                        slidesToScroll: 3
+                    }
+                    }
+                    // You can unslick at a given breakpoint now by adding:
+                    // settings: "unslick"
+                    // instead of a settings object
+                ]
+                });
+            });
+
+            
+            // each filter we click on
+            $(".filter-recent-event > li").on("click", function() {
+                
+            // toggle the filter on/off
+            $(this).data( "filter-on" , !$(this).data("filter-on") );
+            
+            // set all the filter strings to empty
+            var filtersOn = "";
+            var filtersOff = "";
+            var allFilters = "";
+            
+            // loop through each filter
+            $(".filter-recent-event > li").each(function() {
+                
+                // set a variable to hold the value of the filter class
+                // and also if the filter is on/off
+                var filter = $(this).data("filter");
+                var isOn = $(this).data("filter-on");
+
+                // add the filter to the filtersOn / filtersOff collection
+                if( isOn ) {
+                    filtersOn += "." + filter + ", ";
+                } else {
+                    filtersOff += "." + filter + ", ";
                 }
-                // You can unslick at a given breakpoint now by adding:
-                // settings: "unslick"
-                // instead of a settings object
-              ]
+
             });
             
+            // remove the last ", " from each filter collection.
+            filtersOn = filtersOn.replace(/, $/, "");
+            filtersOff = filtersOff.replace(/, $/, "");
+            
+            // remove all filters if none are on.
+            if( filtersOn === "" ) {
+                filtersOn = "*";
+                filtersOff = "";
+            }
+            
+            // combine the filters together ( on + off )
+            allFilters = filtersOn + ":not(" + filtersOff + ")";
+            console.log( allFilters );
+            
+            // now filter the slides.
+            $('.recentItems ')
+                .slick('slickUnfilter')
+                .slick('slickFilter' , allFilters );
+
+            });
+            /*
             var movieFiltered = false;
             var seasonFiltered = false;
             var albumFiltered = false;
@@ -718,7 +754,7 @@ $endDate = date('Y-m-d',strtotime("+".CALENDARENDDAY." days"));
                 $(this).text('Hide Music');
                 albumFiltered = false;
               }
-            });
+            });*/
             
             /*$('.w-refresh').click(function(e){
                 var moreInfo = $(this).closest('div.overlay').addClass("show");
@@ -745,8 +781,8 @@ $endDate = date('Y-m-d',strtotime("+".CALENDARENDDAY." days"));
             // check if browser support HTML5 local storage
 			
             <?php if((NZBGETURL != "" && qualifyUser(NZBGETHOMEAUTH)) || (SABNZBDURL != "" && qualifyUser(SABNZBDHOMEAUTH))){ ?>
-            var queueRefresh = 30000;
-            var historyRefresh = 120000; // This really doesn't need to happen that often
+            var queueRefresh = <?php echo DOWNLOADREFRESH; ?>;
+            var historyRefresh = <?php echo HISTORYREFRESH; ?>; // This really doesn't need to happen that often
 
             var queueLoad = function() {
             <?php if(SABNZBDURL != "") { echo '$("tbody.dl-queue.sabnzbd").load("ajax.php?a=sabnzbd-update&list=queue");'; } ?>
@@ -800,10 +836,37 @@ $endDate = date('Y-m-d',strtotime("+".CALENDARENDDAY." days"));
                         today: { buttonText: '<?php echo $language->translate("TODAY");?>' },
                     },
                     events: [
-<?php if (SICKRAGEURL != "" && qualifyUser(SICKRAGEHOMEAUTH)){ echo getSickrageCalendarWanted($sickrage->future()); echo getSickrageCalendarHistory($sickrage->history("100","downloaded")); } ?>
-<?php if (SONARRURL != "" && qualifyUser(SONARRHOMEAUTH)){ echo getSonarrCalendar($sonarr->getCalendar($startDate, $endDate)); } ?>
-<?php if (RADARRURL != "" && qualifyUser(RADARRHOMEAUTH)){ echo getRadarrCalendar($radarr->getCalendar($startDate, $endDate)); } ?>                 
-<?php if (HEADPHONESURL != "" && qualifyUser(HEADPHONESHOMEAUTH)){ echo getHeadphonesCalendar(HEADPHONESURL, HEADPHONESKEY, "getHistory"); echo getHeadphonesCalendar(HEADPHONESURL, HEADPHONESKEY, "getWanted"); } ?>                                
+<?php 
+if (SICKRAGEURL != "" && qualifyUser(SICKRAGEHOMEAUTH)){
+	try { 
+		echo getSickrageCalendarWanted($sickrage->future());
+	} catch (Exception $e) { 
+		writeLog("error", "SICKRAGE/BEARD ERROR: ".strip($e->getMessage())); 
+	} try { 
+		echo getSickrageCalendarHistory($sickrage->history("100","downloaded"));
+	} catch (Exception $e) { 
+		writeLog("error", "SICKRAGE/BEARD ERROR: ".strip($e->getMessage())); 
+	}
+}
+if (SONARRURL != "" && qualifyUser(SONARRHOMEAUTH)){
+	try {
+		echo getSonarrCalendar($sonarr->getCalendar($startDate, $endDate)); 
+	} catch (Exception $e) { 
+		writeLog("error", "SONARR ERROR: ".strip($e->getMessage())); 
+	}
+}
+if (RADARRURL != "" && qualifyUser(RADARRHOMEAUTH)){ 
+	try { 
+		echo getRadarrCalendar($radarr->getCalendar($startDate, $endDate)); 
+	} catch (Exception $e) { 
+		writeLog("error", "RADARR ERROR: ".strip($e->getMessage())); 
+	}
+}
+if (HEADPHONESURL != "" && qualifyUser(HEADPHONESHOMEAUTH)){
+	echo getHeadphonesCalendar(HEADPHONESURL, HEADPHONESKEY, "getHistory"); 
+	echo getHeadphonesCalendar(HEADPHONESURL, HEADPHONESKEY, "getWanted"); 
+
+}?>                                
                     ],
                     eventRender: function eventRender( event, element, view ) {
                         return ['all', event.imagetype].indexOf($('#imagetype_selector').val()) >= 0
@@ -817,17 +880,208 @@ $endDate = date('Y-m-d',strtotime("+".CALENDARENDDAY." days"));
             $('#imagetype_selector').on('change',function(){
                 $('#calendar').fullCalendar('rerenderEvents');
             })
-            var $divs = $("div.row");
-
-            $('#numBnt').on('click', function () {
-                var numericallyOrderedDivs = $divs.sort(function (a, b) {
-                    return $(a).find("sort").text() > $(b).find("sort").text();
+        </script>
+        <?php } ?>
+        <script>
+            function convertTime(a){
+                if(a){
+                    var hours = Math.trunc(a/60);
+                    var minutes = a % 60;
+                    return hours+"h "+minutes+"m";
+                }else{
+                    return "N/A";
+                }
+            }
+            function convertArray(a, type){
+                var result = "";
+                var count = 1;
+                var color = "";
+                $.each( a, function( key, value ) {
+                    if (count == 1){ color = "gray"; }else{ color = "gray"; }
+                    if(type == "MOVIE"){
+                        result += '<span class="label label-'+color+'">'+value['name']+'</span>&nbsp;';
+                    }else if(type == "TV"){
+                        result += '<span class="label label-'+color+'">'+value+'</span>&nbsp;';
+                    }
+                    count++;
                 });
-                $("#content").html(numericallyOrderedDivs);
+                return result;
+            }
+            function convertTrailer(a){
+                var result = "";
+                var count = 1;
+                $.each( a.results, function( key, value ) {
+                    if (count == 1){
+                        result += '<span id="openTrailer" style="cursor:pointer;width: 100%;display: block;" data-key="'+value['key']+'" data-name="'+value['name']+'" data-site="'+value['site']+'" class="label label-danger"><i class="fa fa-youtube-play" aria-hidden="true"></i> &nbsp;Watch Trailer</span>&nbsp;';
+                    }
+                    count++;
+                });
+                return result;
+            }
+            function convertCast(a){
+                var result = "";
+                var count = 1;
+                $.each( a.cast, function( key, value ) {
+                    if( value['profile_path'] ){
+                        if (count <= 6){
+                            result += '<div class="col-lg-2 col-xs-2"><div class="zero-m"><img style="border-radius:10%;margin-left: auto;margin-right: auto;display: block;" height="50px" src="https://image.tmdb.org/t/p/w150'+value['profile_path']+'" alt="profile"><h5 class="text-center"><strong>'+value['name']+'</strong></h5><h6 class="text-center">'+value['character']+'</h6></div></div>';
+                            count++;
+                        }
+                    }
+                });
+                return result;
+            }
+            function whatIsIt(a){
+                var what = Object.prototype.toString;
+                if(what.call(a) == "[object Array]"){
+                    return a[0].fileName;
+                }else if(what.call(a) == "[object Object]"){
+                    return a.fileName;
+                }
+            }
+            function whatWasIt(a){
+                var what = Object.prototype.toString;
+                if(what.call(a) == "[object Array]"){
+                    return a[0];
+                }else if(what.call(a) == "[object Object]"){
+                    return a;
+                }
+            }
+            $(document).on('click', "#openTrailer", function(){
+                var key = $(this).attr("data-key");
+                $('#iFrameYT').html('<iframe id="calendarYoutube" class="embed-responsive-item" src="https://www.youtube.com/embed/'+key+'" allowfullscreen=""></iframe>');
+                $('#calendarVideo').modal('show');
+            });
+            $(document).on('click', "a[class*=ID-]", function(){
+                $('#calendarExtra').modal('show');
+                var refreshBox = $('#calendarMainID');
+                $("<div class='refresh-preloader'><div class='la-timer la-dark'><div></div></div></div>").appendTo(refreshBox).fadeIn(300);
+                setTimeout(function(){
+                    var refreshPreloader = refreshBox.find('.refresh-preloader'),
+                    deletedRefreshBox = refreshPreloader.fadeOut(300, function(){
+                        refreshPreloader.remove();
+                    });
+                },300);
+                var check = $(this).attr("class");
+                var ID = check.split("--")[1];
+                if (~check.indexOf("tvID")){
+                    var type = "TV";
+                    ajax_request('POST', 'tvdb-get', {
+                        id: ID,
+                    }).done(function(data){ 
+                        if( data.trakt ) {                        
+                            $.ajax({
+                                type: 'GET',
+                                url: 'https://api.themoviedb.org/3/tv/'+data.trakt.tmdb+'?api_key=83cf4ee97bb728eeaf9d4a54e64356a1&append_to_response=videos,credits',
+                                cache: true,
+                                async: true,
+                                complete: function(xhr, status) {
+                                    var result = $.parseJSON(xhr.responseText);
+                                    if (xhr.statusText === "OK") {
+                                        console.log(result);
+                                        $('#calendarTitle').text(result.name);
+                                        $('#calendarRating').html('<span class="label label-gray"><i class="fa fa-thumbs-up white"></i> '+result.vote_average+'</span>&nbsp;');
+                                        $('#calendarRuntime').html('<span class="label label-gray"><i class="fa fa-clock-o white"></i> '+convertTime(whatWasIt(result.episode_run_time))+'</span>&nbsp;');
+                                        $('#calendarSummary').text(result.overview);
+                                        $('#calendarTagline').text("");
+                                        $('#calendarTrailer').html(convertTrailer(result.videos));
+                                        $('#calendarCast').html(convertCast(result.credits));
+                                        $('#calendarGenres').html(convertArray(result.genres, "MOVIE"));
+                                        $('#calendarLang').html(convertArray(result.languages, "TV"));
+                                        $('#calendarPoster').attr("src","https://image.tmdb.org/t/p/w300"+result.poster_path);
+                                        $('#calendarMain').attr("style","background-image: url(https://image.tmdb.org/t/p/w1000"+result.backdrop_path+");background-position: center;-webkit-filter: brightness(50%) contrast(100%);filter: brightness(50%) contrast(100%);top: 0;left: 0;width: 100%;height: 100%;position: fixed;");
+                                        $('#calendarExtra').modal('show');
+                                    }
+                                }
+                            });
+                        }else{
+                           $('#calendarTitle').text(data.series.seriesName);
+                            $('#calendarRating').html('<span class="label label-gray"><i class="fa fa-thumbs-up white"></i> '+data.series.siteRating+'</span>&nbsp');
+                            $('#calendarRuntime').html('<span class="label label-gray"><i class="fa fa-clock-o white"></i> '+convertTime(data.series.runtime)+'</span>&nbsp;');
+                            $('#calendarSummary').text(data.series.overview);
+                            $('#calendarTagline').text("");
+                            $('#calendarTrailer').html("");
+                            $('#calendarCast').html("");
+                            $('#calendarGenres').html(convertArray(data.series.genre, "TV"));
+                            $('#calendarLang').html("");
+                            $('#calendarPoster').attr("src","https://thetvdb.com/banners/_cache/"+whatIsIt(data.poster));
+                            $('#calendarMain').attr("style","background-size: 1000px 563px; background-image: url(ajax.php?a=show-image&image=http://thetvdb.com/banners/"+whatIsIt(data.backdrop)+");background-position: center;-webkit-filter: brightness(50%) contrast(100%);filter: brightness(50%) contrast(100%);top: 0;left: 0;width: 100%;height: 100%;position: fixed;");
+                            $('#calendarExtra').modal('show');
+                        }
+                    });
+                }else if (~check.indexOf("movieID")){
+                    var type = "MOVIE";
+                    $.ajax({
+                        type: 'GET',
+                        url: 'https://api.themoviedb.org/3/movie/'+ID+'?api_key=83cf4ee97bb728eeaf9d4a54e64356a1&append_to_response=videos,credits',
+                        cache: true,
+                        async: true,
+                        complete: function(xhr, status) {
+                            var result = $.parseJSON(xhr.responseText);
+                            console.log(result);
+                            console.log(convertCast(result.credits));
+                            if (xhr.statusText === "OK") {
+                                $('#calendarTitle').text(result.title);
+                                $('#calendarRating').html('<span class="label label-gray"><i class="fa fa-thumbs-up white"></i> '+result.vote_average+'</span>&nbsp;');
+                                $('#calendarRuntime').html('<span class="label label-gray"><i class="fa fa-clock-o white"></i> '+convertTime(result.runtime)+'</span>&nbsp;');
+                                $('#calendarSummary').text(result.overview);
+                                $('#calendarTagline').text(result.tagline);
+                                $('#calendarTrailer').html(convertTrailer(result.videos));
+                                $('#calendarCast').html(convertCast(result.credits));
+                                $('#calendarGenres').html(convertArray(result.genres, "MOVIE"));
+                                $('#calendarLang').html(convertArray(result.spoken_languages, "MOVIE"));
+                                $('#calendarPoster').attr("src","https://image.tmdb.org/t/p/w300"+result.poster_path);
+                                $('#calendarMain').attr("style","background-image: url(https://image.tmdb.org/t/p/w1000"+result.backdrop_path+");background-position: center;-webkit-filter: brightness(50%) contrast(100%);filter: brightness(50%) contrast(100%);top: 0;left: 0;width: 100%;height: 100%;position: fixed;");
+                                $('#calendarExtra').modal('show');
+                            }
+                        }
+                    });
+                }
             });
         </script>
-        <?php } ?>
+        <div id="calendarExtra" class="modal fade in" tabindex="-1" role="dialog">
+            <div class="modal-dialog modal-lg gray-bg" role="document">
+                <div id="calendarMainID" class="modal-content">
+                    <div class="modal-content" id="calendarMain"></div>
+                    <div style="position: inherit; padding: 15px">
+                        <span id="calendarRuntime" class="pull-left"></span>
+                        <span id="calendarRating" class="pull-left"></span>
+                        <span id="calendarGenres" class="pull-right"></span>
+                    </div>
+                    <div class="modal-body">
+                        <div class="row">
+                            <div class="col-lg-2 col-xs-4">
+                                <img style="width:100%;border-radius: 10px;box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);" id="calendarPoster" src="">
+                            </div>
+                            <div class="col-lg-10 col-sm-8">
+                                <h2 id="calendarTitle" class="modal-title text-center">Modal title</h2>
+                                <h6 id="calendarTagline" class="modal-title text-center"><em>Modal title</em></h6>
+                                <p id="calendarSummary">Modal Summary</p>
+                                <div class="" id="calendarCast">Modal Summary</div>
+                            </div>
+                        </div>
+                    </div>
+                   <div style="position: inherit; padding: 15px 0px 30px 0px; margin-top: -20px;">
+                        <div class="col-lg-2 col-xs-4">
+                            <span id="calendarTrailer" class="pull-left" style="width:100%"></span>
+                        </div> 
+                        <div class="col-lg-10 col-sm-8">   
+                            <span id="calendarLang" class="pull-right"></span>
+                        </div>                        
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div id="calendarVideo" class="modal fade in palette-Grey-900 bg" tabindex="-1" role="dialog">
+            <div class="modal-dialog modal-lg gray-bg" role="document">
+                <div id="calendarMainVideo" class="modal-content gray-bg">
+                    <div class="">
+                        <!-- 16:9 aspect ratio -->
+                        <div id="iFrameYT" class="embed-responsive embed-responsive-16by9 gray-bg"></div>
+                    </div>
+                </div>
+            </div>
+        </div>
 
     </body>
-
-</html>
+</html>

binární
images/ellipsis.png


binární
images/guacamole.png


binární
images/livetv.png


binární
images/pf-blue.png


binární
images/pfsense.png


+ 24 - 16
index.php

@@ -8,6 +8,11 @@ upgradeCheck();
 // Lazyload settings
 $databaseConfig = configLazy('config/config.php');
 
+// Load Colours/Appearance
+foreach(loadAppearance() as $key => $value) {
+	$$key = $value;
+}
+
 //Set some variables
 ini_set("display_errors", 1);
 ini_set("error_reporting", E_ALL | E_STRICT);
@@ -19,7 +24,7 @@ $hasOptions = "No";
 $settingsicon = "No";
 $settingsActive = "";
 $action = "";
-$title = "Organizr";
+/*$title = "Organizr";
 $topbar = "#333333"; 
 $topbartext = "#66D9EF";
 $bottombar = "#333333";
@@ -31,7 +36,7 @@ $activetabtext = "#FFFFFF";
 $inactiveicon = "#66D9EF";
 $inactivetext = "#66D9EF";
 $loading = "#66D9EF";
-$hovertext = "#000000";
+$hovertext = "#000000";*/
 $loadingIcon = "images/organizr-load-w-thick.gif";
 $baseURL = "";
 
@@ -65,6 +70,10 @@ if(!file_exists('config/config.php')) {
 
 if (file_exists('config/config.php')) {
 
+    if (!DATABASE_LOCATION){
+		die(header("Refresh:0"));
+	}
+
     $configReady = "Yes";
 
     require_once("user.php");
@@ -143,7 +152,7 @@ if (file_exists('config/config.php')) {
 
     endif;
 
-    if($hasOptions == "Yes") :
+    /*if($hasOptions == "Yes") :
 
         $resulto = $file_db->query('SELECT * FROM options');
 
@@ -165,7 +174,7 @@ if (file_exists('config/config.php')) {
 
         endforeach;
 
-    endif;
+    endif;*/
 
     $userpic = md5( strtolower( trim( $USER->email ) ) );
     if(LOADINGICON !== "") : $loadingIcon = LOADINGICON; endif;
@@ -286,12 +295,12 @@ if(file_exists("images/settings2.png")) : $iconRotate = "false"; $settingsIcon =
 
         }.bottom-bnts {
 
-            background-color: <?=$bottombar;?> !important;
+            background: <?=$bottombar;?> !important;
 
         }.gn-menu-main {
 
 
-            background-color: <?=$topbar;?>;
+            background: <?=$topbar;?>;
 
         }.gn-menu-main ul.gn-menu {
 
@@ -364,7 +373,7 @@ if(file_exists("images/settings2.png")) : $iconRotate = "false"; $settingsIcon =
             background-size: 0 2px,100% 1px;
             background-repeat: no-repeat;
             background-position: center bottom,center calc(100% - 1px);
-            background-color: transparent;
+            background: transparent;
             box-shadow: none;
 
         }.gn-menu li.active i.fa {
@@ -393,7 +402,7 @@ if(file_exists("images/settings2.png")) : $iconRotate = "false"; $settingsIcon =
 
         }div#preloader {
 
-            background-color: <?=$loading;?>;
+            background: <?=$loading;?>;
 
         }.iframe {
 
@@ -1037,7 +1046,7 @@ if(file_exists("images/settings2.png")) : $iconRotate = "false"; $settingsIcon =
             </div>
         </div>
         <?php endif; endif;?>
-		<?php if ($inviteCode){ ?>
+		<?php if(isset($_GET['inviteCode'])){ ?>
 		<div id="inviteSet" class="login-modal modal fade">
 			<div style="background:<?=$sidebar;?>;" class="table-wrapper">
 				<div class="table-row">
@@ -1215,7 +1224,6 @@ if(file_exists("images/settings2.png")) : $iconRotate = "false"; $settingsIcon =
             User.processRegistration();
         });
         $("#editInfo").click(function(){
-
             $( "div[id^='editInfoDiv']" ).toggle();
             $( "div[id^='buttonsDiv']" ).toggle();
         });
@@ -1276,11 +1284,10 @@ if(file_exists("images/settings2.png")) : $iconRotate = "false"; $settingsIcon =
             	cta(e1, e2, {relativeToWindow: true}, function () {
                 $('.login-modal').modal("show");
             });
-
             e.preventDefault();
         });
 		//InviteCode
-		<?php if($inviteCode){ ?>
+		<?php if(isset($_GET['inviteCode'])){ ?>
 		$('#inviteSet').modal("show");	
 		<?php } ?>
 
@@ -1403,6 +1410,7 @@ if(file_exists("images/settings2.png")) : $iconRotate = "false"; $settingsIcon =
             $("li[class^='tab-item active']").first().find("img").addClass("TabOpened");
             if (defaultTab){
                 defaultTab = defaultTab.substr(0, defaultTab.length-1);
+                console.log(defaultTab);
             }else{
                 defaultTabNone = $("li[class^='tab-item']").attr("id");
                 if (defaultTabNone){
@@ -1413,8 +1421,8 @@ if(file_exists("images/settings2.png")) : $iconRotate = "false"; $settingsIcon =
             }
 
             if (defaultTab){
-
-                $("#content").html('<div class="iframe active" data-content-url="'+defaultTab+'"><iframe scrolling="auto" sandbox="allow-forms allow-same-origin allow-pointer-lock allow-scripts allow-popups allow-modals allow-top-navigation" allowfullscreen="true" webkitallowfullscreen="true" mozallowfullscreen="true" frameborder="0" style="width:100%; height:100%; position: absolute;" src="'+defaultTab+'"></iframe></div>');
+                defaultTabName = $("li[class^='tab-item active']").attr("name");
+                $("#content").html('<div class="iframe active" data-content-name="'+defaultTabName+'" data-content-url="'+defaultTab+'"><iframe scrolling="auto" sandbox="allow-presentation allow-forms allow-same-origin allow-pointer-lock allow-scripts allow-popups allow-modals allow-top-navigation" allowfullscreen="true" webkitallowfullscreen="true" mozallowfullscreen="true" frameborder="0" style="width:100%; height:100%; position: absolute;" src="'+defaultTab+'"></iframe></div>');
                 document.getElementById('main-wrapper').focus();
             }
             if (defaultTab == null){
@@ -1605,7 +1613,7 @@ if(file_exists("images/settings2.png")) : $iconRotate = "false"; $settingsIcon =
 
                     $("#content div[class^='iframe active']").attr("class", "iframe hidden");
 
-                    $( '<div class="iframe active" data-content-name="'+thisname+'" data-content-url="'+thisid+'"><iframe scrolling="auto" sandbox="allow-forms allow-same-origin allow-pointer-lock allow-scripts allow-popups allow-modals allow-top-navigation" allowfullscreen="true" webkitallowfullscreen="true" frameborder="0" style="width:100%; height:100%; position: absolute;" src="'+thisid+'"></iframe></div>' ).appendTo( "#content" );
+                    $( '<div class="iframe active" data-content-name="'+thisname+'" data-content-url="'+thisid+'"><iframe scrolling="auto" sandbox="allow-presentation allow-forms allow-same-origin allow-pointer-lock allow-scripts allow-popups allow-modals allow-top-navigation" allowfullscreen="true" webkitallowfullscreen="true" frameborder="0" style="width:100%; height:100%; position: absolute;" src="'+thisid+'"></iframe></div>' ).appendTo( "#content" );
                     document.title = thistitle;
                    // window.location.href = '#' + thisname;
 
@@ -1660,7 +1668,7 @@ if(file_exists("images/settings2.png")) : $iconRotate = "false"; $settingsIcon =
 
                     $("#contentRight div[class^='iframe active']").attr("class", "iframe hidden");
 
-                    $( '<div class="iframe active" data-content-name="'+thisname+'" data-content-url="'+thisid+'"><iframe scrolling="auto" sandbox="allow-forms allow-same-origin allow-pointer-lock allow-scripts allow-popups allow-modals allow-top-navigation" allowfullscreen="true" webkitallowfullscreen="true" frameborder="0" style="width:100%; height:100%; position: absolute;" src="'+thisid+'"></iframe></div>' ).appendTo( "#contentRight" );
+                    $( '<div class="iframe active" data-content-name="'+thisname+'" data-content-url="'+thisid+'"><iframe scrolling="auto" sandbox="allow-presentation allow-forms allow-same-origin allow-pointer-lock allow-scripts allow-popups allow-modals allow-top-navigation" allowfullscreen="true" webkitallowfullscreen="true" frameborder="0" style="width:100%; height:100%; position: absolute;" src="'+thisid+'"></iframe></div>' ).appendTo( "#contentRight" );
                     document.title = thistitle;
                     window.location.href = '#' + thisname;
 

+ 0 - 3
js/custom.js

@@ -88,11 +88,8 @@ $(document).ready(function(){
 			beforeSend: function(){},
 			success: function(data, itemEl, listEl, boxEl, newInputEl, inputEl, id){
 				var parent = itemEl.find(".jFiler-jProgressBar").parent(),
-					new_file_name = JSON.parse(data),
 					filerKit = inputEl.prop("jFiler");
 
-        		filerKit.files_list[id].name = new_file_name;
-
 				itemEl.find(".jFiler-jProgressBar").fadeOut("slow", function(){
 					$("<div class=\"jFiler-item-others text-success\"><i class=\"fa fa-check\"></i> Success</div>").hide().appendTo(parent).fadeIn("slow");
 				});

+ 55 - 27
lang/de.ini

@@ -195,7 +195,7 @@ WEEK = "Woche"
 NZBGET_URL = "NZBGet URL"
 NZBGET_PORT = "NZBGet Port"
 QUEUE = "Warteschlange"
-HISTORY = "Historie"
+HISTORY = "Verlauf"
 FILE = "Datei"
 STATUS = "Status"
 CATEGORY = "Kategorie"
@@ -223,34 +223,34 @@ SMTP_HOST_SENDER_EMAIL = "SMTP Absendeadresse"
 EMBY_URL = "Emby URL"
 EMBY_PORT = "Emby Port"
 EMBY_TOKEN = "Emby Token"
-PLAYING_NOW_ON_EMBY = "Playing Now on EMBY"
-RECENTLY_ADDED_TO_EMBY = "Recently Added to EMBY"
-AUTHTYPE = "Which databases should be used to allow login"
-AUTHBACKEND = "Select backend to use"
-AUTHBACKENDCREATE = "Should accounts be created in Organizr if successfully authenticated against backend"
+PLAYING_NOW_ON_EMBY = "Aktuell läuft auf EMBY"
+RECENTLY_ADDED_TO_EMBY = "Zuletzt zu EMBY hinzugefügt"
+AUTHTYPE = "Welche Datenbank zum Anmelden genutzt werden sollte"
+AUTHBACKEND = "Zu nutzendes Backend auswählen"
+AUTHBACKENDCREATE = "Sollten Konten in Organizr angelegt werden, wenn Authentifizierung im Backend erfolgt ist"
 AUTHBACKENDHOST = "http(s)://192.168.1.100"
-AUTHBACKENDPORT = "Backend Port (eg 21 for FTP, 389 for LDAP, 8096 for Emby)"
-AUTHBACKENDDOMAIN = "Domain to use for LDAP"
-PLEX_USERNAME = "Plex Username"
-PLEX_PASSWORD = "Plex Password"
-BOTH = "Plus Other"
-ONLY = "Only"
-NO_CREATE = "Do Not Create Accounts"
-YES_CREATE = "Create Accounts As Needed"
-RECENT_CONTENT = "Recently Added Content"
-SETTINGS_SAVED = "Settings have been Saved"
-SETTINGS_NOT_SAVED = "Settings could not be saved"
-CALTIMEFORMAT = "Select time format"
-SHOW_HOMEPAGE = "Minimum authentication level to access homepage"
-SHOW_ON_HOMEPAGE = "Minimum authentication level for homepage"
-CUSTOMHTML = "Custom HTML"
+AUTHBACKENDPORT = "Backend Port (bspw. 21 für FTP, 389 für LDAP, 8096 für Emby)"
+AUTHBACKENDDOMAIN = "Domäne für LDAP"
+PLEX_USERNAME = "Plex Benutzername"
+PLEX_PASSWORD = "Plex Passwort"
+BOTH = "und weitere"
+ONLY = "nur"
+NO_CREATE = "Keine Konten anlegen"
+YES_CREATE = "Konten, wenn nötig, anlegen"
+RECENT_CONTENT = "Zuletzt hinzugefügte Inhalte"
+SETTINGS_SAVED = "Einstellungen gespeichert"
+SETTINGS_NOT_SAVED = "Einstellungen konnten nicht gespeichert werden"
+CALTIMEFORMAT = "Zeitformat wählen"
+SHOW_HOMEPAGE = "Mindestauthentifizierungslevel um Homepage abzurufen"
+SHOW_ON_HOMEPAGE = "Mindestauthentifizierungslevel für Homepage"
+CUSTOMHTML = "Eigenes HTML"
 TAB_NAME = "Tab Name"
-NEW_TAB = "New Tab"
-REMOVE = "Remove"
-GIT_BRANCH = "Github branch to use when force installing (Leave this alone unless you are beta testing)"
-GIT_CHECK = "Check for new 'master' releases"
-GIT_FORCE = "Force Install Branch"
-GIT_FORCE_CONFIRM = "Are you sure you want to install this branch? Going from a newer version to an older verison is not recommended or supported."
+NEW_TAB = "Neuer Tab"
+REMOVE = "Entfernen"
+GIT_BRANCH = "Github Branch, die zur erzwungenen Installation genutz wird (nur zum Beta-Testen ändern)"
+GIT_CHECK = "Auf neues 'master' Release prüfen"
+GIT_FORCE = "Installation der Branch erzwingen"
+GIT_FORCE_CONFIRM = "Sicher diese Branch installieren? Von neuen auf alte Versionen zu wechseln wird weder empfohlen, noch unterstützt."
 SPEED_TEST = "Speed Test"
 NOTICE_COLOR = "Notice Color"
 NOTICE_TITLE = "Notice Title"
@@ -284,3 +284,31 @@ USED_BY = "Used By"
 ACCOUNT_MADE = "PLEX Account is now created, Click Join now"
 USERNAME_NAME = "Username or Name"
 ACCOUNT_SUBMITTED = "PLEX Invite Sent|1. Check Email and Accept Invite|2. Close This Modal with Small 'x' on Top Right|3. Sign in"
+PLEX_TAB_NAME = "PLEX Tab Name [only use this if your PLEX URL above is a sub-domain - i.e. https://plex.domain.com]"
+IPINFO_TOKEN = "Get Token from https://ipinfo.io/account/registration as Default will expire"
+GET_PLEX_TOKEN = "Get PLEX Token"
+EMAIL_INVITE_HEADER = "Join My|Server"
+EMAIL_INVITE_TITLE = "LOOK WHO JUST GOT AN INVITE"
+EMAIL_INVITE_MESSAGE = "Here is an invite to join my|server.  The code to join is:"
+EMAIL_INVITE_BUTTON = "JOIN MY|SERVER"
+EMAIL_INVITE_SUBTITLE = "What do I do?"
+EMAIL_INVITE_SUBMESSAGE = "You can click the link above to have it auto fill in the code for you or you could follow this link here:|to take you to my site to fill in the code."
+EMAIL_RESET_HEADER = "Reset Password"
+EMAIL_RESET_TITLE = "LOOK WHO FORGOT THEIR PASSWORD"
+EMAIL_RESET_MESSAGE = "So, you forgot your password huh?  That sucks...  Don't worry, I got you covered.  Here is your new password, it may be freaking long but all you have to do is copy and login to change your password.  Super-Long-New-Password:"
+EMAIL_RESET_BUTTON = "Login"
+EMAIL_RESET_SUBTITLE = "What do I do?"
+EMAIL_RESET_SUBMESSAGE = "You can click the link above to go to my site to login.  Once logged in, click on your image or user icon on top right and change your password."
+EMAIL_NEWUSER_HEADER = "New User"
+EMAIL_NEWUSER_TITLE = "LOOK WHO JUST JOINED THE COOL CLUB"
+EMAIL_NEWUSER_MESSAGE = "Welcome, to my website.  I have many things here... many, many, many shiny things.  Have a look around :)"
+EMAIL_NEWUSER_BUTTON = "Login"
+EMAIL_NEWUSER_SUBTITLE = "What do I do?"
+EMAIL_NEWUSER_SUBMESSAGE = "Now that you have signed up, you can basically do whatever you like.  Enjoy"
+PLAYLISTS = "Playlists"
+DOWNLOAD_REFRESH = "Refresh Download Queue"
+HISTORY_REFRESH = "Refresh History"
+CHECK_FRAME = "Test Frame"
+GENERATE_API_KEY = "Generate API Key"
+ORGANIZR_API_KEY = "Organizr API Key"
+TEST_EMAIL = "Send Test E-Mail"

+ 31 - 3
lang/en.ini

@@ -177,8 +177,8 @@ PLEX_TOKEN = "Plex Token"
 RECENT_MOVIES = "Recent Movies"
 RECENT_TV = "Recent TV"
 RECENT_MUSIC = "Recent Music"
-PLAYING_NOW = "Playing Now"
-PLAYING_NOW_ON_PLEX = "Playing Now on PLEX"
+PLAYING_NOW = "Now Playing"
+PLAYING_NOW_ON_PLEX = "Now Playing on PLEX"
 RECENTLY_ADDED_TO_PLEX = "Recently Added to PLEX"
 MOVIES = "Recent Movies"
 TV_SHOWS = "Recent TV Shows"
@@ -223,7 +223,7 @@ SMTP_HOST_SENDER_EMAIL = "SMTP Sender Email"
 EMBY_URL = "Emby URL"
 EMBY_PORT = "Emby Port"
 EMBY_TOKEN = "Emby Token"
-PLAYING_NOW_ON_EMBY = "Playing Now on EMBY"
+PLAYING_NOW_ON_EMBY = "Now Playing on EMBY"
 RECENTLY_ADDED_TO_EMBY = "Recently Added to EMBY"
 AUTHTYPE = "Which databases should be used to allow login"
 AUTHBACKEND = "Select backend to use"
@@ -284,3 +284,31 @@ USED_BY = "Used By"
 ACCOUNT_MADE = "PLEX Account is now created, Click Join now"
 USERNAME_NAME = "Username or Name"
 ACCOUNT_SUBMITTED = "PLEX Invite Sent|1. Check Email and Accept Invite|2. Close This Modal with Small 'x' on Top Right|3. Sign in"
+PLEX_TAB_NAME = "PLEX Tab Name [only use this if your PLEX URL above is a sub-domain - i.e. https://plex.domain.com]"
+IPINFO_TOKEN = "Get Token from https://ipinfo.io/account/registration as Default will expire"
+GET_PLEX_TOKEN = "Get PLEX Token"
+EMAIL_INVITE_HEADER = "Join My|Server"
+EMAIL_INVITE_TITLE = "LOOK WHO JUST GOT AN INVITE"
+EMAIL_INVITE_MESSAGE = "Here is an invite to join my|server.  The code to join is:"
+EMAIL_INVITE_BUTTON = "JOIN MY|SERVER"
+EMAIL_INVITE_SUBTITLE = "What do I do?"
+EMAIL_INVITE_SUBMESSAGE = "You can click the link above to have it auto fill in the code for you or you could follow this link here:|to take you to my site to fill in the code."
+EMAIL_RESET_HEADER = "Reset Password"
+EMAIL_RESET_TITLE = "LOOK WHO FORGOT THEIR PASSWORD"
+EMAIL_RESET_MESSAGE = "So, you forgot your password huh?  That sucks...  Don't worry, I got you covered.  Here is your new password, it may be freaking long but all you have to do is copy and login to change your password.  Super-Long-New-Password:"
+EMAIL_RESET_BUTTON = "Login"
+EMAIL_RESET_SUBTITLE = "What do I do?"
+EMAIL_RESET_SUBMESSAGE = "You can click the link above to go to my site to login.  Once logged in, click on your image or user icon on top right and change your password."
+EMAIL_NEWUSER_HEADER = "New User"
+EMAIL_NEWUSER_TITLE = "LOOK WHO JUST JOINED THE COOL CLUB"
+EMAIL_NEWUSER_MESSAGE = "Welcome, to my website.  I have many things here... many, many, many shiny things.  Have a look around :)"
+EMAIL_NEWUSER_BUTTON = "Login"
+EMAIL_NEWUSER_SUBTITLE = "What do I do?"
+EMAIL_NEWUSER_SUBMESSAGE = "Now that you have signed up, you can basically do whatever you like.  Enjoy"
+PLAYLISTS = "Playlists"
+DOWNLOAD_REFRESH = "Refresh Download Queue"
+HISTORY_REFRESH = "Refresh History"
+CHECK_FRAME = "Test Frame"
+GENERATE_API_KEY = "Generate API Key"
+ORGANIZR_API_KEY = "Organizr API Key"
+TEST_EMAIL = "Send Test E-Mail"

+ 31 - 3
lang/es.ini

@@ -177,8 +177,8 @@ PLEX_TOKEN = "Plex Token"
 RECENT_MOVIES = "Recent Movies"
 RECENT_TV = "Recent TV"
 RECENT_MUSIC = "Recent Music"
-PLAYING_NOW = "Playing Now"
-PLAYING_NOW_ON_PLEX = "Playing Now on PLEX"
+PLAYING_NOW = "Now Playing"
+PLAYING_NOW_ON_PLEX = "Now Playing on PLEX"
 RECENTLY_ADDED_TO_PLEX = "Recently Added to PLEX"
 MOVIES = "Movies"
 TV_SHOWS = "TV Shows"
@@ -223,7 +223,7 @@ SMTP_HOST_SENDER_EMAIL = "SMTP Sender Email"
 EMBY_URL = "Emby URL"
 EMBY_PORT = "Emby Port"
 EMBY_TOKEN = "Emby Token"
-PLAYING_NOW_ON_EMBY = "Playing Now on EMBY"
+PLAYING_NOW_ON_EMBY = "Now Playing on EMBY"
 RECENTLY_ADDED_TO_EMBY = "Recently Added to EMBY"
 AUTHTYPE = "Which databases should be used to allow login"
 AUTHBACKEND = "Select backend to use"
@@ -284,3 +284,31 @@ USED_BY = "Used By"
 ACCOUNT_MADE = "PLEX Account is now created, Click Join now"
 USERNAME_NAME = "Username or Name"
 ACCOUNT_SUBMITTED = "PLEX Invite Sent|1. Check Email and Accept Invite|2. Close This Modal with Small 'x' on Top Right|3. Sign in"
+PLEX_TAB_NAME = "PLEX Tab Name [only use this if your PLEX URL above is a sub-domain - i.e. https://plex.domain.com]"
+IPINFO_TOKEN = "Get Token from https://ipinfo.io/account/registration as Default will expire"
+GET_PLEX_TOKEN = "Get PLEX Token"
+EMAIL_INVITE_HEADER = "Join My|Server"
+EMAIL_INVITE_TITLE = "LOOK WHO JUST GOT AN INVITE"
+EMAIL_INVITE_MESSAGE = "Here is an invite to join my|server.  The code to join is:"
+EMAIL_INVITE_BUTTON = "JOIN MY|SERVER"
+EMAIL_INVITE_SUBTITLE = "What do I do?"
+EMAIL_INVITE_SUBMESSAGE = "You can click the link above to have it auto fill in the code for you or you could follow this link here:|to take you to my site to fill in the code."
+EMAIL_RESET_HEADER = "Reset Password"
+EMAIL_RESET_TITLE = "LOOK WHO FORGOT THEIR PASSWORD"
+EMAIL_RESET_MESSAGE = "So, you forgot your password huh?  That sucks...  Don't worry, I got you covered.  Here is your new password, it may be freaking long but all you have to do is copy and login to change your password.  Super-Long-New-Password:"
+EMAIL_RESET_BUTTON = "Login"
+EMAIL_RESET_SUBTITLE = "What do I do?"
+EMAIL_RESET_SUBMESSAGE = "You can click the link above to go to my site to login.  Once logged in, click on your image or user icon on top right and change your password."
+EMAIL_NEWUSER_HEADER = "New User"
+EMAIL_NEWUSER_TITLE = "LOOK WHO JUST JOINED THE COOL CLUB"
+EMAIL_NEWUSER_MESSAGE = "Welcome, to my website.  I have many things here... many, many, many shiny things.  Have a look around :)"
+EMAIL_NEWUSER_BUTTON = "Login"
+EMAIL_NEWUSER_SUBTITLE = "What do I do?"
+EMAIL_NEWUSER_SUBMESSAGE = "Now that you have signed up, you can basically do whatever you like.  Enjoy"
+PLAYLISTS = "Playlists"
+DOWNLOAD_REFRESH = "Refresh Download Queue"
+HISTORY_REFRESH = "Refresh History"
+CHECK_FRAME = "Test Frame"
+GENERATE_API_KEY = "Generate API Key"
+ORGANIZR_API_KEY = "Organizr API Key"
+TEST_EMAIL = "Send Test E-Mail"

+ 31 - 3
lang/fr.ini

@@ -177,8 +177,8 @@ PLEX_TOKEN = "Plex Token"
 RECENT_MOVIES = "Recent Movies"
 RECENT_TV = "Recent TV"
 RECENT_MUSIC = "Recent Music"
-PLAYING_NOW = "Playing Now"
-PLAYING_NOW_ON_PLEX = "Playing Now on PLEX"
+PLAYING_NOW = "Now Playing"
+PLAYING_NOW_ON_PLEX = "Now Playing on PLEX"
 RECENTLY_ADDED_TO_PLEX = "Recently Added to PLEX"
 MOVIES = "Movies"
 TV_SHOWS = "TV Shows"
@@ -223,7 +223,7 @@ SMTP_HOST_SENDER_EMAIL = "SMTP Sender Email"
 EMBY_URL = "Emby URL"
 EMBY_PORT = "Emby Port"
 EMBY_TOKEN = "Emby Token"
-PLAYING_NOW_ON_EMBY = "Playing Now on EMBY"
+PLAYING_NOW_ON_EMBY = "Now Playing on EMBY"
 RECENTLY_ADDED_TO_EMBY = "Recently Added to EMBY"
 AUTHTYPE = "Which databases should be used to allow login"
 AUTHBACKEND = "Select backend to use"
@@ -284,3 +284,31 @@ USED_BY = "Used By"
 ACCOUNT_MADE = "PLEX Account is now created, Click Join now"
 USERNAME_NAME = "Username or Name"
 ACCOUNT_SUBMITTED = "PLEX Invite Sent|1. Check Email and Accept Invite|2. Close This Modal with Small 'x' on Top Right|3. Sign in"
+PLEX_TAB_NAME = "PLEX Tab Name [only use this if your PLEX URL above is a sub-domain - i.e. https://plex.domain.com]"
+IPINFO_TOKEN = "Get Token from https://ipinfo.io/account/registration as Default will expire"
+GET_PLEX_TOKEN = "Get PLEX Token"
+EMAIL_INVITE_HEADER = "Join My|Server"
+EMAIL_INVITE_TITLE = "LOOK WHO JUST GOT AN INVITE"
+EMAIL_INVITE_MESSAGE = "Here is an invite to join my|server.  The code to join is:"
+EMAIL_INVITE_BUTTON = "JOIN MY|SERVER"
+EMAIL_INVITE_SUBTITLE = "What do I do?"
+EMAIL_INVITE_SUBMESSAGE = "You can click the link above to have it auto fill in the code for you or you could follow this link here:|to take you to my site to fill in the code."
+EMAIL_RESET_HEADER = "Reset Password"
+EMAIL_RESET_TITLE = "LOOK WHO FORGOT THEIR PASSWORD"
+EMAIL_RESET_MESSAGE = "So, you forgot your password huh?  That sucks...  Don't worry, I got you covered.  Here is your new password, it may be freaking long but all you have to do is copy and login to change your password.  Super-Long-New-Password:"
+EMAIL_RESET_BUTTON = "Login"
+EMAIL_RESET_SUBTITLE = "What do I do?"
+EMAIL_RESET_SUBMESSAGE = "You can click the link above to go to my site to login.  Once logged in, click on your image or user icon on top right and change your password."
+EMAIL_NEWUSER_HEADER = "New User"
+EMAIL_NEWUSER_TITLE = "LOOK WHO JUST JOINED THE COOL CLUB"
+EMAIL_NEWUSER_MESSAGE = "Welcome, to my website.  I have many things here... many, many, many shiny things.  Have a look around :)"
+EMAIL_NEWUSER_BUTTON = "Login"
+EMAIL_NEWUSER_SUBTITLE = "What do I do?"
+EMAIL_NEWUSER_SUBMESSAGE = "Now that you have signed up, you can basically do whatever you like.  Enjoy"
+PLAYLISTS = "Playlists"
+DOWNLOAD_REFRESH = "Refresh Download Queue"
+HISTORY_REFRESH = "Refresh History"
+CHECK_FRAME = "Test Frame"
+GENERATE_API_KEY = "Generate API Key"
+ORGANIZR_API_KEY = "Organizr API Key"
+TEST_EMAIL = "Send Test E-Mail"

+ 31 - 3
lang/it.ini

@@ -177,8 +177,8 @@ PLEX_TOKEN = "Plex Token"
 RECENT_MOVIES = "Recent Movies"
 RECENT_TV = "Recent TV"
 RECENT_MUSIC = "Recent Music"
-PLAYING_NOW = "Playing Now"
-PLAYING_NOW_ON_PLEX = "Playing Now on PLEX"
+PLAYING_NOW = "Now Playing"
+PLAYING_NOW_ON_PLEX = "Now Playing on PLEX"
 RECENTLY_ADDED_TO_PLEX = "Recently Added to PLEX"
 MOVIES = "Movies"
 TV_SHOWS = "TV Shows"
@@ -223,7 +223,7 @@ SMTP_HOST_SENDER_EMAIL = "SMTP Sender Email"
 EMBY_URL = "Emby URL"
 EMBY_PORT = "Emby Port"
 EMBY_TOKEN = "Emby Token"
-PLAYING_NOW_ON_EMBY = "Playing Now on EMBY"
+PLAYING_NOW_ON_EMBY = "Now Playing on EMBY"
 RECENTLY_ADDED_TO_EMBY = "Recently Added to EMBY"
 AUTHTYPE = "Which databases should be used to allow login"
 AUTHBACKEND = "Select backend to use"
@@ -284,3 +284,31 @@ USED_BY = "Used By"
 ACCOUNT_MADE = "PLEX Account is now created, Click Join now"
 USERNAME_NAME = "Username or Name"
 ACCOUNT_SUBMITTED = "PLEX Invite Sent|1. Check Email and Accept Invite|2. Close This Modal with Small 'x' on Top Right|3. Sign in"
+PLEX_TAB_NAME = "PLEX Tab Name [only use this if your PLEX URL above is a sub-domain - i.e. https://plex.domain.com]"
+IPINFO_TOKEN = "Get Token from https://ipinfo.io/account/registration as Default will expire"
+GET_PLEX_TOKEN = "Get PLEX Token"
+EMAIL_INVITE_HEADER = "Join My|Server"
+EMAIL_INVITE_TITLE = "LOOK WHO JUST GOT AN INVITE"
+EMAIL_INVITE_MESSAGE = "Here is an invite to join my|server.  The code to join is:"
+EMAIL_INVITE_BUTTON = "JOIN MY|SERVER"
+EMAIL_INVITE_SUBTITLE = "What do I do?"
+EMAIL_INVITE_SUBMESSAGE = "You can click the link above to have it auto fill in the code for you or you could follow this link here:|to take you to my site to fill in the code."
+EMAIL_RESET_HEADER = "Reset Password"
+EMAIL_RESET_TITLE = "LOOK WHO FORGOT THEIR PASSWORD"
+EMAIL_RESET_MESSAGE = "So, you forgot your password huh?  That sucks...  Don't worry, I got you covered.  Here is your new password, it may be freaking long but all you have to do is copy and login to change your password.  Super-Long-New-Password:"
+EMAIL_RESET_BUTTON = "Login"
+EMAIL_RESET_SUBTITLE = "What do I do?"
+EMAIL_RESET_SUBMESSAGE = "You can click the link above to go to my site to login.  Once logged in, click on your image or user icon on top right and change your password."
+EMAIL_NEWUSER_HEADER = "New User"
+EMAIL_NEWUSER_TITLE = "LOOK WHO JUST JOINED THE COOL CLUB"
+EMAIL_NEWUSER_MESSAGE = "Welcome, to my website.  I have many things here... many, many, many shiny things.  Have a look around :)"
+EMAIL_NEWUSER_BUTTON = "Login"
+EMAIL_NEWUSER_SUBTITLE = "What do I do?"
+EMAIL_NEWUSER_SUBMESSAGE = "Now that you have signed up, you can basically do whatever you like.  Enjoy"
+PLAYLISTS = "Playlists"
+DOWNLOAD_REFRESH = "Refresh Download Queue"
+HISTORY_REFRESH = "Refresh History"
+CHECK_FRAME = "Test Frame"
+GENERATE_API_KEY = "Generate API Key"
+ORGANIZR_API_KEY = "Organizr API Key"
+TEST_EMAIL = "Send Test E-Mail"

+ 31 - 3
lang/nl.ini

@@ -177,8 +177,8 @@ PLEX_TOKEN = "Plex Token"
 RECENT_MOVIES = "Recent Movies"
 RECENT_TV = "Recent TV"
 RECENT_MUSIC = "Recent Music"
-PLAYING_NOW = "Playing Now"
-PLAYING_NOW_ON_PLEX = "Playing Now on PLEX"
+PLAYING_NOW = "Now Playing"
+PLAYING_NOW_ON_PLEX = "Now Playing on PLEX"
 RECENTLY_ADDED_TO_PLEX = "Recently Added to PLEX"
 MOVIES = "Movies"
 TV_SHOWS = "TV Shows"
@@ -223,7 +223,7 @@ SMTP_HOST_SENDER_EMAIL = "SMTP Sender Email"
 EMBY_URL = "Emby URL"
 EMBY_PORT = "Emby Port"
 EMBY_TOKEN = "Emby Token"
-PLAYING_NOW_ON_EMBY = "Playing Now on EMBY"
+PLAYING_NOW_ON_EMBY = "Now Playing on EMBY"
 RECENTLY_ADDED_TO_EMBY = "Recently Added to EMBY"
 AUTHTYPE = "Which databases should be used to allow login"
 AUTHBACKEND = "Select backend to use"
@@ -284,3 +284,31 @@ USED_BY = "Used By"
 ACCOUNT_MADE = "PLEX Account is now created, Click Join now"
 USERNAME_NAME = "Username or Name"
 ACCOUNT_SUBMITTED = "PLEX Invite Sent|1. Check Email and Accept Invite|2. Close This Modal with Small 'x' on Top Right|3. Sign in"
+PLEX_TAB_NAME = "PLEX Tab Name [only use this if your PLEX URL above is a sub-domain - i.e. https://plex.domain.com]"
+IPINFO_TOKEN = "Get Token from https://ipinfo.io/account/registration as Default will expire"
+GET_PLEX_TOKEN = "Get PLEX Token"
+EMAIL_INVITE_HEADER = "Join My|Server"
+EMAIL_INVITE_TITLE = "LOOK WHO JUST GOT AN INVITE"
+EMAIL_INVITE_MESSAGE = "Here is an invite to join my|server.  The code to join is:"
+EMAIL_INVITE_BUTTON = "JOIN MY|SERVER"
+EMAIL_INVITE_SUBTITLE = "What do I do?"
+EMAIL_INVITE_SUBMESSAGE = "You can click the link above to have it auto fill in the code for you or you could follow this link here:|to take you to my site to fill in the code."
+EMAIL_RESET_HEADER = "Reset Password"
+EMAIL_RESET_TITLE = "LOOK WHO FORGOT THEIR PASSWORD"
+EMAIL_RESET_MESSAGE = "So, you forgot your password huh?  That sucks...  Don't worry, I got you covered.  Here is your new password, it may be freaking long but all you have to do is copy and login to change your password.  Super-Long-New-Password:"
+EMAIL_RESET_BUTTON = "Login"
+EMAIL_RESET_SUBTITLE = "What do I do?"
+EMAIL_RESET_SUBMESSAGE = "You can click the link above to go to my site to login.  Once logged in, click on your image or user icon on top right and change your password."
+EMAIL_NEWUSER_HEADER = "New User"
+EMAIL_NEWUSER_TITLE = "LOOK WHO JUST JOINED THE COOL CLUB"
+EMAIL_NEWUSER_MESSAGE = "Welcome, to my website.  I have many things here... many, many, many shiny things.  Have a look around :)"
+EMAIL_NEWUSER_BUTTON = "Login"
+EMAIL_NEWUSER_SUBTITLE = "What do I do?"
+EMAIL_NEWUSER_SUBMESSAGE = "Now that you have signed up, you can basically do whatever you like.  Enjoy"
+PLAYLISTS = "Playlists"
+DOWNLOAD_REFRESH = "Refresh Download Queue"
+HISTORY_REFRESH = "Refresh History"
+CHECK_FRAME = "Test Frame"
+GENERATE_API_KEY = "Generate API Key"
+ORGANIZR_API_KEY = "Organizr API Key"
+TEST_EMAIL = "Send Test E-Mail"

+ 31 - 3
lang/pl.ini

@@ -177,8 +177,8 @@ PLEX_TOKEN = "Plex Token"
 RECENT_MOVIES = "Recent Movies"
 RECENT_TV = "Recent TV"
 RECENT_MUSIC = "Recent Music"
-PLAYING_NOW = "Playing Now"
-PLAYING_NOW_ON_PLEX = "Playing Now on PLEX"
+PLAYING_NOW = "Now Playing"
+PLAYING_NOW_ON_PLEX = "Now Playing on PLEX"
 RECENTLY_ADDED_TO_PLEX = "Recently Added to PLEX"
 MOVIES = "Movies"
 TV_SHOWS = "TV Shows"
@@ -223,7 +223,7 @@ SMTP_HOST_SENDER_EMAIL = "SMTP Sender Email"
 EMBY_URL = "Emby URL"
 EMBY_PORT = "Emby Port"
 EMBY_TOKEN = "Emby Token"
-PLAYING_NOW_ON_EMBY = "Playing Now on EMBY"
+PLAYING_NOW_ON_EMBY = "Now Playing on EMBY"
 RECENTLY_ADDED_TO_EMBY = "Recently Added to EMBY"
 AUTHTYPE = "Which databases should be used to allow login"
 AUTHBACKEND = "Select backend to use"
@@ -284,3 +284,31 @@ USED_BY = "Used By"
 ACCOUNT_MADE = "PLEX Account is now created, Click Join now"
 USERNAME_NAME = "Username or Name"
 ACCOUNT_SUBMITTED = "PLEX Invite Sent|1. Check Email and Accept Invite|2. Close This Modal with Small 'x' on Top Right|3. Sign in"
+PLEX_TAB_NAME = "PLEX Tab Name [only use this if your PLEX URL above is a sub-domain - i.e. https://plex.domain.com]"
+IPINFO_TOKEN = "Get Token from https://ipinfo.io/account/registration as Default will expire"
+GET_PLEX_TOKEN = "Get PLEX Token"
+EMAIL_INVITE_HEADER = "Join My|Server"
+EMAIL_INVITE_TITLE = "LOOK WHO JUST GOT AN INVITE"
+EMAIL_INVITE_MESSAGE = "Here is an invite to join my|server.  The code to join is:"
+EMAIL_INVITE_BUTTON = "JOIN MY|SERVER"
+EMAIL_INVITE_SUBTITLE = "What do I do?"
+EMAIL_INVITE_SUBMESSAGE = "You can click the link above to have it auto fill in the code for you or you could follow this link here:|to take you to my site to fill in the code."
+EMAIL_RESET_HEADER = "Reset Password"
+EMAIL_RESET_TITLE = "LOOK WHO FORGOT THEIR PASSWORD"
+EMAIL_RESET_MESSAGE = "So, you forgot your password huh?  That sucks...  Don't worry, I got you covered.  Here is your new password, it may be freaking long but all you have to do is copy and login to change your password.  Super-Long-New-Password:"
+EMAIL_RESET_BUTTON = "Login"
+EMAIL_RESET_SUBTITLE = "What do I do?"
+EMAIL_RESET_SUBMESSAGE = "You can click the link above to go to my site to login.  Once logged in, click on your image or user icon on top right and change your password."
+EMAIL_NEWUSER_HEADER = "New User"
+EMAIL_NEWUSER_TITLE = "LOOK WHO JUST JOINED THE COOL CLUB"
+EMAIL_NEWUSER_MESSAGE = "Welcome, to my website.  I have many things here... many, many, many shiny things.  Have a look around :)"
+EMAIL_NEWUSER_BUTTON = "Login"
+EMAIL_NEWUSER_SUBTITLE = "What do I do?"
+EMAIL_NEWUSER_SUBMESSAGE = "Now that you have signed up, you can basically do whatever you like.  Enjoy"
+PLAYLISTS = "Playlists"
+DOWNLOAD_REFRESH = "Refresh Download Queue"
+HISTORY_REFRESH = "Refresh History"
+CHECK_FRAME = "Test Frame"
+GENERATE_API_KEY = "Generate API Key"
+ORGANIZR_API_KEY = "Organizr API Key"
+TEST_EMAIL = "Send Test E-Mail"

+ 245 - 18
settings.php

@@ -55,7 +55,7 @@ if(SLIMBAR == "true") {
 
         <title>Settings</title>
 
-        <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
+        <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css?v=<?php echo INSTALLEDVERSION; ?>">
         <link rel="stylesheet" href="bower_components/font-awesome/css/font-awesome.min.css">
         <link rel="stylesheet" href="bower_components/mdi/css/materialdesignicons.min.css">
         <link rel="stylesheet" href="bower_components/metisMenu/dist/metisMenu.min.css">
@@ -146,7 +146,7 @@ if(SLIMBAR == "true") {
 				});
 				$element.appendTo('#submitTabs ul');
 				$element.find('.icp-auto-pend').iconpicker({placement: 'left', hideOnSelect: false, collision: true}).hide();
-    $('.tab-box').scrollTop($('.tab-box')[0].scrollHeight);
+                $('.tab-box').scrollTop($('.tab-box')[0].scrollHeight);
 			}
 			function submitTabs(form) {
 				var formData = {};
@@ -358,7 +358,7 @@ if(SLIMBAR == "true") {
                                     <li><a id="open-logs" box="logs-box"><i class="fa fa-file-text-o blue pull-right"></i>View Logs</a></li>
                                     <li><a id="open-homepage" box="homepage-box"><i class=" fa fa-home yellow pull-right"></i>Edit Homepage</a></li>
                                     <li><a id="open-advanced" box="advanced-box"><i class=" fa fa-cog light-blue pull-right"></i>Advanced</a></li>
-                                    <li><a id="open-invites" box="invites-box"><i class=" fa fa-user-plus gray pull-right"></i>Plex Invites</a></li>
+                                    <?php if(!empty(PLEXURL)){?><li><a id="open-invites" box="invites-box"><i class=" fa fa-user-plus gray pull-right"></i>Plex Invites</a></li><?php }?>
                                     <li><a id="open-info" box="info-box"><i class=" fa fa-info-circle orange pull-right"></i>About</a></li>
                                     <li><a id="open-donate" box="donate-box"><i class=" fa fa-money red pull-right"></i>Donate</a></li>
                                 </ul>
@@ -653,6 +653,21 @@ $userTypes = array(
 	'User' => 'user|admin',
 	'Admin' => 'admin',
 );
+$branchTypes = array(
+	'Master' => 'master',
+	'Develop' => 'develop',
+	'Pre-Develop' => 'cero-dev',
+);
+$refreshSeconds = array(
+	'1 sec' => '1000',
+	'5 secs' => '5000',
+	'10 secs' => '10000',
+	'15 secs' => '15000',
+	'30 secs' => '30000',
+	'60 secs' => '60000',
+	'90 secs' => '90000',
+	'120 secs' => '120000',
+);
 
 // Build Homepage Settings
 echo buildSettings(
@@ -719,6 +734,10 @@ echo buildSettings(
 						'pattern' => '[a-zA-Z0-9]{20}',
 						'value' => PLEXTOKEN,
 					),
+                    array(
+						'type' => 'custom',
+						'html' => '<button id="openPlexModal" type="button" class="btn waves btn-labeled btn-success btn-sm text-uppercase waves-effect waves-float"> <span class="btn-label"><i class="fa fa-ticket"></i></span>'.translate("GET_PLEX_TOKEN").'</button>',
+					),
      				array(
 						'type' => 'text',
 						'placeholder' => "",
@@ -729,15 +748,11 @@ echo buildSettings(
 					),
 					array(
 						'type' => 'text',
-						'placeholder' => "plex",
+						'placeholder' => "Name of Plex Tab i.e. Plex",
 						'labelTranslate' => 'PLEX_TAB_NAME',
 						'name' => 'plexTabName',
 						'value' => PLEXTABNAME,
 					),
-					array(
-						'type' => 'custom',
-						'html' => '<a href="https://support.plex.tv/hc/en-us/articles/204059436-Finding-an-authentication-token-X-Plex-Token">Plex Token Wiki Article</a>',
-					),
 					array(
       					array(
 							'type' => 'checkbox',
@@ -763,6 +778,12 @@ echo buildSettings(
 							'name' => 'plexRecentMusic',
 							'value' => PLEXRECENTMUSIC,
 						),
+                        array(
+							'type' => 'checkbox',
+							'labelTranslate' => 'PLAYLISTS',
+							'name' => 'plexPlaylists',
+							'value' => PLEXPLAYLISTS,
+						),
 						array(
 							'type' => 'checkbox',
 							'labelTranslate' => 'PLAYING_NOW',
@@ -999,6 +1020,20 @@ echo buildSettings(
 						'name' => 'sabnzbdKey',
 						'value' => SABNZBDKEY,
 					),
+                    array(
+						'type' => $userSelectType,
+						'labelTranslate' => 'DOWNLOAD_REFRESH',
+						'name' => 'downloadRefresh',
+						'value' => DOWNLOADREFRESH,
+						'options' => $refreshSeconds,
+					),
+                    array(
+						'type' => $userSelectType,
+						'labelTranslate' => 'HISTORY_REFRESH',
+						'name' => 'historyRefresh',
+						'value' => HISTORYREFRESH,
+						'options' => $refreshSeconds,
+					),
 				),
 			),
 			array(
@@ -1034,6 +1069,20 @@ echo buildSettings(
 						'name' => 'nzbgetPassword',
 						'value' => (empty(NZBGETPASSWORD)?'':randString(20)),
 					),
+                    array(
+						'type' => $userSelectType,
+						'labelTranslate' => 'DOWNLOAD_REFRESH',
+						'name' => 'downloadRefresh',
+						'value' => DOWNLOADREFRESH,
+						'options' => $refreshSeconds,
+					),
+                    array(
+						'type' => $userSelectType,
+						'labelTranslate' => 'HISTORY_REFRESH',
+						'name' => 'historyRefresh',
+						'value' => HISTORYREFRESH,
+						'options' => $refreshSeconds,
+					),
 				),
 			),
 			array(
@@ -1215,11 +1264,11 @@ echo buildSettings(
 						'labelTranslate' => 'AUTHTYPE',
 						'name' => 'authType',
 						'value' => AUTHTYPE,
-						'onchange' => 'if (this.value == \'internal\') { $(\'.be-auth, #authBackend_id, #authBackendCreate_id\').parent().hide(); } else { $(\'#authBackend_id, #authBackendCreate_id\').trigger(\'change\').parent().show(); }',
+						'onchange' => 'if (this.value == \'internal\') { $(\'.be-auth, #authBackend_id, #authBackendCreate_id\').parent().hide(); } else { $(\'#authBackend_id, #authBackendCreate_id\').trigger(\'change\').parent().show(); }if (this.value == \'external\') { alert(\'ATTENTION! Before using this option, Make sure that the ADMIN account that you setup matches at least one username on your external backend.  Otherwide you will lose Admin functionality.  If something messes up, edit config/config.php and change authType to either internal or both.\') } ',
 						'options' => array(
 							'Organizr' => 'internal',
-							'Organizr & Backend' => 'both',
-							// 'Backend' => 'external',
+							(AUTHBACKEND) ? 'Organizr & '.ucwords(AUTHBACKEND) : 'Organizr & Backend' => 'both',
+                            (AUTHBACKEND) ? ucwords(AUTHBACKEND)." Only" : "Backend Only" => 'external',
 						),
 					),
 					array(
@@ -1272,7 +1321,7 @@ echo buildSettings(
 						'type' => 'text',
 						'placeholder' => randString(32),
 						'labelTranslate' => 'EMBY_TOKEN',
-						'name' => 'plexToken',
+						'name' => 'embyToken',
 						'class' => 'be-auth be-auth-emby_all be-auth-emby_connect',
 						'pattern' => '[a-zA-Z0-9]{32}',
 						'value' => EMBYTOKEN,
@@ -1291,6 +1340,19 @@ echo buildSettings(
 						'class' => 'be-auth be-auth-plex',
 						'value' => (empty(PLEXPASSWORD)?'':randString(20)),
 					),
+                    array(
+						'type' => 'text',
+						'labelTranslate' => 'ORGANIZR_API_KEY',
+						'name' => 'organizrAPI',
+						'value' => ORGANIZRAPI,
+					),
+                    array(
+                        'type' => 'button',
+                        'id' => 'generateAPI',
+                        'labelTranslate' => 'GENERATE_API_KEY',
+                        'icon' => 'key',
+                        'onclick' => 'var code = generateCode(); $(\'#organizrAPI_id\').val(code); $(\'#organizrAPI_id\').attr(\'data-changed\', \'true\');',
+                    ),
 				),
 			),
 			array(
@@ -1330,13 +1392,20 @@ echo buildSettings(
 						'name' => 'cookiePassword',
 						'value' => (empty(COOKIEPASSWORD)?'':randString(20)),
 					),
-					array(
+                    array(
 						'type' => 'text',
+						'labelTranslate' => 'IPINFO_TOKEN',
+						'name' => 'ipInfoToken',
+						'value' => IPINFOTOKEN,
+					),
+					array(
+						'type' => 'select',
 						'labelTranslate' => 'GIT_BRANCH',
 						'placeholder' => 'Default: \'master\' - Development: \'develop\' OR \'cero-dev\'',
 						'id' => 'git_branch_id',
 						'name' => 'git_branch',
 						'value' => GIT_BRANCH,
+                        'options' => $branchTypes,
 					),
 					array(
 						array(
@@ -1348,6 +1417,7 @@ echo buildSettings(
 						array(
 							'type' => 'button',
 							'id' => 'gitForceInstall',
+                            'style' => (extension_loaded("ZIP")) ? "" : "display : none",
 							'labelTranslate' => 'GIT_FORCE',
 							'icon' => 'gear',
 							'onclick' => 'if ($(\'#git_branch_id[data-changed]\').length) { alert(\'Branch was altered, save settings first!\') } else { if (confirm(\''.translate('GIT_FORCE_CONFIRM').'\')) { performUpdate(); ajax_request(\'POST\', \'forceBranchInstall\'); } }',
@@ -1416,6 +1486,12 @@ echo buildSettings(
 						),
 					),
 					array(
+                        array(
+							'type' => 'button',
+							'labelTranslate' => 'TEST_EMAIL',
+							'id' => 'testEmail',
+							'icon' => 'flask',
+						),
 						array(
 							'type' => 'checkbox',
 							'labelTranslate' => 'SMTP_HOST_AUTH',
@@ -2133,7 +2209,7 @@ echo buildSettings(
 
 																<td><?=$dateInviteUsed;?></td>
 																<td><?=$usedBy;?></td>
-																<td><?=$ipUsed;?></td>
+																<td style="cursor: pointer" class="ipInfo"><?=$ipUsed;?></td>
 
 																<td><span style="font-size: 100%;" class="label label-<?=$validColor;?>"><?=$row['valid'];?></span></td>
 
@@ -2205,7 +2281,7 @@ echo buildSettings(
 
                                         <div id="loginStats">
 
-                                            <div class="content-box ultra-widget">
+                                            <div class="ultra-widget">
 
                                                 <div class="w-progress">
 
@@ -2293,7 +2369,7 @@ echo buildSettings(
 
                                                     <td><?=$val["username"];?></td>
 
-                                                    <td><?=$val["ip"];?></td>
+                                                    <td style="cursor: pointer" class="ipInfo"><?=$val["ip"];?></td>
 
                                                     <td><span class="label label-<?php getColor($val["auth_type"]);?>"><?=$val["auth_type"];?></span></td>
 
@@ -2329,6 +2405,51 @@ echo buildSettings(
                 </div>
             </div>
             <!--End Content-->
+            <!-- Modal for IP -->
+            <div id="ipModal" class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog">
+                <div class="modal-dialog modal-lg" role="document">
+                    <div class="modal-content">
+                        <div class="modal-header">
+                            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                            <h4 class="modal-title" id="ipIp">Modal title</h4>
+                        </div>
+                        <div class="modal-body">
+                            <h3>Hostname: <small id="ipHostname"></small></h3>
+                            <h3>Location: <small id="ipLocation"></small></h3>
+                            <h3>Org: <small id="ipOrg"></small></h3>
+                            <h3>City: <small id="ipCity"></small></h3>
+                            <h3>Region: <small id="ipRegion"></small></h3>
+                            <h3>Country: <small id="ipCountry"></small></h3>
+                            <h3>Phone: <small id="ipPhone"></small></h3>
+                        </div>
+                        <div class="modal-footer">
+                            <button type="button" class="btn btn-default waves" data-dismiss="modal">Close</button>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <!-- END IP Modal -->
+             <!-- Modal for Plex Token -->
+            <div id="plexModal" class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog">
+                <div class="modal-dialog modal-lg" role="document">
+                    <div class="modal-content">
+                        <div class="modal-header">
+                            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                            <h4 class="modal-title"><?php echo translate("GET_PLEX_TOKEN"); ?></h4>
+                        </div>
+                        <div class="modal-body">
+                            <div style="display:none" id="plexError" class=""></div>
+                            <input class="form-control material" placeholder="<?php echo translate("USERNAME"); ?>" type="text" name="plex_username" id="plex_username" value="<?php echo PLEXUSERNAME;?>">
+                            <input class="form-control material" placeholder="<?php echo translate("PASSWORD"); ?>" type="password" name="plex_password" id="plex_password" value="<?php echo PLEXPASSWORD;?>">
+                        </div>
+                        <div class="modal-footer">
+                            <button type="button" class="btn btn-default waves" data-dismiss="modal"><?php echo translate("CLOSE"); ?></button>
+                            <button id="getPlexToken" type="button" class="btn btn-success waves waves-effect waves-float"><?php echo translate("GET_PLEX_TOKEN"); ?></button>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <!-- END IP Modal -->
 
         </div>
 		 <?php if(isset($_POST['op'])) : ?>
@@ -2346,6 +2467,79 @@ echo buildSettings(
         <?php endif; ?>
 
 		<script>
+            //IP INFO
+            $(".ipInfo").click(function(){
+                $.getJSON("https://ipinfo.io/"+$(this).text()+"/?token=<?php echo IPINFOTOKEN;?>", function (response) {
+                    $('#ipModal').modal('show');
+                    $('#ipIp').text("IP Info for: "+response.ip);
+                    $('#ipHostname').text(response.hostname);
+                    $('#ipLocation').text(response.loc);
+                    $('#ipOrg').text(response.org);
+                    $('#ipCity').text(response.city);
+                    $('#ipRegion').text(response.region);
+                    $('#ipCountry').text(response.country);
+                    $('#ipPhone').text(response.phone);
+                    console.log(response);
+                });
+            });
+            // Plex.tv auth token fetch
+            $("#openPlexModal").click(function() {
+                $('#plexModal').modal('show');
+            });
+            $("#getPlexToken").click(function() {
+                $('#plexError').show();
+                $('#plexError').addClass("well well-sm yellow-bg");
+                $('#plexError').text("Grabbing Token");
+                var plex_username = $("#plex_username").val().trim();
+                var plex_password = $("#plex_password").val().trim();
+                if ((plex_password !== '') && (plex_password !== '')) {
+                    $.ajax({
+                        type: 'POST',
+                        headers: {
+                            'X-Plex-Product':'Organizr',
+                            'X-Plex-Version':'1.0',
+                            'X-Plex-Client-Identifier':'01010101-10101010'
+                        },
+                        url: 'https://plex.tv/users/sign_in.json',
+                        data: {
+                            'user[login]': plex_username,
+                            'user[password]': plex_password,
+                            force: true
+                        },
+                        cache: false,
+                        async: true,
+                        complete: function(xhr, status) {
+                            var result = $.parseJSON(xhr.responseText);
+                            if (xhr.status === 201) {
+                                $('#plexError').removeClass();
+                                $('#plexError').addClass("well well-sm green-bg");
+                                $('#plexError').show();
+                                $('#plexError').text(xhr.statusText);
+                                $("#plexToken_id").val(result.user.authToken);
+                                $("#plexToken_id").attr('data-changed', 'true');
+                                $('#plexModal').modal('hide');
+                            } else {
+                                $('#plexError').removeClass();
+                                $('#plexError').addClass("well well-sm red-bg");
+                                $('#plexError').show();
+                                $('#plexError').text(xhr.statusText);
+                            }
+                        }
+                    });
+                } else {
+                    $('#plexError').text("Enter Username and Password");
+                }
+            });
+            //Generate API
+            function generateCode() {
+                var code = "";
+                var possible = "abcdefghijklmnopqrstuvwxyz0123456789";
+
+                for (var i = 0; i < 20; i++)
+                    code += possible.charAt(Math.floor(Math.random() * possible.length));
+
+                return code;
+            }
 			function performUpdate(){
 				$('#updateStatus').show();
 				setTimeout(function(){
@@ -2630,6 +2824,38 @@ echo buildSettings(
             });
         </script>
         <script>
+            //TestEmail
+            function isUpperCase(str) {
+                return str === str.toUpperCase();
+            }
+            $('#smtpHostAuth_id').change(function() {
+                if($('#smtpHostAuth_id').attr("data-value") == "true"){
+                    $('#smtpHostAuth_id').attr("data-value", "false");
+                }else{
+                    $('#smtpHostAuth_id').attr("data-value", "true");
+                }
+            });
+            $('#testEmail').on('click', function () {
+                var password = '';
+                if(isUpperCase($('#smtpHostPassword_id').val())){
+                    password = '<?php echo SMTPHOSTPASSWORD; ?>';
+                }else{
+                    password = $('#smtpHostPassword_id').val();
+                }
+                console.log("starting");
+                ajax_request('POST', 'test-email', {
+                    emailto: '<?php echo $USER->email;?>',
+                    emailhost: $('#smtpHost_id').val(),
+                    emailport: $('#smtpHostPort_id').val(),
+                    emailusername: $('#smtpHostUsername_id').val(),
+                    emailpassword: password,
+                    emailsendername: $('#smtpHostSenderName_id').val(),
+                    emailsenderemail: $('#smtpHostSenderEmail_id').val(),
+                    emailtype: $('#smtpHostType_id').val(),
+                    emailauth: $('#smtpHostAuth_id').attr("data-value"),
+                });
+                console.log("ajax done");
+            });
             //Custom Themes            
             function changeColor(elementName, elementColor) {
                 var definedElement = document.getElementById(elementName);
@@ -2929,6 +3155,7 @@ echo buildSettings(
                     checkurl: $('#urlTestForm [name=url-test]').val(),
                 });
             });
+
             //Hide Icon box on load
             $( "div[class^='jFiler jFiler-theme-dragdropbox']" ).hide();
             //Set Some Scrollbars
@@ -2985,8 +3212,8 @@ echo buildSettings(
             $("a[id^='ToolTables_datatable_0'] span").html('<?php echo $language->translate("PRINT");?>')
             //Enable Tooltips
             $('[data-toggle="tooltip"]').tooltip(); 
-        	   //AJAX call to github to get version info	
-			         <?php if (GIT_CHECK) { echo 'checkGithub()'; } ?>
+            //AJAX call to github to get version info	
+			<?php if (GIT_CHECK == "true") { echo 'checkGithub()'; } ?>
 
             //Edit Info tab with Github info
             <?php if(file_exists(FAIL_LOG)) : ?>

+ 41 - 319
user.php

@@ -16,7 +16,7 @@
 	
     // Lazyload settings
 	$databaseConfig = configLazy('config/config.php');
-    
+
     if(file_exists('custom.css')) : define('CUSTOMCSS', 'true'); else : define('CUSTOMCSS', 'false'); endif; 
     $notifyExplode = explode("-", NOTIFYEFFECT);
     define('FAIL_LOG', 'loginLog.json');
@@ -27,239 +27,8 @@
         return substr($ip, $start, $end);
     }
 
-
     define('GUEST_HASH', "guest-".guestHash(0, 5));
-    define('EMAIL_CSS', "
-	/* ------------------------------------- 
-		GLOBAL 
-------------------------------------- */
-* { 
-	margin:0;
-	padding:0;
-}
-* { font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif; }
-
-img { 
-	max-width: 100%; 
-}
-.collapse {
-	margin:0;
-	padding:0;
-}
-html {
-  height: 100%;
-}
-body {
-	-webkit-font-smoothing:antialiased; 
-	-webkit-text-size-adjust:none; 
-	width: 100%!important; 
-	min-height: 100%;
-}
-
-
-/* ------------------------------------- 
-		ELEMENTS 
-------------------------------------- */
-a { color: #2BA6CB;}
-
-.btn {
-	text-decoration:none;
-	color: #FFF;
-	background-color: #666;
-	padding:10px 16px;
-	font-weight:bold;
-	margin-right:10px;
-	text-align:center;
-	cursor:pointer;
-	display: inline-block;
-}
-
-p.callout {
-	padding:15px;
-	background-color:#ECF8FF;
-	margin-bottom: 15px;
-}
-.callout a {
-	font-weight:bold;
-	color: #2BA6CB;
-}
-
-table.social {
-/* 	padding:15px; */
-	background-color: #ebebeb;
-	
-}
-.social .soc-btn {
-	padding: 3px 7px;
-	font-size:12px;
-	margin-bottom:10px;
-	text-decoration:none;
-	color: #FFF;font-weight:bold;
-	display:block;
-	text-align:center;
-}
-a.fb { background-color: #3B5998!important; }
-a.tw { background-color: #1daced!important; }
-a.gp { background-color: #DB4A39!important; }
-a.ms { background-color: #000!important; }
-
-.sidebar .soc-btn { 
-	display:block;
-	width:100%;
-}
-
-/* ------------------------------------- 
-		HEADER 
-------------------------------------- */
-table.head-wrap { width: 100%;}
-
-.header.container table td.logo { padding: 15px; }
-.header.container table td.label { padding: 15px; padding-left:0px;}
-
-
-/* ------------------------------------- 
-		BODY 
-------------------------------------- */
-table.body-wrap { width: 100%;}
-
-
-/* ------------------------------------- 
-		FOOTER 
-------------------------------------- */
-table.footer-wrap { width: 100%;	clear:both!important;
-}
-.footer-wrap .container td.content  p { border-top: 1px solid rgb(215,215,215); padding-top:15px;}
-.footer-wrap .container td.content p {
-	font-size:10px;
-	font-weight: bold;
-	
-}
-
-
-/* ------------------------------------- 
-		TYPOGRAPHY 
-------------------------------------- */
-h1,h2,h3,h4,h5,h6 {
-font-family: \"HelveticaNeue-Light\", \"Helvetica Neue Light\", \"Helvetica Neue\", Helvetica, Arial, \"Lucida Grande\", sans-serif; line-height: 1.1; margin-bottom:15px; color:#000;
-}
-h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { font-size: 60%; color: #6f6f6f; line-height: 0; text-transform: none; }
-
-h1 { font-weight:200; font-size: 44px;}
-h2 { font-weight:200; font-size: 37px;}
-h3 { font-weight:500; font-size: 27px;}
-h4 { font-weight:500; font-size: 23px;}
-h5 { font-weight:900; font-size: 17px;}
-h6 { font-weight:900; font-size: 14px; text-transform: uppercase; color:#FFFFFF;}
-
-.collapse { margin:0!important;}
-
-p, ul { 
-	margin-bottom: 10px; 
-	font-weight: normal; 
-	font-size:14px; 
-	line-height:1.6;
-}
-p.lead { font-size:17px; }
-p.last { margin-bottom:0px;}
 
-ul li {
-	margin-left:5px;
-	list-style-position: inside;
-}
-
-/* ------------------------------------- 
-		SIDEBAR 
-------------------------------------- */
-ul.sidebar {
-	background:#ebebeb;
-	display:block;
-	list-style-type: none;
-}
-ul.sidebar li { display: block; margin:0;}
-ul.sidebar li a {
-	text-decoration:none;
-	color: #666;
-	padding:10px 16px;
-/* 	font-weight:bold; */
-	margin-right:10px;
-/* 	text-align:center; */
-	cursor:pointer;
-	border-bottom: 1px solid #777777;
-	border-top: 1px solid #FFFFFF;
-	display:block;
-	margin:0;
-}
-ul.sidebar li a.last { border-bottom-width:0px;}
-ul.sidebar li a h1,ul.sidebar li a h2,ul.sidebar li a h3,ul.sidebar li a h4,ul.sidebar li a h5,ul.sidebar li a h6,ul.sidebar li a p { margin-bottom:0!important;}
-
-
-
-/* --------------------------------------------------- 
-		RESPONSIVENESS
-		Nuke it from orbit. It's the only way to be sure. 
------------------------------------------------------- */
-
-/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
-.container {
-	display:block!important;
-	max-width:600px!important;
-	margin:0 auto!important; /* makes it centered */
-	clear:both!important;
-}
-
-/* This should also be a block element, so that it will fill 100% of the .container */
-.content {
-	padding:15px;
-	max-width:600px;
-	margin:0 auto;
-	display:block; 
-	border-radius: 10px;
-}
-
-/* Let's make sure tables in the content area are 100% wide */
-.content table { width: 100%; }
-
-
-/* Odds and ends */
-.column {
-	width: 300px;
-	float:left;
-}
-.column tr td { padding: 15px; }
-.column-wrap { 
-	padding:0!important; 
-	margin:0 auto; 
-	max-width:600px!important;
-}
-.column table { width:100%;}
-.social .column {
-	width: 280px;
-	min-width: 279px;
-	float:left;
-}
-
-/* Be sure to place a .clear element after each set of columns, just to be safe */
-.clear { display: block; clear: both; }
-
-
-/* ------------------------------------------- 
-		PHONE
-		For clients that support media queries.
-		Nothing fancy. 
--------------------------------------------- */
-@media only screen and (max-width: 600px) {
-	
-	a[class=\"btn\"] { display:block!important; margin-bottom:10px!important; background-image:none!important; margin-right:0!important;}
-
-	div[class=\"column\"] { width: auto!important; float:none!important;}
-	
-	table.social div[class=\"column\"] {
-		width:auto!important;
-	}
-
-}
-	");
-	
 	class User
 	{
 		// =======================================================================
@@ -525,23 +294,19 @@ ul.sidebar li a h1,ul.sidebar li a h2,ul.sidebar li a h3,ul.sidebar li a h4,ul.s
 			if($registered && User::use_mail)
 			{
 				// send email notification
-				$from = User::MAILER_NAME;
-				$replyto = User::MAILER_REPLYTO;
-				$domain_name = User::DOMAIN_NAME;
-				$subject = User::DOMAIN_NAME . " registration";
-				$body = <<<EOT
-	Hi,
-	this is an automated message to let you know that someone signed up at $domain_name with the user name "$username", using this email address as mailing address.
-	Because of the way our user registration works, we have no idea which password was used to register this account (it gets one-way hashed by the browser before it is sent to our user registration system, so that we don't know your password either), so if you registered this account, hopefully you wrote your password down somewhere.
-	However, if you ever forget your password, you can click the "I forgot my password" link in the log-in section for $domain_name and you will be sent an email containing a new, ridiculously long and complicated password that you can use to log in. You can change your password after logging in, but that's up to you. No one's going to guess it, or brute force it, but if other people can read your emails, it's generally a good idea to change passwords.
-	If you were not the one to register this account, you can either contact us the normal way or —much easier— you can ask the system to reset the password for the account, after which you can simply log in with the temporary password and delete the account. That'll teach whoever pretended to be you not to mess with you!
-	Of course, if you did register it yourself, welcome to $domain_name!
-	- the $domain_name team
-EOT;
-				$headers = "From: $from\r\n";
-				$headers .= "Reply-To: $replyto\r\n";
-				$headers .= "X-Mailer: PHP/" . phpversion();
-				//mail($email, $subject, $body, $headers);
+				$subject = "Welcome to ".DOMAIN;
+				$language = new setLanguage;
+				$domain = getServerPath();
+				$body = orgEmail(
+					$header = $language->translate('EMAIL_NEWUSER_HEADER'),
+					$title = $language->translate('EMAIL_NEWUSER_TITLE'), 
+					$user = $username, 
+					$mainMessage =$language->translate('EMAIL_NEWUSER_MESSAGE'),
+					$button = $language->translate('EMAIL_NEWUSER_BUTTON'),
+					$buttonURL = $domain, 
+					$subTitle = $language->translate('EMAIL_NEWUSER_SUBTITLE'), 
+					$subMessage = $language->translate('EMAIL_NEWUSER_SUBMESSAGE')
+					);
                 $this->startEmail($email, $username, $subject, $body);
 			}
 			return $registered;
@@ -597,7 +362,7 @@ EOT;
 				$this->info("email address did not pass validation");
 				return false; }
 			// step 2: if validation passed, see if there is a matching user, and reset the password if there is
-			$newpassword = $this->random_ascii_string(64);
+			$newpassword = $this->random_ascii_string(20);
 			$sha1 = sha1($newpassword);
 			$query = "SELECT username, token FROM users WHERE email = '$email'";
 			$username = "";
@@ -612,23 +377,19 @@ EOT;
 			$this->database->exec($update);
             //$this->info("Email has been sent with new password");
 			// step 3: notify the user of the new password
-			$from = User::MAILER_NAME;
-			$replyto = User::MAILER_REPLYTO;
-			$domain_name = User::DOMAIN_NAME;
-			$subject = User::DOMAIN_NAME . " password reset request";
-			$body = <<<EOT
-	Hi,
-	this is an automated message to let you know that someone requested a password reset for the $domain_name user account with user name "$username", which is linked to this email address.
-	We've reset the password to the following 64 character string, so make sure to copy/paste it without any leading or trailing spaces:
-	$newpassword
-	If you didn't even know this account existed, now is the time to log in and delete it. How dare people use your email address to register accounts! Of course, if you did register it yourself, but you didn't request the reset, some jerk is apparently reset-spamming. We hope he gets run over by a steam shovel driven by rabid ocelots or something.
-	Then again, it's far more likely that you did register this account, and you simply forgot the password so you asked for the reset yourself, in which case: here's your new password, and thank you for your patronage at $domain_name!
-	- the $domain_name team
-EOT;
-			$headers = "From: $from\r\n";
-			$headers .= "Reply-To: $replyto\r\n";
-			$headers .= "X-Mailer: PHP/" . phpversion();
-			//mail($email, $subject, $body, $headers);
+			$subject = DOMAIN . " Password Reset";
+			$language = new setLanguage;
+			$domain = getServerPath();
+			$body = orgEmail(
+					$header = $language->translate('EMAIL_RESET_HEADER'),
+					$title = $language->translate('EMAIL_RESET_TITLE'), 
+					$user = $username, 
+					$mainMessage =$language->translate('EMAIL_RESET_MESSAGE')."<br/>".$newpassword,
+					$button = $language->translate('EMAIL_RESET_BUTTON'),
+					$buttonURL = $domain, 
+					$subTitle = $language->translate('EMAIL_RESET_SUBTITLE'), 
+					$subMessage = $language->translate('EMAIL_RESET_SUBMESSAGE')
+					);
             $this->startEmail($email, $username, $subject, $body);
 		}
 	// ------------------
@@ -976,7 +737,8 @@ EOT;
 		 */
 		function invite_user($username = "none", $email, $server)
 		{
-			$emailCSS = constant('EMAIL_CSS');
+			//lang shit
+			$language = new setLanguage;
 			$domain = getServerPath();
 			$topImage = $domain."images/organizr-logo-h.png";
 			$uServer = strtoupper($server);
@@ -994,57 +756,17 @@ EOT;
 			if($insert && User::use_mail)
 			{
 				// send email notification
-				$subject = DOMAIN . " $uServer invite!";
-				$body = <<<EOT
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-	<head>
-		<meta name="viewport" content="width=device-width"/>
-		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
-		<title>Organizr Email</title>
-		<style>$emailCSS</style>
-	</head>
-	<body bgcolor="#333333">
-		<table class="head-wrap" bgcolor="#333333">
-			<tr>
-				<td></td>
-				<td class="header container">
-					<table bgcolor="#333333">
-						<tr>
-							<td><img src="$topImage"/></td>
-							<td align="right"><h6 class="collapse">Join My $server Server</h6></td>
-						</tr>
-					</table>
-				</td>
-				<td></td>
-			</tr>
-		</table>  
-		<table class="body-wrap">
-			<tr>
-				<td></td>
-				<td class="container" bgcolor="#FFFFFF">
-					<div class="content">
-						<table>
-							<tr>
-								<td>
-									<h3>Hi $username,</h3>
-									<p class="lead">Here is an invite to my $server server.  The code to join is $inviteCode.</p>
-
-									<p class="callout">Click this <a class="btn" href="$link">LINK</a> to automatically fill in the info and join.</a></p> 
-									<p>You could also head over to my website to join by going here: <a href="$domain">$domain</a> and clicking Join My Server.</p>
-								</td>
-							</tr>
-						</table>
-					</div>
-				</td>
-				<td></td>
-			</tr>
-		</table> 
-		<br/><br/><br/><br/> 
-	</body>
-</html>
-EOT;
-				
+				$subject = DOMAIN . " $uServer ".$language->translate('INVITE_CODE');
+				$body = orgEmail(
+					$header = explosion($language->translate('EMAIL_INVITE_HEADER'), 0)." ".$uServer." ".explosion($language->translate('EMAIL_INVITE_HEADER'), 1),
+					$title = $language->translate('EMAIL_INVITE_TITLE'), 
+					$user = $username, 
+					$mainMessage = explosion($language->translate('EMAIL_INVITE_MESSAGE'), 0)." ".$uServer." ".explosion($language->translate('EMAIL_INVITE_MESSAGE'), 1)." ".$inviteCode,
+					$button = explosion($language->translate('EMAIL_INVITE_BUTTON'), 0)." ".$uServer." ".explosion($language->translate('EMAIL_INVITE_BUTTON'), 1),
+					$buttonURL = $link, 
+					$subTitle = $language->translate('EMAIL_INVITE_SUBTITLE'), 
+					$subMessage = explosion($language->translate('EMAIL_INVITE_SUBMESSAGE'), 0)." <a href='".$domain."?inviteCode'>".$domain."</a> ".explosion($language->translate('EMAIL_INVITE_SUBMESSAGE'), 1)
+					);
                 $this->startEmail($email, $username, $subject, $body);
 			}
 		}

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů