From 929954ebd9a2157b9f000ee40fd0c3fc33bc8636 Mon Sep 17 00:00:00 2001 From: DoarMihai Date: Wed, 8 Jan 2025 01:25:21 +0200 Subject: [PATCH] [#2] tv series progress --- app/Models/ItemToFetchJobs.php | 2 + app/Models/Show.php | 10 + app/Models/ShowRecommendation.php | 13 + app/Models/ShowSimilar.php | 13 + app/Models/ShowTranslation.php | 21 ++ .../MediaProcessing/ShowProcessingService.php | 300 +++++++++++++++++- ...1_07_214416_create_show_keywords_table.php | 29 ++ ..._215741_create_show_translations_table.php | 37 +++ ...0757_create_show_watch_providers_table.php | 31 ++ ...1734_create_show_recommendations_table.php | 29 ++ ...1_07_222751_create_show_similars_table.php | 29 ++ 11 files changed, 512 insertions(+), 2 deletions(-) create mode 100644 app/Models/ShowRecommendation.php create mode 100644 app/Models/ShowSimilar.php create mode 100644 app/Models/ShowTranslation.php create mode 100644 database/migrations/2025_01_07_214416_create_show_keywords_table.php create mode 100644 database/migrations/2025_01_07_215741_create_show_translations_table.php create mode 100644 database/migrations/2025_01_07_220757_create_show_watch_providers_table.php create mode 100644 database/migrations/2025_01_07_221734_create_show_recommendations_table.php create mode 100644 database/migrations/2025_01_07_222751_create_show_similars_table.php diff --git a/app/Models/ItemToFetchJobs.php b/app/Models/ItemToFetchJobs.php index c1ff525..9f3eda8 100644 --- a/app/Models/ItemToFetchJobs.php +++ b/app/Models/ItemToFetchJobs.php @@ -21,6 +21,7 @@ class ItemToFetchJobs extends Model public const JOB_WATCH_PROVIDERS = 'WatchProviders'; public const JOB_EXTERNAL_IDS = 'ExternalIds'; public const JOB_DETAILS = 'Details'; + public const JOB_CONTENT_RATINGS = 'ContentRatings'; public const JOBS = [ self::JOB_ALTERNVATIVE_TITLES, @@ -37,6 +38,7 @@ class ItemToFetchJobs extends Model self::JOB_VIDEOS, self::JOB_WATCH_PROVIDERS, self::JOB_EXTERNAL_IDS, + self::JOB_CONTENT_RATINGS, ]; protected $fillable = [ diff --git a/app/Models/Show.php b/app/Models/Show.php index 96b11e2..2855d24 100644 --- a/app/Models/Show.php +++ b/app/Models/Show.php @@ -55,4 +55,14 @@ class Show extends Model { return $this->belongsToMany(Video::class, 'show_videos', 'show_id', 'video_id'); } + + public function keywords() + { + return $this->belongsToMany(Keyword::class, 'show_keywords', 'show_id', 'keyword_id'); + } + + public function watchProviders() + { + return $this->belongsToMany(WatchProvider::class, 'show_watch_providers', 'show_id', 'watch_provider_id'); + } } diff --git a/app/Models/ShowRecommendation.php b/app/Models/ShowRecommendation.php new file mode 100644 index 0000000..cf16dfc --- /dev/null +++ b/app/Models/ShowRecommendation.php @@ -0,0 +1,13 @@ +removeElementFromRemainingJobs($item->tmdb_id, ItemToFetchJobs::JOB_VIDEOS); } + private function getKeywords($item) + { + $tmdbKeywords = $this->showsApi->getKeywords($item->tmdb_id); + + if (empty($tmdbKeywords) || !isset($tmdbKeywords['results'])) { + return; + } + + $show = Show::where('tmdb_id', $item->tmdb_id)->first(); + + foreach ($tmdbKeywords['results'] as $tmdbKeyword) { + $existingKeyword = Keyword::where('tmdb_id', $tmdbKeyword['id'])->first(); + + if (!$existingKeyword) { + $existingKeyword = Keyword::create([ + 'name' => $tmdbKeyword['name'], + 'tmdb_id' => $tmdbKeyword['id'], + ]); + } + + if ($show->whereHas('keywords', function ($query) use ($existingKeyword) { + $query->where('tmdb_id', $existingKeyword->tmdb_id); + })->exists()) { + return; + } else { + $show->keywords()->attach($existingKeyword); + } + } + + $this->removeElementFromRemainingJobs($item->tmdb_id, ItemToFetchJobs::JOB_KEYWORDS); + } + + private function getTranslations($item) + { + $tmdbMovieTranslations = $this->showsApi->getTranslations($item->tmdb_id); + + if (!$tmdbMovieTranslations || !isset($tmdbMovieTranslations['translations'])) { + return; + } + + $show = Show::where('tmdb_id', $item->tmdb_id)->first(); + + foreach ($tmdbMovieTranslations['translations'] as $tmdbTranslation) { + $existingTranslation = ShowTranslation::where('show_id', $show->id) + ->where('name', $tmdbTranslation['name']) + ->first(); + + if (!$existingTranslation) { + ShowTranslation::create([ + 'show_id' => $show->id, + 'iso_3166' => $tmdbTranslation['iso_3166_1'], + 'iso_639' => $tmdbTranslation['iso_639_1'], + 'name' => $tmdbTranslation['name'], + 'english_name' => $tmdbTranslation['english_name'], + 'homepage' => $tmdbTranslation['data']['homepage'], + 'overview' => $tmdbTranslation['data']['overview'], + 'runtime' => $tmdbTranslation['data']['runtime'] ?? 0, + 'tagline' => $tmdbTranslation['data']['tagline'], + 'title' => $tmdbTranslation['data']['title'] ?? '', + ]); + } + } + + $this->removeElementFromRemainingJobs($item->tmdb_id, ItemToFetchJobs::JOB_TRANSLATIONS); + } + + private function getWatchProviders($item) + { + $tmdbWatchProviders = $this->showsApi->getWatchProviders($item->tmdb_id); + + if (empty($tmdbWatchProviders) || empty($tmdbWatchProviders['results'])) { + return; + } + + $show = Show::where('tmdb_id', $item->tmdb_id)->first(); + + if (!$show) { + $itemToFetch = $this->createJob($item->tmdb_id); + $this->getDetails($itemToFetch); + return; + } + + $types = [ + 'flatrate', + 'rent', + 'buy', + ]; + + foreach ($tmdbWatchProviders['results'] as $locale => $tmdbWatchProvider) { + foreach ($types as $type) { + if (!isset($tmdbWatchProvider[$type])) { + continue; + } + $providerInfo = $tmdbWatchProvider[$type]; + $providerInfo = reset($providerInfo); + + if (!isset($providerInfo['provider_id'])) { + continue; + } + + $existingWatchProvider = WatchProvider::where('tmdb_provider_id', $providerInfo['provider_id'])->first(); + + if(!$existingWatchProvider) { + $existingWatchProvider = WatchProvider::create([ + 'type' => $type, + 'logo_path' => $providerInfo['logo_path'], + 'tmdb_provider_id' => $providerInfo['provider_id'], + 'provider_name' => $providerInfo['provider_name'], + 'display_priority' => $providerInfo['display_priority'], + ]); + } + + if (!$show->whereHas('watchProviders', function ($query) use ($show) { + $query->where('show_id', $show->id); + })->exists()) { + $show->watchProviders()->attach($existingWatchProvider, [ + 'locale' => $locale, + 'tmdb_url' => $tmdbWatchProvider['link'], + ]); + } + } + } + + $this->removeElementFromRemainingJobs($item->tmdb_id, ItemToFetchJobs::JOB_WATCH_PROVIDERS); + } + + private function getRecommendations($item) + { + $tmdbRecommendations = $this->showsApi->getRecommendations($item->tmdb_id); + + if (empty($tmdbRecommendations) || empty($tmdbRecommendations['results'])) { + return; + } + + $initialShow = Show::where('tmdb_id', $item->tmdb_id)->first(); + + foreach ($tmdbRecommendations['results'] as $tmdbRecommendation) { + $itemToFetch = ItemToFetch::where('tmdb_id', $tmdbRecommendation['id'])->where('type', ItemToFetch::TYPE_TV_SERIES)->first(); + + if ($itemToFetch) { + $this->getDetails($itemToFetch); + continue; + } + + $show = Show::where('tmdb_id', $tmdbRecommendation['id'])->first(); + + if ($show) { + $recommendationLink = ShowRecommendation::where('show_id', $initialShow->id) + ->where('recommended_show_id', $show->id) + ->first(); + + if (!$recommendationLink) { + ShowRecommendation::create([ + 'show_id' => $initialShow->id, + 'recommended_show_id' => $show->id, + ]); + } + + continue; + } else { + $itemToFetch = ItemToFetch::create([ + 'tmdb_id' => $tmdbRecommendation['id'], + 'type' => ItemToFetch::TYPE_TV_SERIES, + ]); + + $jobs = ItemToFetchJobs::JOBS; + $jobs[] = "Details"; + + ItemToFetchJobs::create([ + 'tmdb_id' => $tmdbRecommendation['id'], + 'type' => ItemToFetch::TYPE_TV_SERIES, + 'remaining_jobs' => json_encode($jobs), + ]); + + $this->getDetails($itemToFetch); + } + + $recommendedShow = Show::where('tmdb_id', $tmdbRecommendation['id'])->first(); + + ShowRecommendation::create([ + 'show_id' => $initialShow->id, + 'recommended_show_id' => $recommendedShow->id, + ]); + } + + $this->removeElementFromRemainingJobs($item->tmdb_id, ItemToFetchJobs::JOB_RECOMMNDATION); + } + + private function getSimilar($item) + { + $tmdbSimilarMovies = $this->showsApi->getSimilar($item->tmdb_id); + + if (empty($tmdbSimilarMovies) || empty($tmdbSimilarMovies['results'])) { + return; + } + + $initialShow = Show::where('tmdb_id', $item->tmdb_id)->first(); + + foreach ($tmdbSimilarMovies['results'] as $tmdbSimilarMovie) { + $itemToFetch = ItemToFetch::where('tmdb_id', $tmdbSimilarMovie['id'])->where('type', ItemToFetch::TYPE_TV_SERIES)->first(); + + if ($itemToFetch) { + $this->getDetails($itemToFetch); + continue; + } + + $similarShow = Show::where('tmdb_id', $tmdbSimilarMovie['id'])->first(); + + if ($similarShow) { + $similarLink = ShowSimilar::where('show_id', $initialShow->id) + ->where('similar_show_id', $similarShow->id) + ->first(); + + if (!$similarLink) { + ShowSimilar::create([ + 'show_id' => $initialShow->id, + 'similar_show_id' => $similarShow->id, + ]); + } + + continue; + } + + + $itemToFetch = ItemToFetch::create([ + 'tmdb_id' => $tmdbSimilarMovie['id'], + 'type' => ItemToFetch::TYPE_TV_SERIES, + ]); + + $jobs = ItemToFetchJobs::JOBS; + $jobs[] = "Details"; + + ItemToFetchJobs::create([ + 'tmdb_id' => $tmdbSimilarMovie['id'], + 'type' => ItemToFetch::TYPE_TV_SERIES, + 'remaining_jobs' => json_encode($jobs), + ]); + + $this->getDetails($itemToFetch); + + $show = Show::where('tmdb_id', $item->tmdb_id)->first(); + $similarShow = Show::where('tmdb_id', $tmdbSimilarMovie['id'])->first(); + + ShowSimilar::create([ + 'show_id' => $show->id, + 'similar_show_id' => $similarShow->id, + ]); + } + + $this->removeElementFromRemainingJobs($item->tmdb_id, ItemToFetchJobs::JOB_SIMILAR); + } + + private function getContentRatings($item) + { + + } + private function processSeasons(Show $show, array $seasons) { foreach ($seasons as $season) { @@ -402,4 +668,34 @@ class ShowProcessingService implements ProcessingInterface } } } + + private function createJob($tmdbId) + { + $itemToFetch = ItemToFetch::where('tmdb_id', $tmdbId)->where('type', ItemToFetch::TYPE_TV_SERIES)->first(); + + if ($itemToFetch) { + return $itemToFetch; + } + + $show = Show::where('tmdb_id', $tmdbId)->first(); + if ($show) { + return; + } + + $itemToFetch = ItemToFetch::create([ + 'tmdb_id' => $tmdbId, + 'type' => ItemToFetch::TYPE_TV_SERIES, + ]); + + $jobs = ItemToFetchJobs::JOBS; + $jobs[] = "Details"; + + ItemToFetchJobs::create([ + 'tmdb_id' => $tmdbId, + 'type' => ItemToFetch::TYPE_TV_SERIES, + 'remaining_jobs' => json_encode($jobs), + ]); + + return $itemToFetch; + } } diff --git a/database/migrations/2025_01_07_214416_create_show_keywords_table.php b/database/migrations/2025_01_07_214416_create_show_keywords_table.php new file mode 100644 index 0000000..1c9337e --- /dev/null +++ b/database/migrations/2025_01_07_214416_create_show_keywords_table.php @@ -0,0 +1,29 @@ +id(); + $table->unsignedBigInteger('show_id'); + $table->unsignedBigInteger('keyword_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('show_keywords'); + } +}; diff --git a/database/migrations/2025_01_07_215741_create_show_translations_table.php b/database/migrations/2025_01_07_215741_create_show_translations_table.php new file mode 100644 index 0000000..209644b --- /dev/null +++ b/database/migrations/2025_01_07_215741_create_show_translations_table.php @@ -0,0 +1,37 @@ +id(); + $table->unsignedBigInteger('show_id'); + $table->string('iso_3166', 10); + $table->string('iso_639', 10); + $table->string('name'); + $table->string('english_name'); + $table->string('homepage', 500); + $table->text('overview'); + $table->integer('runtime'); + $table->string('tagline', 500); + $table->string('title', 500); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('show_translations'); + } +}; diff --git a/database/migrations/2025_01_07_220757_create_show_watch_providers_table.php b/database/migrations/2025_01_07_220757_create_show_watch_providers_table.php new file mode 100644 index 0000000..c427bf9 --- /dev/null +++ b/database/migrations/2025_01_07_220757_create_show_watch_providers_table.php @@ -0,0 +1,31 @@ +id(); + $table->unsignedBigInteger('show_id'); + $table->integer('watch_provider_id'); + $table->string('locale'); + $table->string('tmdb_url'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('show_watch_providers'); + } +}; diff --git a/database/migrations/2025_01_07_221734_create_show_recommendations_table.php b/database/migrations/2025_01_07_221734_create_show_recommendations_table.php new file mode 100644 index 0000000..0d06f51 --- /dev/null +++ b/database/migrations/2025_01_07_221734_create_show_recommendations_table.php @@ -0,0 +1,29 @@ +id(); + $table->unsignedBigInteger('show_id'); + $table->unsignedBigInteger('recommended_show_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('show_recommendations'); + } +}; diff --git a/database/migrations/2025_01_07_222751_create_show_similars_table.php b/database/migrations/2025_01_07_222751_create_show_similars_table.php new file mode 100644 index 0000000..41f6e17 --- /dev/null +++ b/database/migrations/2025_01_07_222751_create_show_similars_table.php @@ -0,0 +1,29 @@ +id(); + $table->unsignedBigInteger('show_id'); + $table->unsignedBigInteger('similar_show_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('show_similars'); + } +};