tv.php 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. <?
  2. # Config
  3. $MEDIA_PATH = '/mnt/media';
  4. $TV_PATH = $MEDIA_PATH . '/TV';
  5. $EXISTS_FILES = array('no_quality_checks', 'more_number_formats', 'skip');
  6. $CONTENT_FILES = array('must_match', 'search_name');
  7. $TVDB_URL = 'http://thetvdb.com/?tab=series';
  8. # True if the input path is junk -- self-links, OS X noise, etc.
  9. function isJunk($path) {
  10. $path = basename($path);
  11. # Ignore certain fixed paths
  12. foreach (array('.', '..', '.DS_Store') as $value) {
  13. if ($path == $value) {
  14. return true;
  15. }
  16. }
  17. # Ignore ._ paths
  18. if (preg_match('/^\.\_/', $path)) {
  19. return true;
  20. }
  21. # Otherwise the path is good
  22. return false;
  23. }
  24. function isMonitored($season_path) {
  25. if (file_exists(dirname($season_path) . '/skip')) {
  26. return false;
  27. }
  28. if (file_exists($season_path . '/season_done')) {
  29. return false;
  30. }
  31. $season = 0;
  32. if (preg_match('/^Season\s+(\d+)$/i', basename($season_path), $matches)) {
  33. $season = $matches[1];
  34. }
  35. if (!$season) {
  36. return false;
  37. }
  38. return true;
  39. }
  40. function findSeasons($path) {
  41. $retval = array();
  42. # Check for the skip file
  43. $skip = false;
  44. if (file_exists($path . '/skip')) {
  45. $skip = true;
  46. }
  47. $dir = opendir($path);
  48. if ($dir === FALSE) {
  49. die('Unable to opendir(): ' . htmlspecialchars($path) . "\n");
  50. }
  51. while (false !== ($season = readdir($dir))) {
  52. # Skip junk
  53. if (isJunk($show)) {
  54. continue;
  55. }
  56. # We only care about directories
  57. $season_path = $path . '/' . $season;
  58. if (!is_dir($season_path)) {
  59. continue;
  60. }
  61. # Record season numbers and monitored status
  62. if (preg_match('/Season\s+(\d+)/i', $season, $matches)) {
  63. $retval[ $matches[1] ] = isMonitored($season_path);
  64. }
  65. }
  66. closedir($dir);
  67. # Sort numerically; the directory listing typically returns a lexicographic order
  68. ksort($retval, SORT_NUMERIC);
  69. return $retval;
  70. }
  71. # Find all shows under the given path
  72. function allShows($base) {
  73. $retval = array();
  74. # Look for series folders
  75. $tv_dir = opendir($base);
  76. if ($tv_dir === FALSE) {
  77. die('Unable to opendir(): ' . htmlspecialchars($path) . "\n");
  78. }
  79. while (false !== ($show = readdir($tv_dir))) {
  80. # Skip junk
  81. if (isJunk($show)) {
  82. continue;
  83. }
  84. # We only care about directories
  85. $show_path = $base . '/' . $show;
  86. if (!is_dir($show_path)) {
  87. continue;
  88. }
  89. # Record the show title and look for season folders
  90. $retval[ $show ] = findSeasons($show_path);
  91. }
  92. closedir($tv_dir);
  93. return $retval;
  94. }
  95. # Print a DL of all shows and note the available and monitored seasons
  96. function printAllShows() {
  97. global $TV_PATH;
  98. global $MEDIA_PATH;
  99. $shows = allShows($TV_PATH);
  100. echo "<dl>\n";
  101. foreach ($shows as $show => $seasons) {
  102. echo '<dt><a href="?show=' . urlencode($show) . '">' . htmlspecialchars($show) . "</a></dt>\n";
  103. foreach ($seasons as $season => $monitored) {
  104. echo '<dd>Season ' . htmlspecialchars($season);
  105. if ($monitored) {
  106. echo ' (monitored)';
  107. }
  108. echo "</dd>\n";
  109. }
  110. }
  111. echo "</dl>\n";
  112. }
  113. function findWebloc($path) {
  114. $retval = false;
  115. $dir = opendir($path);
  116. if ($dir === FALSE) {
  117. die('Unable to opendir(): ' . htmlspecialchars($path) . "\n");
  118. }
  119. while (false !== ($name = readdir($dir))) {
  120. # Skip junk
  121. if (isJunk($name)) {
  122. continue;
  123. }
  124. # We only care about *.webloc files
  125. if (!preg_match('/\.webloc$/', $name)) {
  126. continue;
  127. }
  128. # The file must be readable to be useful
  129. $file = $path . '/' . $name;
  130. if (is_readable($file)) {
  131. $retval = $file;
  132. last;
  133. }
  134. }
  135. closedir($dir);
  136. return $retval;
  137. }
  138. function readWebloc($file) {
  139. global $TVDB_URL;
  140. $retval = array(
  141. 'tvdb-id' => false,
  142. 'tvdb-lid' => false,
  143. 'url' => false,
  144. );
  145. # Read and parse the file
  146. $str = trim(file_get_contents($file));
  147. if (preg_match('/[\?\&]id=(\d+)/', $str, $matches)) {
  148. $retval['tvdb-id'] = $matches[1];
  149. }
  150. if (preg_match('/[\?\&]lid=(\d+)/', $str, $matches)) {
  151. $retval['tvdb-lid'] = $matches[1];
  152. }
  153. # Construct a URL
  154. if ($retval['tvdb-id'] !== false) {
  155. $retval['url'] = $TVDB_URL . '&id=' . $retval['tvdb-id'];
  156. if ($retval['tvdb-lid'] !== false) {
  157. $retval['url'] .= '&lid=' . $retval['tvdb-lid'];
  158. }
  159. }
  160. return $retval;
  161. }
  162. function readFlags($path) {
  163. global $EXISTS_FILES;
  164. global $CONTENT_FILES;
  165. $flags = array();
  166. # Look for all the exists files
  167. foreach ($EXISTS_FILES as $name) {
  168. $flags[ $name ] = false;
  169. if (file_exists($path . '/' . $name)) {
  170. $flags[ $name ] = true;
  171. }
  172. }
  173. # Read all the content files
  174. foreach ($CONTENT_FILES as $name) {
  175. $flags[ $name ] = false;
  176. $file = $path . '/' . $name;
  177. if (is_readable($file)) {
  178. $flags[ $name ] = trim(file_get_contents($file));
  179. }
  180. }
  181. # Read the TVDB IDs from the *.webloc file
  182. $webloc = findWebloc($path);
  183. if ($webloc !== false) {
  184. $flags = array_merge($flags, readWebloc($webloc));
  185. }
  186. return $flags;
  187. }
  188. function printShow($show) {
  189. global $TV_PATH;
  190. global $EXISTS_FILES;
  191. global $CONTENT_FILES;
  192. # Construct our show path and make sure it's reasonable
  193. $path = $TV_PATH . '/' . $show;
  194. if (!is_dir($path)) {
  195. die('Unknown show: ' . htmlspecialchars($show));
  196. }
  197. # Check the flags
  198. $flags = readFlags($path);
  199. # Check the seasons
  200. $seasons = findSeasons($path);
  201. # Header
  202. echo '<h1>' . htmlspecialchars($show) . '</h1>';
  203. echo '<form action="' . $SERVER['PHP_SELF'] . '" method="post">';
  204. # Exists and content flags
  205. echo '<h2>Search Parameters</h2>';
  206. echo '<p>';
  207. foreach ($EXISTS_FILES as $file) {
  208. echo '<label><input value="1" type="checkbox" name="' . htmlspecialchars($file) . '" ';
  209. if ($flags[ $file ]) {
  210. echo 'checked="checked"';
  211. }
  212. echo '/> ' . htmlspecialchars($file) . '</label><br/>';
  213. }
  214. foreach ($CONTENT_FILES as $file) {
  215. echo '<label><input type="text" name="' . htmlspecialchars($file) . '" ';
  216. if ($flags[ $file ]) {
  217. echo 'value="' . htmlspecialchars($flags[ $file ]) . '"';
  218. }
  219. echo '/> ' . htmlspecialchars($file) . '</label><br/>';
  220. }
  221. echo '</p>';
  222. # TVDB URL
  223. echo '<h2>The TVDB</h2>';
  224. echo '<p><a href="' . htmlspecialchars($flags['url']) . '">' . htmlspecialchars($flags['url']) . '</a></p>';
  225. # Seasons
  226. echo '<h2>Seasons</h2>';
  227. echo '<p>';
  228. foreach ($seasons as $season => $monitored) {
  229. echo '<label>Season ' . htmlspecialchars($season) . ' ';
  230. echo '<input type="checkbox" value="1" name="season_' . htmlspecialchars($season) . '" ';
  231. if ($monitored) {
  232. echo 'checked="checked"';
  233. }
  234. echo '/></label><br/>';
  235. }
  236. echo '</p>';
  237. # Footer
  238. echo '</form>';
  239. }
  240. #=========================================================================================
  241. # Send our headers early
  242. header('Content-type: text/html; charset=utf-8');
  243. # Did the user request a specific show?
  244. $show = false;
  245. if (isset($_REQUEST['show'])) {
  246. # This is not a great filter, but it should make the string safe for use as a quoted path
  247. $show = preg_replace('/[\0\n\r]/', '', $_REQUEST['show']);
  248. $show = basename($show);
  249. }
  250. #=========================================================================================
  251. # Generic XHTML 1.1 header
  252. print <<<ENDOLA
  253. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  254. "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
  255. <html xmlns="http://www.w3.org/1999/xhtml">
  256. <head>
  257. <meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
  258. <title>UberZach TV</title>
  259. </head>
  260. <body>
  261. ENDOLA;
  262. if ($show === false) {
  263. printAllShows();
  264. } else {
  265. printShow($show);
  266. }
  267. # Generic XHTML 1.1 footer
  268. print <<<ENDOLA
  269. </body>
  270. </html>
  271. ENDOLA;
  272. ?>