organizr-functions.php 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983
  1. <?php
  2. function organizrSpecialSettings()
  3. {
  4. $refreshSearch = "Refresh";
  5. $tautulliSearch = "tautulli_token";
  6. $tautulli = array_filter($_COOKIE, function ($k) use ($tautulliSearch) {
  7. return stripos($k, $tautulliSearch) !== false;
  8. }, ARRAY_FILTER_USE_KEY);
  9. return array(
  10. 'homepage' => array(
  11. 'refresh' => array_filter($GLOBALS, function ($k) use ($refreshSearch) {
  12. return stripos($k, $refreshSearch) !== false;
  13. }, ARRAY_FILTER_USE_KEY),
  14. 'search' => array(
  15. 'enabled' => (qualifyRequest($GLOBALS['mediaSearchAuth']) && $GLOBALS['mediaSearch'] == true && $GLOBALS['plexToken']) ? true : false,
  16. 'type' => $GLOBALS['mediaSearchType'],
  17. ),
  18. 'ombi' => array(
  19. 'enabled' => (qualifyRequest($GLOBALS['homepageOmbiAuth']) && qualifyRequest($GLOBALS['homepageOmbiRequestAuth']) && $GLOBALS['homepageOmbiEnabled'] == true && $GLOBALS['ssoOmbi'] && isset($_COOKIE['Auth'])) ? true : false,
  20. 'authView' => (qualifyRequest($GLOBALS['homepageOmbiAuth'])) ? true : false,
  21. 'authRequest' => (qualifyRequest($GLOBALS['homepageOmbiRequestAuth'])) ? true : false,
  22. 'sso' => ($GLOBALS['ssoOmbi']) ? true : false,
  23. 'cookie' => (isset($_COOKIE['Auth'])) ? true : false,
  24. ),
  25. 'options' => array(
  26. 'alternateHomepageHeaders' => $GLOBALS['alternateHomepageHeaders'],
  27. )
  28. ),
  29. 'sso' => array(
  30. 'misc' => array(
  31. 'oAuthLogin' => isset($_COOKIE['oAuth']) ? true : false,
  32. 'rememberMe' => $GLOBALS['rememberMe'],
  33. 'rememberMeDays' => $GLOBALS['rememberMeDays']
  34. ),
  35. 'plex' => array(
  36. 'enabled' => ($GLOBALS['ssoPlex']) ? true : false,
  37. 'cookie' => isset($_COOKIE['mpt']) ? true : false,
  38. 'machineID' => (strlen($GLOBALS['plexID']) == 40) ? true : false,
  39. 'token' => ($GLOBALS['plexToken'] !== '') ? true : false,
  40. 'oAuthEnabled' => ($GLOBALS['plexoAuth']) ? true : false,
  41. 'backend' => ($GLOBALS['authBackend'] == 'plex') ? true : false,
  42. ),
  43. 'ombi' => array(
  44. 'enabled' => ($GLOBALS['ssoOmbi']) ? true : false,
  45. 'cookie' => isset($_COOKIE['Auth']) ? true : false,
  46. 'url' => ($GLOBALS['ombiURL'] !== '') ? $GLOBALS['ombiURL'] : false,
  47. 'api' => ($GLOBALS['ombiToken'] !== '') ? true : false,
  48. ),
  49. 'tautulli' => array(
  50. 'enabled' => ($GLOBALS['ssoTautulli']) ? true : false,
  51. 'cookie' => !empty($tautulli) ? true : false,
  52. 'url' => ($GLOBALS['tautulliURL'] !== '') ? $GLOBALS['tautulliURL'] : false,
  53. ),
  54. ),
  55. 'ping' => array(
  56. 'onlineSound' => $GLOBALS['pingOnlineSound'],
  57. 'offlineSound' => $GLOBALS['pingOfflineSound'],
  58. 'statusSounds' => $GLOBALS['statusSounds'],
  59. 'auth' => $GLOBALS['pingAuth'],
  60. 'authMessage' => $GLOBALS['pingAuthMessage'],
  61. 'authMs' => $GLOBALS['pingAuthMs'],
  62. 'ms' => $GLOBALS['pingMs'],
  63. 'adminRefresh' => $GLOBALS['adminPingRefresh'],
  64. 'everyoneRefresh' => $GLOBALS['otherPingRefresh'],
  65. ),
  66. 'notifications' => array(
  67. 'backbone' => $GLOBALS['notificationBackbone'],
  68. 'position' => $GLOBALS['notificationPosition']
  69. ),
  70. 'lockout' => array(
  71. 'enabled' => $GLOBALS['lockoutSystem'],
  72. 'timer' => $GLOBALS['lockoutTimeout'],
  73. 'minGroup' => $GLOBALS['lockoutMinAuth'],
  74. 'maxGroup' => $GLOBALS['lockoutMaxAuth']
  75. ),
  76. 'user' => array(
  77. 'agent' => isset($_SERVER ['HTTP_USER_AGENT']) ? $_SERVER ['HTTP_USER_AGENT'] : null,
  78. 'oAuthLogin' => isset($_COOKIE['oAuth']) ? true : false,
  79. 'local' => (isLocal()) ? true : false
  80. ),
  81. 'login' => array(
  82. 'rememberMe' => $GLOBALS['rememberMe'],
  83. 'rememberMeDays' => $GLOBALS['rememberMeDays'],
  84. ),
  85. 'misc' => array(
  86. 'installedPlugins' => $GLOBALS['installedPlugins'],
  87. 'installedThemes' => $GLOBALS['installedThemes'],
  88. 'return' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : false,
  89. 'authDebug' => $GLOBALS['authDebug'],
  90. 'minimalLoginScreen' => $GLOBALS['minimalLoginScreen'],
  91. 'unsortedTabs' => $GLOBALS['unsortedTabs'],
  92. 'authBackend' => $GLOBALS['authBackend'],
  93. 'newMessageSound' => (isset($GLOBALS['CHAT-newMessageSound-include'])) ? $GLOBALS['CHAT-newMessageSound-include'] : '',
  94. 'uuid' => $GLOBALS['uuid'],
  95. 'docker' => $GLOBALS['docker']
  96. )
  97. );
  98. }
  99. function wizardConfig($array)
  100. {
  101. foreach ($array['data'] as $items) {
  102. foreach ($items as $key => $value) {
  103. if ($key == 'name') {
  104. $newKey = $value;
  105. }
  106. if ($key == 'value') {
  107. $newValue = $value;
  108. }
  109. if (isset($newKey) && isset($newValue)) {
  110. $$newKey = $newValue;
  111. }
  112. }
  113. }
  114. $location = cleanDirectory($location);
  115. $dbName = dbExtension($dbName);
  116. $configVersion = $GLOBALS['installedVersion'];
  117. $configArray = array(
  118. 'dbName' => $dbName,
  119. 'dbLocation' => $location,
  120. 'license' => $license,
  121. 'organizrHash' => $hashKey,
  122. 'organizrAPI' => $api,
  123. 'registrationPassword' => $registrationPassword,
  124. );
  125. // Create Config
  126. $GLOBALS['dbLocation'] = $location;
  127. $GLOBALS['dbName'] = $dbName;
  128. if (createConfig($configArray)) {
  129. // Call DB Create
  130. if (createDB($location, $dbName)) {
  131. // Add in first user
  132. if (createFirstAdmin($location, $dbName, $username, $password, $email)) {
  133. if (createToken($username, $email, gravatar($email), 'Admin', 0, $hashKey, 1)) {
  134. return true;
  135. } else {
  136. return 'token';
  137. }
  138. } else {
  139. return 'admin';
  140. }
  141. } else {
  142. return 'db';
  143. }
  144. } else {
  145. return 'config';
  146. }
  147. return false;
  148. }
  149. function register($array)
  150. {
  151. // Grab username and password from login form
  152. foreach ($array['data'] as $items) {
  153. foreach ($items as $key => $value) {
  154. if ($key == 'name') {
  155. $newKey = $value;
  156. }
  157. if ($key == 'value') {
  158. $newValue = $value;
  159. }
  160. if (isset($newKey) && isset($newValue)) {
  161. $$newKey = $newValue;
  162. }
  163. }
  164. }
  165. if ($registrationPassword == $GLOBALS['registrationPassword']) {
  166. $defaults = defaultUserGroup();
  167. writeLog('success', 'Registration Function - Registration Password Verified', $username);
  168. if (createUser($username, $password, $defaults, $email)) {
  169. writeLog('success', 'Registration Function - A User has registered', $username);
  170. if (createToken($username, $email, gravatar($email), $defaults['group'], $defaults['group_id'], $GLOBALS['organizrHash'], $GLOBALS['rememberMeDays'])) {
  171. writeLoginLog($username, 'success');
  172. writeLog('success', 'Login Function - A User has logged in', $username);
  173. return true;
  174. }
  175. } else {
  176. writeLog('error', 'Registration Function - An error occured', $username);
  177. return 'username taken';
  178. }
  179. } else {
  180. writeLog('warning', 'Registration Function - Wrong Password', $username);
  181. return 'mismatch';
  182. }
  183. }
  184. function removeFile($array)
  185. {
  186. $filePath = $array['data']['path'];
  187. $fileName = $array['data']['name'];
  188. if (file_exists($filePath)) {
  189. if (unlink($filePath)) {
  190. writeLog('success', 'Log Management Function - Log: ' . $fileName . ' has been purged/deleted', 'SYSTEM');
  191. return true;
  192. } else {
  193. writeLog('error', 'Log Management Function - Log: ' . $fileName . ' - Error Occured', 'SYSTEM');
  194. return false;
  195. }
  196. } else {
  197. writeLog('error', 'Log Management Function - Log: ' . $fileName . ' does not exist', 'SYSTEM');
  198. return false;
  199. }
  200. }
  201. function recover($array)
  202. {
  203. $email = $array['data']['email'];
  204. $newPassword = randString(10);
  205. try {
  206. $connect = new Dibi\Connection([
  207. 'driver' => 'sqlite3',
  208. 'database' => $GLOBALS['dbLocation'] . $GLOBALS['dbName'],
  209. ]);
  210. $isUser = $connect->fetch('SELECT * FROM users WHERE email = ? COLLATE NOCASE', $email);
  211. if ($isUser) {
  212. $connect->query('
  213. UPDATE users SET', [
  214. 'password' => password_hash($newPassword, PASSWORD_BCRYPT)
  215. ], '
  216. WHERE email=? COLLATE NOCASE', $email);
  217. if ($GLOBALS['PHPMAILER-enabled']) {
  218. $emailTemplate = array(
  219. 'type' => 'reset',
  220. 'body' => $GLOBALS['PHPMAILER-emailTemplateResetPassword'],
  221. 'subject' => $GLOBALS['PHPMAILER-emailTemplateResetPasswordSubject'],
  222. 'user' => $isUser['username'],
  223. 'password' => $newPassword,
  224. 'inviteCode' => null,
  225. );
  226. $emailTemplate = phpmEmailTemplate($emailTemplate);
  227. $sendEmail = array(
  228. 'to' => $email,
  229. 'user' => $isUser['username'],
  230. 'subject' => $emailTemplate['subject'],
  231. 'body' => phpmBuildEmail($emailTemplate),
  232. );
  233. phpmSendEmail($sendEmail);
  234. }
  235. writeLog('success', 'User Management Function - User: ' . $isUser['username'] . '\'s password was reset', $isUser['username']);
  236. return true;
  237. } else {
  238. writeLog('error', 'User Management Function - Error - User: ' . $email . ' An error Occured', $email);
  239. return 'an error occured';
  240. }
  241. } catch (Dibi\Exception $e) {
  242. writeLog('error', 'User Management Function - Error - User: ' . $email . ' An error Occured', $email);
  243. return 'an error occured';
  244. }
  245. }
  246. function unlock($array)
  247. {
  248. if ($array['data']['password'] == '') {
  249. return 'Password Not Set';
  250. }
  251. try {
  252. $connect = new Dibi\Connection([
  253. 'driver' => 'sqlite3',
  254. 'database' => $GLOBALS['dbLocation'] . $GLOBALS['dbName'],
  255. ]);
  256. $result = $connect->fetch('SELECT * FROM users WHERE id = ?', $GLOBALS['organizrUser']['userID']);
  257. if (!password_verify($array['data']['password'], $result['password'])) {
  258. return 'Password Incorrect';
  259. }
  260. $connect->query('
  261. UPDATE users SET', [
  262. 'locked' => ''
  263. ], '
  264. WHERE id=?', $GLOBALS['organizrUser']['userID']);
  265. writeLog('success', 'User Lockout Function - User: ' . $GLOBALS['organizrUser']['username'] . '\'s account unlocked', $GLOBALS['organizrUser']['username']);
  266. return true;
  267. } catch (Dibi\Exception $e) {
  268. writeLog('error', 'User Management Function - Error - User: ' . $GLOBALS['organizrUser']['username'] . ' An error Occured', $GLOBALS['organizrUser']['username']);
  269. return 'an error occured';
  270. }
  271. }
  272. function lock()
  273. {
  274. if ($GLOBALS['organizrUser']['userID'] == '999') {
  275. return 'Not Allowed on Guest';
  276. }
  277. try {
  278. $connect = new Dibi\Connection([
  279. 'driver' => 'sqlite3',
  280. 'database' => $GLOBALS['dbLocation'] . $GLOBALS['dbName'],
  281. ]);
  282. $connect->query('
  283. UPDATE users SET', [
  284. 'locked' => '1'
  285. ], '
  286. WHERE id=?', $GLOBALS['organizrUser']['userID']);
  287. writeLog('success', 'User Lockout Function - User: ' . $GLOBALS['organizrUser']['username'] . '\'s account unlocked', $GLOBALS['organizrUser']['username']);
  288. return true;
  289. } catch (Dibi\Exception $e) {
  290. writeLog('error', 'User Management Function - Error - User: ' . $GLOBALS['organizrUser']['username'] . ' An error Occured', $GLOBALS['organizrUser']['username']);
  291. return 'an error occured';
  292. }
  293. }
  294. function editUser($array)
  295. {
  296. if ($array['data']['username'] == '' && $array['data']['username'] == '') {
  297. return 'Username/email not set';
  298. }
  299. try {
  300. $connect = new Dibi\Connection([
  301. 'driver' => 'sqlite3',
  302. 'database' => $GLOBALS['dbLocation'] . $GLOBALS['dbName'],
  303. ]);
  304. if (!usernameTakenExcept($array['data']['username'], $array['data']['email'], $GLOBALS['organizrUser']['userID'])) {
  305. $connect->query('
  306. UPDATE users SET', [
  307. 'username' => $array['data']['username'],
  308. 'email' => $array['data']['email'],
  309. 'image' => gravatar($array['data']['email']),
  310. ], '
  311. WHERE id=?', $GLOBALS['organizrUser']['userID']);
  312. if (!empty($array['data']['password'])) {
  313. $connect->query('
  314. UPDATE users SET', [
  315. 'password' => password_hash($array['data']['password'], PASSWORD_BCRYPT)
  316. ], '
  317. WHERE id=?', $GLOBALS['organizrUser']['userID']);
  318. }
  319. writeLog('success', 'User Management Function - User: ' . $array['data']['username'] . '\'s info was changed', $GLOBALS['organizrUser']['username']);
  320. return true;
  321. } else {
  322. return 'Username/Email Already Taken';
  323. }
  324. } catch (Dibi\Exception $e) {
  325. writeLog('error', 'User Management Function - Error - User: ' . $array['data']['username'] . ' An error Occured', $GLOBALS['organizrUser']['username']);
  326. return 'an error occured';
  327. }
  328. }
  329. function clearTautulliTokens()
  330. {
  331. foreach (array_keys($_COOKIE) as $k => $v) {
  332. if (strpos($v, 'tautulli') !== false) {
  333. coookie('delete', $v);
  334. }
  335. }
  336. }
  337. function logout()
  338. {
  339. coookie('delete', $GLOBALS['cookieName']);
  340. coookie('delete', 'mpt');
  341. coookie('delete', 'Auth');
  342. coookie('delete', 'oAuth');
  343. clearTautulliTokens();
  344. revokeToken(array('data' => array('token' => $GLOBALS['organizrUser']['token'])));
  345. $GLOBALS['organizrUser'] = false;
  346. return true;
  347. }
  348. function qualifyRequest($accessLevelNeeded)
  349. {
  350. if (getUserLevel() <= $accessLevelNeeded && getUserLevel() !== null) {
  351. return true;
  352. } else {
  353. return false;
  354. }
  355. }
  356. function getUserLevel()
  357. {
  358. // Grab token
  359. //$requesterToken = isset(getallheaders()['Token']) ? getallheaders()['Token'] : false;
  360. $requesterToken = isset(getallheaders()['Token']) ? getallheaders()['Token'] : (isset($_GET['apikey']) ? $_GET['apikey'] : false);
  361. // Check token or API key
  362. // If API key, return 0 for admin
  363. if (strlen($requesterToken) == 20 && $requesterToken == $GLOBALS['organizrAPI']) {
  364. //DO API CHECK
  365. return 0;
  366. } elseif (isset($GLOBALS['organizrUser'])) {
  367. return $GLOBALS['organizrUser']['groupID'];
  368. }
  369. // All else fails? return guest id
  370. return 999;
  371. }
  372. function organizrStatus()
  373. {
  374. $status = array();
  375. $dependenciesActive = array();
  376. $dependenciesInactive = array();
  377. $extensions = array("PDO_SQLITE", "PDO", "SQLITE3", "zip", "cURL", "openssl", "simplexml", "json", "session");
  378. $functions = array("hash", "fopen", "fsockopen", "fwrite", "fclose", "readfile");
  379. foreach ($extensions as $check) {
  380. if (extension_loaded($check)) {
  381. array_push($dependenciesActive, $check);
  382. } else {
  383. array_push($dependenciesInactive, $check);
  384. }
  385. }
  386. foreach ($functions as $check) {
  387. if (function_exists($check)) {
  388. array_push($dependenciesActive, $check);
  389. } else {
  390. array_push($dependenciesInactive, $check);
  391. }
  392. }
  393. if (!file_exists('config' . DIRECTORY_SEPARATOR . 'config.php')) {
  394. $status['status'] = "wizard";//wizard - ok for test
  395. }
  396. if (count($dependenciesInactive) > 0 || !is_writable(dirname(__DIR__, 2)) || !(version_compare(PHP_VERSION, $GLOBALS['minimumPHP']) >= 0)) {
  397. $status['status'] = "dependencies";
  398. }
  399. $status['status'] = (!empty($status['status'])) ? $status['status'] : $status['status'] = "ok";
  400. $status['writable'] = is_writable(dirname(__DIR__, 2)) ? 'yes' : 'no';
  401. $status['minVersion'] = (version_compare(PHP_VERSION, $GLOBALS['minimumPHP']) >= 0) ? 'yes' : 'no';
  402. $status['dependenciesActive'] = $dependenciesActive;
  403. $status['dependenciesInactive'] = $dependenciesInactive;
  404. $status['version'] = $GLOBALS['installedVersion'];
  405. $status['os'] = getOS();
  406. $status['php'] = phpversion();
  407. return $status;
  408. }
  409. function getSettingsMain()
  410. {
  411. return array(
  412. 'Github' => array(
  413. array(
  414. 'type' => 'select',
  415. 'name' => 'branch',
  416. 'label' => 'Branch',
  417. 'value' => $GLOBALS['branch'],
  418. 'options' => getBranches()
  419. ),
  420. array(
  421. 'type' => 'button',
  422. 'label' => 'Force Install Branch',
  423. 'class' => 'updateNow',
  424. 'icon' => 'fa fa-download',
  425. 'text' => 'Retrieve',
  426. 'attr' => ($GLOBALS['docker']) ? 'title="You can just restart your docker to update"' : '',
  427. 'help' => ($GLOBALS['docker']) ? 'Since you are using the Official Docker image, You can just restart your docker to update' : 'This will re-download all of the source files for Organizr'
  428. )
  429. ),
  430. 'API' => array(
  431. array(
  432. 'type' => 'password-alt',
  433. 'name' => 'organizrAPI',
  434. 'label' => 'Organizr API',
  435. 'value' => $GLOBALS['organizrAPI']
  436. ),
  437. array(
  438. 'type' => 'button',
  439. 'label' => 'Generate New API Key',
  440. 'class' => 'newAPIKey',
  441. 'icon' => 'fa fa-refresh',
  442. 'text' => 'Generate'
  443. )
  444. ),
  445. 'Authentication' => array(
  446. array(
  447. 'type' => 'select',
  448. 'name' => 'authType',
  449. 'id' => 'authSelect',
  450. 'label' => 'Authentication Type',
  451. 'value' => $GLOBALS['authType'],
  452. 'options' => getAuthTypes()
  453. ),
  454. array(
  455. 'type' => 'select',
  456. 'name' => 'authBackend',
  457. 'id' => 'authBackendSelect',
  458. 'label' => 'Authentication Backend',
  459. 'class' => 'backendAuth switchAuth',
  460. 'value' => $GLOBALS['authBackend'],
  461. 'options' => getAuthBackends()
  462. ),
  463. array(
  464. 'type' => 'password-alt',
  465. 'name' => 'plexToken',
  466. 'class' => 'plexAuth switchAuth',
  467. 'label' => 'Plex Token',
  468. 'value' => $GLOBALS['plexToken'],
  469. 'placeholder' => 'Use Get Token Button'
  470. ),
  471. array(
  472. 'type' => 'button',
  473. 'label' => 'Get Plex Token',
  474. 'class' => 'popup-with-form getPlexTokenAuth plexAuth switchAuth',
  475. 'icon' => 'fa fa-ticket',
  476. 'text' => 'Retrieve',
  477. 'href' => '#auth-plex-token-form',
  478. 'attr' => 'data-effect="mfp-3d-unfold"'
  479. ),
  480. array(
  481. 'type' => 'password-alt',
  482. 'name' => 'plexID',
  483. 'class' => 'plexAuth switchAuth',
  484. 'label' => 'Plex Machine',
  485. 'value' => $GLOBALS['plexID'],
  486. 'placeholder' => 'Use Get Plex Machine Button'
  487. ),
  488. array(
  489. 'type' => 'button',
  490. 'label' => 'Get Plex Machine',
  491. 'class' => 'popup-with-form getPlexMachineAuth plexAuth switchAuth',
  492. 'icon' => 'fa fa-id-badge',
  493. 'text' => 'Retrieve',
  494. 'href' => '#auth-plex-machine-form',
  495. 'attr' => 'data-effect="mfp-3d-unfold"'
  496. ),
  497. array(
  498. 'type' => 'input',
  499. 'name' => 'plexAdmin',
  500. 'label' => 'Admin Username',
  501. 'class' => 'plexAuth switchAuth',
  502. 'value' => $GLOBALS['plexAdmin'],
  503. 'placeholder' => 'Admin username for Plex'
  504. ),
  505. array(
  506. 'type' => 'switch',
  507. 'name' => 'plexoAuth',
  508. 'label' => 'Enable Plex oAuth',
  509. 'class' => 'plexAuth switchAuth',
  510. 'value' => $GLOBALS['plexoAuth']
  511. ),
  512. array(
  513. 'type' => 'switch',
  514. 'name' => 'plexStrictFriends',
  515. 'label' => 'Strict Plex Friends ',
  516. 'class' => 'plexAuth switchAuth',
  517. 'value' => $GLOBALS['plexStrictFriends'],
  518. 'help' => 'Enabling this will only allow Friends that have shares to the Machine ID entered above to login, Having this disabled will allow all Friends on your Friends list to login'
  519. ),
  520. array(
  521. 'type' => 'input',
  522. 'name' => 'authBackendHost',
  523. 'class' => 'ldapAuth ftpAuth switchAuth',
  524. 'label' => 'Host Address',
  525. 'value' => $GLOBALS['authBackendHost'],
  526. 'placeholder' => 'http{s) | ftp(s) | ldap(s)://hostname:port'
  527. ),
  528. array(
  529. 'type' => 'input',
  530. 'name' => 'authBaseDN',
  531. 'class' => 'ldapAuth switchAuth',
  532. 'label' => 'Host Base DN',
  533. 'value' => $GLOBALS['authBaseDN'],
  534. 'placeholder' => 'cn=%s,dc=sub,dc=domain,dc=com'
  535. ),
  536. array(
  537. 'type' => 'input',
  538. 'name' => 'embyURL',
  539. 'class' => 'embyAuth switchAuth',
  540. 'label' => 'Emby URL',
  541. 'value' => $GLOBALS['embyURL'],
  542. 'help' => 'Please make sure to use local IP address and port - You also may use local dns name too.',
  543. 'placeholder' => 'http(s)://hostname:port'
  544. ),
  545. array(
  546. 'type' => 'password-alt',
  547. 'name' => 'embyToken',
  548. 'class' => 'embyAuth switchAuth',
  549. 'label' => 'Emby Token',
  550. 'value' => $GLOBALS['embyToken'],
  551. 'placeholder' => ''
  552. ),
  553. /*array(
  554. 'type' => 'button',
  555. 'label' => 'Send Test',
  556. 'class' => 'phpmSendTestEmail',
  557. 'icon' => 'fa fa-paper-plane',
  558. 'text' => 'Send'
  559. )*/
  560. ),
  561. 'Security' => array(
  562. array(
  563. 'type' => 'number',
  564. 'name' => 'lockoutTimeout',
  565. 'label' => 'Inactivity Timer [Minutes]',
  566. 'value' => $GLOBALS['lockoutTimeout'],
  567. 'placeholder' => ''
  568. ),
  569. array(
  570. 'type' => 'select',
  571. 'name' => 'lockoutMinAuth',
  572. 'label' => 'Lockout Groups From',
  573. 'value' => $GLOBALS['lockoutMinAuth'],
  574. 'options' => groupSelect()
  575. ),
  576. array(
  577. 'type' => 'select',
  578. 'name' => 'lockoutMaxAuth',
  579. 'label' => 'Lockout Groups To',
  580. 'value' => $GLOBALS['lockoutMaxAuth'],
  581. 'options' => groupSelect()
  582. ),
  583. array(
  584. 'type' => 'switch',
  585. 'name' => 'lockoutSystem',
  586. 'label' => 'Inactivity Lock',
  587. 'value' => $GLOBALS['lockoutSystem']
  588. ),
  589. array(
  590. 'type' => 'switch',
  591. 'name' => 'authDebug',
  592. 'label' => 'Nginx Auth Debug',
  593. 'help' => 'Important! Do not keep this enabled for too long as this opens up Authentication while testing.',
  594. 'value' => $GLOBALS['authDebug'],
  595. 'class' => 'authDebug'
  596. )
  597. ),
  598. 'Login' => array(
  599. array(
  600. 'type' => 'password-alt',
  601. 'name' => 'registrationPassword',
  602. 'label' => 'Registration Password',
  603. 'help' => 'Sets the password for the Registration form on the login screen',
  604. 'value' => $GLOBALS['registrationPassword'],
  605. ),
  606. array(
  607. 'type' => 'switch',
  608. 'name' => 'hideRegistration',
  609. 'label' => 'Hide Registration',
  610. 'help' => 'Enable this to hide the Registration button on the login screen',
  611. 'value' => $GLOBALS['hideRegistration'],
  612. ),
  613. array(
  614. 'type' => 'number',
  615. 'name' => 'rememberMeDays',
  616. 'label' => 'Remember Me Length',
  617. 'help' => 'Number of days cookies and tokens will be valid for',
  618. 'value' => $GLOBALS['rememberMeDays'],
  619. 'placeholder' => '',
  620. 'attr' => 'min="1"'
  621. ),
  622. array(
  623. 'type' => 'switch',
  624. 'name' => 'rememberMe',
  625. 'label' => 'Remember Me',
  626. 'help' => 'Default status of Remember Me button on login screen',
  627. 'value' => $GLOBALS['rememberMe'],
  628. ),
  629. ),
  630. 'Ping' => array(
  631. array(
  632. 'type' => 'select',
  633. 'name' => 'pingAuth',
  634. 'label' => 'Minimum Authentication',
  635. 'value' => $GLOBALS['pingAuth'],
  636. 'options' => groupSelect()
  637. ),
  638. array(
  639. 'type' => 'select',
  640. 'name' => 'pingAuthMessage',
  641. 'label' => 'Minimum Authentication for Message and Sound',
  642. 'value' => $GLOBALS['pingAuthMessage'],
  643. 'options' => groupSelect()
  644. ),
  645. array(
  646. 'type' => 'select',
  647. 'name' => 'pingOnlineSound',
  648. 'label' => 'Online Sound',
  649. 'value' => $GLOBALS['pingOnlineSound'],
  650. 'options' => getSounds()
  651. ),
  652. array(
  653. 'type' => 'select',
  654. 'name' => 'pingOfflineSound',
  655. 'label' => 'Offline Sound',
  656. 'value' => $GLOBALS['pingOfflineSound'],
  657. 'options' => getSounds()
  658. ),
  659. array(
  660. 'type' => 'switch',
  661. 'name' => 'pingMs',
  662. 'label' => 'Show Ping Time',
  663. 'value' => $GLOBALS['pingMs']
  664. ),
  665. array(
  666. 'type' => 'switch',
  667. 'name' => 'statusSounds',
  668. 'label' => 'Enable Notify Sounds',
  669. 'value' => $GLOBALS['statusSounds'],
  670. 'help' => 'Will play a sound if the server goes down and will play sound if comes back up.',
  671. ),
  672. array(
  673. 'type' => 'select',
  674. 'name' => 'pingAuthMs',
  675. 'label' => 'Minimum Authentication for Time Display',
  676. 'value' => $GLOBALS['pingAuthMs'],
  677. 'options' => groupSelect()
  678. ),
  679. array(
  680. 'type' => 'select',
  681. 'name' => 'adminPingRefresh',
  682. 'label' => 'Admin Refresh Seconds',
  683. 'value' => $GLOBALS['adminPingRefresh'],
  684. 'options' => optionTime()
  685. ),
  686. array(
  687. 'type' => 'select',
  688. 'name' => 'otherPingRefresh',
  689. 'label' => 'Everyone Refresh Seconds',
  690. 'value' => $GLOBALS['otherPingRefresh'],
  691. 'options' => optionTime()
  692. ),
  693. )
  694. );
  695. }
  696. function getSSO()
  697. {
  698. return array(
  699. 'FYI' => array(
  700. array(
  701. 'type' => 'html',
  702. 'label' => 'Important Information',
  703. 'override' => 12,
  704. 'html' => '
  705. <div class="row">
  706. <div class="col-lg-12">
  707. <div class="panel panel-info">
  708. <div class="panel-heading">
  709. <span lang="en">Notice</span>
  710. </div>
  711. <div class="panel-wrapper collapse in" aria-expanded="true">
  712. <div class="panel-body">
  713. <span lang="en">This is not the same as database authentication - i.e. Plex Authentication | Emby Authentication | FTP Authentication<br/>Click Main on the sub-menu above.</span>
  714. </div>
  715. </div>
  716. </div>
  717. </div>
  718. </div>
  719. '
  720. )
  721. ),
  722. 'Plex' => array(
  723. array(
  724. 'type' => 'password-alt',
  725. 'name' => 'plexToken',
  726. 'label' => 'Plex Token',
  727. 'value' => $GLOBALS['plexToken'],
  728. 'placeholder' => 'Use Get Token Button'
  729. ),
  730. array(
  731. 'type' => 'button',
  732. 'label' => 'Get Plex Token',
  733. 'class' => 'popup-with-form getPlexTokenSSO',
  734. 'icon' => 'fa fa-ticket',
  735. 'text' => 'Retrieve',
  736. 'href' => '#sso-plex-token-form',
  737. 'attr' => 'data-effect="mfp-3d-unfold"'
  738. ),
  739. array(
  740. 'type' => 'password-alt',
  741. 'name' => 'plexID',
  742. 'label' => 'Plex Machine',
  743. 'value' => $GLOBALS['plexID'],
  744. 'placeholder' => 'Use Get Plex Machine Button'
  745. ),
  746. array(
  747. 'type' => 'button',
  748. 'label' => 'Get Plex Machine',
  749. 'class' => 'popup-with-form getPlexMachineSSO',
  750. 'icon' => 'fa fa-id-badge',
  751. 'text' => 'Retrieve',
  752. 'href' => '#sso-plex-machine-form',
  753. 'attr' => 'data-effect="mfp-3d-unfold"'
  754. ),
  755. array(
  756. 'type' => 'input',
  757. 'name' => 'plexAdmin',
  758. 'label' => 'Admin Username',
  759. 'value' => $GLOBALS['plexAdmin'],
  760. 'placeholder' => 'Admin username for Plex'
  761. ),
  762. array(
  763. 'type' => 'blank',
  764. 'label' => ''
  765. ),
  766. array(
  767. 'type' => 'html',
  768. 'label' => 'Plex Note',
  769. 'html' => '<span lang="en">Please make sure both Token and Machine are filled in</span>'
  770. ),
  771. array(
  772. 'type' => 'switch',
  773. 'name' => 'ssoPlex',
  774. 'label' => 'Enable',
  775. 'value' => $GLOBALS['ssoPlex']
  776. )
  777. ),
  778. 'Ombi' => array(
  779. array(
  780. 'type' => 'input',
  781. 'name' => 'ombiURL',
  782. 'label' => 'Ombi URL',
  783. 'value' => $GLOBALS['ombiURL'],
  784. 'help' => 'Please make sure to use local IP address and port - You also may use local dns name too.',
  785. 'placeholder' => 'http(s)://hostname:port'
  786. ),
  787. array(
  788. 'type' => 'password-alt',
  789. 'name' => 'ombiToken',
  790. 'label' => 'Token',
  791. 'value' => $GLOBALS['ombiToken']
  792. ),
  793. array(
  794. 'type' => 'switch',
  795. 'name' => 'ssoOmbi',
  796. 'label' => 'Enable',
  797. 'value' => $GLOBALS['ssoOmbi']
  798. )
  799. ),
  800. 'Tautulli' => array(
  801. array(
  802. 'type' => 'input',
  803. 'name' => 'tautulliURL',
  804. 'label' => 'Tautulli URL',
  805. 'value' => $GLOBALS['tautulliURL'],
  806. 'help' => 'Please make sure to use local IP address and port - You also may use local dns name too.',
  807. 'placeholder' => 'http(s)://hostname:port'
  808. ),
  809. array(
  810. 'type' => 'switch',
  811. 'name' => 'ssoTautulli',
  812. 'label' => 'Enable',
  813. 'value' => $GLOBALS['ssoTautulli']
  814. )
  815. )
  816. );
  817. }
  818. function loadAppearance()
  819. {
  820. $appearance = array();
  821. $appearance['logo'] = $GLOBALS['logo'];
  822. $appearance['title'] = $GLOBALS['title'];
  823. $appearance['useLogo'] = $GLOBALS['useLogo'];
  824. $appearance['headerColor'] = $GLOBALS['headerColor'];
  825. $appearance['headerTextColor'] = $GLOBALS['headerTextColor'];
  826. $appearance['sidebarColor'] = $GLOBALS['sidebarColor'];
  827. $appearance['headerTextColor'] = $GLOBALS['headerTextColor'];
  828. $appearance['sidebarTextColor'] = $GLOBALS['sidebarTextColor'];
  829. $appearance['accentColor'] = $GLOBALS['accentColor'];
  830. $appearance['accentTextColor'] = $GLOBALS['accentTextColor'];
  831. $appearance['buttonColor'] = $GLOBALS['buttonColor'];
  832. $appearance['buttonTextColor'] = $GLOBALS['buttonTextColor'];
  833. $appearance['buttonTextHoverColor'] = $GLOBALS['buttonTextHoverColor'];
  834. $appearance['buttonHoverColor'] = $GLOBALS['buttonHoverColor'];
  835. $appearance['loginWallpaper'] = $GLOBALS['loginWallpaper'];
  836. $appearance['customCss'] = $GLOBALS['customCss'];
  837. $appearance['customThemeCss'] = $GLOBALS['customThemeCss'];
  838. $appearance['customJava'] = $GLOBALS['customJava'];
  839. $appearance['customThemeJava'] = $GLOBALS['customThemeJava'];
  840. return $appearance;
  841. }
  842. function getCustomizeAppearance()
  843. {
  844. if (file_exists(dirname(__DIR__, 1) . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'config.php')) {
  845. return array(
  846. 'Top Bar' => array(
  847. array(
  848. 'type' => 'input',
  849. 'name' => 'logo',
  850. 'label' => 'Logo',
  851. 'value' => $GLOBALS['logo']
  852. ),
  853. array(
  854. 'type' => 'input',
  855. 'name' => 'title',
  856. 'label' => 'Title',
  857. 'value' => $GLOBALS['title']
  858. ),
  859. array(
  860. 'type' => 'switch',
  861. 'name' => 'useLogo',
  862. 'label' => 'Use Logo instead of Title',
  863. 'value' => $GLOBALS['useLogo']
  864. )
  865. ),
  866. 'Login Page' => array(
  867. array(
  868. 'type' => 'input',
  869. 'name' => 'loginWallpaper',
  870. 'label' => 'Login Wallpaper',
  871. 'value' => $GLOBALS['loginWallpaper']
  872. ),
  873. array(
  874. 'type' => 'switch',
  875. 'name' => 'minimalLoginScreen',
  876. 'label' => 'Minimal Login Screen',
  877. 'value' => $GLOBALS['minimalLoginScreen']
  878. )
  879. ),
  880. 'Options' => array(
  881. array(
  882. 'type' => 'switch',
  883. 'name' => 'alternateHomepageHeaders',
  884. 'label' => 'Alternate Homepage Titles',
  885. 'value' => $GLOBALS['alternateHomepageHeaders']
  886. ),
  887. array(
  888. 'type' => 'select',
  889. 'name' => 'unsortedTabs',
  890. 'label' => 'Unsorted Tab Placement',
  891. 'value' => $GLOBALS['unsortedTabs'],
  892. 'options' => array(
  893. array(
  894. 'name' => 'Top',
  895. 'value' => 'top'
  896. ),
  897. array(
  898. 'name' => 'Bottom',
  899. 'value' => 'bottom'
  900. )
  901. )
  902. )
  903. ),
  904. 'Colors & Themes' => array(
  905. array(
  906. 'type' => 'html',
  907. 'override' => 12,
  908. 'label' => 'Custom CSS [Can replace colors from above]',
  909. 'html' => '
  910. <div class="row">
  911. <div class="col-lg-12">
  912. <div class="panel panel-info">
  913. <div class="panel-heading">
  914. <span lang="en">Notice</span>
  915. </div>
  916. <div class="panel-wrapper collapse in" aria-expanded="true">
  917. <div class="panel-body">
  918. <span lang="en">The value of #987654 is just a placeholder, you can change to any value you like.</span>
  919. </div>
  920. </div>
  921. </div>
  922. </div>
  923. </div>
  924. ',
  925. ),
  926. array(
  927. 'type' => 'blank',
  928. 'label' => ''
  929. ),
  930. array(
  931. 'type' => 'input',
  932. 'name' => 'headerColor',
  933. 'label' => 'Nav Bar Color',
  934. 'value' => $GLOBALS['headerColor'],
  935. 'class' => 'pick-a-color',
  936. 'attr' => 'data-original="' . $GLOBALS['headerColor'] . '"'
  937. ),
  938. array(
  939. 'type' => 'input',
  940. 'name' => 'headerTextColor',
  941. 'label' => 'Nav Bar Text Color',
  942. 'value' => $GLOBALS['headerTextColor'],
  943. 'class' => 'pick-a-color',
  944. 'attr' => 'data-original="' . $GLOBALS['headerTextColor'] . '"'
  945. ),
  946. array(
  947. 'type' => 'input',
  948. 'name' => 'sidebarColor',
  949. 'label' => 'Side Bar Color',
  950. 'value' => $GLOBALS['sidebarColor'],
  951. 'class' => 'pick-a-color',
  952. 'attr' => 'data-original="' . $GLOBALS['sidebarColor'] . '"'
  953. ),
  954. array(
  955. 'type' => 'input',
  956. 'name' => 'sidebarTextColor',
  957. 'label' => 'Side Bar Text Color',
  958. 'value' => $GLOBALS['sidebarTextColor'],
  959. 'class' => 'pick-a-color',
  960. 'attr' => 'data-original="' . $GLOBALS['sidebarTextColor'] . '"'
  961. ),
  962. array(
  963. 'type' => 'input',
  964. 'name' => 'accentColor',
  965. 'label' => 'Accent Color',
  966. 'value' => $GLOBALS['accentColor'],
  967. 'class' => 'pick-a-color',
  968. 'attr' => 'data-original="' . $GLOBALS['accentColor'] . '"'
  969. ),
  970. array(
  971. 'type' => 'input',
  972. 'name' => 'accentTextColor',
  973. 'label' => 'Accent Text Color',
  974. 'value' => $GLOBALS['accentTextColor'],
  975. 'class' => 'pick-a-color',
  976. 'attr' => 'data-original="' . $GLOBALS['accentTextColor'] . '"'
  977. ),
  978. array(
  979. 'type' => 'input',
  980. 'name' => 'buttonColor',
  981. 'label' => 'Button Color',
  982. 'value' => $GLOBALS['buttonColor'],
  983. 'class' => 'pick-a-color',
  984. 'attr' => 'data-original="' . $GLOBALS['buttonColor'] . '"'
  985. ),
  986. array(
  987. 'type' => 'input',
  988. 'name' => 'buttonTextColor',
  989. 'label' => 'Button Text Color',
  990. 'value' => $GLOBALS['buttonTextColor'],
  991. 'class' => 'pick-a-color',
  992. 'attr' => 'data-original="' . $GLOBALS['buttonTextColor'] . '"'
  993. ),/*
  994. array(
  995. 'type' => 'input',
  996. 'name' => 'buttonHoverColor',
  997. 'label' => 'Button Hover Color',
  998. 'value' => $GLOBALS['buttonHoverColor'],
  999. 'class' => 'pick-a-color',
  1000. 'disabled' => true
  1001. ),
  1002. array(
  1003. 'type' => 'input',
  1004. 'name' => 'buttonTextHoverColor',
  1005. 'label' => 'Button Hover Text Color',
  1006. 'value' => $GLOBALS['buttonTextHoverColor'],
  1007. 'class' => 'pick-a-color',
  1008. 'disabled' => true
  1009. ),*/
  1010. array(
  1011. 'type' => 'select',
  1012. 'name' => 'theme',
  1013. 'label' => 'Theme',
  1014. 'class' => 'themeChanger',
  1015. 'value' => $GLOBALS['theme'],
  1016. 'options' => getThemes()
  1017. ),
  1018. array(
  1019. 'type' => 'select',
  1020. 'name' => 'style',
  1021. 'label' => 'Style',
  1022. 'class' => 'styleChanger',
  1023. 'value' => $GLOBALS['style'],
  1024. 'options' => array(
  1025. array(
  1026. 'name' => 'Light',
  1027. 'value' => 'light'
  1028. ),
  1029. array(
  1030. 'name' => 'Dark',
  1031. 'value' => 'dark'
  1032. ),
  1033. array(
  1034. 'name' => 'Horizontal',
  1035. 'value' => 'horizontal'
  1036. )
  1037. )
  1038. )
  1039. ),
  1040. 'Notifications' => array(
  1041. array(
  1042. 'type' => 'select',
  1043. 'name' => 'notificationBackbone',
  1044. 'class' => 'notifyChanger',
  1045. 'label' => 'Type',
  1046. 'value' => $GLOBALS['notificationBackbone'],
  1047. 'options' => optionNotificationTypes()
  1048. ),
  1049. array(
  1050. 'type' => 'select',
  1051. 'name' => 'notificationPosition',
  1052. 'class' => 'notifyPositionChanger',
  1053. 'label' => 'Position',
  1054. 'value' => $GLOBALS['notificationPosition'],
  1055. 'options' => optionNotificationPositions()
  1056. ),
  1057. array(
  1058. 'type' => 'html',
  1059. 'label' => 'Test Message',
  1060. 'html' => '
  1061. <div class="btn-group m-r-10 dropup">
  1062. <button aria-expanded="false" data-toggle="dropdown" class="btn btn-info btn-outline dropdown-toggle waves-effect waves-light" type="button">
  1063. <i class="fa fa-comment m-r-5"></i>
  1064. <span>Test </span>
  1065. </button>
  1066. <ul role="menu" class="dropdown-menu">
  1067. <li><a onclick="message(\'Test Message\',\'This is a success Message\',activeInfo.settings.notifications.position,\'#FFF\',\'success\',\'5000\');">Success</a></li>
  1068. <li><a onclick="message(\'Test Message\',\'This is a info Message\',activeInfo.settings.notifications.position,\'#FFF\',\'info\',\'5000\');">Info</a></li>
  1069. <li><a onclick="message(\'Test Message\',\'This is a warning Message\',activeInfo.settings.notifications.position,\'#FFF\',\'warning\',\'5000\');">Warning</a></li>
  1070. <li><a onclick="message(\'Test Message\',\'This is a error Message\',activeInfo.settings.notifications.position,\'#FFF\',\'error\',\'5000\');">Error</a></li>
  1071. </ul>
  1072. </div>
  1073. '
  1074. )
  1075. ),
  1076. 'FavIcon' => array(
  1077. array(
  1078. 'type' => 'textbox',
  1079. 'name' => 'favIcon',
  1080. 'class' => '',
  1081. 'label' => 'Fav Icon Code',
  1082. 'value' => $GLOBALS['favIcon'],
  1083. 'placeholder' => 'Paste Contents from https://realfavicongenerator.net/',
  1084. 'attr' => 'rows="10"',
  1085. ),
  1086. array(
  1087. 'type' => 'html',
  1088. 'label' => 'Instructions',
  1089. 'html' => '
  1090. <div class="panel panel-default">
  1091. <div class="panel-heading">
  1092. <a href="https://realfavicongenerator.net/" target="_blank"><span class="label label-info m-l-5">Visit FavIcon Site</span></a>
  1093. </div>
  1094. <div class="panel-wrapper collapse in">
  1095. <div class="panel-body">
  1096. <ul class="list-icons">
  1097. <li lang="en"><i class="fa fa-caret-right text-info"></i> Click [Select your Favicon picture]</li>
  1098. <li lang="en"><i class="fa fa-caret-right text-info"></i> Choose your image to use</li>
  1099. <li lang="en"><i class="fa fa-caret-right text-info"></i> Edit settings to your liking</li>
  1100. <li lang="en"><i class="fa fa-caret-right text-info"></i> At bottom of page on [Favicon Generator Options] under [Path] choose [I cannot or I do not want to place favicon files at the root of my web site.]</li>
  1101. <li lang="en"><i class="fa fa-caret-right text-info"></i> Enter this path <code>plugins/images/faviconCustom</code></li>
  1102. <li lang="en"><i class="fa fa-caret-right text-info"></i> Click [Generate your Favicons and HTML code]</li>
  1103. <li lang="en"><i class="fa fa-caret-right text-info"></i> Download and unzip file and place in <code>plugins/images/faviconCustom</code></li>
  1104. <li lang="en"><i class="fa fa-caret-right text-info"></i> Copy code and paste inside left box</li>
  1105. </ul>
  1106. </div>
  1107. </div>
  1108. </div>
  1109. '
  1110. ),
  1111. ),
  1112. 'Custom CSS' => array(
  1113. array(
  1114. 'type' => 'html',
  1115. 'override' => 12,
  1116. 'label' => 'Custom CSS [Can replace colors from above]',
  1117. 'html' => '<button type="button" class="hidden saveCss btn btn-info btn-circle pull-right m-r-5 m-l-10"><i class="fa fa-save"></i> </button><div id="customCSSEditor" style="height:300px">' . $GLOBALS['customCss'] . '</div>'
  1118. ),
  1119. array(
  1120. 'type' => 'textbox',
  1121. 'name' => 'customCss',
  1122. 'class' => 'hidden cssTextarea',
  1123. 'label' => '',
  1124. 'value' => $GLOBALS['customCss'],
  1125. 'placeholder' => 'No <style> tags needed',
  1126. 'attr' => 'rows="10"',
  1127. ),
  1128. ),
  1129. 'Theme CSS' => array(
  1130. array(
  1131. 'type' => 'html',
  1132. 'override' => 12,
  1133. 'label' => 'Theme CSS [Can replace colors from above]',
  1134. 'html' => '<button type="button" class="hidden saveCssTheme btn btn-info btn-circle pull-right m-r-5 m-l-10"><i class="fa fa-save"></i> </button><div id="customThemeCSSEditor" style="height:300px">' . $GLOBALS['customThemeCss'] . '</div>'
  1135. ),
  1136. array(
  1137. 'type' => 'textbox',
  1138. 'name' => 'customThemeCss',
  1139. 'class' => 'hidden cssThemeTextarea',
  1140. 'label' => '',
  1141. 'value' => $GLOBALS['customThemeCss'],
  1142. 'placeholder' => 'No <style> tags needed',
  1143. 'attr' => 'rows="10"',
  1144. ),
  1145. ),
  1146. 'Custom Javascript' => array(
  1147. array(
  1148. 'type' => 'html',
  1149. 'override' => 12,
  1150. 'label' => 'Custom Javascript',
  1151. 'html' => '<button type="button" class="hidden saveJava btn btn-info btn-circle pull-right m-r-5 m-l-10"><i class="fa fa-save"></i> </button><div id="customJavaEditor" style="height:300px">' . $GLOBALS['customJava'] . '</div>'
  1152. ),
  1153. array(
  1154. 'type' => 'textbox',
  1155. 'name' => 'customJava',
  1156. 'class' => 'hidden javaTextarea',
  1157. 'label' => '',
  1158. 'value' => $GLOBALS['customJava'],
  1159. 'placeholder' => 'No <script> tags needed',
  1160. 'attr' => 'rows="10"',
  1161. ),
  1162. ),
  1163. 'Theme Javascript' => array(
  1164. array(
  1165. 'type' => 'html',
  1166. 'override' => 12,
  1167. 'label' => 'Theme Javascript',
  1168. 'html' => '<button type="button" class="hidden saveJavaTheme btn btn-info btn-circle pull-right m-r-5 m-l-10"><i class="fa fa-save"></i> </button><div id="customThemeJavaEditor" style="height:300px">' . $GLOBALS['customThemeJava'] . '</div>'
  1169. ),
  1170. array(
  1171. 'type' => 'textbox',
  1172. 'name' => 'customThemeJava',
  1173. 'class' => 'hidden javaThemeTextarea',
  1174. 'label' => '',
  1175. 'value' => $GLOBALS['customThemeJava'],
  1176. 'placeholder' => 'No <script> tags needed',
  1177. 'attr' => 'rows="10"',
  1178. ),
  1179. ),
  1180. );
  1181. }
  1182. }
  1183. function editAppearance($array)
  1184. {
  1185. switch ($array['data']['value']) {
  1186. case 'true':
  1187. $array['data']['value'] = (bool)true;
  1188. break;
  1189. case 'false':
  1190. $array['data']['value'] = (bool)false;
  1191. break;
  1192. default:
  1193. $array['data']['value'] = $array['data']['value'];
  1194. }
  1195. //return gettype($array['data']['value']).' - '.$array['data']['value'];
  1196. switch ($array['data']['action']) {
  1197. case 'editCustomizeAppearance':
  1198. $newItem = array(
  1199. $array['data']['name'] => $array['data']['value']
  1200. );
  1201. return (updateConfig($newItem)) ? true : false;
  1202. break;
  1203. default:
  1204. # code...
  1205. break;
  1206. }
  1207. }
  1208. function updateConfigMultiple($array)
  1209. {
  1210. return (updateConfig($array['data']['payload'])) ? true : false;
  1211. }
  1212. function updateConfigMultipleForm($array)
  1213. {
  1214. $newItem = array();
  1215. foreach ($array['data']['payload'] as $k => $v) {
  1216. switch ($v['value']) {
  1217. case 'true':
  1218. $v['value'] = (bool)true;
  1219. break;
  1220. case 'false':
  1221. $v['value'] = (bool)false;
  1222. break;
  1223. default:
  1224. $v['value'] = $v['value'];
  1225. }
  1226. // Hash
  1227. if ($v['type'] == 'password') {
  1228. if (isEncrypted($v['value']) || $v['value'] == '') {
  1229. $v['value'] = $v['value'];
  1230. } else {
  1231. $v['value'] = encrypt($v['value']);
  1232. }
  1233. }
  1234. $newItem[$v['name']] = $v['value'];
  1235. }
  1236. //return $newItem;
  1237. return (updateConfig($newItem)) ? true : false;
  1238. }
  1239. function updateConfigItem($array)
  1240. {
  1241. switch ($array['data']['value']) {
  1242. case 'true':
  1243. $array['data']['value'] = (bool)true;
  1244. break;
  1245. case 'false':
  1246. $array['data']['value'] = (bool)false;
  1247. break;
  1248. default:
  1249. $array['data']['value'] = $array['data']['value'];
  1250. }
  1251. // Hash
  1252. if ($array['data']['type'] == 'password') {
  1253. $array['data']['value'] = encrypt($array['data']['value']);
  1254. }
  1255. $newItem = array(
  1256. $array['data']['name'] => $array['data']['value']
  1257. );
  1258. return (updateConfig($newItem)) ? true : false;
  1259. }
  1260. function getPlugins()
  1261. {
  1262. if (file_exists(dirname(__DIR__, 1) . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'config.php')) {
  1263. $pluginList = [];
  1264. foreach ($GLOBALS['plugins'] as $plugin) {
  1265. foreach ($plugin as $key => $value) {
  1266. if (strpos($value['license'], $GLOBALS['license']) !== false) {
  1267. $plugin[$key]['enabled'] = $GLOBALS[$value['configPrefix'] . '-enabled'];
  1268. $pluginList[$key] = $plugin[$key];
  1269. }
  1270. }
  1271. }
  1272. return $pluginList;
  1273. }
  1274. return false;
  1275. }
  1276. function editPlugins($array)
  1277. {
  1278. switch ($array['data']['action']) {
  1279. case 'enable':
  1280. $newItem = array(
  1281. $array['data']['configName'] => true
  1282. );
  1283. writeLog('success', 'Plugin Function - Enabled Plugin [' . $_POST['data']['name'] . ']', $GLOBALS['organizrUser']['username']);
  1284. return (updateConfig($newItem)) ? true : false;
  1285. break;
  1286. case 'disable':
  1287. $newItem = array(
  1288. $array['data']['configName'] => false
  1289. );
  1290. writeLog('success', 'Plugin Function - Disabled Plugin [' . $_POST['data']['name'] . ']', $GLOBALS['organizrUser']['username']);
  1291. return (updateConfig($newItem)) ? true : false;
  1292. break;
  1293. default:
  1294. # code...
  1295. break;
  1296. }
  1297. }
  1298. function auth()
  1299. {
  1300. $debug = $GLOBALS['authDebug']; // CAREFUL WHEN SETTING TO TRUE AS THIS OPENS AUTH UP
  1301. $ban = isset($_GET['ban']) ? strtoupper($_GET['ban']) : "";
  1302. $whitelist = isset($_GET['whitelist']) ? $_GET['whitelist'] : false;
  1303. $blacklist = isset($_GET['blacklist']) ? $_GET['blacklist'] : false;
  1304. $group = isset($_GET['group']) ? (int)$_GET['group'] : (int)0;
  1305. $currentIP = userIP();
  1306. $unlocked = ($GLOBALS['organizrUser']['locked'] == '1') ? false : true;
  1307. if (isset($GLOBALS['organizrUser'])) {
  1308. $currentUser = $GLOBALS['organizrUser']['username'];
  1309. $currentGroup = $GLOBALS['organizrUser']['groupID'];
  1310. } else {
  1311. $currentUser = 'Guest';
  1312. $currentGroup = getUserLevel();
  1313. }
  1314. $userInfo = "User: $currentUser | Group: $currentGroup | IP: $currentIP | Requesting Access to Group $group | Result: ";
  1315. if ($whitelist) {
  1316. if (in_array($currentIP, arrayIP($whitelist))) {
  1317. !$debug ? exit(http_response_code(200)) : die("$userInfo Whitelist Authorized");
  1318. }
  1319. }
  1320. if ($blacklist) {
  1321. if (in_array($currentIP, arrayIP($blacklist))) {
  1322. !$debug ? exit(http_response_code(401)) : die("$userInfo Blacklisted");
  1323. }
  1324. }
  1325. if ($group !== null) {
  1326. if (qualifyRequest($group) && $unlocked) {
  1327. !$debug ? exit(http_response_code(200)) : die("$userInfo Authorized");
  1328. } else {
  1329. !$debug ? exit(http_response_code(401)) : die("$userInfo Not Authorized");
  1330. }
  1331. } else {
  1332. !$debug ? exit(http_response_code(401)) : die("Not Authorized Due To No Parameters Set");
  1333. }
  1334. }
  1335. function logoOrText()
  1336. {
  1337. if ($GLOBALS['useLogo'] == false) {
  1338. return '<h1>' . $GLOBALS['title'] . '</h1>';
  1339. } else {
  1340. return '<img class="loginLogo" src="' . $GLOBALS['logo'] . '" alt="Home" />';
  1341. }
  1342. }
  1343. function showLogin()
  1344. {
  1345. if ($GLOBALS['hideRegistration'] == false) {
  1346. return '<p><span lang="en">Don\'t have an account?</span><a href="#" class="text-primary m-l-5 to-register"><b lang="en">Sign Up</b></a></p>';
  1347. }
  1348. }
  1349. function showoAuth()
  1350. {
  1351. $buttons = '';
  1352. if ($GLOBALS['plexoAuth']) {
  1353. $buttons .= '<a href="javascript:void(0)" onclick="oAuthStart(\'plex\')" class="btn btn-lg btn-block text-uppercase waves-effect waves-light bg-plex text-muted" data-toggle="tooltip" title="" data-original-title="Login with Plex"> <span>Login with Plex Account</span><i aria-hidden="true" class="mdi mdi-plex m-l-5"></i> </a>';
  1354. }
  1355. return ($buttons) ? '
  1356. <div class="row">
  1357. <div class="col-xs-12 col-sm-12 col-md-12 m-t-10 text-center">
  1358. <div class="social">' . $buttons . '</div>
  1359. </div>
  1360. </div>
  1361. ' : '';
  1362. }
  1363. function getImages()
  1364. {
  1365. $dirname = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'tabs' . DIRECTORY_SEPARATOR;
  1366. $path = 'plugins/images/tabs/';
  1367. $images = scandir($dirname);
  1368. $ignore = array(".", "..", "._.DS_Store", ".DS_Store", ".pydio_id");
  1369. $allIcons = array();
  1370. foreach ($images as $image) {
  1371. if (!in_array($image, $ignore)) {
  1372. $allIcons[] = $path . $image;
  1373. }
  1374. }
  1375. return $allIcons;
  1376. }
  1377. function imageSelect($form)
  1378. {
  1379. $i = 1;
  1380. $images = getImages();
  1381. $return = '<select class="form-control tabIconImageList" id="' . $form . '-chooseImage" name="chooseImage"><option lang="en">Select or type Icon</option>';
  1382. foreach ($images as $image) {
  1383. $i++;
  1384. $return .= '<option value="' . $image . '">' . basename($image) . '</option>';
  1385. }
  1386. return $return . '</select>';
  1387. }
  1388. function editImages()
  1389. {
  1390. $array = array();
  1391. $postCheck = array_filter($_POST);
  1392. $filesCheck = array_filter($_FILES);
  1393. if (!empty($postCheck)) {
  1394. if ($_POST['data']['action'] == 'deleteImage') {
  1395. if (file_exists(dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . $_POST['data']['imagePath'])) {
  1396. writeLog('success', 'Image Manager Function - Deleted Image [' . $_POST['data']['imageName'] . ']', $GLOBALS['organizrUser']['username']);
  1397. return (unlink(dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . $_POST['data']['imagePath'])) ? true : false;
  1398. }
  1399. }
  1400. }
  1401. if (!empty($filesCheck)) {
  1402. ini_set('upload_max_filesize', '10M');
  1403. ini_set('post_max_size', '10M');
  1404. $tempFile = $_FILES['file']['tmp_name'];
  1405. $targetPath = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'tabs' . DIRECTORY_SEPARATOR;
  1406. $targetFile = $targetPath . $_FILES['file']['name'];
  1407. return (move_uploaded_file($tempFile, $targetFile)) ? true : false;
  1408. }
  1409. return false;
  1410. }
  1411. function getThemes()
  1412. {
  1413. $themes = array();
  1414. foreach (glob(dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'css' . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . "*.css") as $filename) {
  1415. $themes[] = array(
  1416. 'name' => preg_replace('/\\.[^.\\s]{3,4}$/', '', basename($filename)),
  1417. 'value' => preg_replace('/\\.[^.\\s]{3,4}$/', '', basename($filename))
  1418. );
  1419. }
  1420. return $themes;
  1421. }
  1422. function getSounds()
  1423. {
  1424. $sounds = array();
  1425. foreach (glob(dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'sounds' . DIRECTORY_SEPARATOR . 'default' . DIRECTORY_SEPARATOR . "*.mp3") as $filename) {
  1426. $sounds[] = array(
  1427. 'name' => preg_replace('/\\.[^.\\s]{3,4}$/', '', basename($filename)),
  1428. 'value' => preg_replace('/\\.[^.\\s]{3,4}$/', '', 'plugins/sounds/default/' . basename($filename) . '.mp3')
  1429. );
  1430. }
  1431. foreach (glob(dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'sounds' . DIRECTORY_SEPARATOR . 'custom' . DIRECTORY_SEPARATOR . "*.mp3") as $filename) {
  1432. $sounds[] = array(
  1433. 'name' => preg_replace('/\\.[^.\\s]{3,4}$/', '', basename($filename)),
  1434. 'value' => preg_replace('/\\.[^.\\s]{3,4}$/', '', 'plugins/sounds/custom/' . basename($filename) . '.mp3')
  1435. );
  1436. }
  1437. return $sounds;
  1438. }
  1439. function getBranches()
  1440. {
  1441. return array(
  1442. array(
  1443. 'name' => 'Develop',
  1444. 'value' => 'v2-develop'
  1445. ),
  1446. array(
  1447. 'name' => 'Master',
  1448. 'value' => 'v2-master'
  1449. )
  1450. );
  1451. }
  1452. function getAuthTypes()
  1453. {
  1454. return array(
  1455. array(
  1456. 'name' => 'Organizr DB',
  1457. 'value' => 'internal'
  1458. ),
  1459. array(
  1460. 'name' => 'Organizr DB + Backend',
  1461. 'value' => 'both'
  1462. ),
  1463. array(
  1464. 'name' => 'Backend Only',
  1465. 'value' => 'external'
  1466. )
  1467. );
  1468. }
  1469. function getAuthBackends()
  1470. {
  1471. $backendOptions = array();
  1472. $backendOptions[] = array(
  1473. 'name' => 'Choose Backend',
  1474. 'value' => false,
  1475. 'disabled' => true
  1476. );
  1477. foreach (array_filter(get_defined_functions()['user'], function ($v) {
  1478. return strpos($v, 'plugin_auth_') === 0;
  1479. }) as $value) {
  1480. $name = str_replace('plugin_auth_', '', $value);
  1481. if (strpos($name, 'disabled') === false) {
  1482. $backendOptions[] = array(
  1483. 'name' => ucwords(str_replace('_', ' ', $name)),
  1484. 'value' => $name
  1485. );
  1486. } else {
  1487. $backendOptions[] = array(
  1488. 'name' => $value(),
  1489. 'value' => 'none',
  1490. 'disabled' => true,
  1491. );
  1492. }
  1493. }
  1494. ksort($backendOptions);
  1495. return $backendOptions;
  1496. }
  1497. function wizardPath($array)
  1498. {
  1499. $path = $array['data']['path'];
  1500. if (file_exists($path)) {
  1501. if (is_writable($path)) {
  1502. return true;
  1503. }
  1504. } else {
  1505. if (is_writable(dirname($path, 1))) {
  1506. if (mkdir($path, 0760, true)) {
  1507. return true;
  1508. }
  1509. }
  1510. }
  1511. return 'permissions';
  1512. }
  1513. function groupSelect()
  1514. {
  1515. $groups = allGroups();
  1516. $select = array();
  1517. foreach ($groups as $key => $value) {
  1518. $select[] = array(
  1519. 'name' => $value['group'],
  1520. 'value' => $value['group_id']
  1521. );
  1522. }
  1523. return $select;
  1524. }
  1525. function getImage()
  1526. {
  1527. $refresh = false;
  1528. $cacheDirectory = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR;
  1529. if (!file_exists($cacheDirectory)) {
  1530. mkdir($cacheDirectory, 0777, true);
  1531. }
  1532. @$image_url = $_GET['img'];
  1533. @$key = $_GET['key'];
  1534. @$image_height = $_GET['height'];
  1535. @$image_width = $_GET['width'];
  1536. @$source = $_GET['source'];
  1537. @$itemType = $_GET['type'];
  1538. if (strpos($key, '$') !== false) {
  1539. $key = explode('$', $key)[0];
  1540. $refresh = true;
  1541. }
  1542. switch ($source) {
  1543. case 'plex':
  1544. $plexAddress = qualifyURL($GLOBALS['plexURL']);
  1545. $image_src = $plexAddress . '/photo/:/transcode?height=' . $image_height . '&width=' . $image_width . '&upscale=1&url=' . $image_url . '&X-Plex-Token=' . $GLOBALS['plexToken'];
  1546. break;
  1547. case 'emby':
  1548. $embyAddress = qualifyURL($GLOBALS['embyURL']);
  1549. $imgParams = array();
  1550. if (isset($_GET['height'])) {
  1551. $imgParams['height'] = 'maxHeight=' . $_GET['height'];
  1552. }
  1553. if (isset($_GET['width'])) {
  1554. $imgParams['width'] = 'maxWidth=' . $_GET['width'];
  1555. }
  1556. $image_src = $embyAddress . '/Items/' . $image_url . '/Images/' . $itemType . '?' . implode('&', $imgParams);
  1557. break;
  1558. default:
  1559. # code...
  1560. break;
  1561. }
  1562. if (isset($image_url) && isset($image_height) && isset($image_width) && isset($image_src)) {
  1563. $cachefile = $cacheDirectory . $key . '.jpg';
  1564. $cachetime = 604800;
  1565. // Serve from the cache if it is younger than $cachetime
  1566. if (file_exists($cachefile) && time() - $cachetime < filemtime($cachefile) && $refresh == false) {
  1567. header("Content-type: image/jpeg");
  1568. //@readfile($cachefile);
  1569. echo @curl('get', $cachefile)['content'];
  1570. exit;
  1571. }
  1572. ob_start(); // Start the output buffer
  1573. header('Content-type: image/jpeg');
  1574. //@readfile($image_src);
  1575. echo @curl('get', $image_src)['content'];
  1576. // Cache the output to a file
  1577. $fp = fopen($cachefile, 'wb');
  1578. fwrite($fp, ob_get_contents());
  1579. fclose($fp);
  1580. ob_end_flush(); // Send the output to the browser
  1581. die();
  1582. } else {
  1583. die("Invalid Request");
  1584. }
  1585. }
  1586. function cacheImage($url, $name)
  1587. {
  1588. $cacheDirectory = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR;
  1589. if (!file_exists($cacheDirectory)) {
  1590. mkdir($cacheDirectory, 0777, true);
  1591. }
  1592. $cachefile = $cacheDirectory . $name . '.jpg';
  1593. @copy($url, $cachefile);
  1594. }
  1595. function downloader($array)
  1596. {
  1597. switch ($array['data']['source']) {
  1598. case 'sabnzbd':
  1599. switch ($array['data']['action']) {
  1600. case 'resume':
  1601. case 'pause':
  1602. sabnzbdAction($array['data']['action'], $array['data']['target']);
  1603. break;
  1604. default:
  1605. # code...
  1606. break;
  1607. }
  1608. break;
  1609. case 'nzbget':
  1610. break;
  1611. default:
  1612. # code...
  1613. break;
  1614. }
  1615. }
  1616. function sabnzbdAction($action = null, $target = null)
  1617. {
  1618. if ($GLOBALS['homepageSabnzbdEnabled'] && !empty($GLOBALS['sabnzbdURL']) && !empty($GLOBALS['sabnzbdToken']) && qualifyRequest($GLOBALS['homepageSabnzbdAuth'])) {
  1619. $url = qualifyURL($GLOBALS['sabnzbdURL']);
  1620. switch ($action) {
  1621. case 'pause':
  1622. $id = ($target !== '' && $target !== 'main' && isset($target)) ? 'mode=queue&name=pause&value=' . $target . '&' : 'mode=pause';
  1623. $url = $url . '/api?' . $id . '&output=json&apikey=' . $GLOBALS['sabnzbdToken'];
  1624. break;
  1625. case 'resume':
  1626. $id = ($target !== '' && $target !== 'main' && isset($target)) ? 'mode=queue&name=resume&value=' . $target . '&' : 'mode=resume';
  1627. $url = $url . '/api?' . $id . '&output=json&apikey=' . $GLOBALS['sabnzbdToken'];
  1628. break;
  1629. default:
  1630. # code...
  1631. break;
  1632. }
  1633. try {
  1634. $options = (localURL($url)) ? array('verify' => false) : array();
  1635. $response = Requests::get($url, array(), $options);
  1636. if ($response->success) {
  1637. $api['content'] = json_decode($response->body, true);
  1638. }
  1639. } catch (Requests_Exception $e) {
  1640. writeLog('error', 'SabNZBd Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
  1641. };
  1642. $api['content'] = isset($api['content']) ? $api['content'] : false;
  1643. return $api;
  1644. }
  1645. }
  1646. // Deluge API isn't working ATM - will get with dev.
  1647. function delugeAction($action = null, $target = null)
  1648. {
  1649. if ($GLOBALS['homepageDelugeEnabled'] && !empty($GLOBALS['delugeURL']) && !empty($GLOBALS['delugePassword']) && qualifyRequest($GLOBALS['homepageDelugeAuth'])) {
  1650. $url = qualifyURL($GLOBALS['delugeURL']);
  1651. try {
  1652. $deluge = new deluge($GLOBALS['delugeURL'], decrypt($GLOBALS['delugePassword']));
  1653. switch ($action) {
  1654. case 'pause':
  1655. $torrents = $deluge->pauseTorrent($target);
  1656. break;
  1657. case 'pauseAll':
  1658. $torrents = $deluge->pauseAllTorrents();
  1659. break;
  1660. case 'resume':
  1661. $torrents = $deluge->resumeTorrent($target);
  1662. break;
  1663. case 'resumeAll':
  1664. $torrents = $deluge->resumeAllTorrents();
  1665. break;
  1666. default:
  1667. # code...
  1668. break;
  1669. }
  1670. $api['content'] = $torrents;
  1671. } catch (Excecption $e) {
  1672. writeLog('error', 'Deluge Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
  1673. }
  1674. $api['content'] = isset($api['content']) ? $api['content'] : false;
  1675. return $api;
  1676. }
  1677. return false;
  1678. }
  1679. function getOrgUsers()
  1680. {
  1681. $result = allUsers();
  1682. if (is_array($result) || is_object($result)) {
  1683. foreach ($result['users'] as $k => $v) {
  1684. $return[$v['username']] = $v['email'];
  1685. }
  1686. return $return;
  1687. }
  1688. }
  1689. function convertPlexName($user, $type)
  1690. {
  1691. $array = userList('plex');
  1692. switch ($type) {
  1693. case "username":
  1694. case "u":
  1695. $plexUser = array_search($user, $array['users']);
  1696. break;
  1697. case "id":
  1698. if (array_key_exists(strtolower($user), $array['users'])) {
  1699. $plexUser = $array['users'][strtolower($user)];
  1700. }
  1701. break;
  1702. default:
  1703. $plexUser = false;
  1704. }
  1705. return (!empty($plexUser) ? $plexUser : null);
  1706. }
  1707. function userList($type = null)
  1708. {
  1709. switch ($type) {
  1710. case 'plex':
  1711. if (!empty($GLOBALS['plexToken']) && !empty($GLOBALS['plexID'])) {
  1712. $url = 'https://plex.tv/api/servers/' . $GLOBALS['plexID'] . '/shared_servers';
  1713. try {
  1714. $headers = array(
  1715. "Accept" => "application/json",
  1716. "X-Plex-Token" => $GLOBALS['plexToken']
  1717. );
  1718. $response = Requests::get($url, $headers, array());
  1719. libxml_use_internal_errors(true);
  1720. if ($response->success) {
  1721. $libraryList = array();
  1722. $plex = simplexml_load_string($response->body);
  1723. foreach ($plex->SharedServer as $child) {
  1724. if (!empty($child['username'])) {
  1725. $username = (string)strtolower($child['username']);
  1726. $email = (string)strtolower($child['email']);
  1727. $libraryList['users'][$username] = (string)$child['id'];
  1728. $libraryList['emails'][$email] = (string)$child['id'];
  1729. $libraryList['both'][$username] = $email;
  1730. }
  1731. }
  1732. $libraryList = array_change_key_case($libraryList, CASE_LOWER);
  1733. return $libraryList;
  1734. }
  1735. } catch (Requests_Exception $e) {
  1736. writeLog('error', 'Plex Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
  1737. };
  1738. }
  1739. break;
  1740. default:
  1741. # code...
  1742. break;
  1743. }
  1744. return false;
  1745. }
  1746. function libraryList($type = null)
  1747. {
  1748. switch ($type) {
  1749. case 'plex':
  1750. if (!empty($GLOBALS['plexToken']) && !empty($GLOBALS['plexID'])) {
  1751. $url = 'https://plex.tv/api/servers/' . $GLOBALS['plexID'];
  1752. try {
  1753. $headers = array(
  1754. "Accept" => "application/json",
  1755. "X-Plex-Token" => $GLOBALS['plexToken']
  1756. );
  1757. $response = Requests::get($url, $headers, array());
  1758. libxml_use_internal_errors(true);
  1759. if ($response->success) {
  1760. $libraryList = array();
  1761. $plex = simplexml_load_string($response->body);
  1762. foreach ($plex->Server->Section as $child) {
  1763. $libraryList['libraries'][(string)$child['title']] = (string)$child['id'];
  1764. }
  1765. $libraryList = array_change_key_case($libraryList, CASE_LOWER);
  1766. return $libraryList;
  1767. }
  1768. } catch (Requests_Exception $e) {
  1769. writeLog('error', 'Plex Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
  1770. };
  1771. }
  1772. break;
  1773. default:
  1774. # code...
  1775. break;
  1776. }
  1777. return false;
  1778. }
  1779. function plexJoinAPI($array)
  1780. {
  1781. return plexJoin($array['data']['username'], $array['data']['email'], $array['data']['password']);
  1782. }
  1783. function plexJoin($username, $email, $password)
  1784. {
  1785. try {
  1786. $url = 'https://plex.tv/users.json';
  1787. $headers = array(
  1788. 'Accept' => 'application/json',
  1789. 'Content-Type' => 'application/x-www-form-urlencoded',
  1790. 'X-Plex-Product' => 'Organizr',
  1791. 'X-Plex-Version' => '2.0',
  1792. 'X-Plex-Client-Identifier' => $GLOBALS['uuid'],
  1793. );
  1794. $data = array(
  1795. 'user[email]' => $email,
  1796. 'user[username]' => $username,
  1797. 'user[password]' => $password,
  1798. );
  1799. $response = Requests::post($url, $headers, $data, array());
  1800. $json = json_decode($response->body, true);
  1801. $errors = (!empty($json['errors']) ? true : false);
  1802. $success = (!empty($json['user']) ? true : false);
  1803. //Use This for later
  1804. $usernameError = (!empty($json['errors']['username']) ? $json['errors']['username'][0] : false);
  1805. $emailError = (!empty($json['errors']['email']) ? $json['errors']['email'][0] : false);
  1806. $passwordError = (!empty($json['errors']['password']) ? $json['errors']['password'][0] : false);
  1807. $errorMessage = "";
  1808. if ($errors) {
  1809. if ($usernameError) {
  1810. $errorMessage .= "[Username Error: " . $usernameError . "]";
  1811. }
  1812. if ($emailError) {
  1813. $errorMessage .= "[Email Error: " . $emailError . "]";
  1814. }
  1815. if ($passwordError) {
  1816. $errorMessage .= "[Password Error: " . $passwordError . "]";
  1817. }
  1818. }
  1819. return (!empty($success) && empty($errors) ? true : $errorMessage);
  1820. } catch (Requests_Exception $e) {
  1821. writeLog('error', 'Plex.TV Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
  1822. };
  1823. return false;
  1824. }
  1825. function checkFrame($array, $url)
  1826. {
  1827. if (array_key_exists("x-frame-options", $array)) {
  1828. if ($array['x-frame-options'] == "deny") {
  1829. return false;
  1830. } elseif ($array['x-frame-options'] == "sameorgin") {
  1831. $digest = parse_url($url);
  1832. $host = (isset($digest['host']) ? $digest['host'] : '');
  1833. if (getServer() == $host) {
  1834. return true;
  1835. } else {
  1836. return false;
  1837. }
  1838. }
  1839. } else {
  1840. if (!$array) {
  1841. return false;
  1842. }
  1843. return true;
  1844. }
  1845. }
  1846. function frameTest($url)
  1847. {
  1848. $array = array_change_key_case(get_headers(qualifyURL($url), 1));
  1849. $url = qualifyURL($url);
  1850. if (checkFrame($array, $url)) {
  1851. return true;
  1852. } else {
  1853. return false;
  1854. }
  1855. }
  1856. function ping($pings)
  1857. {
  1858. if (qualifyRequest($GLOBALS['pingAuth'])) {
  1859. $type = gettype($pings);
  1860. $ping = new Ping("");
  1861. $ping->setTtl(128);
  1862. $ping->setTimeout(2);
  1863. switch ($type) {
  1864. case "array":
  1865. $results = [];
  1866. foreach ($pings as $k => $v) {
  1867. if (strpos($v, ':') !== false) {
  1868. $domain = explode(':', $v)[0];
  1869. $port = explode(':', $v)[1];
  1870. $ping->setHost($domain);
  1871. $ping->setPort($port);
  1872. $latency = $ping->ping('fsockopen');
  1873. } else {
  1874. $ping->setHost($v);
  1875. $latency = $ping->ping();
  1876. }
  1877. if ($latency || $latency === 0) {
  1878. $results[$v] = $latency;
  1879. } else {
  1880. $results[$v] = false;
  1881. }
  1882. }
  1883. break;
  1884. case "string":
  1885. if (strpos($pings, ':') !== false) {
  1886. $domain = explode(':', $pings)[0];
  1887. $port = explode(':', $pings)[1];
  1888. $ping->setHost($domain);
  1889. $ping->setPort($port);
  1890. $latency = $ping->ping('fsockopen');
  1891. } else {
  1892. $ping->setHost($pings);
  1893. $latency = $ping->ping();
  1894. }
  1895. if ($latency || $latency === 0) {
  1896. $results = $latency;
  1897. } else {
  1898. $results = false;
  1899. }
  1900. break;
  1901. }
  1902. return $results;
  1903. }
  1904. return false;
  1905. }
  1906. function guestHash($start, $end)
  1907. {
  1908. $ip = $_SERVER['REMOTE_ADDR'];
  1909. $ip = md5($ip);
  1910. return substr($ip, $start, $end);
  1911. }
  1912. function importUserButtons()
  1913. {
  1914. $emptyButtons = '
  1915. <div class="col-md-12">
  1916. <div class="white-box bg-org">
  1917. <h3 class="box-title m-0" lang="en">Currently User import is available for Plex only.</h3> </div>
  1918. </div>
  1919. ';
  1920. $buttons = '';
  1921. if (!empty($GLOBALS['plexToken'])) {
  1922. $buttons .= '<button class="btn bg-plex text-muted waves-effect waves-light importUsersButton" onclick="importUsers(\'plex\')" type="button"><span class="btn-label"><i class="mdi mdi-plex"></i></span><span lang="en">Import Plex Users</span></button>';
  1923. }
  1924. return ($buttons !== '') ? $buttons : $emptyButtons;
  1925. }
  1926. function settingsDocker()
  1927. {
  1928. $type = ($GLOBALS['docker']) ? 'Official Docker' : 'Native';
  1929. return '<li><div class="bg-info"><i class="mdi mdi-flag mdi-24px text-white"></i></div><span class="text-muted hidden-xs" lang="en">Install Type</span> ' . $type . '</li>';
  1930. }