seriesScraper.php 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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. $GLOBALS['db']->deleteRows("series-episodes", "season-id", $season['id']);
  21. }
  22. $GLOBALS['db']->deleteRows("series-seasons", "series-id", $seriesID);
  23. $GLOBALS['db']->deleteRows("series", "id", $seriesID);
  24. // TODO: Remove files
  25. }
  26. public function update($seriesID) {
  27. $series = Model::getSeriesBySeriesID($seriesID);
  28. self::remove($seriesID);
  29. $this->downloadSeriesByID($series[0]['moviedb-id'], $series[0]['path'], $series[0]['source']);
  30. }
  31. public function scrapeFolder($sourceID) {
  32. if(!file_exists("img/posters")) {
  33. mkdir("img/posters");
  34. }
  35. $source = $GLOBALS['db']->getAllAssoc("sources", "id", $sourceID);
  36. $dirList = scandir($source[0]['path']);
  37. $dirList = array_diff($dirList, array('.', '..', 'formatting.txt', '.Trash-1000'));
  38. foreach($dirList as $dir) {
  39. $this->outputText .= "<b>" . $dir . "</b><br>" . PHP_EOL;
  40. if($GLOBALS['db']->countRows("series", "path", $dir) > 0) {
  41. $this->outputText .= "Exists, skipping..<br><br>" . PHP_EOL;
  42. continue;
  43. }
  44. $series = json_decode(curl_download($this->apiURL . urlencode($dir) . "&language=de&include_image_language=de"), true);
  45. if($series['total_results'] == 1) {
  46. $this->outputText .= "Found 1 series, downloading...<br>" . PHP_EOL;
  47. $this->downloadSeriesByID($series['results'][0]['id'], $dir, $sourceID);
  48. } else if($series['total_results'] < 1) {
  49. $this->outputText .= "<span style=\"color: red;\">Not found!!</span><br>" . PHP_EOL;
  50. } else { // multiple search results
  51. usort($series['results'], array("MovieScraper", "sortByPopularity")); // sort results by popularity, so that you don't have to scroll like 500000x
  52. foreach($series['results'] as $result) {
  53. $this->outputText .= "<pre>" . print_r($result, true) . "</pre>" . PHP_EOL;
  54. $this->outputText .= "<a href=\"?view=scrape&action=scrapeSingleTV&moviedbID=" . $result['id'] . "&path=" . urlencode($dir) . "&sourceID=" . $sourceID . "\" target=\"_blank\">Load</a><br>" . PHP_EOL; // TODO: this
  55. }
  56. }
  57. $this->outputText .= "<br>" . PHP_EOL;
  58. /*
  59. Array
  60. (
  61. [page] => 1
  62. [results] => Array
  63. (
  64. [0] => Array
  65. (
  66. [poster_path] => /hDlezfMSw8oXIFNZ7B9fFLrV8kd.jpg
  67. [popularity] => 1.006821
  68. [id] => 15826
  69. [backdrop_path] => /meQN6iuOulLwOV8LNO6S9z3bJBY.jpg
  70. [vote_average] => 7
  71. [overview] => 1000 Ways to Die is an anthology television series that [...]
  72. [first_air_date] => 2009-02-04
  73. [origin_country] => Array
  74. (
  75. [0] => US
  76. )
  77. [genre_ids] => Array
  78. (
  79. [0] => 99
  80. )
  81. [original_language] => en
  82. [vote_count] => 1
  83. [name] => 1000 Ways to Die
  84. [original_name] => 1000 Ways to Die
  85. )
  86. )
  87. [total_results] => 1
  88. [total_pages] => 1
  89. )
  90. */
  91. }
  92. }
  93. public function downloadSeriesByID($seriesID, $path, $sourceID) {
  94. $source = $GLOBALS['db']->getAllAssoc("sources", "id", $sourceID);
  95. $series = json_decode(curl_download("http://api.themoviedb.org/3/tv/" . $seriesID . "?api_key=a39779a38e0619f8ae58b09f64522597&language=de&include_image_language=de"), true);
  96. //$this->outputText .= "<pre>" . print_r($series, true) . "</pre>";
  97. // Download poster, backdrop
  98. if(!file_exists("img/posters" . $series['poster_path'])) {
  99. file_put_contents("img/posters" . $series['poster_path'], fopen($this->bannerURL . $series['poster_path'], 'r'));
  100. }
  101. if(!file_exists("img/posters" . $series['backdrop_path'])) {
  102. file_put_contents("img/posters" . $series['backdrop_path'], fopen($this->bannerURL . $series['backdrop_path'], 'r'));
  103. }
  104. $cols = array(
  105. "moviedb-id",
  106. "name",
  107. "path",
  108. "poster",
  109. "backdrop",
  110. "overview",
  111. "source"
  112. );
  113. $vals = array(
  114. $series['id'],
  115. $series['name'],
  116. $path,
  117. $series['poster_path'],
  118. $series['backdrop_path'],
  119. $series['overview'],
  120. $sourceID
  121. );
  122. $dbSeriesID = $GLOBALS['db']->insertRow("series", $cols, $vals);
  123. $localSeasons = scandir($source[0]['path'] . "/" . $path);
  124. $localSeasons = array_diff($localSeasons, array('.', '..', 'formatting.txt', '.Trash-1000'));
  125. foreach($localSeasons as $localSeason) {
  126. $season = array_search(ltrim(ltrim($localSeason, "S"), 0), array_column($series['seasons'], 'season_number'));
  127. $cols = array(
  128. "series-id",
  129. "number",
  130. "poster"
  131. );
  132. $vals = array(
  133. $dbSeriesID,
  134. $series['seasons'][$season]['season_number'],
  135. $series['seasons'][$season]['poster_path']
  136. );
  137. $dbSeasonID = $GLOBALS['db'] -> insertRow("series-seasons", $cols, $vals);
  138. if(!file_exists("img/posters" . $series['seasons'][$season]['poster_path'])) {
  139. file_put_contents("img/posters" . $series['seasons'][$season]['poster_path'], fopen($this->bannerURL . $series['seasons'][$season]['poster_path'], 'r'));
  140. }
  141. $localEpisodes = scandir($source[0]['path'] . "/" . $path . "/" . $localSeason);
  142. $localEpisodes = array_diff($localEpisodes, array('.', '..', 'formatting.txt', '.Trash-1000'));
  143. $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")));
  144. $episodes = array();
  145. foreach($dbEpisodes['episodes'] as $episode) {
  146. $episodes[] = get_object_vars($episode);
  147. }
  148. foreach($localEpisodes as $localEpisode) {
  149. $episode = array_search($this::getEpisodeNumberByFilename($localEpisode), array_column($episodes, 'episode_number'));
  150. $cols = array(
  151. "season-id",
  152. "number",
  153. "name",
  154. "thumb",
  155. "path"
  156. );
  157. $vals = array(
  158. $dbSeasonID,
  159. $episodes[$episode]['episode_number'],
  160. $episodes[$episode]['name'],
  161. $episodes[$episode]['still_path'],
  162. $localEpisode
  163. );
  164. $GLOBALS['db'] -> insertRow("series-episodes", $cols, $vals);
  165. if(!file_exists("img/posters" . $episodes[$episode]['still_path'])) {
  166. file_put_contents("img/posters" . $episodes[$episode]['still_path'], fopen($this->bannerURL . $episodes[$episode]['still_path'], 'r'));
  167. }
  168. }
  169. }
  170. $this->outputText .= "Done.";
  171. }
  172. }