From 3af98373fbafc7d979492fb87d21033bd2241890 Mon Sep 17 00:00:00 2001
From: castdrian <adrifcastr@gmail.com>
Date: Tue, 13 Jun 2023 10:41:54 +0200
Subject: [PATCH] finish initial refactor

---
 src/backend/metadata/getmeta.ts | 55 +++++++++++++++++++++++++++++++++
 src/backend/metadata/search.ts  |  1 +
 src/backend/metadata/tmdb.ts    | 27 ----------------
 src/backend/metadata/trakttv.ts | 45 ++++++++++++++++++++-------
 src/backend/metadata/types.ts   | 12 +++++++
 5 files changed, 101 insertions(+), 39 deletions(-)

diff --git a/src/backend/metadata/getmeta.ts b/src/backend/metadata/getmeta.ts
index c4771451..e428199e 100644
--- a/src/backend/metadata/getmeta.ts
+++ b/src/backend/metadata/getmeta.ts
@@ -1,12 +1,17 @@
 import { FetchError } from "ofetch";
 
 import { formatJWMeta, mediaTypeToJW } from "./justwatch";
+import { Tmdb } from "./tmdb";
+import { Trakt, formatTTVMeta } from "./trakttv";
 import {
   JWMediaResult,
   JWSeasonMetaResult,
   JW_API_BASE,
   MWMediaMeta,
   MWMediaType,
+  TMDBMovieData,
+  TMDBShowData,
+  TTVSeasonMetaResult,
 } from "./types";
 import { makeUrl, proxiedFetch } from "../helpers/fetch";
 
@@ -37,6 +42,56 @@ export async function getMetaFromId(
   type: MWMediaType,
   id: string,
   seasonId?: string
+): 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
 ): Promise<DetailedMeta | null> {
   const queryType = mediaTypeToJW(type);
 
diff --git a/src/backend/metadata/search.ts b/src/backend/metadata/search.ts
index 4506514a..8eb246b7 100644
--- a/src/backend/metadata/search.ts
+++ b/src/backend/metadata/search.ts
@@ -16,6 +16,7 @@ export async function searchForMedia(query: MWQuery): Promise<MWMediaMeta[]> {
   const contentType = mediaTypeToTTV(type);
 
   const results = await Trakt.search(searchQuery, contentType);
+  console.log(results[0]);
   cache.set(query, results, 3600);
   return results;
 }
diff --git a/src/backend/metadata/tmdb.ts b/src/backend/metadata/tmdb.ts
index 460e13b4..3aa1821f 100644
--- a/src/backend/metadata/tmdb.ts
+++ b/src/backend/metadata/tmdb.ts
@@ -47,31 +47,4 @@ export abstract class Tmdb {
   public static getMediaPoster(posterPath: string | null): string | undefined {
     if (posterPath) return `https://image.tmdb.org/t/p/w185/${posterPath}`;
   }
-
-  /* public static async getMetaFromId(
-    type: MWMediaType,
-    id: string,
-    seasonId?: string
-  ): Promise<DetailedMeta | null> {
-    console.log("getMetaFromId", type, id, seasonId);
-
-    const details = await Tmdb.getMediaDetails(id, type);
-
-    if (!details) return null;
-
-    let imdbId;
-    if (type === MWMediaType.MOVIE) {
-      imdbId = (details as TMDBMovieData).imdb_id ?? undefined;
-    }
-
-    if (!meta.length) return null;
-
-    console.log(meta);
-
-    return {
-      meta,
-      imdbId,
-      tmdbId: id,
-    };
-  } */
 }
diff --git a/src/backend/metadata/trakttv.ts b/src/backend/metadata/trakttv.ts
index 5fb67a17..ae50aefe 100644
--- a/src/backend/metadata/trakttv.ts
+++ b/src/backend/metadata/trakttv.ts
@@ -2,12 +2,13 @@ import { conf } from "@/setup/config";
 
 import { Tmdb } from "./tmdb";
 import {
-  DetailedMeta,
   MWMediaMeta,
   MWMediaType,
   MWSeasonMeta,
   TMDBShowData,
   TTVContentTypes,
+  TTVEpisodeResult,
+  TTVEpisodeShort,
   TTVMediaResult,
   TTVSearchResult,
   TTVSeasonMetaResult,
@@ -69,14 +70,14 @@ export function formatTTVMeta(
 }
 
 export function TTVMediaToId(media: MWMediaMeta): string {
-  return ["TTV", mediaTypeToTTV(media.type), media.id].join("-");
+  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 !== "TTV") return null;
+  if (prefix !== "MW") return null;
   let mediaType;
   try {
     mediaType = TTVMediaToMediaType(type);
@@ -101,7 +102,6 @@ export async function formatTTVSearchResult(
     media.ids.tmdb.toString(),
     TTVMediaToMediaType(result.type)
   );
-  console.log(details);
 
   const seasons =
     type === MWMediaType.SERIES
@@ -115,7 +115,7 @@ export async function formatTTVSearchResult(
   return {
     title: media.title,
     poster: Tmdb.getMediaPoster(details.poster_path),
-    id: media.ids.trakt,
+    id: media.ids.tmdb,
     original_release_year: media.year,
     ttv_entity_id: media.ids.slug,
     object_type: mediaTypeToTTV(type),
@@ -155,12 +155,33 @@ export abstract class Trakt {
     return formatted.map((v) => formatTTVMeta(v));
   }
 
-  public static async getMetaFromId(
-    type: MWMediaType,
-    id: string,
-    seasonId?: string
-  ): Promise<DetailedMeta | null> {
-    console.log("getMetaFromId", type, id, seasonId);
-    return null;
+  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,
+    }));
   }
 }
diff --git a/src/backend/metadata/types.ts b/src/backend/metadata/types.ts
index 9e87d49d..07671e39 100644
--- a/src/backend/metadata/types.ts
+++ b/src/backend/metadata/types.ts
@@ -311,3 +311,15 @@ export type JWSeasonMetaResult = {
   season_number: number;
   episodes: JWEpisodeShort[];
 };
+
+export interface TTVEpisodeResult {
+  season: number;
+  number: number;
+  title: string;
+  ids: {
+    trakt: number;
+    tvdb: number;
+    imdb: string;
+    tmdb: number;
+  };
+}