Răsfoiți Sursa

homepage work started

causefx 8 ani în urmă
părinte
comite
ec81b46565

+ 1 - 0
.gitignore

@@ -94,3 +94,4 @@ css/themes/*.css
 !css/themes/Organizr.css
 !css/themes/Blue.css
 *sonflix*
+plugins/images/cache/*

+ 26 - 1
api/config/default.php

@@ -18,6 +18,7 @@ return array(
     'theme'=>'Organizr',
     'style'=>'dark',
     'plexURL' => '',
+    'plexTabURL' => '',
     'plexToken' => '',
     'embyURL' => '',
     'embyToken' => '',
@@ -26,5 +27,29 @@ return array(
     'ombiURL' => '',
     'ssoPlex' => false,
     'ssoOmbi' => false,
-    'ssoTautulli' => false
+    'ssoTautulli' => false,
+    'homepagePlexEnabled' => false,
+    'homepagePlexAuth' => '1',
+    'homepageOrdercustomhtml' => '1',
+	'homepageOrdernotice' => '2',
+	'homepageOrderplexsearch' => '3',
+	'homepageOrderspeedtest' => '4',
+	'homepageOrdernzbget' => '5',
+	'homepageOrdersabnzbd' => '6',
+	'homepageOrderplexnowplaying' => '7',
+	'homepageOrderplexrecent' => '8',
+	'homepageOrderplexplaylist' => '9',
+	'homepageOrderembynowplaying' => '10',
+	'homepageOrderembyrecent' => '11',
+	'homepageOrderombi' => '12',
+	'homepageOrdercalendar' => '13',
+	'homepageOrdernoticeguest' => '14',
+	'homepageOrdertransmisson' => '15',
+    'homepageShowStreamNames' => false,
+    'homepageStreamRefresh' => '60000',
+    'homepageRecentRefresh' => '60000',
+    'homepagePlexStreams' => false,
+    'homepagePlexStreamsAuth' => '1',
+    'homepagePlexRecent' => false,
+    'homepagePlexRecentAuth' => '1'
 );

+ 14 - 0
api/functions/api-functions.php

@@ -918,6 +918,20 @@ function allTabs(){
         }
     }
 }
+function allGroups(){
+    if(file_exists('config'.DIRECTORY_SEPARATOR.'config.php')){
+        try {
+        	$connect = new Dibi\Connection([
+        		'driver' => 'sqlite3',
+        		'database' => $GLOBALS['dbLocation'].$GLOBALS['dbName'],
+        	]);
+            $all = $connect->fetchAll('SELECT * FROM groups ORDER BY `group_id` ASC');
+            return $all;
+        } catch (Dibi\Exception $e) {
+            return false;
+        }
+    }
+}
 function loadTabs(){
     if(file_exists('config'.DIRECTORY_SEPARATOR.'config.php')){
         try {

+ 176 - 0
api/functions/homepage-connect-functions.php

@@ -0,0 +1,176 @@
+<?php
+
+function homepageConnect($array){
+	switch ($array['data']['action']) {
+        case 'getPlexStreams':
+			return getPlexStreams();
+            break;
+		case 'getPlexRecent':
+        return getPlexRecent();
+			break;
+        default:
+            # code...
+            break;
+    }
+}
+function streamType($value){
+    if($value == "transcode" || $value == "Transcode"){
+        return "Transcode";
+    }elseif($value == "copy" || $value == "DirectStream"){
+        return "Direct Stream";
+    }elseif($value == "directplay" || $value == "DirectPlay"){
+        return "Direct Play";
+    }else{
+        return "Direct Play";
+    }
+}
+function resolvePlexItem($item) {
+    // Static Height
+    $height = 300;
+    $width = 200;
+    $nowPlayingHeight = 338;
+    $nowPlayingWidth = 600;
+	$widthOverride = 100;
+    $cacheDirectory = dirname(__DIR__,2).DIRECTORY_SEPARATOR.'plugins'.DIRECTORY_SEPARATOR.'images'.DIRECTORY_SEPARATOR.'cache'.DIRECTORY_SEPARATOR;
+    $cacheDirectoryWeb = 'plugins/images/cache/';
+    switch ($item['type']) {
+    	case 'season':
+            $plexItem['type'] = 'tv';
+            $plexItem['title'] = (string)$item['parentTitle'];
+            $plexItem['summary'] = (string)$item['parentSummary'];
+            $plexItem['ratingKey'] = (string)$item['parentRatingKey'];
+            $plexItem['thumb'] = (string)$item['thumb'];
+            $plexItem['key'] = (string)$item['ratingKey'] . "-list";
+            $plexItem['nowPlayingThumb'] = (string)$item['art'];
+            $plexItem['nowPlayingKey'] = (string)$item['ratingKey'] . "-np";
+            break;
+        case 'episode':
+            $plexItem['type'] = 'tv';
+            $plexItem['title'] = (string)$item['grandparentTitle'];
+            $plexItem['summary'] = (string)$item['title'];
+            $plexItem['ratingKey'] = (string)$item['parentRatingKey'];
+            $plexItem['thumb'] = ($item['parentThumb'] ? (string)$item['parentThumb'] : (string)$item['grandparentThumb']);
+            $plexItem['key'] = (string)$item['ratingKey'] . "-list";
+            $plexItem['nowPlayingThumb'] = (string)$item['art'];
+            $plexItem['nowPlayingKey'] = (string)$item['ratingKey'] . "-np";
+            $plexItem['nowPlayingTitle'] = (string)$item['grandparentTitle'].' - '.(string)$item['title'];
+            $plexItem['nowPlayingBottom'] = 'S'.(string)$item['parentIndex'].' · E'.(string)$item['index'];
+            break;
+
+        case 'clip':
+            $useImage = (isset($item['live']) ? "images/livetv.png" : null);
+            $plexItem['type'] = 'clip';
+            $plexItem['title'] = (string)$item['title'];
+            $plexItem['summary'] = (string)$item['summary'];
+            $plexItem['ratingKey'] = (string)$item['parentRatingKey'];
+            $plexItem['thumb'] = (string)$item['thumb'];
+            $plexItem['key'] = (string)$item['ratingKey'] . "-list";
+            $plexItem['nowPlayingThumb'] = (string)$item['art'];
+            $plexItem['nowPlayingKey'] = isset($item['ratingKey']) ? (string)$item['ratingKey'] . "-np" : (isset($item['live']) ? "livetv.png" : ":)");
+            $plexItem['nowPlayingTitle'] = $plexItem['title'];
+            $plexItem['nowPlayingBottom'] = isset($item['extraType']) ? "Trailer" : (isset($item['live']) ? "Live TV" : ":)");
+            break;
+        case 'album':
+        case 'track':
+            $plexItem['type'] = 'music';
+            $plexItem['title'] = (string)$item['parentTitle'];
+            $plexItem['summary'] = (string)$item['title'];
+			$plexItem['ratingKey'] = (string)$item['parentRatingKey'];
+            $plexItem['thumb'] = (string)$item['thumb'];
+            $plexItem['key'] = (string)$item['ratingKey'] . "-list";
+			$plexItem['nowPlayingThumb'] = ($item['parentThumb']) ? (string)$item['parentThumb'] :  (string)$item['art'];
+            $plexItem['nowPlayingKey'] = (string)$item['ratingKey'] . "-np";
+            $plexItem['nowPlayingTitle'] = (string)$item['grandparentTitle'].' - '.(string)$item['title'];
+            $plexItem['nowPlayingBottom'] = (string)$item['parentTitle'];
+
+            break;
+        default:
+            $plexItem['type'] = 'movie';
+            $plexItem['title'] = (string)$item['title'];
+            $plexItem['summary'] = (string)$item['summary'];
+            $plexItem['ratingKey'] = (string)$item['ratingKey'];
+            $plexItem['thumb'] = (string)$item['thumb'];
+            $plexItem['key'] = (string)$item['ratingKey'] . "-list";
+            $plexItem['nowPlayingThumb'] = (string)$item['art'];
+            $plexItem['nowPlayingKey'] = (string)$item['ratingKey'] . "-np";
+            $plexItem['nowPlayingTitle'] = (string)$item['title'];
+            $plexItem['nowPlayingBottom'] = (string)$item['year'];
+		}
+        $plexItem['elapsed'] = (string)$item['viewOffset'];
+        $plexItem['duration'] = ($item['duration']) ? (string)$item['duration'] : (string)$item->Media['duration'];
+        $plexItem['watched'] = (!empty($plexItem['elapsed']) ? floor(($plexItem['elapsed'] / $plexItem['duration']) * 100) : 0);
+        $plexItem['transcoded'] = floor($item->TranscodeSession['progress']- $plexItem['watched']);
+        $plexItem['stream'] = isset($item->Media->Part->Stream['decision']) ? (string)$item->Media->Part->Stream['decision']: '';
+        $plexItem['id'] = str_replace('"', '', (string)$item->Player['machineIdentifier']);
+        $plexItem['state'] = (((string)$item->Player['state'] == "paused") ? "pause" : "play");
+        $plexItem['user'] = ($GLOBALS['homepageShowStreamNames'] && qualifyRequest(1) ) ? (string)$item->User['title'] : "";
+        $plexItem['address'] = $GLOBALS['plexTabURL'] ? $GLOBALS['plexTabURL']."/web/index.html#!/server/".$GLOBALS['plexID']."/details?key=/library/metadata/".$item['ratingKey'] : "https://app.plex.tv/web/app#!/server/".$GLOBALS['plexID']."/details?key=/library/metadata/".$item['ratingKey'];
+        $plexItem['nowPlayingOriginalImage'] = 'api/?v1/image&source=plex&img='.$plexItem['nowPlayingThumb'].'&height='.$nowPlayingHeight.'&width='.$nowPlayingWidth.'&key='.$plexItem['nowPlayingKey'].'$'.randString();
+        $plexItem['originalImage'] = 'api/?v1/image&source=plex&img='.$plexItem['thumb'].'&height='.$height.'&width='.$width.'&key='.$plexItem['key'].'$'.randString();
+        if (file_exists($cacheDirectory.$plexItem['nowPlayingKey'].'.jpg')){ $plexItem['nowPlayingImageURL'] = $cacheDirectoryWeb.$plexItem['nowPlayingKey'].'.jpg'; }
+        if (file_exists($cacheDirectory.$plexItem['key'].'.jpg')){ $plexItem['imageURL']  = $cacheDirectoryWeb.$plexItem['key'].'.jpg'; }
+        if (file_exists($cacheDirectory.$plexItem['nowPlayingKey'].'.jpg') && (time() - 604800) > filemtime($cacheDirectory.$plexItem['nowPlayingKey'].'.jpg') || !file_exists($cacheDirectory.$plexItem['nowPlayingKey'].'.jpg')) {
+            $plexItem['nowPlayingImageURL'] = 'api/?v1/image&source=plex&img='.$plexItem['nowPlayingThumb'].'&height='.$nowPlayingHeight.'&width='.$nowPlayingWidth.'&key='.$plexItem['nowPlayingKey'].'';
+        }
+        if (file_exists($cacheDirectory.$plexItem['key'].'.jpg') && (time() - 604800) > filemtime($cacheDirectory.$plexItem['key'].'.jpg') || !file_exists($cacheDirectory.$plexItem['key'].'.jpg')) {
+            $plexItem['imageURL'] = 'api/?v1/image&source=plex&img='.$plexItem['thumb'].'&height='.$height.'&width='.$width.'&key='.$plexItem['key'].'';
+        }
+        if(!$plexItem['nowPlayingThumb'] ){ $plexItem['nowPlayingOriginalImage']  = $plexItem['nowPlayingImageURL']  = "images/no-np.png"; $plexItem['nowPlayingKey'] = "no-np"; }
+        if(!$plexItem['thumb'] ){  $plexItem['originalImage'] = $plexItem['imageURL'] = "images/no-list.png"; $plexItem['key'] = "no-list"; }
+
+	if(isset($useImage)){ $plexItem['useImage'] = $useImage; }
+    return $plexItem;
+
+}
+function getPlexStreams(){
+	if(!empty($GLOBALS['plexURL']) && !empty($GLOBALS['plexToken']) && !empty($GLOBALS['plexID'] && qualifyRequest($GLOBALS['homepagePlexStreamsAuth']))){
+		try{
+			$url = qualifyURL($GLOBALS['plexURL']);
+			$url = $url."/status/sessions?X-Plex-Token=".$GLOBALS['plexToken'];
+			$options = (localURL($url)) ? array('verify' => false ) : array();
+			$response = Requests::get($url, array(), $options);
+			libxml_use_internal_errors(true);
+			if($response->success){
+				$items = array();
+				$plex = simplexml_load_string($response->body);
+				foreach($plex AS $child) {
+					$items[] = resolvePlexItem($child);
+				}
+				$api['content'] = $items;
+				$api['plexID'] = $GLOBALS['plexID'];
+				$api['showNames'] = true;
+				$api['group'] = '1';
+				return $api;
+			}
+		}catch( Requests_Exception $e ) {
+			writeLog('error', 'Plex Connect Function - Error: '.$e->getMessage(), 'SYSTEM');
+		};
+	}
+	return false;
+}
+function getPlexRecent(){
+	if(!empty($GLOBALS['plexURL']) && !empty($GLOBALS['plexToken']) && !empty($GLOBALS['plexID'] && qualifyRequest($GLOBALS['homepagePlexRecentAuth']))){
+		try{
+			$url = qualifyURL($GLOBALS['plexURL']);
+			$url = $url."/library/recentlyAdded?X-Plex-Token=".$GLOBALS['plexToken'];
+			$options = (localURL($url)) ? array('verify' => false ) : array();
+			$response = Requests::get($url, array(), $options);
+			libxml_use_internal_errors(true);
+			if($response->success){
+				$items = array();
+				$plex = simplexml_load_string($response->body);
+				foreach($plex AS $child) {
+					$items[] = resolvePlexItem($child);
+				}
+				$api['content'] = $items;
+				$api['plexID'] = $GLOBALS['plexID'];
+				$api['showNames'] = true;
+				$api['group'] = '1';
+				return $api;
+			}
+		}catch( Requests_Exception $e ) {
+			writeLog('error', 'Plex Connect Function - Error: '.$e->getMessage(), 'SYSTEM');
+		};
+	}
+	return false;
+}

+ 327 - 0
api/functions/homepage-functions.php

@@ -0,0 +1,327 @@
+<?php
+//homepage order
+function homepageOrder(){
+	$homepageOrder = array(
+		"homepageOrdercustomhtml" => $GLOBALS['homepageOrdercustomhtml'],
+		"homepageOrdernotice" => $GLOBALS['homepageOrdernotice'],
+		"homepageOrderplexsearch" => $GLOBALS['homepageOrderplexsearch'],
+		"homepageOrderspeedtest" => $GLOBALS['homepageOrderspeedtest'],
+		"homepageOrdernzbget" => $GLOBALS['homepageOrdernzbget'],
+		"homepageOrdersabnzbd" => $GLOBALS['homepageOrdersabnzbd'],
+		"homepageOrderplexnowplaying" => $GLOBALS['homepageOrderplexnowplaying'],
+		"homepageOrderplexrecent" => $GLOBALS['homepageOrderplexrecent'],
+		"homepageOrderplexplaylist" => $GLOBALS['homepageOrderplexplaylist'],
+		"homepageOrderembynowplaying" => $GLOBALS['homepageOrderembynowplaying'],
+		"homepageOrderembyrecent" => $GLOBALS['homepageOrderembyrecent'],
+		"homepageOrderombi" => $GLOBALS['homepageOrderombi'],
+		"homepageOrdercalendar" => $GLOBALS['homepageOrdercalendar'],
+		"homepageOrdernoticeguest" => $GLOBALS['homepageOrdernoticeguest'],
+		"homepageOrdertransmisson" => $GLOBALS['homepageOrdertransmisson'],
+	);
+	asort($homepageOrder);
+	return $homepageOrder;
+}
+function buildHomepage(){
+	$homepageOrder = homepageOrder();
+	$homepageBuilt = '';
+	foreach ($homepageOrder as $key => $value) {
+		$homepageBuilt .= buildHomepageItem($key);
+	}
+	return $homepageBuilt;
+}
+function buildHomepageItem($homepageItem){
+	$item = '<div id="'.$homepageItem.'"></div>';
+	switch ($homepageItem) {
+		case 'homepageOrderplexsearch':
+
+			break;
+		case 'homepageOrdercustomhtml':
+
+			break;
+		case 'homepageOrdernotice':
+
+			break;
+		case 'homepageOrdernoticeguest':
+
+			break;
+		case 'homepageOrderspeedtest':
+
+			break;
+		case 'homepageOrdertransmisson':
+
+			break;
+		case 'homepageOrdernzbget':
+
+			break;
+		case 'homepageOrdersabnzbd':
+
+			break;
+		case 'homepageOrderplexnowplaying':
+			if($GLOBALS['homepagePlexStreams']){
+				$item .= '
+				<script>
+				// Plex Stream
+				plexStream();
+				setInterval(function() {
+				    plexStream();
+				}, '.$GLOBALS['homepageStreamRefresh'].');
+				// End Plex Stream
+				</script>
+				';
+			}
+			break;
+		case 'homepageOrderplexrecent':
+			if($GLOBALS['homepagePlexRecent']){
+				$item .= '
+				<script>
+				// Plex Recent
+				plexRecent();
+				setInterval(function() {
+					plexRecent();
+				}, '.$GLOBALS['homepageRecentRefresh'].');
+				// End Plex Recent
+				</script>
+				';
+			}
+			break;
+		case 'homepageOrderplexplaylist':
+
+			break;
+		case 'homepageOrderembynowplaying':
+
+			break;
+		case 'homepageOrderembyrecent':
+
+			break;
+		case 'homepageOrderombi':
+
+			break;
+		case 'homepageOrdercalendar':
+
+			break;
+		default:
+			# code...
+			break;
+	}
+	return $item;
+}
+function getHomepageList(){
+    $groups = groupSelect();
+    $time = array(
+        array(
+            'name' => '5',
+            'value' => '5000'
+        ),
+        array(
+            'name' => '10',
+            'value' => '10000'
+        ),
+        array(
+            'name' => '15',
+            'value' => '15000'
+        ),
+        array(
+            'name' => '30',
+            'value' => '30000'
+        ),
+        array(
+            'name' => '60',
+            'value' => '60000'
+        ),
+    );
+    return array(
+        array(
+            'name' => 'Plex',
+            'enabled' => true,
+            'image' => 'plugins/images/tabs/plex.png',
+            'category' => 'Media Server',
+            'settings' => array(
+                'Enable' => array(
+                    array(
+            			'type' => 'switch',
+            			'name' => 'homepagePlexEnabled',
+            			'label' => 'Enable',
+            			'value' => $GLOBALS['homepagePlexEnabled']
+            		)
+                ),
+                'Connection' => array(
+                    array(
+                        'type' => 'input',
+                        'name' => 'plexURL',
+                        'label' => 'URL',
+                        'value' => $GLOBALS['plexURL']
+                    ),
+                    array(
+                        'type' => 'input',
+                        'name' => 'plexToken',
+                        'label' => 'Token',
+                        'value' => $GLOBALS['plexToken']
+                    ),
+                    array(
+                        'type' => 'input',
+                        'name' => 'plexID',
+                        'label' => 'Plex Machine',
+                        'value' => $GLOBALS['plexID']
+                    )
+                ),
+                'Authentication' => array(
+                    array(
+            			'type' => 'select',
+            			'name' => 'homepagePlexAuth',
+            			'label' => 'Minimum Authentication',
+            			'value' => $GLOBALS['homepagePlexAuth'],
+                        'options' => $groups
+            		)
+                ),
+                'Modules' => array(
+                    array(
+            			'type' => 'switch',
+            			'name' => 'homepagePlexStreams',
+            			'label' => 'Show Streams',
+            			'value' => $GLOBALS['homepagePlexStreams']
+            		),
+                    array(
+    					'type' => 'select',
+    					'name' => 'homepagePlexStreamsAuth',
+                        'label' => 'Stream Authorization',
+    					'value' => $GLOBALS['homepagePlexStreamsAuth'],
+    					'options' => $groups
+    				),
+					array(
+            			'type' => 'switch',
+            			'name' => 'homepagePlexRecent',
+            			'label' => 'Show Recent Items',
+            			'value' => $GLOBALS['homepagePlexRecent']
+            		),
+                    array(
+    					'type' => 'select',
+    					'name' => 'homepagePlexRecentAuth',
+                        'label' => 'Recent Authorization',
+    					'value' => $GLOBALS['homepagePlexRecentAuth'],
+    					'options' => $groups
+    				)
+                ),
+                'Options' => array(
+                    array(
+            			'type' => 'switch',
+            			'name' => 'homepageShowStreamNames',
+            			'label' => 'Show Usernames',
+            			'value' => $GLOBALS['homepageShowStreamNames']
+            		),
+                    array(
+    					'type' => 'select',
+    					'name' => 'homepageStreamRefresh',
+                        'label' => 'Stream Refresh Seconds',
+    					'value' => $GLOBALS['homepageStreamRefresh'],
+    					'options' => $time
+    				),
+					array(
+    					'type' => 'select',
+    					'name' => 'homepageRecentRefresh',
+                        'label' => 'Recent Items Refresh Seconds',
+    					'value' => $GLOBALS['homepageRecentRefresh'],
+    					'options' => $time
+    				)
+                )
+            )
+        ),
+        array(
+            'name' => 'Emby',
+            'enabled' => true,
+            'image' => 'plugins/images/tabs/emby.png',
+            'category' => 'Media Server',
+            'settings' => array(
+                'Enable' => array(
+                    array(
+            			'type' => 'switch',
+            			'name' => 'homepagePlexEnabled',
+            			'label' => 'Enable',
+            			'value' => $GLOBALS['homepagePlexEnabled']
+            		)
+                ),
+                'Connection' => array(
+                    array(
+                        'type' => 'input',
+                        'name' => 'plexURL',
+                        'label' => 'URL',
+                        'value' => $GLOBALS['plexURL']
+                    ),
+                    array(
+                        'type' => 'input',
+                        'name' => 'plexToken',
+                        'label' => 'Token',
+                        'value' => $GLOBALS['plexToken']
+                    )
+                ),
+                'Authentication' => array(
+                    array(
+            			'type' => 'select',
+            			'name' => 'homepagePlexAuth',
+            			'label' => 'Minimum Authentication',
+            			'value' => $GLOBALS['homepagePlexAuth'],
+                        'options' => $groups
+            		)
+                ),
+                'Options' => array(
+                    array(
+    					'type' => 'select',
+    					'name' => 'style',
+    					'label' => 'Style',
+    					'class' => 'styleChanger',
+    					'value' => $GLOBALS['style'],
+    					'options' => $groups
+    				)
+                )
+            )
+        ),
+        array(
+            'name' => 'Sonarr',
+            'enabled' => false,
+            'image' => 'plugins/images/tabs/sonarr.png',
+            'category' => 'PVR',
+            'settings' => array(
+                'Enable' => array(
+                    array(
+            			'type' => 'switch',
+            			'name' => 'homepagePlexEnabled',
+            			'label' => 'Enable',
+            			'value' => $GLOBALS['homepagePlexEnabled']
+            		)
+                ),
+                'Connection' => array(
+                    array(
+                        'type' => 'input',
+                        'name' => 'plexURL',
+                        'label' => 'URL',
+                        'value' => $GLOBALS['plexURL']
+                    ),
+                    array(
+                        'type' => 'input',
+                        'name' => 'plexToken',
+                        'label' => 'Token',
+                        'value' => $GLOBALS['plexToken']
+                    )
+                ),
+                'Authentication' => array(
+                    array(
+            			'type' => 'select',
+            			'name' => 'homepagePlexAuth',
+            			'label' => 'Minimum Authentication',
+            			'value' => $GLOBALS['homepagePlexAuth'],
+                        'options' => $groups
+            		)
+                ),
+                'Options' => array(
+                    array(
+    					'type' => 'select',
+    					'name' => 'style',
+    					'label' => 'Style',
+    					'class' => 'styleChanger',
+    					'value' => $GLOBALS['style'],
+    					'options' => $groups
+    				)
+                )
+            )
+        )
+    );
+}

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

@@ -98,6 +98,14 @@ function random_ascii_string($length){
     }
     return $randomString;
 }
+// Generate Random string
+function randString($length = 10, $chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ') {
+	$tmp = '';
+	for ($i = 0; $i < $length; $i++) {
+		$tmp .= substr(str_shuffle($chars), 0, 1);
+	}
+    return $tmp;
+}
 function encrypt($password, $key = null) {
     $key = (isset($GLOBALS['organizrHash'])) ? $GLOBALS['organizrHash'] : $key;
     return openssl_encrypt($password, 'AES-256-CBC', $key, 0, fillString($key,16));

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

@@ -685,6 +685,74 @@ function wizardPath($array){
     }
     return 'permissions';
 }
+function groupSelect(){
+    $groups = allGroups();
+    $select = array();
+    foreach ($groups as $key => $value) {
+        $select[] = array(
+            'name' => $value['group'],
+            'value' => $value['group_id']
+        );
+    }
+    return $select;
+}
+function getImage() {
+	$refresh = false;
+    $cacheDirectory = dirname(__DIR__,2).DIRECTORY_SEPARATOR.'plugins'.DIRECTORY_SEPARATOR.'images'.DIRECTORY_SEPARATOR.'cache'.DIRECTORY_SEPARATOR;
+    if (!file_exists($cacheDirectory)) {
+        mkdir($cacheDirectory, 0777, true);
+    }
+	@$image_url = $_GET['img'];
+	@$key = $_GET['key'];
+    @$image_height = $_GET['height'];
+    @$image_width = $_GET['width'];
+	@$source = $_GET['source'];
+    @$itemType = $_GET['type'];
+	if(strpos($key, '$') !== false){
+		$key = explode('$', $key)[0];
+		$refresh = true;
+	}
+	switch ($source) {
+        case 'plex':
+            $plexAddress = qualifyURL($GLOBALS['plexURL']);
+            $image_src = $plexAddress . '/photo/:/transcode?height='.$image_height.'&width='.$image_width.'&upscale=1&url=' . $image_url . '&X-Plex-Token=' . $GLOBALS['plexToken'];
+            break;
+        case 'emby':
+            $embyAddress = qualifyURL($GLOBALS['embyURL']);
+        	$imgParams = array();
+        	if (isset($_GET['height'])) { $imgParams['height'] = 'maxHeight='.$_GET['height']; }
+        	if (isset($_GET['width'])) { $imgParams['width'] = 'maxWidth='.$_GET['width']; }
+            $image_src = $embyAddress . '/Items/'.$image_url.'/Images/'.$itemType.'?'.implode('&', $imgParams);
+            break;
+        default:
+            # code...
+            break;
+    }
+
+	if(isset($image_url) && isset($image_height) && isset($image_width) && isset($image_src)) {
+
+        $cachefile = $cacheDirectory.$key.'.jpg';
+        $cachetime = 604800;
+        // Serve from the cache if it is younger than $cachetime
+        if (file_exists($cachefile) && time() - $cachetime < filemtime($cachefile) && $refresh == false) {
+            header("Content-type: image/jpeg");
+            @readfile($cachefile);
+            exit;
+        }
+		ob_start(); // Start the output buffer
+        header('Content-type: image/jpeg');
+		@readfile($image_src);
+		//echo @curl_get($image_src);
+        // Cache the output to a file
+        $fp = fopen($cachefile, 'wb');
+        fwrite($fp, ob_get_contents());
+        fclose($fp);
+        ob_end_flush(); // Send the output to the browser
+		die();
+	} else {
+		die("Invalid Request");
+	}
+}
 /*
 function sendEmail($email = null, $username = "Organizr User", $subject, $body, $cc = null, $bcc = null){
 	try {

+ 86 - 0
api/index.php

@@ -37,6 +37,19 @@ switch ($function) {
                 break;
         }
         break;
+    case 'v1_homepage':
+        switch ($method) {
+            case 'GET':
+                $result['status'] = 'success';
+                $result['statusText'] = 'success';
+                $result['data'] = $pageHomepage;
+                break;
+            default:
+                $result['status'] = 'error';
+                $result['statusText'] = 'The function requested is not defined for method: '.$method;
+                break;
+        }
+        break;
     case 'v1_settings_plugins':
         switch ($method) {
             case 'GET':
@@ -56,6 +69,55 @@ switch ($function) {
                 break;
         }
         break;
+    case 'v1_settings_tab_editor_homepage':
+        switch ($method) {
+            case 'GET':
+                if(qualifyRequest(1)){
+                    $result['status'] = 'success';
+                    $result['statusText'] = 'success';
+                    $result['data'] = $pageSettingsTabEditorHomepage;
+                }else{
+                    $result['status'] = 'error';
+                    $result['statusText'] = 'API/Token invalid or not set';
+                    $result['data'] = null;
+                }
+                break;
+            default:
+                $result['status'] = 'error';
+                $result['statusText'] = 'The function requested is not defined for method: '.$method;
+                break;
+        }
+        break;
+    case 'v1_settings_homepage_list':
+        switch ($method) {
+            case 'GET':
+                if(qualifyRequest(1)){
+                    $result['status'] = 'success';
+                    $result['statusText'] = 'success';
+                    $result['data'] = getHomepageList();
+                }else{
+                    $result['status'] = 'error';
+                    $result['statusText'] = 'API/Token invalid or not set';
+                    $result['data'] = null;
+                }
+                break;
+            case 'POST':
+                if(qualifyRequest(1)){
+                    $result['status'] = 'success';
+                    $result['statusText'] = 'success';
+                    $result['data'] = editPlugins($_POST);
+                }else{
+                    $result['status'] = 'error';
+                    $result['statusText'] = 'API/Token invalid or not set';
+                    $result['data'] = null;
+                }
+                break;
+            default:
+                $result['status'] = 'error';
+                $result['statusText'] = 'The function requested is not defined for method: '.$method;
+                break;
+        }
+        break;
     case 'v1_settings_plugins_list':
         switch ($method) {
             case 'GET':
@@ -192,6 +254,19 @@ switch ($function) {
                 break;
         }
         break;
+    case 'v1_homepage_connect':
+        switch ($method) {
+            case 'POST':
+                $result['status'] = 'success';
+                $result['statusText'] = 'success';
+                $result['data'] = homepageConnect($_POST);
+                break;
+            default:
+                $result['status'] = 'error';
+                $result['statusText'] = 'The function requested is not defined for method: '.$method;
+                break;
+        }
+        break;
     case 'v1_settings_tab_editor_tabs':
         switch ($method) {
             case 'GET':
@@ -729,6 +804,17 @@ switch ($function) {
                 break;
         }
         break;
+    case 'v1_image':
+        switch ($method) {
+            case 'GET':
+                getImage();
+                break;
+            default:
+                $result['status'] = 'error';
+                $result['statusText'] = 'The function requested is not defined for method: '.$method;
+                break;
+        }
+        break;
     default:
         //No Function Available
         $result['status'] = 'error';

+ 33 - 0
api/pages/homepage.php

@@ -0,0 +1,33 @@
+<?php
+if(file_exists('config'.DIRECTORY_SEPARATOR.'config.php')){
+$pageHomepage = '
+<script>
+$("#owl-demo2").owlCarousel({
+    margin:20,
+    nav:true,
+    autoplay:true,
+    responsive:{
+        0:{
+            items:1
+        },
+        480:{
+            items:2
+        },
+        700:{
+            items:4
+        },
+        1000:{
+            items:3
+        },
+        1100:{
+            items:5
+        }
+    }
+})
+</script>
+<link href="plugins/bower_components/owl.carousel/owl.carousel.min.css" rel="stylesheet" type="text/css" />
+<link href="plugins/bower_components/owl.carousel/owl.theme.default.css" rel="stylesheet" type="text/css" />
+<div class="container-fluid p-t-10" id="homepage-items">'.buildHomepage().'</div>
+<!-- /.container-fluid -->
+';
+}

+ 19 - 0
api/pages/settings-tab-editor-homepage.php

@@ -0,0 +1,19 @@
+<?php
+
+$pageSettingsTabEditorHomepage = '
+<script>
+	buildHomepage();
+</script>
+<div class="panel bg-org panel-info">
+    <div class="panel-heading">
+		<span lang="en">Homepage Items</span>
+        <!-- <button type="button" class="btn btn-success btn-circle pull-right popup-with-form m-r-5" href="#new-image-form" data-effect="mfp-3d-unfold"><i class="fa fa-upload"></i> </button> -->
+	</div>
+    <div class="panel-wrapper collapse in" aria-expanded="true">
+        <div class="panel-body bg-org" >
+        <div class="row el-element-overlay m-b-40" id="settings-homepage-list"></div>
+        </div>
+    </div>
+</div>
+
+';

+ 5 - 0
api/pages/settings.php

@@ -46,6 +46,8 @@ $pageSettings = '
                             </li>
                             <li onclick="changeSettingsMenu(\'Settings::Tab Editor::Categories\');loadSettingsPage(\'api/?v1/settings/tab/editor/categories\',\'#settings-tab-editor-categories\',\'Category Editor\');" role="presentation" class=""><a href="#settings-tab-editor-categories" aria-controls="home" role="tab" data-toggle="tab" aria-expanded="false"><span class="visible-xs"><i class="ti-layout-list-thumb"></i></span><span class="hidden-xs" lang="en"> Categories</span></a>
                             </li>
+                            <li onclick="changeSettingsMenu(\'Settings::Tab Editor::Homepage Items\');loadSettingsPage(\'api/?v1/settings/tab/editor/homepage\',\'#settings-tab-editor-homepage\',\'Homepage Items\');" role="presentation" class=""><a href="#settings-tab-editor-homepage" aria-controls="home" role="tab" data-toggle="tab" aria-expanded="false"><span class="visible-xs"><i class="ti-home"></i></span><span class="hidden-xs" lang="en"> Homepage Items</span></a>
+                            </li>
                         </ul>
                         <!-- Tab panes -->
                         <div class="tab-content">
@@ -56,6 +58,9 @@ $pageSettings = '
                             <div role="tabpanel" class="tab-pane fade" id="settings-tab-editor-categories">
                                 <h2 lang="en">Loading...</h2>
                             </div>
+                            <div role="tabpanel" class="tab-pane fade" id="settings-tab-editor-homepage">
+                                <h2 lang="en">Loading...</h2>
+                            </div>
                         </div>
                     </section>
                     <! -- Customzie -->

+ 1 - 1
api/plugins/js/php-mailer.js

@@ -51,7 +51,7 @@ $(document).on('change asColorPicker::close', '#PHPMAILER-settings-page :input',
             $('#PHPMAILER-settings-page :input').prop('disabled', null);
             input.emulateTab();
         },
-        1500
+        2000
     );
 
 });

+ 14 - 0
css/organizr.css

@@ -140,3 +140,17 @@ img.lazyload.tabImages {
 height: 120px !important;
 object-fit: contain;
 }
+.recent-cover{
+	background-position: center;background-size: cover;height: 150px;width: 150px;
+  top: 74px;
+    position: absolute;
+}
+.recent-poster{
+	background-position: center;background-size: cover;height: 225px;width: 150px;
+}
+.recent-title{
+  position: absolute;
+  bottom: 0px;
+  background: rgba(31, 31, 31, 0.73);
+  width: inherit;
+}

+ 1 - 0
index.php

@@ -129,6 +129,7 @@
 	<script src="plugins/bower_components/jquery-asColorPicker-master/libs/jquery-asColor.js"></script>
     <script src="plugins/bower_components/jquery-asColorPicker-master/dist/jquery-asColorPicker.min.js"></script>
 	<script src="plugins/bower_components/dropzone-master/dist/dropzone.js"></script>
+	<script src="plugins/bower_components/owl.carousel/owl.carousel.min.js"></script>
 	<script src="js/functions.js?v=<?php echo $GLOBALS['installedVersion']; ?>"></script>
 	<script src="js/custom.js?v=<?php echo $GLOBALS['installedVersion']; ?>"></script>
 	<?php echo pluginFiles('js'); ?>

+ 73 - 0
js/custom.js

@@ -89,6 +89,35 @@ function pageLoad(){
             alphaConvert: false
         }
     });
+    $(function () {
+        $('#owl-demo2').owlCarousel({
+    	    margin:0,
+    	    nav:false,
+    		autoplay:false,
+            dots:false,
+    	    responsive:{
+    	        0:{
+    	            items:1,
+                    center:true,
+                    stagePadding: 50
+    	        },
+    	        480:{
+    	            items:2,
+                    center:true,
+                    stagePadding: 50
+    	        },
+    	        700:{
+    	            items:4
+    	        },
+    	        960:{
+    	            items:6
+    	        },
+    	        1100:{
+    	            items:7
+    	        }
+    	    }
+    	})
+    });
 
 
     /* ===== Theme Settings ===== */
@@ -1395,6 +1424,50 @@ $(document).on("click", ".testPath", function () {
         });
     }
 });
+// Save Homepage Form
+$(document).on('change asColorPicker::close', '.homepageForm :input', function(e) {
+    var input = $(this);
+    switch ($(this).attr('type')) {
+        case 'switch':
+        case 'checkbox':
+            var value = $(this).prop("checked") ? true : false;
+            break;
+        default:
+            var value = $(this).val();
+    }
+	var post = {
+        api:'api/?v1/update/config',
+        name:$(this).attr("name"),
+        type:$(this).attr("data-type"),
+        value:value,
+        messageTitle:'',
+        messageBody:'Updated Value for '+$(this).parent().parent().find('label').text(),
+        error:'Organizr Function: API Connection Failed'
+    };
+	var callbacks = $.Callbacks();
+    //callbacks.add( buildCustomizeAppearance );
+    settingsAPI(post,callbacks);
+    //disable button then renable
+    $('.homepageForm :input').prop('disabled', 'true');
+    setTimeout(
+        function(){
+            $('.homepageForm :input').prop('disabled', null);
+            input.emulateTab();
+        },
+        2000
+    );
+
+});
+$(document).on({
+    mouseenter: function () {
+        $(this).find('.progress').toggleClass('progress-lg');
+        $(this).find('.progress').find('span').toggleClass('hidden');
+    },
+    mouseleave: function () {
+        $(this).find('.progress').toggleClass('progress-lg');
+        $(this).find('.progress').find('span').toggleClass('hidden');
+    }
+}, '.nowPlayingItem');
 /* ===== Open-Close Right Sidebar ===== */
 
 $(document).on("click", ".right-side-toggle", function () {

+ 196 - 3
js/functions.js

@@ -54,7 +54,14 @@ function languageList(){
 	};
 }
 function sleep(ms) {
-  return new Promise(resolve => setTimeout(resolve, ms));
+	return new Promise(resolve => setTimeout(resolve, ms));
+}
+function contains(target, pattern){
+    var value = 0;
+    pattern.forEach(function(word){
+      value = value + target.includes(word);
+    });
+    return (value === 1)
 }
 function timerIncrement() {
     idleTime = idleTime + 1;
@@ -192,6 +199,7 @@ function reloadOrganizr(){
 }
 function hideFrames(){
 	$(".iFrame-listing div[class^='frame-container']").addClass("hidden").removeClass('show');
+	$(".internal-listing div[class^='internal-container']").addClass("hidden").removeClass('show');
 }
 function closeSideMenu(){
 	$('.fix-header').removeClass('show-sidebar');
@@ -238,9 +246,9 @@ function switchTab(tab, type){
 		case '0':
 		case 'internal':
 			swapDisplay('internal');
-			$('#menu-'+cleanClass(tab)).find('a').addClass("active");
 			var newTab = $('#internal-'+tab);
 			var tabURL = newTab.attr('data-url');
+			$('#menu-'+cleanClass(tab)).find('a').addClass("active");
 			if(newTab.hasClass('loaded')){
 				console.log('Tab Function: Switching to tab: '+tab);
 				newTab.addClass("show").removeClass('hidden');
@@ -626,6 +634,34 @@ function buildPluginsItem(array){
 
 	return panes;
 }
+function buildHomepageItem(array){
+	var listing = '';
+	if (Array.isArray(array)) {
+		$.each(array, function(i,v) {
+			listing += `
+			<div class="col-lg-2 col-md-2 col-sm-4 col-xs-4">
+				<div class="white-box bg-org m-0">
+					<div class="el-card-item p-0">
+						<div class="el-card-avatar el-overlay-1">
+							<a class="popup-with-form" href="#homepage-`+v.name+`-form" data-effect="mfp-3d-unfold"><img class="lazyload tabImages" data-src="`+v.image+`"></a>
+						</div>
+						<div class="el-card-content">
+							<h3 class="box-title">`+v.name+`</h3>
+							<small class="elip text-uppercase">`+v.category+`</small><br>
+						</div>
+					</div>
+				</div>
+			</div>
+			<form id="homepage-`+v.name+`-form" class="mfp-hide white-popup-block mfp-with-anim homepageForm">
+			    <h1 lang="en">Edit Settings</h1>
+			    <fieldset style="border:0;">`+buildFormGroup(v.settings)+`</fieldset>
+			    <div class="clearfix"></div>
+			</form>
+			`;
+		});
+	}
+	return listing;
+}
 function buildPlugins(){
 	ajaxloader(".content-wrap","in");
 	organizrAPI('GET','api/?v1/settings/plugins/list').success(function(data) {
@@ -636,6 +672,17 @@ function buildPlugins(){
 	});
 	ajaxloader();
 }
+function buildHomepage(){
+	ajaxloader(".content-wrap","in");
+	organizrAPI('GET','api/?v1/settings/homepage/list').success(function(data) {
+		var response = JSON.parse(data);
+		console.log(response);
+		$('#settings-homepage-list').html(buildHomepageItem(response.data));
+	}).fail(function(xhr) {
+		console.error("Organizr Function: API Connection Failed");
+	});
+	ajaxloader();
+}
 function buildFormGroup(array){
 	var group = '';
 	$.each(array, function(i,v) {
@@ -932,7 +979,7 @@ function tabProcess(arrayItems) {
 					case 0:
 					case '0':
 					case 'internal':
-						internalList += buildInternalContainer(v.name,v.url,v.type);
+						internalList = buildInternalContainer(v.name,v.url,v.type);
 						$(internalList).appendTo($('.internal-listing'));
 						break;
 					case 1:
@@ -1752,6 +1799,152 @@ function setSSO(){
 		}
 	});
 }
+function buildPlexStreamItem(array){
+	var cards = '';
+	var count = 0;
+	var total = array.length;
+	var start = ['1','5','9','13','17','21'];
+	var end = ['4','8','12','16','20','24'];
+	$.each(array, function(i,v) {
+		var icon = '';
+		var width = 100;
+		var bg = '';
+
+			count++;
+			if(contains(''+count, start)){ cards += '<div class="row">'; };
+
+
+
+
+
+		switch (v.type) {
+			case 'music':
+				icon = 'icon-music-tone-alt';
+				width = 56;
+				bg = `
+				<img class="" style="width: 56%;display:block;position: absolute;left:0px;overflow: hidden;filter: blur(0px) grayscale(1);" src="`+v.nowPlayingImageURL+`">
+				<img class="" style="width: 56%;display:block;position: absolute;right:0px;overflow: hidden;filter: blur(0px) grayscale(1);" src="`+v.nowPlayingImageURL+`">
+				`;
+				break;
+			case 'movie':
+				//title = v.title;
+				//year = v.year;
+				icon = 'icon-film';
+				break;
+			case 'tv':
+				icon = 'icon-screen-desktop';
+				break;
+			default:
+
+		}
+		cards += `
+		<div class="col-lg-3 col-md-4 col-sm-6 col-xs-12 nowPlayingItem">
+			<div class="white-box">
+				<div class="el-card-item p-b-10">
+					<div class="el-card-avatar el-overlay-1 m-b-0">`+bg+`<img style="width:`+width+`%;margin-left: auto;margin-right: auto;" src="`+v.nowPlayingImageURL+`">
+						<div class="el-overlay">
+							<ul class="el-info p-t-20 m-t-20">
+								<li><a class="btn default btn-outline" href="javascript:void(0);"><i class="icon-graph"></i></a></li><li><a class="btn default btn-outline image-popup-vertical-fit" href="../plugins/images/users/1.jpg"><i class="icon-info"></i></a></li>
+								<li><a class="btn default btn-outline" href="javascript:void(0);"><i class="icon-share-alt"></i></a></li><li><a class="btn default btn-outline" href="javascript:void(0);"><i class="icon-refresh"></i></a></li><li><a class="btn default btn-outline" href="javascript:void(0);"><i class="icon-graph"></i></a></li>
+							</ul>
+						</div>
+					</div>
+					<div class="el-card-content">
+						<div class="progress">
+							<div class="progress-bar progress-bar-primary" style="width: `+v.watched+`%;" role="progressbar"><span class="hidden">`+v.watched+`%</span></div>
+							<div class="progress-bar progress-bar-inverse" style="width: `+v.transcoded+`%;" role="progressbar"></div>
+						</div>
+						<h3 class="box-title pull-left p-l-10 elip" style="width:90%">`+v.nowPlayingTitle+`</h3>
+						<h3 class="box-title pull-right vertical-middle" style="width:10%"><i class="icon-control-`+v.state+` fa-fw text-primary" style=""></i></h3>
+						<div class="clearfix"></div>
+						<small class="pull-left p-l-10"><i class="`+icon+` fa-fw text-primary"></i>`+v.nowPlayingBottom+`</small>
+						<small class="pull-right p-r-10">`+v.user+` <i class="icon-user"></i></small>
+						<br>
+					</div>
+				</div>
+			</div>
+		</div>
+		`;
+		if(contains(''+count, end) || count == total ){ cards += '</div><!--end-->'; };
+
+	});
+	return cards;
+}
+function buildPlexRecentItem(array){
+	var items = '';
+	$.each(array, function(i,v) {
+		var className = '';
+		switch (v.type) {
+			case 'music':
+				className = 'recent-cover';
+				break;
+			case 'movie':
+				className = 'recent-poster';
+				break;
+			case 'tv':
+				className = 'recent-poster';
+				break;
+			default:
+
+		}
+		items += '<div class="item lazyload '+className+'" data-src="'+v.imageURL+'"><span class="elip recent-title">'+v.title+'</span></div>';
+
+	});
+	return items;
+}
+function buildPlexStream(array){
+	var streams = array.content.length;
+	return `
+	<div id="plexStreams" data-check="`+escape(JSON.stringify(array.content))+`">
+		<div class="row el-element-overlay m-b-20">
+		    <div class="col-md-12">
+		        <h4 lang="en">Active Plex Streams `+streams+`</h4>
+		        <hr>
+		    </div>
+		    <!-- .cards -->
+			`+buildPlexStreamItem(array.content)+`
+		    <!-- /.cards-->
+		</div>
+	</div>
+	`;
+}
+function buildPlexRecent(array){
+	var recent = array.content.length;
+	return `
+	<div id="plexRecent" data-check="`+escape(JSON.stringify(array.content))+`" class="row">
+        <div class="col-lg-12">
+            <div class="panel panel-default">
+                <div class="panel-heading" lang="en">Recently Added to Plex</div>
+                <div class="panel-wrapper p-b-10 collapse in">
+                    <div id="owl-demo2" class="owl-carousel owl-theme">
+						`+buildPlexRecentItem(array.content)+`
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+	`;
+}
+function plexStream(){
+	ajaxloader(".content-wrap","in");
+	organizrAPI('POST','api/?v1/homepage/connect',{action:'getPlexStreams'}).success(function(data) {
+		var response = JSON.parse(data);
+		$('#homepageOrderplexnowplaying').html(buildPlexStream(response.data));
+	}).fail(function(xhr) {
+		console.error("Organizr Function: API Connection Failed");
+	});
+	ajaxloader();
+}
+function plexRecent(){
+	ajaxloader(".content-wrap","in");
+	organizrAPI('POST','api/?v1/homepage/connect',{action:'getPlexRecent'}).success(function(data) {
+		var response = JSON.parse(data);
+		$('#homepageOrderplexrecent').html(buildPlexRecent(response.data));
+	}).fail(function(xhr) {
+		console.error("Organizr Function: API Connection Failed");
+	});
+	ajaxloader();
+}
 //Generate API
 function generateCode() {
     var code = "";