coryd.dev/api/watching-import.php

152 lines
4.6 KiB
PHP

<?php
require_once __DIR__.'/../bootstrap.php';
use App\Classes\ApiHandler;
use GuzzleHttp\Client;
class WatchingImportHandler extends ApiHandler
{
private string $tmdbApiKey;
private string $tmdbImportToken;
public function __construct()
{
parent::__construct();
$this->ensureCliAccess();
$this->tmdbApiKey = $_ENV['TMDB_API_KEY'] ?? getenv('TMDB_API_KEY');
$this->tmdbImportToken = $_ENV['WATCHING_IMPORT_TOKEN'] ?? getenv('WATCHING_IMPORT_TOKEN');
}
public function handleRequest(): void
{
$input = json_decode(file_get_contents('php://input'), true);
if (! $input) {
$this->sendErrorResponse('Invalid or missing JSON body', 400);
}
$providedToken = $input['token'] ?? null;
$tmdbId = $input['tmdb_id'] ?? null;
$mediaType = $input['media_type'] ?? null;
if ($providedToken !== $this->tmdbImportToken) {
$this->sendErrorResponse('Unauthorized access', 401);
}
if (! $tmdbId || ! $mediaType) {
$this->sendErrorResponse('tmdb_id and media_type are required', 400);
}
try {
$mediaData = $this->fetchTMDBData($tmdbId, $mediaType);
$this->processMedia($mediaData, $mediaType);
$this->sendResponse(['message' => 'Media imported successfully'], 200);
} catch (\Exception $e) {
$this->sendErrorResponse('Error: '.$e->getMessage(), 500);
}
}
private function fetchTMDBData(string $tmdbId, string $mediaType): array
{
$client = new Client();
$url = "https://api.themoviedb.org/3/{$mediaType}/{$tmdbId}";
$response = $client->get($url, [
'query' => ['api_key' => $this->tmdbApiKey],
'headers' => ['Accept' => 'application/json'],
]);
$data = json_decode($response->getBody(), true);
if (empty($data)) {
throw new \Exception("No data found for TMDB ID: {$tmdbId}");
}
return $data;
}
private function processMedia(array $mediaData, string $mediaType): void
{
$tagline = $mediaData['tagline'] ?? null;
$overview = $mediaData['overview'] ?? null;
$description = '';
if (! empty($tagline)) {
$description .= '> '.trim($tagline)."\n\n";
}
if (! empty($overview)) {
$description .= trim($overview);
}
$id = $mediaData['id'];
$title = $mediaType === 'movie' ? $mediaData['title'] : $mediaData['name'];
$year = $mediaData['release_date'] ?? $mediaData['first_air_date'] ?? null;
$year = $year ? substr($year, 0, 4) : null;
$tags = array_map(
fn ($genre) => strtolower(trim($genre['name'])),
$mediaData['genres'] ?? []
);
$slug = $mediaType === 'movie'
? "/watching/movies/{$id}"
: "/watching/shows/{$id}";
$payload = [
'title' => $title,
'year' => $year,
'description' => $description,
'tmdb_id' => $id,
'slug' => $slug,
];
$table = $mediaType === 'movie' ? 'movies' : 'shows';
try {
$response = $this->makeRequest('POST', $table, [
'json' => $payload,
'headers' => ['Prefer' => 'return=representation'],
]);
} catch (\Exception $e) {
$response = $this->fetchFromApi($table, "tmdb_id=eq.{$id}")[0] ?? [];
}
$record = $response[0] ?? [];
if (! empty($record['id'])) {
$mediaId = $record['id'];
$tagIds = $this->getTagIds($tags);
if (! empty($tagIds)) {
$this->associateTagsWithMedia($mediaType, $mediaId, array_values($tagIds));
}
}
}
private function getTagIds(array $tags): array
{
$map = [];
foreach ($tags as $tag) {
$response = $this->fetchFromApi('tags', 'name=ilike.'.urlencode($tag));
if (! empty($response[0]['id'])) {
$map[strtolower($tag)] = $response[0]['id'];
}
}
return $map;
}
private function associateTagsWithMedia(string $mediaType, int $mediaId, array $tagIds): void
{
$junction = $mediaType === 'movie' ? 'movies_tags' : 'shows_tags';
$mediaColumn = $mediaType === 'movie' ? 'movies_id' : 'shows_id';
foreach ($tagIds as $tagId) {
$this->makeRequest('POST', $junction, ['json' => [
$mediaColumn => $mediaId,
'tags_id' => $tagId,
]]);
}
}
}
$handler = new WatchingImportHandler();
$handler->handleRequest();