Files
mtdb_movie/app/Services/Data/Tmdb/TmdbApi.php
maher 703f50a09d
Some checks failed
Build / run (push) Has been cancelled
first commit
2025-10-29 11:42:25 +01:00

226 lines
6.4 KiB
PHP
Executable File

<?php
namespace App\Services\Data\Tmdb;
use App\Actions\People\DeletePeople;
use App\Actions\Titles\DeleteSeasons;
use App\Actions\Titles\DeleteTitles;
use App\Models\Person;
use App\Models\Title;
use Common\Core\HttpClient;
use Common\Settings\Settings;
use Exception;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
class TmdbApi
{
public const TMDB_BASE = 'https://api.themoviedb.org/3/';
public const DEFAULT_TMDB_LANGUAGE = 'en-US';
protected bool $includeAdult = false;
protected string $language = self::DEFAULT_TMDB_LANGUAGE;
protected HttpClient $http;
public function __construct(private Settings $settings)
{
$this->http = new HttpClient(['exceptions' => true]);
$this->language = $this->settings->get(
'tmdb.language',
self::DEFAULT_TMDB_LANGUAGE,
);
$this->includeAdult = $this->settings->get('tmdb.includeAdult', false);
}
public function getPerson(Person $person): array|null
{
$appends = [];
// only import filmography if it's set by user
if ($this->settings->get('content.automate_filmography')) {
$appends[] = 'combined_credits';
}
$response = $this->call("person/{$person->tmdb_id}", [
'append_to_response' => implode(',', $appends),
]);
// person does not exist anymore on themoviedb
if (
Arr::get($response, 'success') === false &&
Arr::get($response, 'status_code') === 34
) {
if (config('common.site.tmdb_delete_when_sync')) {
app(DeletePeople::class)->execute([$person->id]);
return null;
} else {
return [];
}
}
$response['fully_synced'] = true;
return app(TransformData::class)
->execute([$response])
->first();
}
public function getSeason(Title $title, $seasonNumber)
{
if (!$title->tmdb_id) {
return [];
}
$response = $this->call("tv/{$title->tmdb_id}/season/{$seasonNumber}", [
'append_to_response' => 'credits',
]);
// season does not exist anymore on themoviedb
if (
Arr::get($response, 'success') === false &&
Arr::get($response, 'status_code') === 34
) {
if (config('common.site.tmdb_delete_when_sync')) {
$seasonId = $title
->seasons()
->where('number', $seasonNumber)
->value('id');
app(DeleteSeasons::class)->execute([$seasonId]);
return null;
} else {
return [];
}
}
$data = app(TransformData::class)
->execute([$response])
->first();
$data['fully_synced'] = true;
return $data;
}
public function getTitle(Title $title): array|null
{
$appends = [
'credits',
'external_ids',
'images',
'content_ratings',
'keywords',
'release_dates',
'videos',
'seasons',
];
$uri = $title->is_series ? 'tv' : 'movie';
$response = $this->call("$uri/{$title->tmdb_id}", [
'append_to_response' => implode(',', $appends),
]);
// title does not exist anymore on themoviedb
if (
Arr::get($response, 'success') === false &&
Arr::get($response, 'status_code') === 34
) {
if (config('common.site.tmdb_delete_when_sync')) {
app(DeleteTitles::class)->execute([$title->id]);
return null;
} else {
return [];
}
}
$data = app(TransformData::class)
->execute([$response])
->first();
// fall back to english videos if there are no videos in the current language
if (!Str::startsWith($this->language, 'en') && empty($data['videos'])) {
$videos = $this->call("$uri/{$title->tmdb_id}/videos", [
'language' => 'en-US',
]);
$videos = app(TransformData::class)->formatVideos(
$videos['results'],
);
$data['videos'] = $videos;
}
$data['fully_synced'] = true;
return $data;
}
public function search(string $query, array $params = []): Collection
{
$response = $this->call('search/multi', ['query' => $query]);
$results = app(TransformData::class)->execute($response['results']);
$type = Arr::get($params, 'type');
$limit = Arr::get($params, 'limit', 8);
if ($type) {
$results = $results->filter(
fn($result) => $result['type'] === $type,
);
}
return $results
->sortByDesc('popularity')
->slice(0, $limit)
->values();
}
public function browse($page = 1, $type = 'movie', $queryParams = []): array
{
if ($page > 500) {
throw new Exception('Maximum page is 500');
}
if ($type === 'series') {
$type = 'tv';
}
$apiParams = array_merge(
['sort_by' => 'popularity.desc', 'page' => $page],
$queryParams,
);
$response = $this->call("discover/$type", $apiParams);
$response['results'] = app(TransformData::class)->execute(
$response['results'],
);
return $response;
}
public function trendingPeople(): Collection
{
$response = $this->call('person/popular');
return app(TransformData::class)->execute($response['results']);
}
protected function call(string $uri, array $queryParams = []): array
{
$key = config('services.tmdb.key');
$url = self::TMDB_BASE . "$uri?api_key=$key";
$queryParams = array_merge(
[
// need to send "true" and not "1" otherwise tmdb will not work
'include_adult' => $this->includeAdult ? 'true' : 'false',
'language' => $this->language,
'region' => 'US',
'include_image_language' => 'en,null',
],
$queryParams,
);
$url .= '&' . urldecode(http_build_query($queryParams));
return $this->http->get($url, [
'verify' => false,
]);
}
}