فهرست منبع

Merge pull request #325 from causefx/cero-dev

Cero dev
causefx 9 سال پیش
والد
کامیت
5e372216a7
18فایلهای تغییر یافته به همراه1036 افزوده شده و 1182 حذف شده
  1. 54 18
      ajax.php
  2. 4 0
      config/configDefaults.php
  3. 47 1
      css/settings.css
  4. 0 185
      downloader.php
  5. 35 128
      error.php
  6. 318 138
      functions.php
  7. 66 136
      homepage.php
  8. 6 4
      index.php
  9. 120 0
      js/ajax.js
  10. 9 1
      lang/de.ini
  11. 9 1
      lang/en.ini
  12. 9 1
      lang/es.ini
  13. 9 1
      lang/fr.ini
  14. 9 1
      lang/it.ini
  15. 9 1
      lang/nl.ini
  16. 9 1
      lang/pl.ini
  17. 320 564
      settings.php
  18. 3 1
      user.php

+ 54 - 18
ajax.php

@@ -1,6 +1,8 @@
 <?php
-// Include functions if not already included
+// Include functions and user
 require_once('functions.php');
+require_once("user.php");
+$GLOBALS['USER'] = new User('registration_callback');
 
 // Upgrade environment
 upgradeCheck();
@@ -17,47 +19,56 @@ unset($_POST['action']);
 
 // No Action
 if (!isset($action)) {
-	debug_out('No Action Specified!',1);
+	sendNotification(false, 'No Action Specified!');
 }
 
 // Process Request
+$response = array();
 switch ($_SERVER['REQUEST_METHOD']) {
 	case 'GET':
 		switch ($action) {
 			case 'emby-image':
 				qualifyUser(EMBYHOMEAUTH, true);
 				getEmbyImage();
+				die();
 				break;
 			case 'plex-image':
 				qualifyUser(PLEXHOMEAUTH, true);
 				getPlexImage();
+				die();
 				break;
 			case 'emby-streams':
 				qualifyUser(EMBYHOMEAUTH, true);
 				echo getEmbyStreams(12);
+				die();
 				break;
 			case 'plex-streams':
 				qualifyUser(PLEXHOMEAUTH, true);
 				echo getPlexStreams(12);
+				die();
 				break;
 			case 'emby-recent':
 				qualifyUser(EMBYHOMEAUTH, true);
 				echo getEmbyRecent($_GET['type'], 12);
+				die();
 				break;
 			case 'plex-recent':
 				qualifyUser(PLEXHOMEAUTH, true);
 				echo getPlexRecent($_GET['type'], 12);
+				die();
 				break;
 			case 'sabnzbd-update':
-				qualifyUser(NZBGETHOMEAUTH, true);
-				
+				qualifyUser(SABNZBDHOMEAUTH, true);
+				echo sabnzbdConnect($_GET['list'] ? $_GET['list'] : die('Error!'));
+				die();
 				break;
 			case 'nzbget-update':
 				qualifyUser(NZBGETHOMEAUTH, true);
-				
+				echo nzbgetConnect($_GET['list'] ? $_GET['list'] : die('Error!'));
+				die();
 				break;
 			default:
-				debug_out('Unsupported Action!',1);
+				sendNotification(false, 'Unsupported Action!');
 		}
 		break;
 	case 'POST':
@@ -66,44 +77,69 @@ switch ($_SERVER['REQUEST_METHOD']) {
 		switch ($action) {
 			case 'upload-images':
 				uploadFiles('images/', array('jpg', 'png', 'svg', 'jpeg', 'bmp'));
+				sendNotification(true);
 				break;
 			case 'remove-images':
 				removeFiles('images/'.(isset($_POST['file'])?$_POST['file']:''));
+				sendNotification(true);
 				break;
 			case 'update-config':
 				sendNotification(updateConfig($_POST));
 				break;
-			case 'editCSS':
-				write_ini_file($_POST["css-show"], "custom.css");
-				echo '<script>window.top.location = window.top.location.href.split(\'#\')[0];</script>';
-				break;
 			case 'update-appearance':
-				sendNotification(updateDBOptions($_POST));
+				// Custom CSS Special Case START
+				if (isset($_POST['customCSS'])) {
+					if ($_POST['customCSS']) {
+						write_ini_file($_POST['customCSS'], 'custom.css');
+					} else {
+						unlink('custom.css');
+					}
+					$response['parent']['reload'] = true;
+				}
+				unset($_POST['customCSS']);
+				// Custom CSS Special Case END
+				$response['notify'] = sendNotification(updateDBOptions($_POST),false,false);
 				break;
 			case 'deleteDB':
 				deleteDatabase();
-				echo json_encode(array('result' => 'success'));
+				sendNotification(true, 'Database Deleted!');
 				break;
 			case 'upgradeInstall':
 				upgradeInstall();
-				echo json_encode(array('result' => 'success'));
+				$response['notify'] = sendNotification(true, 'Performing Checks', false);
+				$response['tab']['goto'] = 'updatedb.php';
+				break;
+			case 'forceBranchInstall':
+				upgradeInstall(GIT_BRANCH);
+				$response['notify'] = sendNotification(true, 'Performing Checks', false);
+				$response['tab']['goto'] = 'updatedb.php';
 				break;
 			case 'deleteLog':
 				sendNotification(unlink(FAIL_LOG));
 				break;
+			case 'submit-tabs':
+				$response['notify'] = sendNotification(updateTabs($_POST) , false, false);
+				$response['show_apply'] = true;
+				break;
 			default:
-				debug_out('Unsupported Action!',1);
+				sendNotification(false, 'Unsupported Action!');
 		}
 		break;
 	case 'PUT':
-		debug_out('Unsupported Action!',1);
+		sendNotification(false, 'Unsupported Action!');
 		break;
 	case 'DELETE':
-		debug_out('Unsupported Action!',1);
+		sendNotification(false, 'Unsupported Action!');
 		break;
 	default:
-		debug_out('Unknown Request Type!',1);
+		sendNotification(false, 'Unknown Request Type!');
 }
 
-
+if ($response) {
+	header('Content-Type: application/json');
+	echo json_encode($response);
+	die();
+} else {
+	sendNotification(false, 'Error: No Output Specified!');
+}
 

+ 4 - 0
config/configDefaults.php

@@ -67,4 +67,8 @@ return array(
 	"gravatar" => "true",
 	"calTimeFormat" => "h(:mm)t",
 	"homePageAuthNeeded" => false,
+	"homepageCustomHTML1" => "",
+	"homepageCustomHTML1Auth" => false,
+	"git_branch" => "master",
+	"git_check" => true,
 );

+ 47 - 1
css/settings.css

@@ -8,4 +8,50 @@ div.colour-field {
 
 div.colour-field input {
 	color: #000;
-}
+}
+
+input.invalid {
+	background-color: #ffb5b5 !important;
+}
+
+input.invalid + p.help-text::after {
+	content: " - Does not match pattern!";
+}
+
+
+div.form-content input:not([type=radio]) {
+	width: 100% !important;
+}
+
+tab > div.row {
+	padding: 0px 10px 0px 10px;
+}
+
+tab > div.row > div {
+	padding: 1px 5px !important;
+}
+
+tab > div.row > div:first-child {
+	max-width: 42px;
+}
+
+tab > div.row > div:first-child .tabIconView {
+	width: 100% !important;
+	margin: 7px 0px !important;
+}
+
+tab > div.row button {
+	margin: 9px 0px !important;
+}
+
+tab > div.row div.custom-field {
+	margin: 8px 0px !important;
+}
+
+tab p.help-text {
+	margin: 0px !important;
+}
+
+#submitTabs ul > li {
+	padding: 0px 10px !important;
+}

+ 0 - 185
downloader.php

@@ -1,185 +0,0 @@
-<?php
-
-$auth = strpos($_SERVER['HTTP_REFERER'], "homepage.php");
-
-if ($auth === false) { die("WTF? Bro!"); }
-
-require_once("user.php");
-
-isset($_GET['downloader']) ? $downloader = $_GET['downloader'] : die("Error");
-isset($_GET['list']) ? $list = $_GET['list'] : die("Error");
-    
-if($downloader == "nzbget"){
-    
-    $url = NZBGETURL;
-    $username = NZBGETUSERNAME;
-    $password = NZBGETPASSWORD;
-
-    $urlCheck = stripos($url, "http");
-
-    if ($urlCheck === false) {
-
-        $url = "http://" . $url;
-
-    }
-
-    $address = $url;
-
-    $api = file_get_contents("$url/$username:$password/jsonrpc/$list");
-
-    $api = json_decode($api, true);
-
-    $i = 0;
-
-    $gotNZB = "";
-
-    foreach ($api['result'] AS $child) {
-
-        $i++;
-
-        $downloadName = $child['NZBName'];
-        $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>'.$downloadName.'</td>
-                        <td>'.$downloadStatus.'</td>
-                        <td>'.$downloadCategory.'</td>
-
-                        <td>
-
-                            <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($i > 0){ echo $gotNZB; }
-    if($i == 0){ echo '<tr><td colspan="4"><p class="text-center">No Results</p></td></tr>'; }
-    
-}
-    
-if($downloader == "sabnzbd"){
-    
-    $url = SABNZBDURL;
-    $key = SABNZBDKEY;
-    
-    $urlCheck = stripos($url, "http");
-
-    if ($urlCheck === false) {
-        
-        $url = "http://" . $url;
-    
-    }
-    
-    $address = $url;
-
-    $api = file_get_contents("$url/api?mode=$list&output=json&apikey=$key&limit=40");
-                    
-    $api = json_decode($api, true);
-    
-    $i = 0;
-    
-    $gotNZB = "";
-    
-    foreach ($api[$list]['slots'] AS $child) {
-        
-        $i++;
-        
-        if($list == "queue"){ 
-            
-            $downloadName = $child['filename']; 
-            $downloadCategory = $child['cat']; 
-            $downloadPercent = (($child['mb'] - $child['mbleft']) / $child['mb']) * 100; 
-            $progressBar = "progress-bar-striped active"; 
-            
-            if($child['missing'] > "400"){ 
-                
-                $downloadHealth = "danger"; 
-            
-            }elseif($child['missing'] <= "200"){ 
-            
-                $downloadHealth = "success"; 
-            
-            }elseif($child['missing'] <= "400"){ 
-            
-                $downloadHealth = "warning"; 
-            
-            }
-
-        } 
-        
-        if($list == "history"){ 
-            
-            $downloadName = $child['name'];
-            $downloadCategory = $child['category']; 
-            $downloadPercent = "100"; 
-            $progressBar = ""; 
-            $downloadHealth = "success"; 
-        
-        }
-        
-        $downloadStatus = $child['status'];
-        
-        $gotNZB .= '<tr>
-
-                        <td>'.$downloadName.'</td>
-                        <td>'.$downloadStatus.'</td>
-                        <td>'.$downloadCategory.'</td>
-
-                        <td>
-
-                            <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($i > 0){ echo $gotNZB; }
-    if($i == 0){ echo '<tr><td colspan="4"><p class="text-center">No Results</p></td></tr>'; }
-
-}
-
-?>

+ 35 - 128
error.php

@@ -1,19 +1,39 @@
 <?php
+// Include functions if not already included
+require_once('functions.php');
 
-$requested = (isset($_SERVER['HTTPS']) ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
+// Upgrade environment
+upgradeCheck();
+
+// Lazyload settings
+$databaseConfig = configLazy('config/config.php');
+
+// Load USER
+require_once("user.php");
+$USER = new User("registration_callback");
+
+// Create Database Connection
+$file_db = new PDO('sqlite:'.DATABASE_LOCATION.'users.db');
+$file_db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 
-if (isset($_GET['error'])) {
-    
-    $status = $_GET['error'];
-    
-}else{
-    
-    $status = "";
-    
+// Some PHP config stuff
+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'),
        403 => array('Forbidden', 'The server has refused to fulfill your request.', 'sowwy'),
@@ -25,99 +45,18 @@ $codes = array(
        503 => array('Service Unavailable', 'The server is currently unavailable (because it is overloaded or down for maintenance).', 'confused'),
        504 => array('Gateway Timeout', 'The upstream server failed to send a request in the time allowed by the server.', 'confused'),
        999 => array('Not Logged In', 'You need to be logged in to access this page.', 'confused'),
-    
 );
 
-@$errorTitle = $codes[$status][0];
-@$message = $codes[$status][1];
-@$errorImage = $codes[$status][2];
-
-if ($errorTitle == false || strlen($status) != 3) {
-    
-    $message = 'Please supply a valid status code.';
-    $errorTitle = "Error";
-    $errorImage = "confused";
-
-}
-
-$data = false;
-
-ini_set("display_errors", 1);
-ini_set("error_reporting", E_ALL | E_STRICT);
-
-require_once("user.php");
-require_once("functions.php");
-$USER = new User("registration_callback");
-
-$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;
+$errorTitle = $codes[$status][0];
+$message = $codes[$status][1];
+$errorImage = $codes[$status][2];
 
 ?>
 
 <!DOCTYPE html>
 
 <html lang="en" class="no-js">
-
     <head>
-        
         <meta charset="UTF-8">
         <meta name="viewport" content="width=device-width, initial-scale=1.0">
         <meta http-equiv="X-UA-Compatible" content="IE=edge">
@@ -128,61 +67,29 @@ endif;
         <link rel="stylesheet" href="<?php echo dirname($_SERVER['SCRIPT_NAME']); ?>/bower_components/bootstrap/dist/css/bootstrap.min.css">
         <link rel="stylesheet" href="<?php echo dirname($_SERVER['SCRIPT_NAME']); ?>/bower_components/Waves/dist/waves.min.css"> 
         <link rel="stylesheet" href="<?php echo dirname($_SERVER['SCRIPT_NAME']); ?>/css/style.css">
-        
     </head>
-
     <body class="gray-bg" style="padding: 0;">
-
         <div class="main-wrapper" style="position: initial;">
-
             <div style="margin:0 20px; overflow:hidden">
-                
                 <div class="table-wrapper" style="background:<?=$sidebar;?>;">
-                
                     <div class="table-row">
-                
                         <div class="table-cell text-center">
-                        
                             <div class="login i-block">
-                                
                                 <div class="content-box">
-                                    
                                     <div class="biggest-box" style="background:<?=$topbar;?>;">
-                
                                         <h1 class="zero-m text-uppercase" style="color:<?=$topbartext;?>; font-size: 40px;"><?=$errorTitle;?></h1>
-                
                                     </div>
-                
                                     <div class="big-box text-left">
-                
-                                        <center><img src="/images/<?=$errorImage;?>.png" style="height: 200px;"></center>
+                                        <center><img src="images/<?=$errorImage;?>.png" style="height: 200px;"></center>
                                         <h4 style="color: <?=$topbar;?>;" class="text-center"><?php echo $message;?></h4>
-
-                                        <button style="background:<?=$topbar;?>;" onclick="goBack()" type="button" class="btn log-in btn-block btn-primary text-uppercase waves waves-effect waves-float"><text style="color:<?=$topbartext;?>;"><?php echo $language->translate("GO_BACK");?></text></button>					                                    
+                                        <button style="background:<?=$topbar;?>;" onclick="window.history.back();" type="button" class="btn log-in btn-block btn-primary text-uppercase waves waves-effect waves-float"><text style="color:<?=$topbartext;?>;"><?php echo $language->translate("GO_BACK");?></text></button>
                                     </div>
-                                
                                 </div>
-                            
                             </div>
-                        
                         </div>
-                    
                     </div>
-                
                 </div>
-
             </div>
-
         </div>
-        
-        <script>
-            
-            function goBack() {
-                window.history.back();
-            }
-            
-        </script>
-
     </body>
-
 </html>

+ 318 - 138
functions.php

@@ -2,7 +2,7 @@
 
 // ===================================
 // Define Version
- define('INSTALLEDVERSION', '1.33');
+ define('INSTALLEDVERSION', '1.34');
 // ===================================
 
 // Debugging output functions
@@ -379,7 +379,7 @@ function post_request($url, $data, $headers = array(), $referer='') {
     $urlDigest = parse_url($url);
 
     // extract host and path:
-    $host = $urlDigest['host'].(isset($urlDigest['port'])?':'.$urlDigest['port']:'');
+    $host = $urlDigest['host'];
     $path = $urlDigest['path'];
 	
     if ($urlDigest['scheme'] != 'http') {
@@ -387,7 +387,7 @@ function post_request($url, $data, $headers = array(), $referer='') {
     }
 
     // open a socket connection on port 80 - timeout: 30 sec
-    $fp = fsockopen($host, 80, $errno, $errstr, 30);
+    $fp = fsockopen($host, (isset($urlDigest['port'])?':'.$urlDigest['port']:80), $errno, $errstr, 30);
 
     if ($fp){
 
@@ -445,8 +445,8 @@ function resolveEmbyItem($address, $token, $item) {
 	
 	switch ($itemDetails['Type']) {
 		case 'Episode':
-			$title = $itemDetails['SeriesName'].': '.$itemDetails['Name'].(isset($itemDetails['ParentIndexNumber']) && isset($itemDetails['IndexNumber'])?' (Season '.$itemDetails['ParentIndexNumber'].': Episode '.$itemDetails['IndexNumber'].')':'');
-			$imageId = $itemDetails['SeriesId'];
+			$title = (isset($itemDetails['SeriesName'])?$itemDetails['SeriesName'].': ':'').$itemDetails['Name'].(isset($itemDetails['ParentIndexNumber']) && isset($itemDetails['IndexNumber'])?' (Season '.$itemDetails['ParentIndexNumber'].': Episode '.$itemDetails['IndexNumber'].')':'');
+			$imageId = (isset($itemDetails['SeriesId'])?$itemDetails['SeriesId']:$itemDetails['Id']);
 			$width = 100;
 			$image = 'carousel-image season';
 			$style = '';
@@ -611,6 +611,12 @@ function getPlexStreams($size){
 function getEmbyRecent($type, $size) {
     $address = qualifyURL(EMBYURL);
 	
+	// Currently Logged In User
+	$username = false;
+	if (isset($GLOBALS['USER'])) {
+		$username = strtolower($GLOBALS['USER']->username);
+	}
+	
 	// Resolve Types
 	switch ($type) {
 		case 'movie':
@@ -632,15 +638,20 @@ function getEmbyRecent($type, $size) {
 	
 	// Get A User
 	$userIds = json_decode(file_get_contents($address.'/Users?api_key='.EMBYTOKEN),true);
+	$showPlayed = true;
 	foreach ($userIds as $value) { // Scan for admin user
-		$userId = $value['Id'];
 		if (isset($value['Policy']) && isset($value['Policy']['IsAdministrator']) && $value['Policy']['IsAdministrator']) {
+			$userId = $value['Id'];
+		}
+		if ($username && strtolower($value['Name']) == $username) {
+			$userId = $value['Id'];
+			$showPlayed = false;
 			break;
 		}
 	}
 	
 	// Get the latest Items
-	$latest = json_decode(file_get_contents($address.'/Users/'.$userId.'/Items/Latest?'.$embyTypeQuery.'EnableImages=false&api_key='.EMBYTOKEN),true);
+	$latest = json_decode(file_get_contents($address.'/Users/'.$userId.'/Items/Latest?'.$embyTypeQuery.'EnableImages=false&api_key='.EMBYTOKEN.($showPlayed?'':'&IsPlayed=false')),true);
 	
 	// For Each Item In Category
 	$items = array();
@@ -701,6 +712,7 @@ function getEmbyImage() {
 		$image_src = $embyAddress . '/Items/'.$itemId.'/Images/Primary?'.implode('&', $imgParams);
 		header('Content-type: image/jpeg');
 		readfile($image_src);
+		die();
 	} else {
 		debug_out('Invalid Request',1);
 	}
@@ -718,6 +730,7 @@ function getPlexImage() {
 		$image_src = $plexAddress . '/photo/:/transcode?height='.$image_height.'&width='.$image_width.'&upscale=1&url=' . $image_url . '&X-Plex-Token=' . PLEXTOKEN;
 		header('Content-type: image/jpeg');
 		readfile($image_src);
+		die();
 	} else {
 		echo "Invalid Plex Request";	
 	}
@@ -766,7 +779,7 @@ function createConfig($array, $path = 'config/config.php', $nest = 0) {
 				$item = $v;
 				break;
 			case 'string':
-				$item = '"'.addslashes($v).'"';
+				$item = "'".str_replace(array('\\',"'"),array('\\\\',"\'"),$v)."'";
 				break;
 			case 'array':
 				$item = createConfig($v, false, $nest+1);
@@ -776,13 +789,13 @@ function createConfig($array, $path = 'config/config.php', $nest = 0) {
 		}
 		
 		if($allowCommit) {
-			$output[] = str_repeat("\t",$nest+1).'"'.$k.'" => '.$item;
+			$output[] = str_repeat("\t",$nest+1)."'$k' => $item";
 		}
 	}
 	
 	if (!$nest && !isset($array['CONFIG_VERSION'])) {
 		// Inject Current Version
-		$output[] = "\t".'"CONFIG_VERSION" => "'.INSTALLEDVERSION.'"';
+		$output[] = "\t'CONFIG_VERSION' => '".INSTALLEDVERSION."'";
 	}
 	
 	// Build output
@@ -1000,8 +1013,18 @@ function upgradeCheck() {
 		// Update Version and Commit
 		$config['CONFIG_VERSION'] = '1.33';
 		$createConfigSuccess = createConfig($config);
+		unset($config);
+	}
+	
+	// Upgrade to 1.33
+	$config = loadConfig();
+	if (isset($config['database_Location']) && (!isset($config['CONFIG_VERSION']) || $config['CONFIG_VERSION'] < '1.34')) {
+		// Upgrade database to latest version
+		updateSQLiteDB($config['database_Location']);
 		
-		$effectiveVersion = $config['CONFIG_VERSION'];
+		// Update Version and Commit
+		$config['CONFIG_VERSION'] = '1.34';
+		$createConfigSuccess = createConfig($config);
 		unset($config);
 	}
 	
@@ -1201,6 +1224,8 @@ function buildSettings($array) {
 	<script>
 		$(document).ready(function() {
 			$(\'#'.$pageID.'_form\').find(\'input, select, textarea\').on(\'change\', function() { $(this).attr(\'data-changed\', \'true\'); });
+			var '.$pageID.'Validate = function() { if (this.value && !RegExp(\'^\'+this.pattern+\'$\').test(this.value)) { $(this).addClass(\'invalid\'); } else { $(this).removeClass(\'invalid\'); } };
+			$(\'#'.$pageID.'_form\').find(\'input[pattern]\').each('.$pageID.'Validate).on(\'keyup\', '.$pageID.'Validate);
 			$(\'#'.$pageID.'_form\').find(\'select[multiple]\').on(\'click\', function() { $(this).attr(\'data-changed\', \'true\'); });
 			
 			$(\'#'.$pageID.'_form\').submit(function () {
@@ -1224,11 +1249,9 @@ function buildSettings($array) {
 				});
 				if (hasVals) {
 					console.log(newVals);
-					$.post(\'ajax.php?a='.(isset($array['submitAction'])?$array['submitAction']:'update-config').'\', newVals, function(data) {
-						console.log(data);
+					ajax_request(\'POST\', \''.(isset($array['submitAction'])?$array['submitAction']:'update-config').'\', newVals, function(data, code) {
 						$(\'#'.$pageID.'_form\').find(\'[data-changed=true]\').removeAttr(\'data-changed\');
-						parent.notify(data.html, data.icon, data.type, data.length, data.layout, data.effect);
-					}, \'json\');
+					});
 				} else {
 					parent.notify(\'Nothing to update!\', \'bullhorn\', \'success\', 5000, \'bar\', \'slidetop\');
 				}
@@ -1259,8 +1282,11 @@ function buildField($params, $sizeSm = 12, $sizeMd = 12, $sizeLg = 12) {
 	
 	// Tags
 	$tags = array();
-	foreach(array('placeholder','style','disabled','readonly','pattern','min','max','required','onkeypress','onchange','onfocus','onleave','href') as $value) {
-		$tags[] = (isset($params[$value])?$value.'="'.$params[$value].'"':'');
+	foreach(array('placeholder','style','disabled','readonly','pattern','min','max','required','onkeypress','onchange','onfocus','onleave','href','onclick') as $value) {
+		if (isset($params[$value])) {
+			if (is_string($params[$value])) { $tags[] = $value.'="'.$params[$value].'"';
+			} else if ($params[$value] === true) { $tags[] = $value; }
+		}
 	}
 	
 	$format = (isset($params['format']) && in_array($params['format'],array(false,'colour','color'))?$params['format']:false);
@@ -1292,15 +1318,21 @@ function buildField($params, $sizeSm = 12, $sizeMd = 12, $sizeLg = 12) {
 		case 'checkbox':
 		case 'toggle':
 			$checked = ((is_bool($val) && $val) || trim($val) === 'true'?' checked':'');
+			$colour = (isset($params['colour'])?$params['colour']:'success');
 			$labelOut = '<label for="'.$id.'"></label>'.$label;
-			$field = '<input id="'.$id.'" name="'.$name.'" type="checkbox" class="switcher switcher-success'.$class.'" '.implode(' ',$tags).' value="'.$val.'"'.$checked.'>';
+			$field = '<input id="'.$id.'" name="'.$name.'" type="checkbox" class="switcher switcher-'.$colour.' '.$class.'" '.implode(' ',$tags).' data-value="'.$val.'"'.$checked.'>';
+			break;
+		case 'radio':
+			$labelOut = '';
+			$checked = ((is_bool($val) && $val) || ($val && trim($val) !== 'false')?' checked':'');
+			$bType = (isset($params['buttonType'])?$params['buttonType']:'success');
+			$field = '<div class="radio radio-'.$bType.'"><input id="'.$id.'" name="'.$name.'" type="radio" class="'.$class.'" '.implode(' ',$tags).' value="'.$val.'"'.$checked.'><label for="'.$id.'">'.$label.'</label></div>';
 			break;
 		case 'date':
 			$field = 'Unsupported, planned.';
 			break;
 		case 'hidden':
-			$labelOut = '';
-			$field = '<input id="'.$id.'" name="'.$name.'" type="hidden" class="'.$class.'" '.implode(' ',$tags).' value="'.$val.'">';
+			return '<input id="'.$id.'" name="'.$name.'" type="hidden" class="'.$class.'" '.implode(' ',$tags).' value="'.$val.'">';
 			break;
 		case 'header':
 			$labelOut = '';
@@ -1314,6 +1346,28 @@ function buildField($params, $sizeSm = 12, $sizeMd = 12, $sizeLg = 12) {
 			$bDropdown = (isset($params['buttonDrop'])?$params['buttonDrop']:'');
 			$field = ($bDropdown?'<div class="btn-group">':'').'<button id="'.$id.'" type="button" class="btn waves btn-labeled btn-'.$bType.' btn-sm text-uppercase waves-effect waves-float'.$class.''.($bDropdown?' dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"':'"').' '.implode(' ',$tags).'><span class="btn-label"><i class="fa fa-'.$icon.'"></i></span>'.$label.'</button>'.($bDropdown?$bDropdown.'</div>':'');
 			break;
+		case 'textarea':
+			$rows = (isset($params['rows'])?$params['rows']:5);
+			$field = '<textarea id="'.$id.'" name="'.$name.'" class="form-control'.$class.'" rows="'.$rows.'" '.implode(' ',$tags).'>'.$val.'</textarea>';
+			break;
+		case 'custom':
+			// Settings
+			$settings = array(
+				'$id' => $id,
+				'$name' => $name,
+				'$val' => $val,
+				'$label' => $label,
+				'$labelOut' => $labelOut,
+			);
+			// Get HTML
+			$html = (isset($params['html'])?$params['html']:'Nothing Specified!');
+			// If LabelOut is in html dont print it twice
+			$labelOut = (strpos($html,'$label')!==false?'':$labelOut);
+			// Replace variables in settings
+			$html = preg_replace_callback('/\$\w+\b/', function ($match) use ($settings) { return (isset($settings[$match[0]])?$settings[$match[0]]:'{'.$match[0].' is undefined}'); }, $html);
+			// Build Field
+			$field = '<div id="'.$id.'_html" class="custom-field">'.$html.'</div>';
+			break;
 		case 'space':
 			$labelOut = '';
 			$field = str_repeat('<br>', (isset($params['value'])?$params['value']:1));
@@ -1340,6 +1394,120 @@ function buildField($params, $sizeSm = 12, $sizeMd = 12, $sizeLg = 12) {
 	return '<div class="'.$wrapClass.' col-sm-'.$sizeSm.' col-md-'.$sizeMd.' col-lg-'.$sizeLg.'">'.$labelBef.$field.$labelAft.'</div>';
 }
 
+// Tab Settings Generation
+function printTabRow($data) {
+	$hidden = false;
+	if ($data===false) {
+		$hidden = true;
+		$data = array( // New Tab Defaults
+			'id' => 'new',
+			'name' => '',
+			'url' => '',
+			'icon' => 'fa-diamond',
+			'iconurl' => '',
+			'active' => 'true',
+			'user' => 'true',
+			'guest' => 'true',
+			'window' => 'false',
+			'defaultz' => '',
+		);
+	}
+	$image = '<span style="font: normal normal normal 30px/1 FontAwesome;" class="fa fa-hand-paper-o"></span>';
+	
+	$output = '
+		<li id="tab-'.$data['id'].'" class="list-group-item" style="position: relative; left: 0px; top: 0px; '.($hidden?' display: none;':'').'">
+			<tab class="content-form form-inline">
+				<div class="row">
+					'.buildField(array(
+						'type' => 'custom',
+						'html' => '<div class="action-btns tabIconView"><a style="margin-left: 0px">'.($data['iconurl']?'<img src="'.$data['iconurl'].'" height="30" width="30">':'<span style="font: normal normal normal 30px/1 FontAwesome;" class="fa '.($data['icon']?$data['icon']:'hand-paper-o').'"></span>').'</a></div>',
+					),12,1,1).'
+					'.buildField(array(
+						'type' => 'hidden',
+						'id' => 'tab-'.$data['id'].'-id',
+						'name' => 'id['.$data['id'].']',
+						'value' => $data['id'],
+					),12,2,1).'
+					'.buildField(array(
+						'type' => 'text',
+						'id' => 'tab-'.$data['id'].'-name',
+						'name' => 'name['.$data['id'].']',
+						'required' => true,
+						'placeholder' => 'Organizr Homepage',
+						'labelTranslate' => 'TAB_NAME',
+						'value' => $data['name'],
+					),12,2,1).'
+					'.buildField(array(
+						'type' => 'text',
+						'id' => 'tab-'.$data['id'].'-url',
+						'name' => 'url['.$data['id'].']',
+						'required' => true,
+						'placeholder' => 'homepage.php',
+						'labelTranslate' => 'TAB_URL',
+						'value' => $data['url'],
+					),12,2,1).'
+					'.buildField(array(
+						'type' => 'text',
+						'id' => 'tab-'.$data['id'].'-iconurl',
+						'name' => 'iconurl['.$data['id'].']',
+						'placeholder' => 'images/organizr.png',
+						'labelTranslate' => 'ICON_URL',
+						'value' => $data['iconurl'],
+					),12,2,1).'
+					'.buildField(array(
+						'type' => 'custom',
+						'id' => 'tab-'.$data['id'].'-icon',
+						'name' => 'icon['.$data['id'].']',
+						'html' => '- '.translate('OR').' - <div class="input-group"><input data-placement="bottomRight" class="form-control material icp-auto'.($hidden?'-pend':'').'" id="$id" name="$name" value="$val" type="text" /><span class="input-group-addon"></span></div>',
+						'value' => $data['icon'],
+					),12,1,1).'
+					'.buildField(array(
+						'type' => 'checkbox',
+						'labelTranslate' => 'ACTIVE',
+						'name' => 'active['.$data['id'].']',
+						'value' => $data['active'],
+					),12,1,1).'
+					'.buildField(array(
+						'type' => 'checkbox',
+						'labelTranslate' => 'USER',
+						'colour' => 'primary',
+						'name' => 'user['.$data['id'].']',
+						'value' => $data['user'],
+					),12,1,1).'
+					'.buildField(array(
+						'type' => 'checkbox',
+						'labelTranslate' => 'GUEST',
+						'colour' => 'warning',
+						'name' => 'guest['.$data['id'].']',
+						'value' => $data['guest'],
+					),12,1,1).'
+					'.buildField(array(
+						'type' => 'checkbox',
+						'labelTranslate' => 'NO_IFRAME',
+						'colour' => 'danger',
+						'name' => 'window['.$data['id'].']',
+						'value' => $data['window'],
+					),12,1,1).'
+					'.buildField(array(
+						'type' => 'radio',
+						'labelTranslate' => 'DEFAULT',
+						'name' => 'defaultz['.$data['id'].']',
+						'value' => $data['defaultz'],
+						'onclick' => "$('[type=radio][id!=\''+this.id+'\']').each(function() { this.checked=false; });",
+					),12,1,1).'
+					'.buildField(array(
+						'type' => 'button',
+						'icon' => 'trash',
+						'labelTranslate' => 'REMOVE',
+						'onclick' => "$(this).parents('li').remove();",
+					),12,1,1).'
+				</div>
+			</tab>
+		</li>
+	';
+	return $output;
+}
+
 // Timezone array
 function timezoneOptions() {
 	$output = array();
@@ -1402,6 +1570,7 @@ function createSQLiteDB($path = false) {
 		// Create Tabs
 		$tabs = $GLOBALS['file_db']->query('CREATE TABLE `tabs` (
 			`id`	INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
+			`order`	INTEGER,
 			`users_id`	INTEGER,
 			`name`	TEXT,
 			`url`	TEXT,
@@ -1516,12 +1685,11 @@ function updateDBOptions($values) {
 }
 
 // Send AJAX notification
-function sendNotification($success, $message = false) {
-	header('Content-Type: application/json');
+function sendNotification($success, $message = false, $send = true) {
 	$notifyExplode = explode("-", NOTIFYEFFECT);
 	if ($success) {
 		$msg = array(
-			'html' => '<strong>'.translate("SETTINGS_SAVED").'</strong>'.($message?'<br>'.$message:''),
+			'html' => ($message?'<br>'.$message:'<strong>'.translate("SETTINGS_SAVED").'</strong>'),
 			'icon' => 'floppy-o',
 			'type' => 'success',
 			'length' => '5000',
@@ -1530,7 +1698,7 @@ function sendNotification($success, $message = false) {
 		);
 	} else {
 		$msg = array(
-			'html' => '<strong>'.translate("SETTINGS_NOT_SAVED").'</strong>'.($message?'<br>'.$message:''),
+			'html' => ($message?'<br>'.$message:'<strong>'.translate("SETTINGS_NOT_SAVED").'</strong>'),
 			'icon' => 'floppy-o',
 			'type' => 'failed',
 			'length' => '5000',
@@ -1538,8 +1706,14 @@ function sendNotification($success, $message = false) {
 			'effect' => $notifyExplode[1],
 		);
 	}
-	echo json_encode($msg);
-	die();
+	
+	// Send and kill script?
+	if ($send) {
+		header('Content-Type: application/json');
+		echo json_encode(array('notify'=>$msg));
+		die();
+	}
+	return $msg;
 }
 
 // Load colours from the database
@@ -1607,7 +1781,7 @@ function deleteDatabase() {
 }
 
 // Upgrade the installation
-function upgradeInstall() {
+function upgradeInstall($branch = 'master') {
     function downloadFile($url, $path){
         $folderPath = "upgrade/";
         if(!mkdir($folderPath)) : echo "can't make dir"; endif;
@@ -1665,10 +1839,10 @@ function upgradeInstall() {
         } else if (file_exists ( $src ))
             copy ( $src, $dst );
     }
-
-    $url = "https://github.com/causefx/Organizr/archive/master.zip";
+	
+    $url = 'https://github.com/causefx/Organizr/archive/'.$branch.'.zip';
     $file = "upgrade.zip";
-    $source = __DIR__ . "/upgrade/Organizr-master/";
+    $source = __DIR__ . '/upgrade/Organizr-'.$branch.'/';
     $cleanup = __DIR__ . "/upgrade/";
     $destination = __DIR__ . "/";
     downloadFile($url, $file);
@@ -1679,6 +1853,120 @@ function upgradeInstall() {
 	return true;
 }
 
+// NzbGET Items
+function nzbgetConnect($list = 'listgroups') {
+    $url = qualifyURL(NZBGETURL);
+    
+    $api = file_get_contents($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>'.$downloadName.'</td>
+                        <td>'.$downloadStatus.'</td>
+                        <td>'.$downloadCategory.'</td>
+                        <td>
+                            <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>';
+	}
+}
+
+// Sabnzbd Items
+function sabnzbdConnect($list = 'queue') {
+    $url = qualifyURL(SABNZBDURL);
+	
+    $api = file_get_contents($url.'/api?mode='.$list.'&output=json&apikey='.SABNZBDKEY); 
+    $api = json_decode($api, true);
+    
+    $gotNZB = array();
+    
+    foreach ($api[$list]['slots'] AS $child) {
+        if($list == "queue"){ $downloadName = $child['filename']; $downloadCategory = $child['cat']; $downloadPercent = (($child['mb'] - $child['mbleft']) / $child['mb']) * 100; $progressBar = "progress-bar-striped active"; } 
+        if($list == "history"){ $downloadName = $child['name']; $downloadCategory = $child['category']; $downloadPercent = "100"; $progressBar = ""; }
+        $downloadStatus = $child['status'];
+        
+        $gotNZB[] = '<tr>
+                        <td>'.$downloadName.'</td>
+                        <td>'.$downloadStatus.'</td>
+                        <td>'.$downloadCategory.'</td>
+                        <td>
+                            <div class="progress">
+                                <div class="progress-bar progress-bar-success '.$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>';
+	}
+}
+
+// Apply new tab settings
+function updateTabs($tabs) {
+	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);
+	}
+	// Validate
+	if (!isset($tabs['defaultz'])) { $tabs['defaultz'][current(array_keys($tabs['name']))] = 'true'; }
+	if (isset($tabs['name']) && isset($tabs['url']) && is_array($tabs['name'])) {
+		// Clear Existing Tabs
+		$GLOBALS['file_db']->query("DELETE FROM tabs");
+		// Process New Tabs
+		$totalValid = 0;
+		foreach ($tabs['name'] as $key => $value) {
+			// Qualify
+			if (!$value || !isset($tabs['url']) || !$tabs['url'][$key]) { continue; }
+			$totalValid++;
+			$fields = array();
+			foreach(array('id','name','url','icon','iconurl','order') as $v) {
+				if (isset($tabs[$v]) && isset($tabs[$v][$key])) { $fields[$v] = $tabs[$v][$key]; }
+			}
+			foreach(array('active','user','guest','defaultz','window') as $v) {
+				if (isset($tabs[$v]) && isset($tabs[$v][$key])) { $fields[$v] = ($tabs[$v][$key]!=='false'?'true':'false'); }
+			}
+			$GLOBALS['file_db']->query('INSERT INTO tabs (`'.implode('`,`',array_keys($fields)).'`) VALUES (\''.implode("','",$fields).'\');');
+		}
+		return $totalValid;
+	} else {
+		return false;
+	}
+	return false;
+}
+
 // ==============
 
 function clean($strin) {
@@ -2078,114 +2366,6 @@ function getRadarrCalendar($array){
 
 }
 
-function nzbgetConnect($url, $username, $password, $list){
-    $url = qualifyURL(NZBGETURL);
-    
-    $api = file_get_contents("$url/$username:$password/jsonrpc/$list");
-                    
-    $api = json_decode($api, true);
-    
-    $i = 0;
-    
-    $gotNZB = "";
-    
-    foreach ($api['result'] AS $child) {
-        
-        $i++;
-        //echo '<pre>' . var_export($child, true) . '</pre>';
-        $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>'.$downloadName.'</td>
-                        <td>'.$downloadStatus.'</td>
-                        <td>'.$downloadCategory.'</td>
-
-                        <td>
-
-                            <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($i > 0){ return $gotNZB; }
-    if($i == 0){ echo '<tr><td colspan="4"><p class="text-center">No Results</p></td></tr>'; }
-
-}
-
-function sabnzbdConnect($url, $key, $list){
-    $url = qualifyURL(SABNZBDURL);
-
-    $api = file_get_contents("$url/api?mode=$list&output=json&apikey=$key");
-                    
-    $api = json_decode($api, true);
-    
-    $i = 0;
-    
-    $gotNZB = "";
-    
-    foreach ($api[$list]['slots'] AS $child) {
-        
-        $i++;
-        if($list == "queue"){ $downloadName = $child['filename']; $downloadCategory = $child['cat']; $downloadPercent = (($child['mb'] - $child['mbleft']) / $child['mb']) * 100; $progressBar = "progress-bar-striped active"; } 
-        if($list == "history"){ $downloadName = $child['name']; $downloadCategory = $child['category']; $downloadPercent = "100"; $progressBar = ""; }
-        $downloadStatus = $child['status'];
-        
-        $gotNZB .= '<tr>
-
-                        <td>'.$downloadName.'</td>
-                        <td>'.$downloadStatus.'</td>
-                        <td>'.$downloadCategory.'</td>
-
-                        <td>
-
-                            <div class="progress">
-
-                                <div class="progress-bar progress-bar-success '.$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($i > 0){ return $gotNZB; }
-    if($i == 0){ echo '<tr><td colspan="4"><p class="text-center">No Results</p></td></tr>'; }
-
-}
-
 function getHeadphonesCalendar($url, $key, $list){
 	$url = qualifyURL(HEADPHONESURL);
     

+ 66 - 136
homepage.php

@@ -103,6 +103,23 @@ $endDate = date('Y-m-d',strtotime("+".CALENDARENDDAY." days"));
 
         <link rel="stylesheet" href="css/style.css">
 
+        <!--Scripts-->
+        <script src="bower_components/jquery/dist/jquery.min.js"></script>
+        <script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
+        <script src="bower_components/moment/min/moment.min.js"></script>
+        <script src="bower_components/jquery.nicescroll/jquery.nicescroll.min.js"></script>
+        <script src="bower_components/slimScroll/jquery.slimscroll.min.js"></script>
+        <script src="bower_components/malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.js"></script>
+        <script src="bower_components/jquery.nicescroll/jquery.nicescroll.min.js"></script>
+        <script src="bower_components/cta/dist/cta.min.js"></script>
+        <script src="bower_components/fullcalendar/dist/fullcalendar.js"></script>
+
+        <script src="js/jqueri_ui_custom/jquery-ui.min.js"></script>
+	    <script src="js/jquery.mousewheel.min.js" type="text/javascript"></script>
+		
+		<!--Other-->
+		<script src="js/ajax.js?v=<?php echo INSTALLEDVERSION; ?>"></script>
+		
         <!--[if lt IE 9]>
         <script src="bower_components/html5shiv/dist/html5shiv.min.js"></script>
         <script src="bower_components/respondJs/dest/respond.min.js"></script>
@@ -183,7 +200,6 @@ endif; ?>
     </head>
 
     <body class="scroller-body" style="padding: 0px;">
-
         <div class="main-wrapper" style="position: initial;">
             <div id="content" class="container-fluid">
 <!-- <button id="numBnt">Numerical</button> -->
@@ -191,124 +207,75 @@ endif; ?>
                 <?php if((NZBGETURL != "" && qualifyUser(NZBGETHOMEAUTH)) || (SABNZBDURL != "" && qualifyUser(SABNZBDHOMEAUTH))) { ?>
                 <div id="downloadClientRow" class="row">
                     <sort>2</sort>
-
                     <div class="col-xs-12 col-md-12">
                         <div class="content-box">
-
                             <div class="tabbable panel with-nav-tabs panel-default">
-
                                 <div class="panel-heading">
-
                                     <div class="content-tools i-block pull-right">
-
                                         <a id="getDownloader" class="repeat-btn">
-
                                             <i class="fa fa-repeat"></i>
-
                                         </a>
-
                                         <a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
                                             <i class="fa fa-chevron-down"></i>
                                         </a>
+										<!-- Lets Move This To Homepage Settings
                                         <ul id="downloaderSeconds" class="dropdown-menu" style="top: 32px !important">
-
                                             <li data-value="5000"><a>Refresh every 5 seconds</a></li>
                                             <li data-value="10000"><a>Refresh every 10 seconds</a></li>
                                             <li data-value="30000"><a>Refresh every 30 seconds</a></li>
                                             <li data-value="60000"><a>Refresh every 60 seconds</a></li>
-
                                         </ul>
-
+										-->
                                     </div>
-
                                     <h3 class="pull-left"><?php if(NZBGETURL != ""){ echo "NZBGet "; } if(SABNZBDURL != ""){ echo "SABnzbd "; } ?></h3>
-
                                     <ul class="nav nav-tabs pull-right">
-
                                         <li class="active"><a href="#downloadQueue" data-toggle="tab" aria-expanded="true"><?php echo $language->translate("QUEUE");?></a></li>
-
                                         <li class=""><a href="#downloadHistory" data-toggle="tab" aria-expanded="false"><?php echo $language->translate("HISTORY");?></a></li>
-
                                     </ul>
-
                                     <div class="clearfix"></div>
-
                                 </div>
-
                                 <div class="panel-body">
-
                                     <div class="tab-content">
-
                                         <div class="tab-pane fade active in" id="downloadQueue">
-
                                             <div class="table-responsive" style="max-height: 300px">
-
                                                 <table class="table table-striped progress-widget zero-m" style="max-height: 300px">
-
                                                     <thead>
-
                                                         <tr>
-
                                                             <th><?php echo $language->translate("FILE");?></th>
                                                             <th><?php echo $language->translate("STATUS");?></th>
                                                             <th><?php echo $language->translate("CATEGORY");?></th>
                                                             <th><?php echo $language->translate("PROGRESS");?></th>
-
                                                         </tr>
-
                                                     </thead>
-
-                                                    <tbody id="downloaderQueue">                               
-
-                                                    </tbody>
-
+                                                    <tbody class="dl-queue sabnzbd"></tbody>
+                                                    <tbody class="dl-queue nzbget"></tbody>
                                                 </table>
-
                                             </div>
-
                                         </div>
-
                                         <div class="tab-pane fade" id="downloadHistory">
-
                                             <div class="table-responsive" style="max-height: 300px">
-
                                                 <table class="table table-striped progress-widget zero-m" style="max-height: 300px">
-
                                                     <thead>
-
                                                         <tr>
-
-                                                            <th>File</th>
-                                                            <th>Status</th>
-                                                            <th>Category</th>
-                                                            <th>Progress</th>
-
+                                                            <th><?php echo $language->translate("FILE");?></th>
+                                                            <th><?php echo $language->translate("STATUS");?></th>
+                                                            <th><?php echo $language->translate("CATEGORY");?></th>
+                                                            <th><?php echo $language->translate("PROGRESS");?></th>
                                                         </tr>
-
                                                     </thead>
-
-                                                    <tbody id="downloaderHistory">                                      
-
-                                                    </tbody>
-
+                                                    <tbody class="dl-history sabnzbd"></tbody>
+                                                    <tbody class="dl-history nzbget"></tbody>
                                                 </table>
-
                                             </div>
-
                                         </div>
-
                                     </div>
-
                                 </div>
-
                             </div>
                         </div>
-
                     </div>
-
                 </div>
                 <?php } ?>
-				<?php if (qualifyUser(PLEXHOMEAUTH)) { ?>
+				<?php if (qualifyUser(PLEXHOMEAUTH) && PLEXTOKEN) { ?>
                 <div id="plexRow" class="row">
                     <sort>3</sort>
 
@@ -322,7 +289,7 @@ endif; ?>
 
                 </div>
 				<?php } ?>
-				<?php if (qualifyUser(EMBYHOMEAUTH)) { ?>
+				<?php if (qualifyUser(EMBYHOMEAUTH) && EMBYTOKEN) { ?>
                 <div id="embyRow" class="row">
                     <sort>3</sort>
 
@@ -362,23 +329,19 @@ endif; ?>
                     </div>
                 </div>
                 <?php } ?>
-
+				
+                <?php if (qualifyUser(HOMEPAGECUSTOMHTML1AUTH) && HOMEPAGECUSTOMHTML1) { ?>
+				<div>
+					<?php echo HOMEPAGECUSTOMHTML1; ?>
+				</div>
+                <?php } ?>
             </div>    
         </div>
-        <!--Scripts-->
-        <script src="bower_components/jquery/dist/jquery.min.js"></script>
-        <script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
-        <script src="bower_components/moment/min/moment.min.js"></script>
-        <script src="bower_components/jquery.nicescroll/jquery.nicescroll.min.js"></script>
-        <script src="bower_components/slimScroll/jquery.slimscroll.min.js"></script>
-        <script src="bower_components/malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.js"></script>
-        <script src="bower_components/jquery.nicescroll/jquery.nicescroll.min.js"></script>
-        <script src="bower_components/cta/dist/cta.min.js"></script>
-        <script src="bower_components/fullcalendar/dist/fullcalendar.js"></script>
-
-        <script src="js/jqueri_ui_custom/jquery-ui.min.js"></script>
-	    <script src="js/jquery.mousewheel.min.js" type="text/javascript"></script>
         <script>
+		function localStorageSupport() {
+			return (('localStorage' in window) && window['localStorage'] !== null)
+		}
+		
         $( document ).ready(function() {
              $('.repeat-btn').click(function(){
                 var refreshBox = $(this).closest('div.content-box');
@@ -409,67 +372,34 @@ endif; ?>
                 mousescrollstep: 60
             });*/
             // check if browser support HTML5 local storage
-            function localStorageSupport() {
-                return (('localStorage' in window) && window['localStorage'] !== null)
-            }
+			
             <?php if((NZBGETURL != "" && qualifyUser(NZBGETHOMEAUTH)) || (SABNZBDURL != "" && qualifyUser(SABNZBDHOMEAUTH))){ ?>
-            var downloaderSeconds = localStorage.getItem("downloaderSeconds");
-            var myInterval = undefined;
-            $("ul").find("[data-value='" + downloaderSeconds + "']").addClass("active");
-            if(  downloaderSeconds === null ) {
-                localStorage.setItem("downloaderSeconds",'60000');
-                var downloaderSeconds = "60000";
-            }
-            $('#downloaderSeconds li').click(function() {
-                $('#downloaderSeconds li').removeClass("active");
-                $(this).addClass("active");
-
-                var newDownloaderSeconds = $(this).attr('data-value');
-                console.log('New Time is ' + newDownloaderSeconds + ' Old Time was ' + downloaderSeconds);
-                if (localStorageSupport) {
-                    localStorage.setItem("downloaderSeconds",newDownloaderSeconds);
-                }
-                if(typeof myInterval != 'undefined'){ clearInterval(myInterval); }
-                refreshDownloader(newDownloaderSeconds);
-            });
-            <?php } ?>
-            <?php if((NZBGETURL != "" && qualifyUser(NZBGETHOMEAUTH))){ ?>
-            $("#downloaderHistory").load("downloader.php?downloader=nzbget&list=history");
-            $("#downloaderQueue").load("downloader.php?downloader=nzbget&list=listgroups");
-            refreshDownloader = function(secs){
-                myInterval = setInterval(function(){
-                    $("#downloaderHistory").load("downloader.php?downloader=nzbget&list=history");
-                    $("#downloaderQueue").load("downloader.php?downloader=nzbget&list=listgroups");
-                }, secs);                
-            }
-
-            refreshDownloader(downloaderSeconds);
-
-            $("#getDownloader").click(function(){
-                $("#downloaderHistory").load("downloader.php?downloader=nzbget&list=history");
-                $("#downloaderQueue").load("downloader.php?downloader=nzbget&list=listgroups");
-                console.log('completed'); 
-            });
-
-            <?php } ?>
-            <?php if((SABNZBDURL != "" && qualifyUser(SABNZBDHOMEAUTH))){ ?>
-            $("#downloaderHistory").load("downloader.php?downloader=sabnzbd&list=history");
-            $("#downloaderQueue").load("downloader.php?downloader=sabnzbd&list=queue");
-            refreshDownloader = function(secs){
-                myInterval = setInterval(function(){
-                    $("#downloaderHistory").load("downloader.php?downloader=sabnzbd&list=history");
-                    $("#downloaderQueue").load("downloader.php?downloader=sabnzbd&list=queue");
-                }, secs);                
-            }
-
-            refreshDownloader(downloaderSeconds);
-
-            $("#getDownloader").click(function(){
-                $("#downloaderHistory").load("downloader.php?downloader=sabnzbd&list=history");
-                $("#downloaderQueue").load("downloader.php?downloader=sabnzbd&list=queue");
-                console.log('completed'); 
-            });
-
+			var queueRefresh = 30000;
+			var historyRefresh = 120000; // 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");'; } ?>
+				<?php if(NZBGETURL != "") { echo '$("tbody.dl-queue.nzbget").load("ajax.php?a=nzbget-update&list=listgroups");'; } ?>
+			};
+			
+			var historyLoad = function() {
+				<?php if(SABNZBDURL != "") { echo '$("tbody.dl-history.sabnzbd").load("ajax.php?a=sabnzbd-update&list=history");'; } ?>
+				<?php if(NZBGETURL != "") { echo '$("tbody.dl-history.nzbget").load("ajax.php?a=nzbget-update&list=history");'; } ?>
+			};
+			
+			// Initial Loads
+			queueLoad();
+			historyLoad();
+			
+			// Interval Loads
+			var queueInterval = setInterval(queueLoad, queueRefresh);
+			var historyInterval = setInterval(historyLoad, historyRefresh);
+			
+			// Manual Load
+			$("#getDownloader").click(function() {
+				queueLoad();
+				historyLoad();
+			});
             <?php } ?>
         });
         </script>

+ 6 - 4
index.php

@@ -117,8 +117,8 @@ if (file_exists('config/config.php')) {
 
         if($USER->authenticated && $USER->role == "admin") :
 
-            $result = $file_db->query('SELECT * FROM tabs WHERE active = "true"');
-            $getsettings = $file_db->query('SELECT * FROM tabs WHERE active = "true"');
+            $result = $file_db->query('SELECT * FROM tabs WHERE active = "true" ORDER BY `order` asc');
+            $getsettings = $file_db->query('SELECT * FROM tabs WHERE active = "true" ORDER BY `order` asc');
 
             foreach($getsettings as $row) :
 
@@ -132,11 +132,11 @@ if (file_exists('config/config.php')) {
 
         elseif($USER->authenticated && $USER->role == "user") :
 
-            $result = $file_db->query('SELECT * FROM tabs WHERE active = "true" AND user = "true"');
+            $result = $file_db->query('SELECT * FROM tabs WHERE active = "true" AND user = "true" ORDER BY `order` asc');
 
         else :
 
-            $result = $file_db->query('SELECT * FROM tabs WHERE active = "true" AND guest = "true"');
+            $result = $file_db->query('SELECT * FROM tabs WHERE active = "true" AND guest = "true" ORDER BY `order` asc');
 
         endif;
 
@@ -266,6 +266,8 @@ if(file_exists("images/settings2.png")) : $iconRotate = "false"; $settingsIcon =
         <meta name="theme-color" content="#2d89ef">
         <link rel="stylesheet" type="text/css" href="css/addtohomescreen.css">
         <script src="js/addtohomescreen.js"></script>
+		<!--Other-->
+		<script src="js/ajax.js?v=<?php echo INSTALLEDVERSION; ?>"></script>
         <!--[if lt IE 9]>
         <script src="bower_components/html5shiv/dist/html5shiv.min.js"></script>
         <script src="bower_components/respondJs/dest/respond.min.js"></script>

+ 120 - 0
js/ajax.js

@@ -0,0 +1,120 @@
+function ajax_request(method, action, data, callback, options) {
+	var ajax_response_action = function(data, req_code) {
+		if (typeof options === 'object' && options.replacecallback === true && typeof callback === 'function') {
+			callback(data, req_code);
+		} else {
+			// Use just JSON data
+			data = data.responseJSON;
+			
+			// Check if data object is valid
+			if (typeof data === 'object') {				
+				// Check if we are doing notifications
+				if (typeof data.notify === 'object') {
+					if (typeof parent.notify === 'function') {
+						var notifyString = (data.notify.html?data.notify.html:'Ajax Complete!;')
+						var notifyIcon = (data.notify.icon?data.notify.icon:'bullhorn;')
+						var notifyType = (data.notify.type?data.notify.type:'success;')
+						var notifyLength = (data.notify.length?data.notify.length:4000)
+						var notifyLayout = (data.notify.layout?data.notify.layout:'bar')
+						var notifyEffect = (data.notify.effect?data.notify.effect:'slidetop')
+						
+						parent.notify(notifyString, notifyIcon, notifyType, notifyLength, notifyLayout, notifyEffect);
+					} else {
+						console.log(data.notify);
+					}
+				}
+				
+				// Show Apply
+				if (data.show_apply === true) {
+					$('#apply').show();
+				}
+				
+				// Callback
+				if (typeof data.callback === 'string') {
+					eval(data.callback);
+				}
+				
+				// Internal Process Function
+				var scopefunctions = function(scopeObj, data) {
+					
+					// Reload?
+					if (data.reload === true) {
+						console.log(scopeObj.location.href );
+						scopeObj.location.href = scopeObj.location.href;
+						scopeObj.location.reload(true);
+					}
+					
+					// Navigate?
+					if (typeof data.goto === 'string') {
+						if (!/^http(s)?:\/\//i.test(data.goto)) {
+							if (/^\//.test(data.goto)) {
+								data.goto = scopeObj.location.origin + data.goto;
+							} else {
+								var currentLoc = scopeObj.location.pathname.split('/');
+								currentLoc.splice(-1);
+								data.goto = currentLoc.join('/') + '/' + data.goto;
+							}
+						}
+						scopeObj.location.href = data.goto;
+					}
+					
+					// Replace body with
+					if (typeof data.content === 'string') {
+						scopeObj.document.getElementsByTagName('body').innerHTML = data.content;
+					}
+				}
+				
+				// Tab Scope
+				if (typeof data.tab === 'object') {
+					scopefunctions(window, data.tab);
+				}
+				
+				// Page Functions
+				if (typeof data.parent === 'object') {
+					scopefunctions(window.parent, data.parent);
+				}
+			} else {
+				// Dunno what this is
+				console.log(data);
+			}
+			
+			// Custom Callback (in addition to default actions);
+			if (typeof callback !== 'undefined') {
+				if (typeof callback === 'function') {
+					callback(data, req_code);
+				} else {
+					console.log('Specified callback is not valid');
+					console.log(callback);
+				}
+			}
+		}
+	};
+	
+	// Data must be an object
+	if (typeof data !== 'object') { data = {}; }
+	var ajax_settings = {
+		async: true,
+		accepts: 'application/json',
+		cache: false,
+		complete: ajax_response_action,
+		contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
+		crossDomain: false,
+		data: data,
+		dataType: 'json',
+		error: function (xhr, req_code, error) {
+			console.log(xhr);
+			console.log(req_code);
+			console.log(error);
+		},
+		headers: {
+			action: action,
+		},
+		method: method,
+	};
+	
+	var result = $.ajax('ajax.php?a='+action, ajax_settings);
+	
+	console.log(result);
+	
+	return result;
+}

+ 9 - 1
lang/de.ini

@@ -242,4 +242,12 @@ 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"
+SHOW_ON_HOMEPAGE = "Minimum authentication level for homepage"
+CUSTOMHTML = "Custom 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."

+ 9 - 1
lang/en.ini

@@ -242,4 +242,12 @@ 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"
+SHOW_ON_HOMEPAGE = "Minimum authentication level for homepage"
+CUSTOMHTML = "Custom 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."

+ 9 - 1
lang/es.ini

@@ -242,4 +242,12 @@ 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"
+SHOW_ON_HOMEPAGE = "Minimum authentication level for homepage"
+CUSTOMHTML = "Custom 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."

+ 9 - 1
lang/fr.ini

@@ -242,4 +242,12 @@ 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"
+SHOW_ON_HOMEPAGE = "Minimum authentication level for homepage"
+CUSTOMHTML = "Custom 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."

+ 9 - 1
lang/it.ini

@@ -242,4 +242,12 @@ 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"
+SHOW_ON_HOMEPAGE = "Minimum authentication level for homepage"
+CUSTOMHTML = "Custom 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."

+ 9 - 1
lang/nl.ini

@@ -242,4 +242,12 @@ 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"
+SHOW_ON_HOMEPAGE = "Minimum authentication level for homepage"
+CUSTOMHTML = "Custom 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."

+ 9 - 1
lang/pl.ini

@@ -242,4 +242,12 @@ 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"
+SHOW_ON_HOMEPAGE = "Minimum authentication level for homepage"
+CUSTOMHTML = "Custom 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."

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 320 - 564
settings.php


+ 3 - 1
user.php

@@ -504,6 +504,7 @@ EOT;
 		 */
 		function register_user($username, $email, $sha1, &$registration_callback = false, $settings)
 		{
+			$username = strtolower($username);
 			$dbpassword = $this->token_hash_password($username, $sha1, "");
 			if($dbpassword==$sha1) die("password hashing is not implemented.");
             $newRole = "admin"; 
@@ -566,7 +567,8 @@ EOT;
 		 * Log a user in
 		 */
 		function login_user($username, $sha1, $remember, $password, $surface = true) {
-
+			$username = strtolower($username);
+			
             $buildLog = function($username, $authType) {
                 if(file_exists(FAIL_LOG)) {
                     $getFailLog = str_replace("\r\ndate", "date", file_get_contents(FAIL_LOG));

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است