seriesScraper.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. <?php
  2. ignore_user_abort(true);
  3. class SeriesScraper {
  4. private $apiURL = "http://api.themoviedb.org/3/search/tv?api_key=a39779a38e0619f8ae58b09f64522597&query=";
  5. private $bannerURL = "https://image.tmdb.org/t/p/original";
  6. private $outputText = "";
  7. public function __construct() {
  8. }
  9. public function getOutputText() {
  10. return $this->outputText;
  11. }
  12. public static function getEpisodeNumberByFilename($filename) {
  13. preg_match("/([a-zA-Z0-9äöüÄÖÜß\-\.\,\w]+)-[S|s]([0-9]+)[E|e]([0-9]+)-([a-zA-Z0-9äöüÄÖÜß\-\.\,\w\:]+)\.([a-zA-Z0-9\(\).*\w\,]+)/", $filename, $output);
  14. return ltrim($output[3], 0);
  15. }
  16. public static function remove($seriesID) {
  17. $series = Model::getSeriesBySeriesID($seriesID);
  18. $seasons = Model::getSeasonsBySeriesID($seriesID);
  19. foreach($seasons as $season) {
  20. $episodes = $GLOBALS['db']->getAllAssoc("series-episodes", "season-id", $season['id']);
  21. foreach($episodes as $episode) {
  22. unlink("img/posters/" . $episode['thumb']);
  23. }
  24. $GLOBALS['db']->deleteRows("series-episodes", "season-id", $season['id']);
  25. }
  26. $seasons = $GLOBALS['db']->getAllAssoc("series-seasons", "series-id", $seriesID);
  27. foreach($seasons as $season) {
  28. unlink("img/posters/" . $season['poster']);
  29. }
  30. $GLOBALS['db']->deleteRows("series-seasons", "series-id", $seriesID);
  31. $series = $GLOBALS['db']->getAllAssoc("series", "id", $seriesID);
  32. unlink("img/posters/" . $series[0]['poster']);
  33. unlink("img/posters/" . $series[0]['backdrop']);
  34. $GLOBALS['db']->deleteRows("series", "id", $seriesID);
  35. header("Location: " . $GLOBALS['conf']['baseURL'] . "?view=admin");
  36. }
  37. public function update($seriesID) {
  38. $series = Model::getSeriesBySeriesID($seriesID);
  39. self::remove($seriesID);
  40. $this->downloadSeriesByID($series[0]['moviedb-id'], $series[0]['path'], $series[0]['source']);
  41. header("Location: " . $GLOBALS['conf']['baseURL'] . "?view=admin");
  42. }
  43. public function scrapeFolder($sourceID) {
  44. if(!file_exists("img/posters")) {
  45. mkdir("img/posters");
  46. }
  47. $source = $GLOBALS['db']->getAllAssoc("sources", "id", $sourceID);
  48. $dirList = scandir($source[0]['path']);
  49. $dirList = array_diff($dirList, array('.', '..', 'formatting.txt', '.Trash-1000', 'queue.hbq'));
  50. foreach($dirList as $dir) {
  51. $this->outputText .= "<b>" . $dir . "</b><br>" . PHP_EOL;
  52. if($GLOBALS['db']->countRows("series", "path", $dir) > 0) {
  53. $this->outputText .= "Exists, updating..<br>" . PHP_EOL;
  54. self::updateByID($GLOBALS['db']->getString("id", "series", "path", $dir));
  55. $this->outputText .= "<br>" . PHP_EOL;
  56. continue;
  57. }
  58. $series = json_decode(curl_download($this->apiURL . urlencode($dir) . "&language=de&include_image_language=de"), true);
  59. if($series['total_results'] == 1) {
  60. $this->outputText .= "Found 1 series, downloading...<br>" . PHP_EOL;
  61. $this->downloadSeriesByID($series['results'][0]['id'], $dir, $sourceID);
  62. } else if($series['total_results'] < 1) {
  63. $this->outputText .= "<span style=\"color: red;\">Not found!!</span><br>" . PHP_EOL;
  64. } else { // multiple search results
  65. usort($series['results'], array("MovieScraper", "sortByPopularity")); // sort results by popularity, so that you don't have to scroll 500000x
  66. foreach($series['results'] as $result) {
  67. $this->outputText .= "<pre>" . print_r($result, true) . "</pre>" . PHP_EOL;
  68. $this->outputText .= "<a href=\"?view=scrape&action=scrapeSingleTV&moviedbID=" . $result['id'] . "&path=" . urlencode($dir) . "&sourceID=" . $sourceID . "\" target=\"_blank\">Load</a><br /><br />" . PHP_EOL; // TODO: this
  69. }
  70. }
  71. $this->outputText .= "<br>" . PHP_EOL;
  72. }
  73. }
  74. public function downloadSeriesByID($seriesID, $path, $sourceID) {
  75. $source = $GLOBALS['db']->getAllAssoc("sources", "id", $sourceID);
  76. $series = json_decode(curl_download("http://api.themoviedb.org/3/tv/" . $seriesID . "?api_key=a39779a38e0619f8ae58b09f64522597&language=de&include_image_language=de"), true);
  77. //$this->outputText .= "<pre>" . print_r($series, true) . "</pre>";
  78. // Download poster, backdrop
  79. if(!file_exists("img/posters" . $series['poster_path'])) {
  80. file_put_contents("img/posters" . $series['poster_path'], fopen($this->bannerURL . $series['poster_path'], 'r'));
  81. }
  82. if(!file_exists("img/posters" . $series['backdrop_path'])) {
  83. file_put_contents("img/posters" . $series['backdrop_path'], fopen($this->bannerURL . $series['backdrop_path'], 'r'));
  84. }
  85. $cols = array(
  86. "moviedb-id",
  87. "name",
  88. "path",
  89. "poster",
  90. "backdrop",
  91. "overview",
  92. "source"
  93. );
  94. $vals = array(
  95. $series['id'],
  96. $series['name'],
  97. $path,
  98. ltrim($series['poster_path'], "/"),
  99. ltrim($series['backdrop_path'], "/"),
  100. $series['overview'],
  101. $sourceID
  102. );
  103. $dbSeriesID = $GLOBALS['db']->insertRow("series", $cols, $vals);
  104. $localSeasons = scandir($source[0]['path'] . "/" . $path);
  105. $localSeasons = array_diff($localSeasons, array('.', '..', 'formatting.txt', '.Trash-1000'));
  106. foreach($localSeasons as $localSeason) {
  107. $season = array_search(ltrim(ltrim($localSeason, "S"), 0), array_column($series['seasons'], 'season_number'));
  108. $cols = array(
  109. "series-id",
  110. "number",
  111. "poster"
  112. );
  113. $vals = array(
  114. $dbSeriesID,
  115. $series['seasons'][$season]['season_number'],
  116. ltrim($series['seasons'][$season]['poster_path'], "/")
  117. );
  118. $dbSeasonID = $GLOBALS['db'] -> insertRow("series-seasons", $cols, $vals);
  119. if(!file_exists("img/posters" . $series['seasons'][$season]['poster_path'])) {
  120. file_put_contents("img/posters" . $series['seasons'][$season]['poster_path'], fopen($this->bannerURL . $series['seasons'][$season]['poster_path'], 'r'));
  121. }
  122. $localEpisodes = scandir($source[0]['path'] . "/" . $path . "/" . $localSeason);
  123. $localEpisodes = array_diff($localEpisodes, array('.', '..', 'formatting.txt', '.Trash-1000'));
  124. $dbEpisodes = get_object_vars(json_decode(curl_download("http://api.themoviedb.org/3/tv/" . $seriesID . "/season/" . ltrim(ltrim($localSeason, "S"), 0) . "?api_key=a39779a38e0619f8ae58b09f64522597&language=de&include_image_language=de")));
  125. $episodes = array();
  126. foreach($dbEpisodes['episodes'] as $episode) {
  127. $episodes[] = get_object_vars($episode);
  128. }
  129. foreach($localEpisodes as $localEpisode) {
  130. $episode = array_search($this::getEpisodeNumberByFilename($localEpisode), array_column($episodes, 'episode_number'));
  131. $cols = array(
  132. "season-id",
  133. "number",
  134. "name",
  135. "thumb",
  136. "path"
  137. );
  138. $vals = array(
  139. $dbSeasonID,
  140. $episodes[$episode]['episode_number'],
  141. $episodes[$episode]['name'],
  142. ltrim($episodes[$episode]['still_path'], "/"),
  143. $localEpisode
  144. );
  145. $GLOBALS['db'] -> insertRow("series-episodes", $cols, $vals);
  146. if(!file_exists("img/posters" . $episodes[$episode]['still_path'])) {
  147. file_put_contents("img/posters" . $episodes[$episode]['still_path'], fopen($this->bannerURL . $episodes[$episode]['still_path'], 'r'));
  148. }
  149. }
  150. }
  151. $this->outputText .= "Done.";
  152. }
  153. public function updateByID($seriesID) {
  154. $seriesPath = $GLOBALS['db']->customQuery("SELECT `series`.`path` AS 'seriespath', `sources`.`path` AS 'sourcepath' FROM `series`, `sources` WHERE `series`.`id` = " . $seriesID . " AND `series`.`source` = `sources`.`id`");
  155. $seriesPath = implode("/", array_reverse($seriesPath[0]));
  156. $series = $GLOBALS['db']->getAllAssoc("series", "id", $seriesID);
  157. $seriesDB = json_decode(curl_download("http://api.themoviedb.org/3/tv/" . $series[0]['moviedb-id'] . "?api_key=a39779a38e0619f8ae58b09f64522597&language=de&include_image_language=de"), true);
  158. if($series[0]['poster'] != ltrim($seriesDB['poster_path'], "/")) { // poster
  159. //error_log("New Poster, old: " . $series[0]['poster'] . " new: " . ltrim($seriesDB['poster_path'], "/"));
  160. if(file_exists("img/posters/" . $series[0]['poster']) && !is_dir("img/posters/" . $series[0]['poster'])) {
  161. unlink("img/posters/" . $series[0]['poster']);
  162. }
  163. file_put_contents("img/posters" . $seriesDB['poster_path'], fopen($this->bannerURL . $seriesDB['poster_path'], 'r'));
  164. $GLOBALS['db']->updateRow("series", "poster", '"' . ltrim($seriesDB['poster_path'], "/") . '"', "id", $seriesID);
  165. }
  166. if($series[0]['backdrop'] != ltrim($seriesDB['backdrop_path'], "/")) { // backdrop
  167. //error_log("New Backdrop, old: " . $series[0]['backdrop'] . " new: " . ltrim($seriesDB['backdrop_path'], "/"));
  168. if(file_exists("img/posters/" . $series[0]['backdrop']) && !is_dir("img/posters/" . $series[0]['backdrop'])) {
  169. unlink("img/posters/" . $series[0]['backdrop']);
  170. }
  171. file_put_contents("img/posters" . $seriesDB['backdrop_path'], fopen($this->bannerURL . $seriesDB['backdrop_path'], 'r'));
  172. $GLOBALS['db']->updateRow("series", "backdrop", '"' . ltrim($seriesDB['backdrop_path'], "/") . '"', "id", $seriesID);
  173. }
  174. $seasons = $GLOBALS['db']->getAllAssoc("series-seasons", "series-id", $seriesID);
  175. $localSeasons = scandir($seriesPath);
  176. $localSeasons = array_diff($localSeasons, array('.', '..', 'formatting.txt', '.Trash-1000', 'queue.hbq'));
  177. foreach($seasons as $season) { // TODO: check for new seasons
  178. if(!in_array("S" . sprintf("%02d", $season['number']), $localSeasons)) {
  179. //error_log("Season " . "S" . sprintf("%02d", $season['number']) . " not existing anymore");
  180. $GLOBALS['db']->deleteRows("series-seasons", "id", $seasons['id']);
  181. continue;
  182. }
  183. unset($localSeasons[array_search("S" . sprintf("%02d", $season['number']), $localSeasons)]);
  184. $seasonDB = array_search(ltrim($season['number'], 0), array_column($seriesDB['seasons'], 'season_number'));
  185. $seasonDB = $seriesDB['seasons'][$seasonDB];
  186. if($season['poster'] != ltrim($seasonDB['poster_path'], "/")) {
  187. //error_log("New Season-Poster, old: " . $season['poster'] . " new: " . ltrim($seasonDB['poster_path'], "/"));
  188. if(file_exists("img/posters/" . $season['poster']) && !is_dir("img/posters/" . $season['poster'])) {
  189. unlink("img/posters/" . $season['poster']);
  190. }
  191. file_put_contents("img/posters" . $seasonDB['poster_path'], fopen($this->bannerURL . $seasonDB['poster_path'], 'r'));
  192. $GLOBALS['db']->updateRow("series-seasons", "poster", '"' . ltrim($seasonDB['poster_path'], "/") . '"', "id", $season['id']);
  193. }
  194. $episodesDB = json_decode(curl_download("http://api.themoviedb.org/3/tv/" . $series[0]['moviedb-id'] . "/season/" . $season['number'] . "?api_key=a39779a38e0619f8ae58b09f64522597&language=de&include_image_language=de"), true);
  195. $episodes = $GLOBALS['db']->getAllAssoc("series-episodes", "season-id", $season['id']);
  196. $localEpisodes = scandir($seriesPath . "/" . "S" . sprintf("%02d", $season['number']));
  197. $localEpisodes = array_diff($localEpisodes, array('.', '..', 'formatting.txt', '.Trash-1000', 'queue.hbq'));
  198. foreach($episodes as $episode) {
  199. if(!in_array($episode['path'], $localEpisodes)) {
  200. //error_log("Episode " . $episode['number'] . " not existing anymore");
  201. $GLOBALS['db']->deleteRows("series-episodes", "id", $episode['id']);
  202. continue;
  203. }
  204. unset($localEpisodes[array_search($episode['path'], $localEpisodes)]);
  205. $episodeDB = array_search($episode['number'], array_column($episodesDB['episodes'], 'episode_number'));
  206. $episodeDB = $episodesDB['episodes'][$episodeDB];
  207. if($episode['thumb'] != ltrim($episodeDB['still_path'], "/")) {
  208. //error_log("New Episode-Poster, old: " . $episode['thumb'] . " new: " . ltrim($episodeDB['still_path'], "/"));
  209. if(file_exists("img/posters/" . $episode['thumb']) && !is_dir("img/posters/" . $episode['thumb'])) {
  210. unlink("img/posters/" . $episode['thumb']);
  211. }
  212. file_put_contents("img/posters" . $episodeDB['still_path'], fopen($this->bannerURL . $episodeDB['still_path'], 'r'));
  213. $GLOBALS['db']->updateRow("series-episodes", "thumb", '"' . ltrim($episodeDB['still_path'], "/") . '"', "id", $episode['id']);
  214. }
  215. }
  216. if(sizeof($localEpisodes) > 0) {
  217. //error_log("New Episode(s); " . print_r($localEpisodes, true));
  218. $this->outputText .= "New Episode(s), Please update again.<br>";
  219. $cols = array(
  220. "season-id",
  221. "number",
  222. "name",
  223. "thumb",
  224. "path"
  225. );
  226. foreach($localEpisodes as $localEpisode) {
  227. $vals = array(
  228. $season['id'],
  229. ltrim(ltrim(self::getEpisodeNumberByFilename($localEpisode), "S"), 0),
  230. "",
  231. "",
  232. $localEpisode
  233. );
  234. $GLOBALS['db']->insertRow("series-episodes", $cols, $vals);
  235. }
  236. }
  237. }
  238. if(sizeof($localSeasons) > 0) {
  239. //error_log("New Season(s): " . print_r($localSeasons, true));
  240. $this->outputText .= "New Season(s), Please update again.<br>";
  241. $cols = array(
  242. "series-id",
  243. "number",
  244. "poster",
  245. "enabled"
  246. );
  247. foreach($localSeasons as $localSeason) {
  248. $vals = array(
  249. $seriesID,
  250. ltrim(ltrim($localSeason, "S"), 0),
  251. "",
  252. 1
  253. );
  254. $GLOBALS['db']->insertRow("series-seasons", $cols, $vals);
  255. }
  256. }
  257. }
  258. }