From 745fd213f964bfad34b5e6b55b8e29557544e2f5 Mon Sep 17 00:00:00 2001 From: Vivy Bot Date: Thu, 5 Feb 2026 20:59:34 +0700 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20automatic=20thumbnail?= =?UTF-8?q?=20generation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/episode/episode.model.ts | 3 ++ .../PUT/updateEpisode.repository.ts | 18 +++++++++ .../updateAllEpisodeThumbnail.controller.ts | 21 +++++++++++ src/modules/internal/index.ts | 2 + ...tAllEpisodeWithThumbnailLink.repository.ts | 34 +++++++++++++++++ .../http/updateAllEpisodeThumbnail.service.ts | 37 +++++++++++++++++++ 6 files changed, 115 insertions(+) create mode 100644 src/modules/episode/episode.model.ts create mode 100644 src/modules/episode/repositories/PUT/updateEpisode.repository.ts create mode 100644 src/modules/internal/controllers/updateAllEpisodeThumbnail.controller.ts create mode 100644 src/modules/internal/repositories/getAllEpisodeWithThumbnailLink.repository.ts create mode 100644 src/modules/internal/services/http/updateAllEpisodeThumbnail.service.ts diff --git a/src/modules/episode/episode.model.ts b/src/modules/episode/episode.model.ts new file mode 100644 index 0000000..368dbc3 --- /dev/null +++ b/src/modules/episode/episode.model.ts @@ -0,0 +1,3 @@ +import { prisma } from "../../utils/databases/prisma/connection"; + +export const episodeModel = prisma.episode; diff --git a/src/modules/episode/repositories/PUT/updateEpisode.repository.ts b/src/modules/episode/repositories/PUT/updateEpisode.repository.ts new file mode 100644 index 0000000..92b09ec --- /dev/null +++ b/src/modules/episode/repositories/PUT/updateEpisode.repository.ts @@ -0,0 +1,18 @@ +import { Prisma } from "@prisma/client"; +import { AppError } from "../../../../helpers/error/instances/app"; +import { episodeModel } from "../../episode.model"; + +export const updateEpisodeRepository = async ( + payload: Prisma.EpisodeUncheckedUpdateInput, +) => { + try { + return await episodeModel.update({ + where: { + id: payload.id as string, + }, + data: payload, + }); + } catch (error) { + throw new AppError(500, "Failed to edit episode", error); + } +}; diff --git a/src/modules/internal/controllers/updateAllEpisodeThumbnail.controller.ts b/src/modules/internal/controllers/updateAllEpisodeThumbnail.controller.ts new file mode 100644 index 0000000..0e58fed --- /dev/null +++ b/src/modules/internal/controllers/updateAllEpisodeThumbnail.controller.ts @@ -0,0 +1,21 @@ +import { Context } from "elysia"; +import { mainErrorHandler } from "../../../helpers/error/handler"; +import { returnWriteResponse } from "../../../helpers/callback/httpResponse"; +import { updateAllEpisodeThumbnailService } from "../services/http/updateAllEpisodeThumbnail.service"; + +export const updateAllEpisodeThumbnailController = async ( + ctx: Context & { body: { service_reference_id: string } }, +) => { + try { + const newEpisodeThumbnailsCount = await updateAllEpisodeThumbnailService( + ctx.body.service_reference_id, + ); + return returnWriteResponse( + ctx.set, + 204, + `Updating ${newEpisodeThumbnailsCount} episode thumbnails successfully.`, + ); + } catch (error) { + return mainErrorHandler(ctx.set, error); + } +}; diff --git a/src/modules/internal/index.ts b/src/modules/internal/index.ts index 471c1c9..f80574b 100644 --- a/src/modules/internal/index.ts +++ b/src/modules/internal/index.ts @@ -3,9 +3,11 @@ import { bulkInsertEpisodeController } from "./controllers/bulkInsertEpisode.con import { bulkInsertMediaController } from "./controllers/bulkInsertMedia.controller"; import { createVideoServiceInternalController } from "./controllers/createVideoService.controller"; import { bulkInsertVideoController } from "./controllers/bulkInsertVideo.controller"; +import { updateAllEpisodeThumbnailController } from "./controllers/updateAllEpisodeThumbnail.controller"; export const internalModule = new Elysia({ prefix: "/internal" }) .post("/media/bulk-insert", bulkInsertMediaController) .post("/episode/bulk-insert", bulkInsertEpisodeController) + .post("/episode/update-thumbnails", updateAllEpisodeThumbnailController) .post("/video/bulk-insert", bulkInsertVideoController) .post("/video-service", createVideoServiceInternalController); diff --git a/src/modules/internal/repositories/getAllEpisodeWithThumbnailLink.repository.ts b/src/modules/internal/repositories/getAllEpisodeWithThumbnailLink.repository.ts new file mode 100644 index 0000000..07a19e3 --- /dev/null +++ b/src/modules/internal/repositories/getAllEpisodeWithThumbnailLink.repository.ts @@ -0,0 +1,34 @@ +import { AppError } from "../../../helpers/error/instances/app"; +import { prisma } from "../../../utils/databases/prisma/connection"; + +export const getAllEpisodeWithThumbnailLinkRepository = async ( + serviceReferenceId: string, +) => { + try { + return await prisma.episode.findMany({ + where: { + deletedAt: null, + }, + select: { + id: true, + episode: true, + videos: { + where: { + deletedAt: null, + serviceId: serviceReferenceId, + }, + select: { + code: true, + service: { + select: { + endpointThumbnail: true, + }, + }, + }, + }, + }, + }); + } catch (error) { + throw new AppError(500, "Failed to update all episode thumbnails", error); + } +}; diff --git a/src/modules/internal/services/http/updateAllEpisodeThumbnail.service.ts b/src/modules/internal/services/http/updateAllEpisodeThumbnail.service.ts new file mode 100644 index 0000000..2d936e0 --- /dev/null +++ b/src/modules/internal/services/http/updateAllEpisodeThumbnail.service.ts @@ -0,0 +1,37 @@ +import { AppError } from "../../../../helpers/error/instances/app"; +import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder"; +import { updateEpisodeRepository } from "../../../episode/repositories/PUT/updateEpisode.repository"; +import { getAllEpisodeWithThumbnailLinkRepository } from "../../repositories/getAllEpisodeWithThumbnailLink.repository"; + +export const updateAllEpisodeThumbnailService = async ( + serviceReferenceId: string, +) => { + try { + if (!serviceReferenceId) + throw new AppError(400, "Service Reference ID is required."); + + const episodesData = await getAllEpisodeWithThumbnailLinkRepository( + serviceReferenceId, + ); + console.log("episodesData", episodesData); + + let updatedThumbnailsCount = 0; + for (const episode of episodesData) { + if (episode.videos.length === 0) continue; + await updateEpisodeRepository({ + id: episode.id, + pictureThumbnail: + episode.videos[0].service.endpointThumbnail?.replace( + ":code:", + episode.videos[0].code, + ) || null, + }); + + updatedThumbnailsCount++; + } + + return updatedThumbnailsCount; + } catch (error) { + ErrorForwarder(error); + } +};