Просмотр исходного кода

Merge pull request #1207 from causefx/v2-develop

V2 develop
causefx 7 лет назад
Родитель
Сommit
1ba1875777

+ 5 - 0
.gitignore

@@ -145,3 +145,8 @@ api/plugins/*
 !api/plugins/misc/speedTest/telemetry.php
 !api/plugins/misc/speedTest/telemetry.php
 !api/plugins/misc/speedTest/telemetry_settings.php
 !api/plugins/misc/speedTest/telemetry_settings.php
 !api/plugins/misc/speedTest/speedtest_worker.min.js
 !api/plugins/misc/speedTest/speedtest_worker.min.js
+
+# =========================
+# Custom files
+# =========================
+api/pages/custom/*.php

+ 8 - 1
api/config/default.php

@@ -57,6 +57,8 @@ return array(
 	'couchpotatoToken' => '',
 	'couchpotatoToken' => '',
 	'sickrageURL' => '',
 	'sickrageURL' => '',
 	'sickrageToken' => '',
 	'sickrageToken' => '',
+	'jdownloaderURL' => '',
+	'jdownloaderCombine' => false,
 	'sabnzbdURL' => '',
 	'sabnzbdURL' => '',
 	'sabnzbdToken' => '',
 	'sabnzbdToken' => '',
 	'sabnzbdCombine' => false,
 	'sabnzbdCombine' => false,
@@ -101,6 +103,8 @@ return array(
 	'homepagCustomHTMLtwoAuth' => '1',
 	'homepagCustomHTMLtwoAuth' => '1',
 	'homepageDelugeEnabled' => false,
 	'homepageDelugeEnabled' => false,
 	'homepageDelugeAuth' => '1',
 	'homepageDelugeAuth' => '1',
+    'homepageJdownloaderEnabled' => false,
+	'homepageJdownloaderAuth' => '1',
 	'homepageSabnzbdEnabled' => false,
 	'homepageSabnzbdEnabled' => false,
 	'homepageSabnzbdAuth' => '1',
 	'homepageSabnzbdAuth' => '1',
 	'homepageSonarrEnabled' => false,
 	'homepageSonarrEnabled' => false,
@@ -152,6 +156,7 @@ return array(
 	'homepageOrderrTorrent' => '15',
 	'homepageOrderrTorrent' => '15',
 	'homepageOrderdownloader' => '16',
 	'homepageOrderdownloader' => '16',
 	'homepageOrderhealthchecks' => '17',
 	'homepageOrderhealthchecks' => '17',
+    "homepageOrderjdownloader" => '18',
 	'homepageShowStreamNames' => false,
 	'homepageShowStreamNames' => false,
 	'homepageShowStreamNamesAuth' => '1',
 	'homepageShowStreamNamesAuth' => '1',
 	'homepageStreamRefresh' => '60000',
 	'homepageStreamRefresh' => '60000',
@@ -224,5 +229,7 @@ return array(
 	'description' => 'Organizr - Accept no others',
 	'description' => 'Organizr - Accept no others',
 	'debugErrors' => false,
 	'debugErrors' => false,
 	'healthChecksURL' => 'https://healthchecks.io/api/v1/checks/',
 	'healthChecksURL' => 'https://healthchecks.io/api/v1/checks/',
-	'gaTrackingID' => ''
+	'gaTrackingID' => '',
+	'loginAttempts' => '3',
+	'loginLockout' => '60000'
 );
 );

+ 4 - 0
api/functions.php

@@ -49,6 +49,10 @@ getOrganizrUserToken();
 foreach (glob(__DIR__ . DIRECTORY_SEPARATOR . 'pages' . DIRECTORY_SEPARATOR . "*.php") as $filename) {
 foreach (glob(__DIR__ . DIRECTORY_SEPARATOR . 'pages' . DIRECTORY_SEPARATOR . "*.php") as $filename) {
 	require_once $filename;
 	require_once $filename;
 }
 }
+// Include all custom pages files
+foreach (glob(__DIR__ . DIRECTORY_SEPARATOR . 'pages' . DIRECTORY_SEPARATOR . 'custom' . DIRECTORY_SEPARATOR . "*.php") as $filename) {
+	require_once $filename;
+}
 // Include all plugin files
 // Include all plugin files
 foreach (glob(__DIR__ . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . "*.php") as $filename) {
 foreach (glob(__DIR__ . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . "*.php") as $filename) {
 	require_once $filename;
 	require_once $filename;

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

@@ -31,6 +31,10 @@ function apiLogin()
 				'name' => 'tfaCode',
 				'name' => 'tfaCode',
 				'value' => (isset($_POST['tfaCode'])) ? $_POST['tfaCode'] : false
 				'value' => (isset($_POST['tfaCode'])) ? $_POST['tfaCode'] : false
 			),
 			),
+			array(
+				'name' => 'loginAttempts',
+				'value' => (isset($_POST['loginAttempts'])) ? $_POST['loginAttempts'] : false
+			),
 			array(
 			array(
 				'name' => 'output',
 				'name' => 'output',
 				'value' => true
 				'value' => true
@@ -74,6 +78,11 @@ function login($array)
 	$days = (isset($remember)) ? $GLOBALS['rememberMeDays'] : 1;
 	$days = (isset($remember)) ? $GLOBALS['rememberMeDays'] : 1;
 	$oAuth = (isset($oAuth)) ? $oAuth : false;
 	$oAuth = (isset($oAuth)) ? $oAuth : false;
 	$output = (isset($output)) ? $output : false;
 	$output = (isset($output)) ? $output : false;
+	$loginAttempts = (isset($loginAttempts)) ? $loginAttempts : false;
+	if($loginAttempts > $GLOBALS['loginAttempts'] || isset($_COOKIE['lockout'])){
+		coookieSeconds('set', 'lockout', $GLOBALS['loginLockout'], $GLOBALS['loginLockout']);
+		return 'lockout';
+	}
 	try {
 	try {
 		$database = new Dibi\Connection([
 		$database = new Dibi\Connection([
 			'driver' => 'sqlite3',
 			'driver' => 'sqlite3',
@@ -194,7 +203,12 @@ function login($array)
 			// authentication failed
 			// authentication failed
 			writeLoginLog($username, 'error');
 			writeLoginLog($username, 'error');
 			writeLog('error', 'Login Function - Wrong Password', $username);
 			writeLog('error', 'Login Function - Wrong Password', $username);
-			return 'mismatch';
+			if($loginAttempts >= $GLOBALS['loginAttempts']){
+				coookieSeconds('set', 'lockout', $GLOBALS['loginLockout'], $GLOBALS['loginLockout']);
+				return 'lockout';
+			}else{
+				return 'mismatch';
+			}
 		}
 		}
 	} catch (Dibi\Exception $e) {
 	} catch (Dibi\Exception $e) {
 		return $e;
 		return $e;

+ 63 - 4
api/functions/homepage-connect-functions.php

@@ -19,13 +19,16 @@ function homepageConnect($array)
 			return (qualifyRequest($GLOBALS['homepagePlexPlaylistAuth'])) ? getPlexPlaylists() : false;
 			return (qualifyRequest($GLOBALS['homepagePlexPlaylistAuth'])) ? getPlexPlaylists() : false;
 			break;
 			break;
 		case 'getEmbyStreams':
 		case 'getEmbyStreams':
-			return (qualifyRequest($GLOBALS['homepageEmbyStreamsAuth'])) ? embyConnect('streams') : false;
+			return (qualifyRequest($GLOBALS['homepageEmbyStreamsAuth']) && $GLOBALS['homepageEmbyEnabled']) ? embyConnect('streams') : false;
 			break;
 			break;
 		case 'getEmbyRecent':
 		case 'getEmbyRecent':
-			return (qualifyRequest($GLOBALS['homepageEmbyRecentAuth'])) ? embyConnect('recent') : false;
+			return (qualifyRequest($GLOBALS['homepageEmbyRecentAuth']) && $GLOBALS['homepageEmbyEnabled']) ? embyConnect('recent') : false;
 			break;
 			break;
 		case 'getEmbyMetadata':
 		case 'getEmbyMetadata':
-			return (qualifyRequest($GLOBALS['homepageEmbyAuth'])) ? embyConnect('metadata', $array['data']['key'], true) : false;
+			return (qualifyRequest($GLOBALS['homepageEmbyAuth']) && $GLOBALS['homepageEmbyEnabled']) ? embyConnect('metadata', $array['data']['key'], true) : false;
+			break;
+		case 'getJdownloader':
+			return jdownloaderConnect();
 			break;
 			break;
 		case 'getSabnzbd':
 		case 'getSabnzbd':
 			return sabnzbdConnect();
 			return sabnzbdConnect();
@@ -63,7 +66,7 @@ function homepageConnect($array)
 
 
 function healthChecksTags($tags)
 function healthChecksTags($tags)
 {
 {
-	$return = 'tag=';
+	$return = '?tag=';
 	if (!$tags) {
 	if (!$tags) {
 		return '';
 		return '';
 	} elseif ($tags == '*') {
 	} elseif ($tags == '*') {
@@ -732,6 +735,46 @@ function embyConnect($action, $key = null, $skip = false)
 	return false;
 	return false;
 }
 }
 
 
+function jdownloaderConnect()
+{
+    if ($GLOBALS['homepageJdownloaderEnabled'] && !empty($GLOBALS['jdownloaderURL']) && qualifyRequest($GLOBALS['homepageJdownloaderAuth'])) {
+        $url = qualifyURL($GLOBALS['jdownloaderURL']);
+        $url = $url . '/';
+        try {
+            $options = (localURL($url)) ? array('verify' => false) : array();
+            $response = Requests::get($url, array(), $options);
+            if ($response->success) {
+                $temp = json_decode($response->body, true);
+                $packages = $temp['packages'];
+                if ($packages['downloader']) {
+                    $api['content']['queueItems'] = $packages['downloader'];
+                } else {
+                    $api['content']['queueItems'] = [];
+                }
+                $grabbed = array();
+                if ($packages['linkgrabber_decrypted']) {
+                    $grabbed = array_merge($grabbed, $packages['linkgrabber_decrypted']);
+                }
+                if ($packages['linkgrabber_failed']) {
+                    $grabbed = array_merge($grabbed, $packages['linkgrabber_failed']);
+                }
+                if ($packages['linkgrabber_offline']) {
+                    $grabbed = array_merge($grabbed, $packages['linkgrabber_offline']);
+                }
+                $api['content']['grabberItems'] = $grabbed;
+
+                $status = array($temp['downloader_state'], $temp['grabber_collecting'], $temp['update_ready']);
+                $api['content']['$status'] = $status;
+            }
+        } catch (Requests_Exception $e) {
+            writeLog('error', 'JDownloader Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
+        };
+        $api['content'] = isset($api['content']) ? $api['content'] : false;
+        return $api;
+    }
+    return false;
+}
+
 function sabnzbdConnect()
 function sabnzbdConnect()
 {
 {
 	if ($GLOBALS['homepageSabnzbdEnabled'] && !empty($GLOBALS['sabnzbdURL']) && !empty($GLOBALS['sabnzbdToken']) && qualifyRequest($GLOBALS['homepageSabnzbdAuth'])) {
 	if ($GLOBALS['homepageSabnzbdEnabled'] && !empty($GLOBALS['sabnzbdURL']) && !empty($GLOBALS['sabnzbdToken']) && qualifyRequest($GLOBALS['homepageSabnzbdAuth'])) {
@@ -2402,6 +2445,22 @@ function testAPIConnection($array)
 				return 'URL/s and/or Token/s not setup';
 				return 'URL/s and/or Token/s not setup';
 			}
 			}
 			break;
 			break;
+        case 'jdownloader':
+            if (!empty($GLOBALS['jdownloaderURL'])) {
+                $url = qualifyURL($GLOBALS['jdownloaderURL']);
+                try {
+                    $options = (localURL($url)) ? array('verify' => false) : array();
+                    $response = Requests::get($url, array(), $options);
+                    if ($response->success) {
+                        return true;
+                    }
+                } catch (Requests_Exception $e) {
+                    return $e->getMessage();
+                };
+            } else {
+                return 'URL and/or Token not setup';
+            }
+            break;
 		case 'sabnzbd':
 		case 'sabnzbd':
 			if (!empty($GLOBALS['sabnzbdURL']) && !empty($GLOBALS['sabnzbdToken'])) {
 			if (!empty($GLOBALS['sabnzbdURL']) && !empty($GLOBALS['sabnzbdToken'])) {
 				$url = qualifyURL($GLOBALS['sabnzbdURL']);
 				$url = qualifyURL($GLOBALS['sabnzbdURL']);

+ 115 - 3
api/functions/homepage-functions.php

@@ -6,6 +6,7 @@ function homepageOrder()
 		"homepageOrdercustomhtml" => $GLOBALS['homepageOrdercustomhtml'],
 		"homepageOrdercustomhtml" => $GLOBALS['homepageOrdercustomhtml'],
 		"homepageOrdercustomhtmlTwo" => $GLOBALS['homepageOrdercustomhtmlTwo'],
 		"homepageOrdercustomhtmlTwo" => $GLOBALS['homepageOrdercustomhtmlTwo'],
 		"homepageOrdernzbget" => $GLOBALS['homepageOrdernzbget'],
 		"homepageOrdernzbget" => $GLOBALS['homepageOrdernzbget'],
+		"homepageOrderjdownloader" => $GLOBALS['homepageOrderjdownloader'],
 		"homepageOrdersabnzbd" => $GLOBALS['homepageOrdersabnzbd'],
 		"homepageOrdersabnzbd" => $GLOBALS['homepageOrdersabnzbd'],
 		"homepageOrderplexnowplaying" => $GLOBALS['homepageOrderplexnowplaying'],
 		"homepageOrderplexnowplaying" => $GLOBALS['homepageOrderplexnowplaying'],
 		"homepageOrderplexrecent" => $GLOBALS['homepageOrderplexrecent'],
 		"homepageOrderplexrecent" => $GLOBALS['homepageOrderplexrecent'],
@@ -173,6 +174,30 @@ function buildHomepageItem($homepageItem)
 				}
 				}
 			}
 			}
 			break;
 			break;
+        case 'homepageOrderjdownloader':
+            if ($GLOBALS['homepageJdownloaderEnabled'] && qualifyRequest($GLOBALS['homepageJdownloaderAuth'])) {
+                if ($GLOBALS['jdownloaderCombine']) {
+                    $item .= '
+					<script>
+					// JDownloader
+					buildDownloaderCombined(\'jdownloader\');
+					homepageDownloader("jdownloader", "' . $GLOBALS['homepageDownloadRefresh'] . '");
+					// End JDownloader
+					</script>
+					';
+                } else {
+                    $item .= '<div class="white-box"><h2 class="text-center" lang="en">Loading Download Queue...</h2></div>';
+                    $item .= '
+					<script>
+					// JDownloader
+					$("#' . $homepageItem . '").html(buildDownloader("jdownloader"));
+					homepageDownloader("jdownloader", "' . $GLOBALS['homepageDownloadRefresh'] . '");
+					// End JDownloader
+					</script>
+					';
+                }
+            }
+            break;
 		case 'homepageOrdersabnzbd':
 		case 'homepageOrdersabnzbd':
 			if ($GLOBALS['homepageSabnzbdEnabled'] && qualifyRequest($GLOBALS['homepageSabnzbdAuth'])) {
 			if ($GLOBALS['homepageSabnzbdEnabled'] && qualifyRequest($GLOBALS['homepageSabnzbdAuth'])) {
 				if ($GLOBALS['sabnzbdCombine']) {
 				if ($GLOBALS['sabnzbdCombine']) {
@@ -234,7 +259,7 @@ function buildHomepageItem($homepageItem)
 			}
 			}
 			break;
 			break;
 		case 'homepageOrderembynowplaying':
 		case 'homepageOrderembynowplaying':
-			if ($GLOBALS['homepageEmbyStreams']) {
+			if ($GLOBALS['homepageEmbyStreams'] && $GLOBALS['homepageEmbyEnabled']) {
 				$item .= '<div class="white-box"><h2 class="text-center" lang="en">Loading Now Playing...</h2></div>';
 				$item .= '<div class="white-box"><h2 class="text-center" lang="en">Loading Now Playing...</h2></div>';
 				$item .= '
 				$item .= '
 				<script>
 				<script>
@@ -246,7 +271,7 @@ function buildHomepageItem($homepageItem)
 			}
 			}
 			break;
 			break;
 		case 'homepageOrderembyrecent':
 		case 'homepageOrderembyrecent':
-			if ($GLOBALS['homepageEmbyRecent']) {
+			if ($GLOBALS['homepageEmbyRecent'] && $GLOBALS['homepageEmbyEnabled']) {
 				$item .= '<div class="white-box"><h2 class="text-center" lang="en">Loading Recent...</h2></div>';
 				$item .= '<div class="white-box"><h2 class="text-center" lang="en">Loading Recent...</h2></div>';
 				$item .= '
 				$item .= '
 				<script>
 				<script>
@@ -975,6 +1000,86 @@ function getHomepageList()
 				)
 				)
 			)
 			)
 		),
 		),
+        array(
+            'name' => 'JDownloader',
+            'enabled' => (strpos('personal', $GLOBALS['license']) !== false) ? true : false,
+            'image' => 'plugins/images/tabs/jdownloader.png',
+            'category' => 'Downloader',
+            'settings' => array(
+	            'custom' => '
+				<div class="row">
+                    <div class="col-lg-12">
+                        <div class="panel panel-info">
+                            <div class="panel-heading">
+								<span lang="en">Notice</span>
+                            </div>
+                            <div class="panel-wrapper collapse in" aria-expanded="true">
+                                <div class="panel-body">
+									<ul class="list-icons">
+                                        <li><i class="fa fa-chevron-right text-danger"></i> <a href="https://pypi.org/project/myjd-api/" target="_blank">Download [myjd-api] Module</a></li>
+                                    </ul>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+				</div>
+				',
+                'Enable' => array(
+                    array(
+                        'type' => 'switch',
+                        'name' => 'homepageJdownloaderEnabled',
+                        'label' => 'Enable',
+                        'value' => $GLOBALS['homepageJdownloaderEnabled']
+                    ),
+                    array(
+                        'type' => 'select',
+                        'name' => 'homepageJdownloaderAuth',
+                        'label' => 'Minimum Authentication',
+                        'value' => $GLOBALS['homepageJdownloaderAuth'],
+                        'options' => $groups
+                    )
+                ),
+                'Connection' => array(
+                    array(
+                        'type' => 'input',
+                        'name' => 'jdownloaderURL',
+                        'label' => 'URL',
+                        'value' => $GLOBALS['jdownloaderURL'],
+                        'help' => 'Please make sure to use local IP address and port - You also may use local dns name too.',
+                        'placeholder' => 'http(s)://hostname:port'
+                    )
+                ),
+                'Misc Options' => array(
+                    array(
+                        'type' => 'select',
+                        'name' => 'homepageDownloadRefresh',
+                        'label' => 'Refresh Seconds',
+                        'value' => $GLOBALS['homepageDownloadRefresh'],
+                        'options' => optionTime()
+                    ),
+                    array(
+                        'type' => 'switch',
+                        'name' => 'jdownloaderCombine',
+                        'label' => 'Add to Combined Downloader',
+                        'value' => $GLOBALS['jdownloaderCombine']
+                    ),
+                ),
+                'Test Connection' => array(
+                    array(
+                        'type' => 'blank',
+                        'label' => 'Please Save before Testing'
+                    ),
+                    array(
+                        'type' => 'button',
+                        'label' => '',
+                        'icon' => 'fa fa-flask',
+                        'class' => 'pull-right',
+                        'text' => 'Test Connection',
+                        'attr' => 'onclick="testAPIConnection(\'jdownloader\')"'
+                    ),
+                )
+            )
+        ),
 		array(
 		array(
 			'name' => 'SabNZBD',
 			'name' => 'SabNZBD',
 			'enabled' => (strpos('personal', $GLOBALS['license']) !== false) ? true : false,
 			'enabled' => (strpos('personal', $GLOBALS['license']) !== false) ? true : false,
@@ -2228,6 +2333,13 @@ function buildHomepageSettings()
 					$class .= ' faded';
 					$class .= ' faded';
 				}
 				}
 				break;
 				break;
+            case 'homepageOrderjdownloader':
+                $class = 'bg-sab';
+                $image = 'plugins/images/tabs/jdownloader.png';
+                if (!$GLOBALS['homepageJdownloaderEnabled']) {
+                    $class .= ' faded';
+                }
+                break;
 			case 'homepageOrdersabnzbd':
 			case 'homepageOrdersabnzbd':
 				$class = 'bg-sab';
 				$class = 'bg-sab';
 				$image = 'plugins/images/tabs/sabnzbd.png';
 				$image = 'plugins/images/tabs/sabnzbd.png';
@@ -2290,7 +2402,7 @@ function buildHomepageSettings()
 			case 'homepageOrderdownloader':
 			case 'homepageOrderdownloader':
 				$class = 'bg-inverse';
 				$class = 'bg-inverse';
 				$image = 'plugins/images/tabs/downloader.png';
 				$image = 'plugins/images/tabs/downloader.png';
-				if (!$GLOBALS['sabnzbdCombine'] && !$GLOBALS['nzbgetCombine'] && !$GLOBALS['rTorrentCombine'] && !$GLOBALS['delugeCombine'] && !$GLOBALS['transmissionCombine'] && !$GLOBALS['qBittorrentCombine']) {
+				if (!$GLOBALS['jdownloaderCombine'] && !$GLOBALS['sabnzbdCombine'] && !$GLOBALS['nzbgetCombine'] && !$GLOBALS['rTorrentCombine'] && !$GLOBALS['delugeCombine'] && !$GLOBALS['transmissionCombine'] && !$GLOBALS['qBittorrentCombine']) {
 					$class .= ' faded';
 					$class .= ' faded';
 				}
 				}
 				break;
 				break;

+ 49 - 0
api/functions/normal-functions.php

@@ -126,6 +126,55 @@ function coookie($type, $name, $value = '', $days = -1, $http = true)
 	}
 	}
 }
 }
 
 
+function coookieSeconds($type, $name, $value = '', $ms, $http = true)
+{
+	if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == "https") {
+		$Secure = true;
+		$HTTPOnly = true;
+	} elseif (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' && $_SERVER['HTTPS'] !== '') {
+		$Secure = true;
+		$HTTPOnly = true;
+	} else {
+		$Secure = false;
+		$HTTPOnly = false;
+	}
+	if (!$http) {
+		$HTTPOnly = false;
+	}
+	$Path = '/';
+	$Domain = parseDomain($_SERVER['HTTP_HOST']);
+	$DomainTest = parseDomain($_SERVER['HTTP_HOST'], true);
+	if ($type == 'set') {
+		$_COOKIE[$name] = $value;
+		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
+			. (empty($ms) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() + ($ms / 1000)) . ' GMT')
+			. (empty($Path) ? '' : '; path=' . $Path)
+			. (empty($Domain) ? '' : '; domain=' . $Domain)
+			. (!$Secure ? '' : '; secure')
+			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
+		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
+			. (empty($ms) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() + ($ms / 1000)) . ' GMT')
+			. (empty($Path) ? '' : '; path=' . $Path)
+			. (empty($Domain) ? '' : '; domain=' . $DomainTest)
+			. (!$Secure ? '' : '; secure')
+			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
+	} elseif ($type == 'delete') {
+		unset($_COOKIE[$name]);
+		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
+			. (empty($ms) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() - 3600) . ' GMT')
+			. (empty($Path) ? '' : '; path=' . $Path)
+			. (empty($Domain) ? '' : '; domain=' . $Domain)
+			. (!$Secure ? '' : '; secure')
+			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
+		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
+			. (empty($ms) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() - 3600) . ' GMT')
+			. (empty($Path) ? '' : '; path=' . $Path)
+			. (empty($Domain) ? '' : '; domain=' . $DomainTest)
+			. (!$Secure ? '' : '; secure')
+			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
+	}
+}
+
 function getOS()
 function getOS()
 {
 {
 	if (PHP_SHLIB_SUFFIX == "dll") {
 	if (PHP_SHLIB_SUFFIX == "dll") {

+ 15 - 0
api/functions/organizr-functions.php

@@ -708,6 +708,20 @@ function getSettingsMain()
 			)*/
 			)*/
 		),
 		),
 		'Security' => array(
 		'Security' => array(
+			array(
+				'type' => 'number',
+				'name' => 'loginAttempts',
+				'label' => 'Max Login Attempts',
+				'value' => $GLOBALS['loginAttempts'],
+				'placeholder' => ''
+			),
+			array(
+				'type' => 'select',
+				'name' => 'loginLockout',
+				'label' => 'Login Lockout Seconds',
+				'value' => $GLOBALS['loginLockout'],
+				'options' => optionTime()
+			),
 			array(
 			array(
 				'type' => 'number',
 				'type' => 'number',
 				'name' => 'lockoutTimeout',
 				'name' => 'lockoutTimeout',
@@ -1693,6 +1707,7 @@ function approvedFileExtension($filename)
 		case 'png':
 		case 'png':
 		case 'jpeg':
 		case 'jpeg':
 		case 'jpg':
 		case 'jpg':
+		case 'svg':
 			return true;
 			return true;
 			break;
 			break;
 		default:
 		default:

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

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

+ 20 - 0
api/index.php

@@ -34,6 +34,12 @@ if (!in_array($function, $approvedFunctionsBypass)) {
 }
 }
 $result['request'] = key($_GET);
 $result['request'] = key($_GET);
 $result['params'] = $_POST;
 $result['params'] = $_POST;
+
+//Custom Page Check
+if(strpos($function,'v1_custom_page_') !== false){
+	$endpoint = explode('v1_custom_page_', $function)[1];
+	$function = 'v1_custom_page';
+}
 switch ($function) {
 switch ($function) {
 	case 'v1_settings_page':
 	case 'v1_settings_page':
 		switch ($method) {
 		switch ($method) {
@@ -1355,6 +1361,20 @@ switch ($function) {
 				break;
 				break;
 		}
 		}
 		break;
 		break;
+	case 'v1_custom_page':
+		switch ($method) {
+			case 'GET':
+				$customPage = 'customPage'.ucwords($endpoint);
+				$result['status'] = 'success';
+				$result['statusText'] = 'success';
+				$result['data'] = $$customPage;
+				break;
+			default:
+				$result['status'] = 'error';
+				$result['statusText'] = 'The function requested is not defined for method: ' . $method;
+				break;
+		}
+		break;
 	default:
 	default:
 		//No Function Available
 		//No Function Available
 		$result['status'] = 'error';
 		$result['status'] = 'error';

+ 14 - 0
api/pages/custom/index.html

@@ -0,0 +1,14 @@
+Place all custom page files here....
+
+make sure to start page contents like so:
+<pre>
+&lt;?php
+// This is a check to make sure organizr is setup already...
+if (file_exists('config' . DIRECTORY_SEPARATOR . 'config.php')) {
+    // All variables need to start with $customPage .... Make sure to change Simple to any word (First Letter needs to be capital)... i.e. $customPageNewish
+	// Also make sure to escape single quotes
+	$customPageSimple = '
+        &lt;h1&gt;THIS IS JUST A TEST&lt;/h1&gt;
+    ';
+}
+</pre>

+ 1 - 0
api/pages/login.php

@@ -13,6 +13,7 @@ if(activeInfo.settings.login.rememberMe){
   <div class="login-box login-sidebar animated slideInRight">
   <div class="login-box login-sidebar animated slideInRight">
     <div class="white-box">
     <div class="white-box">
       <form class="form-horizontal" id="loginform" onsubmit="return false;">
       <form class="form-horizontal" id="loginform" onsubmit="return false;">
+      	<input id="login-attempts" class="form-control" name="loginAttempts" type="hidden">
         <a href="javascript:void(0)" class="text-center db visible-xs" id="login-logo">' . logoOrText() . '</a>
         <a href="javascript:void(0)" class="text-center db visible-xs" id="login-logo">' . logoOrText() . '</a>
         <div id="oAuth-div" class="form-group hidden">
         <div id="oAuth-div" class="form-group hidden">
           <div class="col-xs-12">
           <div class="col-xs-12">

+ 27 - 1
css/organizr.css

@@ -1237,8 +1237,9 @@ span.fc-title {
     font-size: 30px;
     font-size: 30px;
 }
 }
 .downloaderCount {
 .downloaderCount {
-    margin-top: -45px;
+    margin-top: -15px;
     margin-left: -45px;
     margin-left: -45px;
+    position: absolute;
 }
 }
 .loginTitle {
 .loginTitle {
     height: 22px;
     height: 22px;
@@ -1313,6 +1314,11 @@ span.fc-title {
         float: none;
         float: none;
     }
     }
 }
 }
+.col-lg-12,
+.col-md-12 {
+    float: left;
+    width: 100%;
+}
 #newRequestButton {
 #newRequestButton {
     border-top-right-radius: 3px;
     border-top-right-radius: 3px;
     border-bottom-right-radius: 3px;
     border-bottom-right-radius: 3px;
@@ -1346,6 +1352,26 @@ span.fc-title {
 .btn-danger i.ti-trash {
 .btn-danger i.ti-trash {
     margin-left: -1.5px;
     margin-left: -1.5px;
 }
 }
+.has-coupon-text {
+    position: absolute;
+    top: 0;
+    left: 0;
+    background: rgba(108, 169, 76, 0.73);
+    width: inherit;
+    color: white;
+    display: none;
+}
+.item:hover .has-coupon-text {
+    display: block;
+}
+span.has-coupon {
+    position: absolute;
+    top: 0;
+    right: 0;
+    background: rgba(108, 169, 76, 0.73);
+    width: 23px;
+    color: white;
+}
 /*
 /*
 body,
 body,
 html {
 html {

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
css/organizr.min.css


+ 16 - 3
js/custom.js

@@ -2,6 +2,7 @@
 /*global $, jQuery, alert*/
 /*global $, jQuery, alert*/
 var idleTime = 0;
 var idleTime = 0;
 var hasCookie = false;
 var hasCookie = false;
+var loginAttempts = 0;
 $(document).ajaxComplete(function () {
 $(document).ajaxComplete(function () {
     pageLoad();
     pageLoad();
     //new SimpleBar($('.internal-listing')[0]);
     //new SimpleBar($('.internal-listing')[0]);
@@ -337,6 +338,8 @@ function doneTypingMediaSearch () {
 }
 }
 $(document).on("click", ".login-button", function(e) {
 $(document).on("click", ".login-button", function(e) {
     e.preventDefault;
     e.preventDefault;
+    loginAttempts = loginAttempts + 1;
+    $('#login-attempts').val(loginAttempts);
     var check = (local('g','loggingIn'));
     var check = (local('g','loggingIn'));
     if(check == null) {
     if(check == null) {
         local('s','loggingIn', true);
         local('s','loggingIn', true);
@@ -358,6 +361,18 @@ $(document).on("click", ".login-button", function(e) {
                 $('div.login-box').unblock({});
                 $('div.login-box').unblock({});
                 message('Login Error', ' Wrong username/email/password combo', activeInfo.settings.notifications.position, '#FFF', 'warning', '10000');
                 message('Login Error', ' Wrong username/email/password combo', activeInfo.settings.notifications.position, '#FFF', 'warning', '10000');
                 console.error('Organizr Function: Login failed - wrong username/email/password');
                 console.error('Organizr Function: Login failed - wrong username/email/password');
+            } else if (html.data == 'lockout') {
+                $('div.login-box').block({
+                    message: '<h5><i class="fa fa-close"></i> Locked Out!</h4>',
+                    css: {
+                        color: '#fff',
+                        border: '1px solid #e91e63',
+                        backgroundColor: '#f44336'
+                    }
+                });
+                message('Login Error', ' You have been Locked out', activeInfo.settings.notifications.position, '#FFF', 'error', '10000');
+                console.error('Organizr Function: Login failed - User has been locked out');
+                setTimeout(function(){ local('r','loggingIn'); location.reload() }, 10000);
             } else if (html.data == '2FA') {
             } else if (html.data == '2FA') {
                 $('div.login-box').unblock({});
                 $('div.login-box').unblock({});
                 $('#tfa-div').removeClass('hidden');
                 $('#tfa-div').removeClass('hidden');
@@ -1510,15 +1525,13 @@ $(document).on("click", ".refreshImage", function(e) {
             break;
             break;
         case 'recent-item':
         case 'recent-item':
             var orginalElementAlt = $(this).parent().parent().parent().find('.imageSourceAlt');
             var orginalElementAlt = $(this).parent().parent().parent().find('.imageSourceAlt');
-            var orginalElement = $(this).parent().parent().parent().find('.imageSource');
+            var orginalElement = $(this).parent().parent().parent().parent().find('.imageSource');
             orginalElement.attr('style', 'background-image: url("'+original+'");');
             orginalElement.attr('style', 'background-image: url("'+original+'");');
             orginalElementAlt.attr('src', original);
             orginalElementAlt.attr('src', original);
             break;
             break;
         default:
         default:
 
 
     }
     }
-    //console.log(orginalElement)
-    //console.log('replaced image with : '+original);
     setTimeout(function(){
     setTimeout(function(){
         message('Image Refreshed ',' Clear Cache Please',activeInfo.settings.notifications.position,'#FFF','success','3000');
         message('Image Refreshed ',' Clear Cache Please',activeInfo.settings.notifications.position,'#FFF','success','3000');
     }, 1000);
     }, 1000);

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
js/custom.min.js


+ 142 - 5
js/functions.js

@@ -1183,7 +1183,7 @@ function loadMarketplaceThemesItems(themes){
                 <td>`+v.category+`</td>
                 <td>`+v.category+`</td>
                 <td>`+v.status+`</td>
                 <td>`+v.status+`</td>
                 <td style="text-align:center"><button type="button" onclick='aboutTheme(`+JSON.stringify(v)+`);' class="btn btn-success btn-outline btn-circle btn-lg popup-with-form" href="#about-theme-form" data-effect="mfp-3d-unfold"><i class="fa fa-info"></i></button></td>
                 <td style="text-align:center"><button type="button" onclick='aboutTheme(`+JSON.stringify(v)+`);' class="btn btn-success btn-outline btn-circle btn-lg popup-with-form" href="#about-theme-form" data-effect="mfp-3d-unfold"><i class="fa fa-info"></i></button></td>
-                <td style="text-align:center"><button type="button" onclick='installTheme(`+JSON.stringify(v)+`);' class="btn btn-info btn-outline btn-circle btn-lg"><i class="`+installButton+`"></i></button></td>
+                <td style="text-align:center"><button type="button" onclick='installTheme(`+JSON.stringify(v)+`);themeAnalytics("`+ v.name +`");' class="btn btn-info btn-outline btn-circle btn-lg"><i class="`+installButton+`"></i></button></td>
                 <td style="text-align:center"><button type="button" onclick='removeTheme(`+JSON.stringify(v)+`);' class="btn btn-danger btn-outline btn-circle btn-lg" `+removeButton+`><i class="fa fa-trash"></i></button></td>
                 <td style="text-align:center"><button type="button" onclick='removeTheme(`+JSON.stringify(v)+`);' class="btn btn-danger btn-outline btn-circle btn-lg" `+removeButton+`><i class="fa fa-trash"></i></button></td>
             </tr>
             </tr>
         `;
         `;
@@ -1483,7 +1483,6 @@ function installTheme(theme=null){
             orgErrorAlert('<h4>' + e + '</h4>' + formatDebug(data));
             orgErrorAlert('<h4>' + e + '</h4>' + formatDebug(data));
             return false;
             return false;
         }
         }
-        console.log(data);
         if(html.data.substr(0, 7) == 'Success'){
         if(html.data.substr(0, 7) == 'Success'){
             var newThemes = html.data.split('!@!');
             var newThemes = html.data.split('!@!');
             activeInfo.settings.misc.installedThemes = newThemes[1];
             activeInfo.settings.misc.installedThemes = newThemes[1];
@@ -1895,6 +1894,8 @@ function checkTabHomepageItem(id, name, url, urlLocal){
         addEditHomepageItem(id,'Plex');
         addEditHomepageItem(id,'Plex');
     }else if(name.includes('emby') || url.includes('emby') || urlLocal.includes('emby')){
     }else if(name.includes('emby') || url.includes('emby') || urlLocal.includes('emby')){
         addEditHomepageItem(id,'Emby');
         addEditHomepageItem(id,'Emby');
+    }else if(name.includes('jdownloader') || url.includes('jdownloader') || urlLocal.includes('jdownloader')){
+        addEditHomepageItem(id,'jDownloader');
     }else if(name.includes('sab') || url.includes('sab') || urlLocal.includes('sab')){
     }else if(name.includes('sab') || url.includes('sab') || urlLocal.includes('sab')){
         addEditHomepageItem(id,'SabNZBD');
         addEditHomepageItem(id,'SabNZBD');
     }else if(name.includes('nzbget') || url.includes('nzbget') || urlLocal.includes('nzbget')){
     }else if(name.includes('nzbget') || url.includes('nzbget') || urlLocal.includes('nzbget')){
@@ -3287,15 +3288,24 @@ function sponsorAbout(id,array){
 function buildSponsor(array){
 function buildSponsor(array){
     var sponsors = '';
     var sponsors = '';
     $.each(array, function(i,v) {
     $.each(array, function(i,v) {
-        var sponsorAboutModal = (v.about) ? 'data-toggle="modal" data-target="#sponsor-'+i+'-modal"' : 'onclick="window.open(\''+ v.website +'\', \'_blank\')"';
+        var hasCoupon = '';
+        if(v.about){
+            if(v.coupon){
+                hasCoupon = `
+                    <span class="text-center has-coupon-text">Has Coupon</span>
+                    <span class="text-center has-coupon"><i class="fa fa-ticket" aria-hidden="true"></i></span>
+                `;
+            }
+        }
+        var sponsorAboutModal = (v.about) ? 'data-toggle="modal" data-target="#sponsor-'+i+'-modal" onclick="sponsorAnalytics(\''+v.company_name+'\');"' : 'onclick="window.open(\''+ v.website +'\', \'_blank\');sponsorAnalytics(\''+v.company_name+'\');"';
         sponsors += `
         sponsors += `
             <!-- /.usercard -->
             <!-- /.usercard -->
             <div class="item lazyload recent-sponsor mouse imageSource mouse" `+sponsorAboutModal+` data-src="`+v.logo+`">
             <div class="item lazyload recent-sponsor mouse imageSource mouse" `+sponsorAboutModal+` data-src="`+v.logo+`">
                 <span class="elip recent-title">`+v.company_name+`</span>
                 <span class="elip recent-title">`+v.company_name+`</span>
+                `+ hasCoupon +`
             </div>
             </div>
             <!-- /.usercard-->
             <!-- /.usercard-->
         `;
         `;
-
     });
     });
     sponsors += `
     sponsors += `
         <!-- /.usercard -->
         <!-- /.usercard -->
@@ -3315,6 +3325,46 @@ function buildSponsorModal(array){
     });
     });
     return sponsors;
     return sponsors;
 }
 }
+function sponsorAnalytics(sponsor_name){
+    var uuid = activeInfo.settings.misc.uuid;
+    $.ajax({
+        type: 'POST',
+        url: 'https://api.organizr.app/',
+        data: {
+            'sponsor_name': sponsor_name,
+            'user_uuid': uuid,
+            'cmd': 'sponsor'
+        },
+        cache: false,
+        async: true,
+        complete: function(xhr, status) {
+            if (xhr.status === 200) {
+                var result = $.parseJSON(xhr.responseText);
+                console.log(result.response.message);
+            }
+        }
+    });
+}
+function themeAnalytics(theme_name){
+    var uuid = activeInfo.settings.misc.uuid;
+    $.ajax({
+        type: 'POST',
+        url: 'https://api.organizr.app/',
+        data: {
+            'theme_name': theme_name,
+            'user_uuid': uuid,
+            'cmd': 'theme'
+        },
+        cache: false,
+        async: true,
+        complete: function(xhr, status) {
+            if (xhr.status === 200) {
+                var result = $.parseJSON(xhr.responseText);
+                console.log(result.response.message);
+            }
+        }
+    });
+}
 function updateBar(){
 function updateBar(){
 	return `
 	return `
 	<div class="white-box m-0">
 	<div class="white-box m-0">
@@ -4359,6 +4409,7 @@ function buildRecent(array, type){
 			`+dropdownMenu+`
 			`+dropdownMenu+`
 			<hr class="hidden-xs"><div class="clearfix"></div>
 			<hr class="hidden-xs"><div class="clearfix"></div>
 		</div>
 		</div>
+		<div class="clearfix"></div>
 		`;
 		`;
 	}else{
 	}else{
 		var header = `
 		var header = `
@@ -4455,6 +4506,7 @@ function buildPlaylist(array, type){
 			</div>
 			</div>
 			<hr class="hidden-xs"><div class="clearfix"></div>
 			<hr class="hidden-xs"><div class="clearfix"></div>
 		</div>
 		</div>
+		<div class="clearfix"></div>
 		`;
 		`;
 	}else{
 	}else{
 		var header = `
 		var header = `
@@ -4537,6 +4589,7 @@ function buildRequest(array){
 			</div>
 			</div>
 			<hr class="hidden-xs"><div class="clearfix"></div>
 			<hr class="hidden-xs"><div class="clearfix"></div>
 		</div>
 		</div>
+		<div class="clearfix"></div>
 		`;
 		`;
 	}else{
 	}else{
 		var header = `
 		var header = `
@@ -4852,6 +4905,67 @@ function buildDownloaderItem(array, source, type='none'){
     var history = '';
     var history = '';
     var count = 0;
     var count = 0;
 	switch (source) {
 	switch (source) {
+        case 'jdownloader':
+            if(array.content === false){
+                queue = '<tr><td class="max-texts" lang="en">Connection Error to ' + source + '</td></tr>';
+                break;
+            }
+
+            /*
+            if(array.content.$status[0] != 'RUNNING'){
+                var state = `<a href="#"><span class="downloader mouse" data-source="jdownloader" data-action="resume" data-target="main"><i class="fa fa-play"></i></span></a>`;
+                var active = 'grayscale';
+            }else{
+                var state = `<a href="#"><span class="downloader mouse" data-source="jdownloader" data-action="pause" data-target="main"><i class="fa fa-pause"></i></span></a>`;
+                var active = '';
+            }
+            $('.jdownloader-downloader-action').html(state);
+            */
+
+            if(array.content.queueItems.length == 0){
+                queue = '<tr><td class="max-texts" lang="en">Nothing in queue</td></tr>';
+            }
+            $.each(array.content.queueItems, function(i,v) {
+                count = count + 1;
+                if(v.speed == null){
+                    if(v.percentage == '100'){
+                        v.speed = '--';
+                    }else{
+                        v.speed = 'Stopped';
+                    }
+                }
+                if(v.eta == null){
+                    if(v.percentage == '100'){
+                        v.eta = 'Complete';
+                    }else{
+                        v.eta = '--';
+                    }
+                }
+                queue += `
+                <tr>
+                    <td class="max-texts">`+v.name+`</td>
+                    <td class="hidden-xs">`+v.speed+`</td>
+                    <td class="hidden-xs" alt="`+v.done+`">`+v.size+`</td>
+                    <td class="hidden-xs">`+v.eta+`</td>
+                    <td class="text-right">
+                        <div class="progress progress-lg m-b-0">
+                            <div class="progress-bar progress-bar-info" style="width: `+v.percentage+`%;" role="progressbar">`+v.percentage+`%</div>
+                        </div>
+                    </td>
+                </tr>
+                `;
+            });
+            if(array.content.grabberItems.length == 0){
+                history = '<tr><td class="max-texts" lang="en">Nothing in Linkgrabbber</td></tr>';
+            }
+            $.each(array.content.grabberItems, function(i,v) {
+                history += `
+                <tr>
+                    <td class="max-texts">`+ v.name+`</td>
+                </tr>
+                `;
+            });
+            break;
 		case 'sabnzbd':
 		case 'sabnzbd':
             if(array.content === false){
             if(array.content === false){
                 queue = '<tr><td class="max-texts" lang="en">Connection Error to ' + source + '</td></tr>';
                 queue = '<tr><td class="max-texts" lang="en">Connection Error to ' + source + '</td></tr>';
@@ -5165,6 +5279,7 @@ function buildDownloader(source){
     var queueButton = 'QUEUE';
     var queueButton = 'QUEUE';
     var historyButton = 'HISTORY';
     var historyButton = 'HISTORY';
     switch (source) {
     switch (source) {
+        case 'jdownloader':
         case 'sabnzbd':
         case 'sabnzbd':
         case 'nzbget':
         case 'nzbget':
             var queue = true;
             var queue = true;
@@ -5231,6 +5346,7 @@ function buildDownloader(source){
 			`+menu+`
 			`+menu+`
 			<hr class="hidden-xs"><div class="clearfix"></div>
 			<hr class="hidden-xs"><div class="clearfix"></div>
 		</div>
 		</div>
+		<div class="clearfix"></div>
 		`;
 		`;
 	}else{
 	}else{
 		var header = `
 		var header = `
@@ -5259,6 +5375,7 @@ function buildDownloaderCombined(source){
     var queueButton = 'QUEUE';
     var queueButton = 'QUEUE';
     var historyButton = 'HISTORY';
     var historyButton = 'HISTORY';
     switch (source) {
     switch (source) {
+        case 'jdownloader':
         case 'sabnzbd':
         case 'sabnzbd':
         case 'nzbget':
         case 'nzbget':
             var queue = true;
             var queue = true;
@@ -5324,6 +5441,7 @@ function buildDownloaderCombined(source){
                 `+mainMenu+`
                 `+mainMenu+`
                 <div class="clearfix"></div>
                 <div class="clearfix"></div>
             </div>
             </div>
+            <div class="clearfix"></div>
             `;
             `;
         }else{
         }else{
             var header = `
             var header = `
@@ -5471,7 +5589,9 @@ function buildHealthChecks(array){
 		    </div>
 		    </div>
 			<div class="clearfix"></div>
 			<div class="clearfix"></div>
 		    <!-- .cards -->
 		    <!-- .cards -->
-			`+buildHealthChecksItem(array.content.checks)+`
+		    <div class="healthCheckCards">
+			    `+buildHealthChecksItem(array.content.checks)+`
+			</div>
 		    <!-- /.cards-->
 		    <!-- /.cards-->
 		</div>
 		</div>
 	</div>
 	</div>
@@ -5585,6 +5705,9 @@ function homepageDownloader(type, timeout){
 	var timeout = (typeof timeout !== 'undefined') ? timeout : activeInfo.settings.homepage.refresh.homepageDownloadRefresh;
 	var timeout = (typeof timeout !== 'undefined') ? timeout : activeInfo.settings.homepage.refresh.homepageDownloadRefresh;
 	//if(isHidden()){ return; }
 	//if(isHidden()){ return; }
 	switch (type) {
 	switch (type) {
+        case 'jdownloader':
+            var action = 'getJdownloader';
+            break;
 		case 'sabnzbd':
 		case 'sabnzbd':
 			var action = 'getSabnzbd';
 			var action = 'getSabnzbd';
 			break;
 			break;
@@ -6948,6 +7071,20 @@ function launch(){
                     getPingList(json);
                     getPingList(json);
                 }
                 }
                 loadCustomJava(json.appearance);
                 loadCustomJava(json.appearance);
+                if(getCookie('lockout')){
+                    $('.show-login').click();
+                    setTimeout(function(){
+                        $('div.login-box').block({
+                            message: '<h5><i class="fa fa-close"></i> Locked Out!</h4>',
+                            css: {
+                                color: '#fff',
+                                border: '1px solid #e91e63',
+                                backgroundColor: '#f44336'
+                            }
+                        });
+                    }, 1000);
+                    setTimeout(function(){ location.reload() }, 60000);
+                }
 				break;
 				break;
 			default:
 			default:
 				console.error('Organizr Function: Action not set or defined');
 				console.error('Organizr Function: Action not set or defined');

+ 4 - 4
js/langpack/nb[Bokm&aring;l].json

@@ -242,7 +242,7 @@
         "Organizr Mod Picks": "Organizr moderatroer anbefaler",
         "Organizr Mod Picks": "Organizr moderatroer anbefaler",
         "Requests": "Forespørsler",
         "Requests": "Forespørsler",
         "Become Sponsor": "Bli sponsor",
         "Become Sponsor": "Bli sponsor",
-        "Splash Page": "Splash Page",
+        "Splash Page": "Popup",
         "Lock Screen": "Lås Skjerm",
         "Lock Screen": "Lås Skjerm",
         "If you signed in with a Emby Acct... Please use the following link to change your password there:": "Om du logget inn med en Emby konto, benytt denne linken for å bytte passord:",
         "If you signed in with a Emby Acct... Please use the following link to change your password there:": "Om du logget inn med en Emby konto, benytt denne linken for å bytte passord:",
         "Password Notice": "Password melding",
         "Password Notice": "Password melding",
@@ -254,8 +254,8 @@
         "Save": "Lagre",
         "Save": "Lagre",
         "STATUS": "Status",
         "STATUS": "Status",
         "PLUGIN": "Utvidelse",
         "PLUGIN": "Utvidelse",
-        "Plugin Marketplace": "Plugin Marketplace",
-        "Marketplace": "Marketplace",
+        "Plugin Marketplace": "Plugin Marked",
+        "Marketplace": "Marked",
         "Chat": "Chat",
         "Chat": "Chat",
         "Current Directory: ": "Nåværende mappe:␣",
         "Current Directory: ": "Nåværende mappe:␣",
         "Suggested Directory: ": "Foreslått mappe:␣",
         "Suggested Directory: ": "Foreslått mappe:␣",
@@ -272,7 +272,7 @@
         "Beerpay.io": "Beerpay.io",
         "Beerpay.io": "Beerpay.io",
         "Sponsors": "Sponsorer",
         "Sponsors": "Sponsorer",
         "THEME": "Tema",
         "THEME": "Tema",
-        "Theme Marketplace": "Theme Marketplace",
+        "Theme Marketplace": "Tema Marked",
         "Test Tab": "Test Tab",
         "Test Tab": "Test Tab",
         "Select or type Icon": "Velg eller skriv inn",
         "Select or type Icon": "Velg eller skriv inn",
         "Choose Icon": "Velg ikon",
         "Choose Icon": "Velg ikon",

+ 7 - 7
js/langpack/pl[Polish].json

@@ -27,7 +27,7 @@
         "Installed": "Zainstalowane",
         "Installed": "Zainstalowane",
         "Install Update": "Zainstaluj aktualizację",
         "Install Update": "Zainstaluj aktualizację",
         "Organizr Versions": "Wersje Organizr",
         "Organizr Versions": "Wersje Organizr",
-        "About": "Informacje",
+        "About": "O aplikacji",
         "Organizr Logs": "Dzienniki Organizr",
         "Organizr Logs": "Dzienniki Organizr",
         "Main Settings": "Podstawowe ustawienia",
         "Main Settings": "Podstawowe ustawienia",
         "Updates": "Aktualizacje",
         "Updates": "Aktualizacje",
@@ -154,15 +154,15 @@
         "Load More": "Wczytaj więcej",
         "Load More": "Wczytaj więcej",
         "Request": "Zgłoszenie",
         "Request": "Zgłoszenie",
         "No Results": "Brak wyników",
         "No Results": "Brak wyników",
-        "Airs Today TV": "Dziś w TV",
-        "Popular TV": "Popularne programy TV",
-        "Top TV": "Najlepsze programy TV",
+        "Airs Today TV": "Dziś w telewizji",
+        "Popular TV": "Popularne seriale",
+        "Top TV": "Najlepsze seriale",
         "Upcoming Movies": "Nadchodzące filmy",
         "Upcoming Movies": "Nadchodzące filmy",
         "Popular Movies": "Popularne filmy",
         "Popular Movies": "Popularne filmy",
         "Top Movies": "Najlepsze filmy",
         "Top Movies": "Najlepsze filmy",
         "In Theatres": "W kinach",
         "In Theatres": "W kinach",
         "Suggestions": "Sugestie",
         "Suggestions": "Sugestie",
-        "TV": "TV",
+        "TV": "Serial",
         "Movie": "Film",
         "Movie": "Film",
         "Denied": "Odmówione",
         "Denied": "Odmówione",
         "Unapproved": "Niezatwierdzone",
         "Unapproved": "Niezatwierdzone",
@@ -239,7 +239,7 @@
         "Loading Now Playing...": "Wczytywanie teraz odtwarzanych...",
         "Loading Now Playing...": "Wczytywanie teraz odtwarzanych...",
         "Loading Playlists...": "Wczytywanie playlist...",
         "Loading Playlists...": "Wczytywanie playlist...",
         "Loading Download Queue...": "Wczytywanie kolejki pobierania...",
         "Loading Download Queue...": "Wczytywanie kolejki pobierania...",
-        "Organizr Mod Picks": "Organizr Mod Picks",
+        "Organizr Mod Picks": "Od autora Organizr",
         "Requests": "Zgłoszenia",
         "Requests": "Zgłoszenia",
         "Become Sponsor": "Zostań sponsorem",
         "Become Sponsor": "Zostań sponsorem",
         "Splash Page": "Strona powitalna",
         "Splash Page": "Strona powitalna",
@@ -434,7 +434,7 @@
         "Nav Bar Color": "Kolor paska nawigacji",
         "Nav Bar Color": "Kolor paska nawigacji",
         "Unsorted Tab Placement": "Pozycja nieposortowanych kart",
         "Unsorted Tab Placement": "Pozycja nieposortowanych kart",
         "Alternate Homepage Titles": "Alternatywne tytuły strony głównej",
         "Alternate Homepage Titles": "Alternatywne tytuły strony głównej",
-        "Minimal Login Screen": "Minimalistyczny ekran logowania",
+        "Minimal Login Screen": "Uproszczony ekran logowania",
         "Login Wallpaper": "Tapeta ekranu logowania",
         "Login Wallpaper": "Tapeta ekranu logowania",
         "Use Logo instead of Title": "Użyj logo zamiast tytułu",
         "Use Logo instead of Title": "Użyj logo zamiast tytułu",
         "Title": "Tytuł",
         "Title": "Tytuł",

+ 1 - 1
js/sponsors.json

@@ -1,7 +1,7 @@
 [
 [
   {
   {
     "company_name": "EvoSeedbox",
     "company_name": "EvoSeedbox",
-    "logo": "https://s3.amazonaws.com/helpshelf-production/media/uploads/sites/evoseedbox/EVO.png",
+    "logo": "https://user-images.githubusercontent.com/16184466/59205364-9d5c5380-8b57-11e9-909c-95ddc5634a72.jpg",
     "website": "https://evoseedbox.com/",
     "website": "https://evoseedbox.com/",
     "coupon": "evoizr",
     "coupon": "evoizr",
     "coupon_about": "100% off First Month",
     "coupon_about": "100% off First Month",

+ 7 - 0
js/version.json

@@ -187,5 +187,12 @@
     "new": "Plex Admin and Strict info to debug area",
     "new": "Plex Admin and Strict info to debug area",
     "fixed": "Radarr image problem if Radarr Auth is on|Plex login for admin using username and pass for SSO|Powershell update script|Login screen for oAuth only as backend",
     "fixed": "Radarr image problem if Radarr Auth is on|Plex login for admin using username and pass for SSO|Powershell update script|Login screen for oAuth only as backend",
     "notes": "Please report bugs in GitHub issues page|Updated language translations|Added more default tab images"
     "notes": "Please report bugs in GitHub issues page|Updated language translations|Added more default tab images"
+  },
+  "2.0.270": {
+    "date": "2019-06-29 00:35",
+    "title": "Small Weekly Update",
+    "new": "Login lockout feature|JDownloader HP Support - rix|Coupon indicator on sponsor section|Sponsor API call|Custom Pages API endpoint|Theme analytics|SVG added to whitelist",
+    "fixed": "Homepage Loading Sections Displaying for Disabled Items (#1204)|Healthchecks tag issue|Updated Evo logo|Updated Netdata logo|Updated Nextcloud logo|CSS fix for alt headers on HP|HP Downloader counter on MS Edge|Cache image button on recent items",
+    "notes": "Please report bugs in GitHub issues page|Updated language translations"
   }
   }
 }
 }

+ 0 - 11
package-lock.json

@@ -1,11 +0,0 @@
-{
-  "requires": true,
-  "lockfileVersion": 1,
-  "dependencies": {
-    "yuicompressor": {
-      "version": "2.4.8",
-      "resolved": "https://registry.npmjs.org/yuicompressor/-/yuicompressor-2.4.8.tgz",
-      "integrity": "sha1-mNJnUfFm49uRmy/j6nz2Qt6ZjYs="
-    }
-  }
-}

BIN
plugins/images/tabs/jdownloader.png


BIN
plugins/images/tabs/netdata.png


BIN
plugins/images/tabs/nextcloud.png


Некоторые файлы не были показаны из-за большого количества измененных файлов