2023-01-15 15:01:07 +00:00
|
|
|
import { FetchError } from "ofetch";
|
2023-04-24 15:41:54 +00:00
|
|
|
|
2023-06-12 19:25:24 +00:00
|
|
|
import { formatJWMeta, mediaTypeToJW } from "./justwatch";
|
2023-06-13 08:41:54 +00:00
|
|
|
import { Tmdb } from "./tmdb";
|
2023-06-13 09:01:07 +00:00
|
|
|
import {
|
|
|
|
TTVMediaToMediaType,
|
|
|
|
Trakt,
|
|
|
|
formatTTVMeta,
|
|
|
|
mediaTypeToTTV,
|
|
|
|
} from "./trakttv";
|
2023-01-15 15:01:07 +00:00
|
|
|
import {
|
|
|
|
JWMediaResult,
|
2023-01-22 18:26:08 +00:00
|
|
|
JWSeasonMetaResult,
|
2023-01-15 15:01:07 +00:00
|
|
|
JW_API_BASE,
|
2023-06-12 19:25:24 +00:00
|
|
|
MWMediaMeta,
|
|
|
|
MWMediaType,
|
2023-06-13 08:41:54 +00:00
|
|
|
TMDBMovieData,
|
|
|
|
TMDBShowData,
|
|
|
|
TTVSeasonMetaResult,
|
2023-06-12 19:25:24 +00:00
|
|
|
} from "./types";
|
2023-04-24 15:41:54 +00:00
|
|
|
import { makeUrl, proxiedFetch } from "../helpers/fetch";
|
2023-01-13 23:12:56 +00:00
|
|
|
|
|
|
|
type JWExternalIdType =
|
|
|
|
| "eidr"
|
|
|
|
| "imdb_latest"
|
|
|
|
| "imdb"
|
|
|
|
| "tmdb_latest"
|
|
|
|
| "tmdb"
|
|
|
|
| "tms";
|
|
|
|
|
|
|
|
interface JWExternalId {
|
|
|
|
provider: JWExternalIdType;
|
|
|
|
external_id: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface JWDetailedMeta extends JWMediaResult {
|
|
|
|
external_ids: JWExternalId[];
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface DetailedMeta {
|
|
|
|
meta: MWMediaMeta;
|
2023-05-21 16:12:45 +00:00
|
|
|
imdbId?: string;
|
2023-05-21 19:00:35 +00:00
|
|
|
tmdbId?: string;
|
2023-01-13 23:12:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export async function getMetaFromId(
|
|
|
|
type: MWMediaType,
|
2023-01-22 18:26:08 +00:00
|
|
|
id: string,
|
|
|
|
seasonId?: string
|
2023-06-13 08:41:54 +00:00
|
|
|
): Promise<DetailedMeta | null> {
|
|
|
|
const result = await Trakt.searchById(id, mediaTypeToJW(type));
|
|
|
|
if (!result) return null;
|
|
|
|
const details = await Tmdb.getMediaDetails(id, type);
|
|
|
|
|
|
|
|
if (!details) return null;
|
|
|
|
|
|
|
|
let imdbId;
|
|
|
|
if (type === MWMediaType.MOVIE) {
|
|
|
|
imdbId = (details as TMDBMovieData).imdb_id ?? undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
let seasonData: TTVSeasonMetaResult | undefined;
|
|
|
|
|
|
|
|
if (type === MWMediaType.SERIES) {
|
|
|
|
const seasons = (details as TMDBShowData).seasons;
|
|
|
|
const season =
|
|
|
|
seasons?.find((v) => v.id.toString() === seasonId) ?? seasons?.[0];
|
|
|
|
|
|
|
|
const episodes = await Trakt.getEpisodes(
|
|
|
|
result.ttv_entity_id,
|
|
|
|
season?.season_number ?? 1
|
|
|
|
);
|
|
|
|
|
|
|
|
if (season && episodes) {
|
|
|
|
seasonData = {
|
|
|
|
id: season.id.toString(),
|
|
|
|
season_number: season.season_number,
|
|
|
|
title: season.name,
|
|
|
|
episodes,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const meta = formatTTVMeta(result, seasonData);
|
|
|
|
if (!meta) return null;
|
|
|
|
|
|
|
|
console.log(meta);
|
|
|
|
|
|
|
|
return {
|
|
|
|
meta,
|
|
|
|
imdbId,
|
|
|
|
tmdbId: id,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function getLegacyMetaFromId(
|
|
|
|
type: MWMediaType,
|
|
|
|
id: string,
|
|
|
|
seasonId?: string
|
2023-01-15 15:01:07 +00:00
|
|
|
): Promise<DetailedMeta | null> {
|
|
|
|
const queryType = mediaTypeToJW(type);
|
|
|
|
|
|
|
|
let data: JWDetailedMeta;
|
|
|
|
try {
|
|
|
|
const url = makeUrl("/content/titles/{type}/{id}/locale/en_US", {
|
|
|
|
type: queryType,
|
|
|
|
id,
|
|
|
|
});
|
2023-01-22 19:51:58 +00:00
|
|
|
data = await proxiedFetch<JWDetailedMeta>(url, { baseURL: JW_API_BASE });
|
2023-01-15 15:01:07 +00:00
|
|
|
} catch (err) {
|
|
|
|
if (err instanceof FetchError) {
|
|
|
|
// 400 and 404 are treated as not found
|
|
|
|
if (err.statusCode === 400 || err.statusCode === 404) return null;
|
|
|
|
}
|
|
|
|
throw err;
|
|
|
|
}
|
2023-01-13 23:12:56 +00:00
|
|
|
|
2023-03-10 19:54:56 +00:00
|
|
|
let imdbId = data.external_ids.find(
|
2023-01-13 23:12:56 +00:00
|
|
|
(v) => v.provider === "imdb_latest"
|
2023-03-10 19:59:10 +00:00
|
|
|
)?.external_id;
|
2023-03-10 19:54:56 +00:00
|
|
|
if (!imdbId)
|
2023-03-10 19:59:10 +00:00
|
|
|
imdbId = data.external_ids.find((v) => v.provider === "imdb")?.external_id;
|
2023-03-10 19:54:56 +00:00
|
|
|
|
2023-05-21 19:00:35 +00:00
|
|
|
let tmdbId = data.external_ids.find(
|
|
|
|
(v) => v.provider === "tmdb_latest"
|
|
|
|
)?.external_id;
|
|
|
|
if (!tmdbId)
|
|
|
|
tmdbId = data.external_ids.find((v) => v.provider === "tmdb")?.external_id;
|
|
|
|
|
2023-01-22 18:26:08 +00:00
|
|
|
let seasonData: JWSeasonMetaResult | undefined;
|
|
|
|
if (data.object_type === "show") {
|
|
|
|
const seasonToScrape = seasonId ?? data.seasons?.[0].id.toString() ?? "";
|
|
|
|
const url = makeUrl("/content/titles/show_season/{id}/locale/en_US", {
|
|
|
|
id: seasonToScrape,
|
|
|
|
});
|
2023-01-22 19:51:58 +00:00
|
|
|
seasonData = await proxiedFetch<any>(url, { baseURL: JW_API_BASE });
|
2023-01-22 18:26:08 +00:00
|
|
|
}
|
|
|
|
|
2023-01-13 23:12:56 +00:00
|
|
|
return {
|
2023-01-22 18:26:08 +00:00
|
|
|
meta: formatJWMeta(data, seasonData),
|
2023-01-13 23:12:56 +00:00
|
|
|
imdbId,
|
2023-05-21 19:00:35 +00:00
|
|
|
tmdbId,
|
2023-01-13 23:12:56 +00:00
|
|
|
};
|
|
|
|
}
|
2023-06-13 09:01:07 +00:00
|
|
|
|
|
|
|
export function MWMediaToId(media: MWMediaMeta): string {
|
|
|
|
return ["MW", mediaTypeToTTV(media.type), media.id].join("-");
|
|
|
|
}
|
|
|
|
|
|
|
|
export function decodeMWId(
|
|
|
|
paramId: string
|
|
|
|
): { id: string; type: MWMediaType } | null {
|
|
|
|
const [prefix, type, id] = paramId.split("-", 3);
|
|
|
|
if (prefix !== "MW") return null;
|
|
|
|
let mediaType;
|
|
|
|
try {
|
|
|
|
mediaType = TTVMediaToMediaType(type);
|
|
|
|
} catch {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
type: mediaType,
|
|
|
|
id,
|
|
|
|
};
|
|
|
|
}
|