From e60058c1c092e351eabaa84a91f4a4777150220e Mon Sep 17 00:00:00 2001 From: DoarMihai Date: Mon, 30 Dec 2024 22:41:34 +0200 Subject: [PATCH] [#1] lists --- .../Controllers/Auth/RegisterController.php | 2 + app/Models/MediaList.php | 20 ++++ app/Models/MediaListItem.php | 15 +++ app/Models/User.php | 7 ++ .../MovieProcessingService.php | 91 ++++++++++++++++++- app/Service/TMDBApi/ListApi.php | 12 +++ .../0001_01_01_000000_create_users_table.php | 2 + ..._12_30_170520_create_media_lists_table.php | 36 ++++++++ ...4_12_30_170605_create_user_media_lists.php | 29 ++++++ ...0_170611_create_media_list_items_table.php | 31 +++++++ routes/console.php | 24 ++++- 11 files changed, 264 insertions(+), 5 deletions(-) create mode 100644 app/Models/MediaList.php create mode 100644 app/Models/MediaListItem.php create mode 100644 app/Service/TMDBApi/ListApi.php create mode 100644 database/migrations/2024_12_30_170520_create_media_lists_table.php create mode 100644 database/migrations/2024_12_30_170605_create_user_media_lists.php create mode 100644 database/migrations/2024_12_30_170611_create_media_list_items_table.php diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 961ea36..d5698e8 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -7,6 +7,7 @@ use App\Models\User; use Illuminate\Foundation\Auth\RegistersUsers; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Validator; +use Illuminate\Support\Str; class RegisterController extends Controller { @@ -65,6 +66,7 @@ class RegisterController extends Controller { return User::create([ 'name' => $data['name'], + 'slug' => Str::slug($data['name']), 'email' => $data['email'], 'password' => Hash::make($data['password']), ]); diff --git a/app/Models/MediaList.php b/app/Models/MediaList.php new file mode 100644 index 0000000..1966c84 --- /dev/null +++ b/app/Models/MediaList.php @@ -0,0 +1,20 @@ + 'hashed', ]; } + + public function mediaLists() + { + return $this->belongsToMany(MediaList::class, 'user_media_lists', 'user_id', 'media_list_id'); + } } diff --git a/app/Service/MediaProcessing/MovieProcessingService.php b/app/Service/MediaProcessing/MovieProcessingService.php index b07a6ff..0c43659 100644 --- a/app/Service/MediaProcessing/MovieProcessingService.php +++ b/app/Service/MediaProcessing/MovieProcessingService.php @@ -6,16 +6,21 @@ use App\Models\Comment; use App\Models\ExternalId; use App\Models\Genre; use App\Models\Image; +use App\Models\ItemToFetch; use App\Models\ItemToFetchJobs; use App\Models\Keyword; +use App\Models\MediaList; +use App\Models\MediaListItem; use App\Models\Movie; use App\Models\MovieAlternativeTitle; use App\Models\MovieCollection; use App\Models\Person; use App\Models\ReleaseDate; use App\Models\Translation; +use App\Models\User; use App\Models\Video; use App\Models\WatchProvider; +use App\Service\TMDBApi\ListApi; use App\Service\TMDBApi\MoviesApi; use App\Service\TMDBApi\PersonApi; use Illuminate\Support\Str; @@ -24,13 +29,16 @@ class MovieProcessingService implements ProcessingInterface { private MoviesApi $moviesApi; private PersonApi $personApi; + private ListApi $listApi; public function __construct( MoviesApi $moviesApi, - PersonApi $personApi + PersonApi $personApi, + ListApi $listApi ) { $this->moviesApi = $moviesApi; $this->personApi = $personApi; + $this->listApi = $listApi; } public function process($item, $job) @@ -409,6 +417,87 @@ class MovieProcessingService implements ProcessingInterface $this->removeElementFromRemainingJobs($item->tmdb_id, ItemToFetchJobs::JOB_VIDEOS); } + public function getLists($item) + { + $tmdbLists = $this->moviesApi->getLists($item->tmdb_id); + + if (empty($tmdbLists) || empty($tmdbLists['results'])) { + return; + } + + foreach ($tmdbLists['results'] as $tmdbList) { + $list = MediaList::where('tmdb_id', $tmdbList['id'])->first(); + $tmdbList['tmdb_id'] = $tmdbList['id']; + unset($tmdbList['id']); + + if (!$list) { + $list = MediaList::create($tmdbList); + } + + $listDetails = $this->listApi->details($tmdbList['tmdb_id']); + + if (empty($listDetails)) { + continue; + } + + $user = User::where('name', $listDetails['created_by'])->first(); + + if (!$user) { + $user = User::create([ + 'name' => $listDetails['created_by'], + 'slug' => Str::slug($listDetails['created_by']), + 'email' => $listDetails['created_by'].'@nowhere.wtf', + 'password' => 'no_password_neeeded_here', + 'is_dummy_account' => true, + ]); + } + + if (!$user->whereHas('mediaLists', function ($query) use ($list) { + $query->where('media_list_id', $list->id); + })->exists()) { + $user->mediaLists()->attach($list); + } + + foreach ($tmdbList['items'] as $tmdbListItem) { + $mediaListItem = MediaListItem::where('media_list_id', $list->id) + ->where('tmdb_id', $tmdbListItem['id']) + ->first(); + + if (!$mediaListItem) { + $movie = Movie::where('tmdb_id', $item->tmdb_id)->first(); + + if (!$movie) { + $itemToFetch = ItemToFetch::where('tmdb_id', $item->tmdb_id)->first(); + + if (!$itemToFetch) { + $itemToFetch = ItemToFetch::create([ + 'tmdb_id' => $item->tmdb_id, + 'type' => ItemToFetch::TYPE_MOVIE, + ]); + + $jobs = ItemToFetchJobs::JOBS; + $jobs[] = "Details"; + + ItemToFetchJobs::create([ + 'tmdb_id' => $item->tmdb_id, + 'type' => ItemToFetch::TYPE_MOVIE, + 'remaining_jobs' => json_encode($jobs), + ]); + } + + MediaListItem::create([ + 'media_list_id' => $list->id, + 'item_type' => ItemToFetch::TYPE_MOVIE, + 'tmdb_id' => $item->tmdb_id, + ]); + } + } + } + } + + $this->removeElementFromRemainingJobs($item->tmdb_id, ItemToFetchJobs::JOB_LISTS); + } + private function processMovieCollection(int $movieId, $belongsToCollection) { $movieCollection = MovieCollection::where('tmdb_id', $belongsToCollection['id'])->first(); diff --git a/app/Service/TMDBApi/ListApi.php b/app/Service/TMDBApi/ListApi.php new file mode 100644 index 0000000..7855ba4 --- /dev/null +++ b/app/Service/TMDBApi/ListApi.php @@ -0,0 +1,12 @@ +get("list/" . $listId); + } +} diff --git a/database/migrations/0001_01_01_000000_create_users_table.php b/database/migrations/0001_01_01_000000_create_users_table.php index 05fb5d9..e13f4d0 100644 --- a/database/migrations/0001_01_01_000000_create_users_table.php +++ b/database/migrations/0001_01_01_000000_create_users_table.php @@ -14,9 +14,11 @@ return new class extends Migration Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); + $table->string('slug'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); + $table->boolean('is_dummy_account')->default(0); $table->rememberToken(); $table->timestamps(); }); diff --git a/database/migrations/2024_12_30_170520_create_media_lists_table.php b/database/migrations/2024_12_30_170520_create_media_lists_table.php new file mode 100644 index 0000000..7ef9121 --- /dev/null +++ b/database/migrations/2024_12_30_170520_create_media_lists_table.php @@ -0,0 +1,36 @@ +id(); + $table->text('description')->nullable(); + $table->integer('favorites_count')->default(0); + $table->unsignedBigInteger('tmdb_id'); + $table->integer('item_count')->default(0); + $table->string('iso_639_1', 2); + $table->string('iso_3166_1', 2); + $table->string('list_type', 15); + $table->string('name', 550); + $table->string('poster_path', 550); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('media_lists'); + } +}; diff --git a/database/migrations/2024_12_30_170605_create_user_media_lists.php b/database/migrations/2024_12_30_170605_create_user_media_lists.php new file mode 100644 index 0000000..634017f --- /dev/null +++ b/database/migrations/2024_12_30_170605_create_user_media_lists.php @@ -0,0 +1,29 @@ +id(); + $table->unsignedBigInteger('user_id'); + $table->unsignedBigInteger('media_list_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('user_media_lists'); + } +}; diff --git a/database/migrations/2024_12_30_170611_create_media_list_items_table.php b/database/migrations/2024_12_30_170611_create_media_list_items_table.php new file mode 100644 index 0000000..a042374 --- /dev/null +++ b/database/migrations/2024_12_30_170611_create_media_list_items_table.php @@ -0,0 +1,31 @@ +id(); + $table->unsignedBigInteger('media_list_id'); + $table->unsignedBigInteger('item_id'); + $table->enum('item_type', ['movie', 'show']); + $table->unsignedBigInteger('tmdb_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('media_list_items'); + } +}; diff --git a/routes/console.php b/routes/console.php index c9dcb0c..ed5fc49 100644 --- a/routes/console.php +++ b/routes/console.php @@ -12,11 +12,27 @@ Artisan::command('inspire', function () { })->purpose('Display an inspiring quote')->hourly(); // fetch export every week, saturday at 8 and 9 -Schedule::command(FetchExportCommand::class, ['type', 'movies'])->weeklyOn(6, '8:00'); -Schedule::command(FetchExportCommand::class, ['type', 'tv_series'])->weeklyOn(6, '9:00'); +Schedule::command(FetchExportCommand::class, ['movies'])->weeklyOn(6, '8:00'); +Schedule::command(FetchExportCommand::class, ['tv_series'])->weeklyOn(6, '9:00'); + +Schedule::command(FetchExportItemsCommand::class, ['movie'])->twiceDaily(17,19); +Schedule::command(FetchExportItemsCommand::class, ['movie', '50', 'AlternativeTitles'])->twiceDaily(14,23); +Schedule::command(FetchExportItemsCommand::class, ['movie', '50', 'Credits'])->twiceDaily(14,23); +Schedule::command(FetchExportItemsCommand::class, ['movie', '50', 'Images'])->twiceDaily(14,23); +Schedule::command(FetchExportItemsCommand::class, ['movie', '50', 'Keywords'])->twiceDaily(14,23); +Schedule::command(FetchExportItemsCommand::class, ['movie', '50', 'Releases'])->twiceDaily(14,23); +Schedule::command(FetchExportItemsCommand::class, ['movie', '50', 'Translations'])->twiceDaily(14,23); +Schedule::command(FetchExportItemsCommand::class, ['movie', '50', 'Similar'])->twiceDaily(14,23); +Schedule::command(FetchExportItemsCommand::class, ['movie', '50', 'Recommendations'])->twiceDaily(14,23); +Schedule::command(FetchExportItemsCommand::class, ['movie', '50', 'Reviews'])->twiceDaily(14,23); +Schedule::command(FetchExportItemsCommand::class, ['movie', '50', 'Lists'])->twiceDaily(14,23); +Schedule::command(FetchExportItemsCommand::class, ['movie', '50', 'Changes'])->twiceDaily(14,23); +Schedule::command(FetchExportItemsCommand::class, ['movie', '50', 'Videos'])->twiceDaily(14,23); +Schedule::command(FetchExportItemsCommand::class, ['movie', '50', 'WatchProviders'])->twiceDaily(14,23); +Schedule::command(FetchExportItemsCommand::class, ['movie', '50', 'ExternalIds'])->twiceDaily(14,23); + +Schedule::command(FetchExportItemsCommand::class, ['tv_series'])->twiceDaily(17,19); -Schedule::command(FetchExportItemsCommand::class, ['type', 'movie'])->twiceDaily(17,19); -Schedule::command(FetchExportItemsCommand::class, ['type', 'tv_series'])->twiceDaily(17,19); // fetch items data Schedule::command(FetchItemDataCommand::class)->twiceDaily(18,20);