wip: reconstruct bulk insert video service
This commit is contained in:
@ -538,8 +538,9 @@ Table episodes {
|
|||||||
|
|
||||||
Table videos {
|
Table videos {
|
||||||
id String [pk]
|
id String [pk]
|
||||||
service video_services [not null]
|
video_service video_services [not null]
|
||||||
episode episodes [not null]
|
episode episodes [not null]
|
||||||
|
priority Int
|
||||||
video_code String [not null]
|
video_code String [not null]
|
||||||
short_code String
|
short_code String
|
||||||
thumbnail_code String
|
thumbnail_code String
|
||||||
@ -551,6 +552,11 @@ Table videos {
|
|||||||
media_id String [not null]
|
media_id String [not null]
|
||||||
created_by_id String [not null]
|
created_by_id String [not null]
|
||||||
video_submission video_submissions
|
video_submission video_submissions
|
||||||
|
video_service_id String [not null]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(media_id, episode_number, priority) [unique]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Table video_submissions {
|
Table video_submissions {
|
||||||
@ -695,11 +701,6 @@ Table home_media_banners {
|
|||||||
created_by_id String [not null]
|
created_by_id String [not null]
|
||||||
}
|
}
|
||||||
|
|
||||||
Table VideoToVideoService {
|
|
||||||
serviceId String [ref: > video_services.id]
|
|
||||||
videosId String [ref: > videos.id]
|
|
||||||
}
|
|
||||||
|
|
||||||
Enum user_role {
|
Enum user_role {
|
||||||
user
|
user
|
||||||
contributor
|
contributor
|
||||||
@ -887,6 +888,8 @@ Ref: episodes.created_by_id > users.id
|
|||||||
|
|
||||||
Ref: episodes.media_id > medias.id
|
Ref: episodes.media_id > medias.id
|
||||||
|
|
||||||
|
Ref: videos.video_service_id > video_services.id
|
||||||
|
|
||||||
Ref: videos.(episode_number, media_id) > episodes.(episode_number, media_id)
|
Ref: videos.(episode_number, media_id) > episodes.(episode_number, media_id)
|
||||||
|
|
||||||
Ref: video_submissions.created_by_id > users.id
|
Ref: video_submissions.created_by_id > users.id
|
||||||
|
|||||||
@ -690,7 +690,7 @@ model Episode {
|
|||||||
|
|
||||||
model Video {
|
model Video {
|
||||||
id String @id @default(uuid(7)) @db.Uuid
|
id String @id @default(uuid(7)) @db.Uuid
|
||||||
video_service VideoService @relation(fields: [videoServiceId], references: [id])
|
video_service VideoService @relation(fields: [video_service_id], references: [id])
|
||||||
episode Episode @relation(fields: [episode_number, media_id], references: [episode_number, media_id])
|
episode Episode @relation(fields: [episode_number, media_id], references: [episode_number, media_id])
|
||||||
priority Int? @db.SmallInt
|
priority Int? @db.SmallInt
|
||||||
video_code String @db.VarChar(255)
|
video_code String @db.VarChar(255)
|
||||||
@ -705,7 +705,7 @@ model Video {
|
|||||||
media_id String @db.Uuid
|
media_id String @db.Uuid
|
||||||
created_by_id String @db.Uuid
|
created_by_id String @db.Uuid
|
||||||
video_submission VideoSubmission?
|
video_submission VideoSubmission?
|
||||||
videoServiceId String @db.Uuid
|
video_service_id String @db.Uuid
|
||||||
|
|
||||||
@@unique([media_id, episode_number, priority])
|
@@unique([media_id, episode_number, priority])
|
||||||
@@map("videos")
|
@@map("videos")
|
||||||
|
|||||||
@ -1,25 +0,0 @@
|
|||||||
import { Context, Static } from "elysia";
|
|
||||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
|
||||||
import { returnWriteResponse } from "../../../helpers/callback/httpResponse";
|
|
||||||
import { updateAllEpisodeThumbnailService } from "../services/http/updateAllEpisodeThumbnail.service";
|
|
||||||
import { updateAllEpisodeThumbnailSchema } from "../schemas/updateAllEpisodeThumbnail.schema";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updating all episode thumbnails for a specific target service reference ID.
|
|
||||||
*
|
|
||||||
* This controller handles the bulk update of episode thumbnails for all episodes associated with a specific service reference ID.
|
|
||||||
* It fetches the latest thumbnail data from external sources and updates the existing episode records in the database accordingly.
|
|
||||||
*
|
|
||||||
* See OpenAPI documentation for request/response schema.
|
|
||||||
*/
|
|
||||||
export const updateAllEpisodeThumbnailController = async (ctx: {
|
|
||||||
set: Context["set"];
|
|
||||||
body: Static<typeof updateAllEpisodeThumbnailSchema.body>;
|
|
||||||
}) => {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -3,12 +3,10 @@ import { bulkInsertEpisodeController } from "./controllers/bulkInsertEpisode.con
|
|||||||
import {bulkInsertMediaController} from "./controllers/bulkInsertMedia.controller";
|
import {bulkInsertMediaController} from "./controllers/bulkInsertMedia.controller";
|
||||||
import {createVideoServiceInternalController} from "./controllers/createVideoService.controller";
|
import {createVideoServiceInternalController} from "./controllers/createVideoService.controller";
|
||||||
import {bulkInsertVideoController} from "./controllers/bulkInsertVideo.controller";
|
import {bulkInsertVideoController} from "./controllers/bulkInsertVideo.controller";
|
||||||
import { updateAllEpisodeThumbnailController } from "./controllers/updateAllEpisodeThumbnail.controller";
|
|
||||||
import {purgeUnusedSessionController} from "./controllers/purgeUnusedSession.controller";
|
import {purgeUnusedSessionController} from "./controllers/purgeUnusedSession.controller";
|
||||||
import {createHeroBannerController} from "./controllers/createHeroBanner.controller";
|
import {createHeroBannerController} from "./controllers/createHeroBanner.controller";
|
||||||
import {bulkInsertMediaSchema} from "./schemas/bulkInsertMedia.schema";
|
import {bulkInsertMediaSchema} from "./schemas/bulkInsertMedia.schema";
|
||||||
import {bulkInsertEpisodeSchema} from "./schemas/bulkInsertEpisode.schema";
|
import {bulkInsertEpisodeSchema} from "./schemas/bulkInsertEpisode.schema";
|
||||||
import { updateAllEpisodeThumbnailSchema } from "./schemas/updateAllEpisodeThumbnail.schema";
|
|
||||||
import {bulkInsertVideoSchema} from "./schemas/bulkInsertVideo.schema";
|
import {bulkInsertVideoSchema} from "./schemas/bulkInsertVideo.schema";
|
||||||
import {createVideoServiceInternalSchema} from "./schemas/createVideoServiceInternal.schema";
|
import {createVideoServiceInternalSchema} from "./schemas/createVideoServiceInternal.schema";
|
||||||
import {purgeUnusedSessionSchema} from "./schemas/purgeUnusedSession.schema";
|
import {purgeUnusedSessionSchema} from "./schemas/purgeUnusedSession.schema";
|
||||||
@ -20,7 +18,6 @@ export const internalModule = new Elysia({
|
|||||||
})
|
})
|
||||||
.post("/media/bulk-insert", bulkInsertMediaController, bulkInsertMediaSchema)
|
.post("/media/bulk-insert", bulkInsertMediaController, bulkInsertMediaSchema)
|
||||||
.post("/episode/bulk-insert", bulkInsertEpisodeController, bulkInsertEpisodeSchema)
|
.post("/episode/bulk-insert", bulkInsertEpisodeController, bulkInsertEpisodeSchema)
|
||||||
.put("/episode/update-thumbnails", updateAllEpisodeThumbnailController, updateAllEpisodeThumbnailSchema)
|
|
||||||
.post("/video/bulk-insert", bulkInsertVideoController, bulkInsertVideoSchema)
|
.post("/video/bulk-insert", bulkInsertVideoController, bulkInsertVideoSchema)
|
||||||
.post("/video-service", createVideoServiceInternalController, createVideoServiceInternalSchema)
|
.post("/video-service", createVideoServiceInternalController, createVideoServiceInternalSchema)
|
||||||
.post("/user-session/purge-unused", purgeUnusedSessionController, purgeUnusedSessionSchema)
|
.post("/user-session/purge-unused", purgeUnusedSessionController, purgeUnusedSessionSchema)
|
||||||
|
|||||||
@ -1,28 +0,0 @@
|
|||||||
import { AppError } from "../../../helpers/error/instances/app";
|
|
||||||
import { prisma } from "../../../utils/databases/prisma/connection";
|
|
||||||
|
|
||||||
export const findEpisodeWithMediaIdRepository = async ({
|
|
||||||
media,
|
|
||||||
episode,
|
|
||||||
}: {
|
|
||||||
media: string;
|
|
||||||
episode: number;
|
|
||||||
}) => {
|
|
||||||
try {
|
|
||||||
const foundEpisode = await prisma.episode.findUnique({
|
|
||||||
where: {
|
|
||||||
mediaId_episode: {
|
|
||||||
mediaId: media,
|
|
||||||
episode: episode,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (!foundEpisode) throw new AppError(404, "Episode not found");
|
|
||||||
return foundEpisode;
|
|
||||||
} catch (error) {
|
|
||||||
throw new AppError(500, "Error finding episode with media id", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,34 +1,27 @@
|
|||||||
import {SystemAccountId} from "../../../../config/account/system";
|
import {SystemAccountId} from "../../../../config/account/system";
|
||||||
import {ErrorForwarder} from "../../../../helpers/error/instances/forwarder";
|
import {ErrorForwarder} from "../../../../helpers/error/instances/forwarder";
|
||||||
import { findEpisodeWithMediaIdRepository } from "../../repositories/findEpisodeWithMediaId.repository";
|
|
||||||
import {bulkInsertVideoRepository} from "../../repositories/bulkInsertVideo.repository";
|
import {bulkInsertVideoRepository} from "../../repositories/bulkInsertVideo.repository";
|
||||||
import {Static} from "elysia";
|
import {Static} from "elysia";
|
||||||
import {bulkInsertVideoSchema} from "../../schemas/bulkInsertVideo.schema";
|
import {bulkInsertVideoSchema} from "../../schemas/bulkInsertVideo.schema";
|
||||||
|
import {Prisma} from "@prisma/client";
|
||||||
|
|
||||||
export const bulkInsertVideoService = async (body: Static<typeof bulkInsertVideoSchema.body>) => {
|
export const bulkInsertVideoService = async (body: Static<typeof bulkInsertVideoSchema.body>) => {
|
||||||
try {
|
try {
|
||||||
const insertedVideos: string[] = [];
|
const constructedInput: Prisma.VideoCreateManyInput[] = body.data.flatMap((d) => (
|
||||||
for (const episodeData of body.data) {
|
d.videos.flatMap((v) => (
|
||||||
const episodeId = await findEpisodeWithMediaIdRepository({
|
{
|
||||||
media: body.media_id,
|
created_by_id: SystemAccountId,
|
||||||
episode: episodeData.episode,
|
media_id: body.media_id,
|
||||||
});
|
episode_number: d.episode,
|
||||||
|
video_service_id: v.service_id,
|
||||||
for (const videoData of episodeData.videos) {
|
video_code: v.video_code,
|
||||||
const insertedVideo = await bulkInsertVideoRepository({
|
short_code: v.short_code,
|
||||||
pendingUpload: false,
|
thumbnail_code: v.thumbnail_code,
|
||||||
episodeId: episodeId.id,
|
download_code: v.download_code
|
||||||
serviceId: videoData.service_id,
|
|
||||||
videoCode: videoData.video_code,
|
|
||||||
thumbnailCode: videoData.thumbnail_code,
|
|
||||||
uploadedBy: SystemAccountId,
|
|
||||||
});
|
|
||||||
|
|
||||||
insertedVideos.push(insertedVideo.id);
|
|
||||||
}
|
}
|
||||||
}
|
))
|
||||||
|
));
|
||||||
return insertedVideos;
|
return constructedInput
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ErrorForwarder(error);
|
ErrorForwarder(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,40 +0,0 @@
|
|||||||
import { AppError } from "../../../../helpers/error/instances/app";
|
|
||||||
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
|
||||||
import { bulkUpdateThumbnailRepository } from "../../../episode/repositories/PUT/bulkUpdateThumbnail.repository";
|
|
||||||
import { getAllVideoServiceWithEpisodeRepository } from "../../../videoService/repositories/GET/getAllVideoServiceWithEpisode.repository";
|
|
||||||
|
|
||||||
export const updateAllEpisodeThumbnailService = async (
|
|
||||||
serviceReferenceId?: string,
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
if (!serviceReferenceId)
|
|
||||||
throw new AppError(400, "Service Reference ID is required.");
|
|
||||||
|
|
||||||
const videosData = await getAllVideoServiceWithEpisodeRepository(
|
|
||||||
serviceReferenceId,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!videosData || videosData.length === 0)
|
|
||||||
throw new AppError(
|
|
||||||
404,
|
|
||||||
"No episode with no thumbnail found in the specified video service.",
|
|
||||||
);
|
|
||||||
|
|
||||||
const updatePayload = videosData.flatMap((videoService) => {
|
|
||||||
const { endpointThumbnail, videos } = videoService;
|
|
||||||
return videos.map((video) => ({
|
|
||||||
episodeId: video.episode.id,
|
|
||||||
thumbnailCode: endpointThumbnail!.replace(
|
|
||||||
":code:",
|
|
||||||
video.thumbnailCode || video.videoCode,
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
await bulkUpdateThumbnailRepository(updatePayload);
|
|
||||||
|
|
||||||
return updatePayload.length;
|
|
||||||
} catch (error) {
|
|
||||||
ErrorForwarder(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
import { AppError } from "../../../../helpers/error/instances/app";
|
|
||||||
import { videoServiceModel } from "../../model";
|
|
||||||
|
|
||||||
export const getAllVideoServiceWithEpisodeRepository = async (
|
|
||||||
videoServiceId: string,
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
return await videoServiceModel.findMany({
|
|
||||||
where: {
|
|
||||||
id: videoServiceId,
|
|
||||||
endpointThumbnail: {
|
|
||||||
not: null,
|
|
||||||
},
|
|
||||||
videos: {
|
|
||||||
some: {
|
|
||||||
episode: {
|
|
||||||
pictureThumbnail: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
endpointThumbnail: true,
|
|
||||||
videos: {
|
|
||||||
select: {
|
|
||||||
thumbnailCode: true,
|
|
||||||
videoCode: true,
|
|
||||||
episode: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw new AppError(
|
|
||||||
500,
|
|
||||||
"An error occurred while fetching video services with episodes.",
|
|
||||||
error,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user