8 changed files with 315 additions and 264 deletions
@ -1,187 +0,0 @@
@@ -1,187 +0,0 @@
|
||||
import { conf } from "@/setup/config"; |
||||
|
||||
import { Tmdb } from "./tmdb"; |
||||
import { |
||||
MWMediaMeta, |
||||
MWMediaType, |
||||
MWSeasonMeta, |
||||
TMDBShowData, |
||||
TTVContentTypes, |
||||
TTVEpisodeResult, |
||||
TTVEpisodeShort, |
||||
TTVMediaResult, |
||||
TTVSearchResult, |
||||
TTVSeasonMetaResult, |
||||
} from "./types"; |
||||
import { mwFetch } from "../helpers/fetch"; |
||||
|
||||
export function mediaTypeToTTV(type: MWMediaType): TTVContentTypes { |
||||
if (type === MWMediaType.MOVIE) return "movie"; |
||||
if (type === MWMediaType.SERIES) return "show"; |
||||
throw new Error("unsupported type"); |
||||
} |
||||
|
||||
export function TTVMediaToMediaType(type: string): MWMediaType { |
||||
if (type === "movie") return MWMediaType.MOVIE; |
||||
if (type === "show") return MWMediaType.SERIES; |
||||
throw new Error("unsupported type"); |
||||
} |
||||
|
||||
export function formatTTVMeta( |
||||
media: TTVMediaResult, |
||||
season?: TTVSeasonMetaResult |
||||
): MWMediaMeta { |
||||
const type = TTVMediaToMediaType(media.object_type); |
||||
let seasons: undefined | MWSeasonMeta[]; |
||||
if (type === MWMediaType.SERIES) { |
||||
seasons = media.seasons |
||||
?.sort((a, b) => a.season_number - b.season_number) |
||||
.map( |
||||
(v): MWSeasonMeta => ({ |
||||
title: v.title, |
||||
id: v.id.toString(), |
||||
number: v.season_number, |
||||
}) |
||||
); |
||||
} |
||||
|
||||
return { |
||||
title: media.title, |
||||
id: media.id.toString(), |
||||
year: media.original_release_year?.toString(), |
||||
poster: media.poster, |
||||
type, |
||||
seasons: seasons as any, |
||||
seasonData: season |
||||
? ({ |
||||
id: season.id.toString(), |
||||
number: season.season_number, |
||||
title: season.title, |
||||
episodes: season.episodes |
||||
.sort((a, b) => a.episode_number - b.episode_number) |
||||
.map((v) => ({ |
||||
id: v.id.toString(), |
||||
number: v.episode_number, |
||||
title: v.title, |
||||
})), |
||||
} as any) |
||||
: (undefined as any), |
||||
}; |
||||
} |
||||
|
||||
export function TTVMediaToId(media: MWMediaMeta): string { |
||||
return ["MW", mediaTypeToTTV(media.type), media.id].join("-"); |
||||
} |
||||
|
||||
export function decodeTTVId( |
||||
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, |
||||
}; |
||||
} |
||||
|
||||
export async function formatTTVSearchResult( |
||||
result: TTVSearchResult |
||||
): Promise<TTVMediaResult> { |
||||
const type = TTVMediaToMediaType(result.type); |
||||
const media = result[result.type]; |
||||
|
||||
if (!media) throw new Error("invalid result"); |
||||
|
||||
const details = await Tmdb.getMediaDetails( |
||||
media.ids.tmdb.toString(), |
||||
TTVMediaToMediaType(result.type) |
||||
); |
||||
|
||||
const seasons = |
||||
type === MWMediaType.SERIES |
||||
? (details as TMDBShowData).seasons?.map((v) => ({ |
||||
id: v.id, |
||||
title: v.name, |
||||
season_number: v.season_number, |
||||
})) |
||||
: undefined; |
||||
|
||||
return { |
||||
title: media.title, |
||||
poster: Tmdb.getMediaPoster(details.poster_path), |
||||
id: media.ids.tmdb, |
||||
original_release_year: media.year, |
||||
ttv_entity_id: media.ids.slug, |
||||
object_type: mediaTypeToTTV(type), |
||||
seasons, |
||||
}; |
||||
} |
||||
|
||||
export abstract class Trakt { |
||||
private static baseURL = "https://api.trakt.tv"; |
||||
|
||||
private static headers = { |
||||
"Content-Type": "application/json", |
||||
"trakt-api-version": "2", |
||||
"trakt-api-key": conf().TRAKT_CLIENT_ID, |
||||
}; |
||||
|
||||
private static async get<T>(url: string): Promise<T> { |
||||
const res = await mwFetch<any>(url, { |
||||
headers: Trakt.headers, |
||||
baseURL: Trakt.baseURL, |
||||
}); |
||||
return res; |
||||
} |
||||
|
||||
public static async search( |
||||
query: string, |
||||
type: "movie" | "show" |
||||
): Promise<MWMediaMeta[]> { |
||||
const data = await Trakt.get<TTVSearchResult[]>( |
||||
`/search/${type}?query=${encodeURIComponent(query)}` |
||||
); |
||||
|
||||
const formatted = await Promise.all( |
||||
// eslint-disable-next-line no-return-await
|
||||
data.map(async (v) => await formatTTVSearchResult(v)) |
||||
); |
||||
return formatted.map((v) => formatTTVMeta(v)); |
||||
} |
||||
|
||||
public static async searchById( |
||||
tmdbId: string, |
||||
type: "movie" | "show" |
||||
): Promise<TTVMediaResult> { |
||||
const data = await Trakt.get<TTVSearchResult[]>( |
||||
`/search/tmdb/${tmdbId}?type=${type}` |
||||
); |
||||
|
||||
const formatted = await Promise.all( |
||||
// eslint-disable-next-line no-return-await
|
||||
data.map(async (v) => await formatTTVSearchResult(v)) |
||||
); |
||||
return formatted[0]; |
||||
} |
||||
|
||||
public static async getEpisodes( |
||||
slug: string, |
||||
season: number |
||||
): Promise<TTVEpisodeShort[]> { |
||||
const data = await Trakt.get<TTVEpisodeResult[]>( |
||||
`/shows/${slug}/seasons/${season}` |
||||
); |
||||
|
||||
return data.map((e) => ({ |
||||
id: e.ids.tmdb, |
||||
episode_number: e.number, |
||||
title: e.title, |
||||
})); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue