Compare commits
7 Commits
502e7b10c6
...
refactor/i
| Author | SHA1 | Date | |
|---|---|---|---|
| a46b465409 | |||
| 9cfb793e59 | |||
| 51693959b6 | |||
| d914046288 | |||
| 7387386aee | |||
| 7a63b43c9f | |||
| 107582dd32 |
@ -169,10 +169,11 @@ Table user_watch_histories {
|
|||||||
episode episodes [not null]
|
episode episodes [not null]
|
||||||
updated_at DateTime [not null]
|
updated_at DateTime [not null]
|
||||||
user_id String [not null]
|
user_id String [not null]
|
||||||
episode_id String [not null]
|
episode_number Int [not null]
|
||||||
|
media_id String [not null]
|
||||||
|
|
||||||
indexes {
|
indexes {
|
||||||
(user_id, episode_id) [pk]
|
(user_id, episode_number, media_id) [pk]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,6 +255,7 @@ Table medias {
|
|||||||
related_media media_relations [not null]
|
related_media media_relations [not null]
|
||||||
updated_by_id String
|
updated_by_id String
|
||||||
deleted_by_id String
|
deleted_by_id String
|
||||||
|
episodes episodes [not null]
|
||||||
home_media_banners home_media_banners [not null]
|
home_media_banners home_media_banners [not null]
|
||||||
saved_to_collections media_collections [not null]
|
saved_to_collections media_collections [not null]
|
||||||
|
|
||||||
@ -454,13 +456,16 @@ Table media_external_links {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Table media_characters {
|
Table media_characters {
|
||||||
id String [pk]
|
|
||||||
media medias [not null]
|
media medias [not null]
|
||||||
character characters [not null]
|
character characters [not null]
|
||||||
voice_actors voice_actors [not null]
|
voice_actors voice_actors [not null]
|
||||||
role character_role [not null]
|
role character_role [not null]
|
||||||
media_id String [not null]
|
media_id String [not null]
|
||||||
character_id String [not null]
|
character_id String [not null]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(character_id, media_id) [pk]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Table characters {
|
Table characters {
|
||||||
@ -480,11 +485,16 @@ Table characters {
|
|||||||
|
|
||||||
Table voice_actors {
|
Table voice_actors {
|
||||||
id String [pk]
|
id String [pk]
|
||||||
media_character_id String [not null]
|
|
||||||
language String [not null]
|
language String [not null]
|
||||||
actor_staff staff [not null]
|
actor_staff staff [not null]
|
||||||
staff_id String [not null]
|
staff_id String [not null]
|
||||||
|
media_id String [not null]
|
||||||
|
character_id String [not null]
|
||||||
media_character media_characters [not null]
|
media_character media_characters [not null]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(media_id, character_id, staff_id, language) [unique]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Table staff {
|
Table staff {
|
||||||
@ -499,9 +509,7 @@ Table staff {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Table episodes {
|
Table episodes {
|
||||||
id String [pk]
|
episode_number Int [not null]
|
||||||
media_id String [not null]
|
|
||||||
episode Int [not null]
|
|
||||||
mal_url String
|
mal_url String
|
||||||
forum_url String
|
forum_url String
|
||||||
title String [not null]
|
title String [not null]
|
||||||
@ -520,12 +528,19 @@ Table episodes {
|
|||||||
created_by_id String [not null]
|
created_by_id String [not null]
|
||||||
comments comments [not null]
|
comments comments [not null]
|
||||||
watch_histories user_watch_histories [not null]
|
watch_histories user_watch_histories [not null]
|
||||||
|
media medias [not null]
|
||||||
|
media_id String [not null]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(media_id, episode_number) [pk]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
@ -533,9 +548,15 @@ Table videos {
|
|||||||
created_at DateTime [default: `now()`, not null]
|
created_at DateTime [default: `now()`, not null]
|
||||||
deleted_at DateTime
|
deleted_at DateTime
|
||||||
updated_at DateTime [not null]
|
updated_at DateTime [not null]
|
||||||
episode_id String [not null]
|
episode_number Int [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 {
|
||||||
@ -595,7 +616,8 @@ Table comments {
|
|||||||
updated_at DateTime [not null]
|
updated_at DateTime [not null]
|
||||||
deleted_at DateTime
|
deleted_at DateTime
|
||||||
user_id String [not null]
|
user_id String [not null]
|
||||||
episode_id String [not null]
|
episode_number Int [not null]
|
||||||
|
media_id String [not null]
|
||||||
likes comment_likes [not null]
|
likes comment_likes [not null]
|
||||||
audit_logs comment_audit_logs [not null]
|
audit_logs comment_audit_logs [not null]
|
||||||
reports comment_reports [not null]
|
reports comment_reports [not null]
|
||||||
@ -679,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
|
||||||
@ -787,7 +804,7 @@ Ref: user_follows.following_id > users.id
|
|||||||
|
|
||||||
Ref: user_watch_histories.user_id > users.id
|
Ref: user_watch_histories.user_id > users.id
|
||||||
|
|
||||||
Ref: user_watch_histories.episode_id > episodes.id
|
Ref: user_watch_histories.(episode_number, media_id) > episodes.(episode_number, media_id)
|
||||||
|
|
||||||
Ref: collection_members.collection_id > collections.id
|
Ref: collection_members.collection_id > collections.id
|
||||||
|
|
||||||
@ -865,11 +882,15 @@ Ref: media_characters.character_id > characters.id
|
|||||||
|
|
||||||
Ref: voice_actors.staff_id > staff.id
|
Ref: voice_actors.staff_id > staff.id
|
||||||
|
|
||||||
Ref: voice_actors.media_character_id > media_characters.id
|
Ref: voice_actors.(media_id, character_id) > media_characters.(media_id, character_id)
|
||||||
|
|
||||||
Ref: episodes.created_by_id > users.id
|
Ref: episodes.created_by_id > users.id
|
||||||
|
|
||||||
Ref: videos.episode_id > episodes.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: video_submissions.created_by_id > users.id
|
Ref: video_submissions.created_by_id > users.id
|
||||||
|
|
||||||
@ -885,7 +906,7 @@ Ref: video_service_submissions.video_service_id - video_services.id
|
|||||||
|
|
||||||
Ref: comments.user_id > users.id
|
Ref: comments.user_id > users.id
|
||||||
|
|
||||||
Ref: comments.episode_id > episodes.id
|
Ref: comments.(episode_number, media_id) > episodes.(episode_number, media_id)
|
||||||
|
|
||||||
Ref: comment_likes.user_id > users.id
|
Ref: comment_likes.user_id > users.id
|
||||||
|
|
||||||
|
|||||||
@ -279,13 +279,14 @@ model UserFollow {
|
|||||||
|
|
||||||
model UserWatchHistory {
|
model UserWatchHistory {
|
||||||
user User @relation(fields: [user_id], references: [id])
|
user User @relation(fields: [user_id], references: [id])
|
||||||
episode Episode @relation(fields: [episode_id], references: [id])
|
episode Episode @relation(fields: [episode_number, media_id], references: [episode_number, media_id])
|
||||||
updated_at DateTime @updatedAt @db.Timestamptz()
|
updated_at DateTime @updatedAt @db.Timestamptz()
|
||||||
|
|
||||||
user_id String @db.Uuid
|
user_id String @db.Uuid
|
||||||
episode_id String @db.Uuid
|
episode_number Int @db.SmallInt
|
||||||
|
media_id String @db.Uuid
|
||||||
|
|
||||||
@@id([user_id, episode_id])
|
@@id([user_id, episode_number, media_id])
|
||||||
@@map("user_watch_histories")
|
@@map("user_watch_histories")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,6 +377,7 @@ model Media {
|
|||||||
related_media MediaRelation[] @relation("MediaRelationRelatedMedia")
|
related_media MediaRelation[] @relation("MediaRelationRelatedMedia")
|
||||||
updated_by_id String? @db.Uuid
|
updated_by_id String? @db.Uuid
|
||||||
deleted_by_id String? @db.Uuid
|
deleted_by_id String? @db.Uuid
|
||||||
|
episodes Episode[]
|
||||||
home_media_banners HomeMediaBanner[]
|
home_media_banners HomeMediaBanner[]
|
||||||
saved_to_collections MediaCollection[]
|
saved_to_collections MediaCollection[]
|
||||||
|
|
||||||
@ -640,8 +642,8 @@ model VoiceActor {
|
|||||||
character_id String @db.Uuid
|
character_id String @db.Uuid
|
||||||
media_character MediaCharacter @relation(fields: [media_id, character_id], references: [media_id, character_id])
|
media_character MediaCharacter @relation(fields: [media_id, character_id], references: [media_id, character_id])
|
||||||
|
|
||||||
@@map("voice_actors")
|
|
||||||
@@unique([media_id, character_id, staff_id, language])
|
@@unique([media_id, character_id, staff_id, language])
|
||||||
|
@@map("voice_actors")
|
||||||
}
|
}
|
||||||
|
|
||||||
model Staff {
|
model Staff {
|
||||||
@ -659,49 +661,53 @@ model Staff {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model Episode {
|
model Episode {
|
||||||
id String @id @default(uuid(7)) @db.Uuid
|
episode_number Int @db.SmallInt
|
||||||
media_id String @db.Uuid
|
mal_url String? @db.VarChar(255)
|
||||||
episode Int @db.SmallInt
|
forum_url String? @db.VarChar(255)
|
||||||
mal_url String? @db.VarChar(255)
|
title String @db.VarChar(155)
|
||||||
forum_url String? @db.VarChar(255)
|
title_origin String? @db.VarChar(155)
|
||||||
title String @db.VarChar(155)
|
title_romanji String? @db.VarChar(155)
|
||||||
title_origin String? @db.VarChar(155)
|
aired_at DateTime? @db.Date
|
||||||
title_romanji String? @db.VarChar(155)
|
filler Boolean
|
||||||
aired_at DateTime? @db.Date
|
recap Boolean
|
||||||
filler Boolean
|
total_score Int @default(0)
|
||||||
recap Boolean
|
score_count Int @default(0)
|
||||||
total_score Int @default(0)
|
deleted_at DateTime? @db.Timestamptz()
|
||||||
score_count Int @default(0)
|
updated_at DateTime @updatedAt @db.Timestamptz()
|
||||||
deleted_at DateTime? @db.Timestamptz()
|
created_at DateTime @default(now()) @db.Timestamptz()
|
||||||
updated_at DateTime @updatedAt @db.Timestamptz()
|
created_by User @relation(fields: [created_by_id], references: [id])
|
||||||
created_at DateTime @default(now()) @db.Timestamptz()
|
|
||||||
created_by User @relation(fields: [created_by_id], references: [id])
|
|
||||||
|
|
||||||
videos Video[]
|
videos Video[]
|
||||||
created_by_id String @db.Uuid
|
created_by_id String @db.Uuid
|
||||||
comments Comment[]
|
comments Comment[]
|
||||||
watch_histories UserWatchHistory[]
|
watch_histories UserWatchHistory[]
|
||||||
|
media Media @relation(fields: [media_id], references: [id])
|
||||||
|
media_id String @db.Uuid
|
||||||
|
|
||||||
@@index([media_id, episode])
|
@@id([media_id, episode_number])
|
||||||
@@map("episodes")
|
@@map("episodes")
|
||||||
}
|
}
|
||||||
|
|
||||||
model Video {
|
model Video {
|
||||||
id String @id @default(uuid(7)) @db.Uuid
|
id String @id @default(uuid(7)) @db.Uuid
|
||||||
service VideoService[]
|
video_service VideoService @relation(fields: [video_service_id], references: [id])
|
||||||
Episode Episode @relation(fields: [episode_id], references: [id])
|
episode Episode @relation(fields: [episode_number, media_id], references: [episode_number, media_id])
|
||||||
video_code String @db.VarChar(255)
|
priority Int? @db.SmallInt
|
||||||
short_code String? @db.VarChar(255)
|
video_code String @db.VarChar(255)
|
||||||
thumbnail_code String? @db.VarChar(255)
|
short_code String? @db.VarChar(255)
|
||||||
download_code String? @db.VarChar(255)
|
thumbnail_code String? @db.VarChar(255)
|
||||||
created_at DateTime @default(now()) @db.Timestamptz()
|
download_code String? @db.VarChar(255)
|
||||||
deleted_at DateTime? @db.Timestamptz()
|
created_at DateTime @default(now()) @db.Timestamptz()
|
||||||
updated_at DateTime @updatedAt @db.Timestamptz()
|
deleted_at DateTime? @db.Timestamptz()
|
||||||
|
updated_at DateTime @updatedAt @db.Timestamptz()
|
||||||
|
|
||||||
episode_id String @db.Uuid
|
episode_number Int @db.SmallInt
|
||||||
|
media_id String @db.Uuid
|
||||||
created_by_id String @db.Uuid
|
created_by_id String @db.Uuid
|
||||||
video_submission VideoSubmission?
|
video_submission VideoSubmission?
|
||||||
|
video_service_id String @db.Uuid
|
||||||
|
|
||||||
|
@@unique([media_id, episode_number, priority])
|
||||||
@@map("videos")
|
@@map("videos")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -762,17 +768,18 @@ model VideoServiceSubmission {
|
|||||||
model Comment {
|
model Comment {
|
||||||
id String @id @default(uuid(7)) @db.Uuid
|
id String @id @default(uuid(7)) @db.Uuid
|
||||||
user User @relation(fields: [user_id], references: [id])
|
user User @relation(fields: [user_id], references: [id])
|
||||||
episode Episode @relation(fields: [episode_id], references: [id])
|
episode Episode @relation(fields: [episode_number, media_id], references: [episode_number, media_id])
|
||||||
content String @db.Text
|
content String @db.Text
|
||||||
created_at DateTime @default(now()) @db.Timestamptz()
|
created_at DateTime @default(now()) @db.Timestamptz()
|
||||||
updated_at DateTime @updatedAt @db.Timestamptz()
|
updated_at DateTime @updatedAt @db.Timestamptz()
|
||||||
deleted_at DateTime? @db.Timestamptz()
|
deleted_at DateTime? @db.Timestamptz()
|
||||||
|
|
||||||
user_id String @db.Uuid
|
user_id String @db.Uuid
|
||||||
episode_id String @db.Uuid
|
episode_number Int @db.SmallInt
|
||||||
likes CommentLike[]
|
media_id String @db.Uuid
|
||||||
audit_logs CommentAuditLog[]
|
likes CommentLike[]
|
||||||
reports CommentReport[]
|
audit_logs CommentAuditLog[]
|
||||||
|
reports CommentReport[]
|
||||||
|
|
||||||
@@map("comments")
|
@@map("comments")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,27 +1,24 @@
|
|||||||
import Elysia from "elysia";
|
import Elysia from "elysia";
|
||||||
import { bulkInsertEpisodeController } from "./controllers/bulkInsertEpisode.controller";
|
import {bulkInsertEpisodeController} from "./controllers/bulkInsertEpisode.controller";
|
||||||
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 {bulkInsertVideoSchema} from "./schemas/bulkInsertVideo.schema";
|
||||||
import { updateAllEpisodeThumbnailSchema } from "./schemas/updateAllEpisodeThumbnail.schema";
|
import {createVideoServiceInternalSchema} from "./schemas/createVideoServiceInternal.schema";
|
||||||
import { bulkInsertVideoSchema } from "./schemas/bulkInsertVideo.schema";
|
import {purgeUnusedSessionSchema} from "./schemas/purgeUnusedSession.schema";
|
||||||
import { createVideoServiceInternalSchema } from "./schemas/createVideoServiceInternal.schema";
|
import {createHeroBannerSchema} from "./schemas/createHeroBanner.schema";
|
||||||
import { purgeUnusedSessionSchema } from "./schemas/purgeUnusedSession.schema";
|
|
||||||
import { createHeroBannerSchema } from "./schemas/createHeroBanner.schema";
|
|
||||||
|
|
||||||
export const internalModule = new Elysia({
|
export const internalModule = new Elysia({
|
||||||
prefix: "/internal",
|
prefix: "/internal",
|
||||||
tags: ["Internal"],
|
tags: ["Internal"],
|
||||||
})
|
})
|
||||||
.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)
|
.post("/hero-banner", createHeroBannerController, createHeroBannerSchema);
|
||||||
.post("/hero-banner", createHeroBannerController, createHeroBannerSchema);
|
|
||||||
|
|||||||
@ -1,26 +1,46 @@
|
|||||||
import { Prisma } from "@prisma/client";
|
import {AppError} from "../../../helpers/error/instances/app";
|
||||||
import { AppError } from "../../../helpers/error/instances/app";
|
import {prisma} from "../../../utils/databases/prisma/connection";
|
||||||
import { prisma } from "../../../utils/databases/prisma/connection";
|
import {SystemAccountId} from "../../../config/account/system";
|
||||||
import { generateUUIDv7 } from "../../../helpers/databases/uuidv7";
|
|
||||||
|
|
||||||
|
export interface BulkInsertEpisodesPayload {
|
||||||
|
media_id: string
|
||||||
|
episode_number: number
|
||||||
|
title: string
|
||||||
|
title_romanji: string
|
||||||
|
title_origin: string
|
||||||
|
aired_at: Date
|
||||||
|
score: number
|
||||||
|
filler: boolean
|
||||||
|
recap: boolean
|
||||||
|
forum_url: string
|
||||||
|
created_by_id: string
|
||||||
|
}
|
||||||
|
|
||||||
export const bulkInsertEpisodesRepository = async (
|
export const bulkInsertEpisodesRepository = async (
|
||||||
payload: Omit<Prisma.EpisodeUncheckedCreateInput, "id">,
|
payload: BulkInsertEpisodesPayload[]
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
return await prisma.episode.upsert({
|
await prisma.$transaction(async (tx) => {
|
||||||
where: {
|
await Promise.all(
|
||||||
mediaId_episode: {
|
payload.map(async (episode) =>
|
||||||
mediaId: payload.mediaId as string,
|
await tx.episode.upsert({
|
||||||
episode: payload.episode as number,
|
where: {
|
||||||
},
|
media_id_episode_number: {
|
||||||
},
|
media_id: episode.media_id,
|
||||||
update: payload,
|
episode_number: episode.episode_number
|
||||||
create: {
|
}
|
||||||
id: generateUUIDv7(),
|
},
|
||||||
...payload,
|
update: episode,
|
||||||
},
|
create: {
|
||||||
});
|
...episode,
|
||||||
} catch (err) {
|
created_by_id: SystemAccountId
|
||||||
throw new AppError(500, "Failed to bulk insert episodes", err);
|
}
|
||||||
}
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
throw new AppError(500, "Failed to bulk insert episodes", err);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,10 +1,123 @@
|
|||||||
import {AppError} from "../../../helpers/error/instances/app";
|
import {AppError} from "../../../helpers/error/instances/app";
|
||||||
import {MediaChar} from "../types/mediaCharacters";
|
import {MediaChar} from "../types/mediaCharacters";
|
||||||
|
import {prisma} from "../../../utils/databases/prisma/connection";
|
||||||
|
import {character_role} from "@prisma/client";
|
||||||
|
|
||||||
export const bulkInsertMediaCharacterRepository = async (animeMalId: number, characters: MediaChar[]) => {
|
export const bulkInsertMediaCharacterRepository = async (
|
||||||
|
mediaId: string,
|
||||||
|
characters: MediaChar[]
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
return characters[0].character.name;
|
const chars = characters.map(c => ({
|
||||||
|
mal_id: c.character.mal_id,
|
||||||
|
name: c.character.name,
|
||||||
|
image: c.character.images.webp.image_url,
|
||||||
|
small_image: c.character.images.webp.small_image_url,
|
||||||
|
fanpage_url: c.character.url
|
||||||
|
}));
|
||||||
|
|
||||||
|
const staffs = characters.flatMap(c =>
|
||||||
|
c.voice_actors.map(v => ({
|
||||||
|
mal_id: v.person.mal_id,
|
||||||
|
name: v.person.name,
|
||||||
|
image: v.person.images.jpg.image_url
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
await prisma.$transaction(async (tx) => {
|
||||||
|
|
||||||
|
// Insert Character
|
||||||
|
await tx.character.createMany({
|
||||||
|
data: chars,
|
||||||
|
skipDuplicates: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Insert Staff
|
||||||
|
await tx.staff.createMany({
|
||||||
|
data: staffs,
|
||||||
|
skipDuplicates: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get inserted characters
|
||||||
|
const insertedChar = await tx.character.findMany({
|
||||||
|
where: {
|
||||||
|
mal_id: {
|
||||||
|
in: chars.map(c => c.mal_id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
mal_id: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get inserted staffs
|
||||||
|
const insertedStaff = await tx.staff.findMany({
|
||||||
|
where: {
|
||||||
|
mal_id: {
|
||||||
|
in: staffs.map(s => s.mal_id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
mal_id: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Build lookup map
|
||||||
|
const characterMap = new Map(
|
||||||
|
insertedChar.map(c => [c.mal_id!, c.id])
|
||||||
|
);
|
||||||
|
const staffMap = new Map(
|
||||||
|
insertedStaff.map(s => [s.mal_id!, s.id])
|
||||||
|
);
|
||||||
|
|
||||||
|
// Connect media with characters
|
||||||
|
const mediaCharacters = characters.map(c => {
|
||||||
|
const characterId = characterMap.get(c.character.mal_id);
|
||||||
|
if (!characterId)
|
||||||
|
throw new AppError(500, `Character ${c.character.mal_id} not found`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
media_id: mediaId,
|
||||||
|
character_id: characterId,
|
||||||
|
role: c.role.toLowerCase() as character_role
|
||||||
|
};
|
||||||
|
});
|
||||||
|
await tx.mediaCharacter.createMany({
|
||||||
|
data: mediaCharacters,
|
||||||
|
skipDuplicates: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Insert all voice actor of characters
|
||||||
|
const voiceActors = characters.flatMap(c => {
|
||||||
|
const characterId = characterMap.get(c.character.mal_id);
|
||||||
|
if (!characterId)
|
||||||
|
throw new AppError(500, `Character ${c.character.mal_id} not found`);
|
||||||
|
|
||||||
|
return c.voice_actors.map(v => {
|
||||||
|
const staffId = staffMap.get(v.person.mal_id);
|
||||||
|
if (!staffId) throw new AppError(500, `Staff ${v.person.mal_id} not found`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
media_id: mediaId,
|
||||||
|
character_id: characterId,
|
||||||
|
staff_id: staffId,
|
||||||
|
language: v.language
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
await tx.voiceActor.createMany({
|
||||||
|
data: voiceActors,
|
||||||
|
skipDuplicates: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new AppError(500, "Failed to bulk insert media characters", error);
|
throw new AppError(
|
||||||
|
500,
|
||||||
|
"Failed to bulk insert media characters",
|
||||||
|
error
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
import {AppError} from "../../../helpers/error/instances/app";
|
||||||
|
import {MediaFullInfoResponse} from "../types/mediaFullInfo.type";
|
||||||
|
import {prisma} from "../../../utils/databases/prisma/connection";
|
||||||
|
import slugify from "slugify";
|
||||||
|
|
||||||
|
export const bulkInsertMediaGenreRepository = async (mediaData: MediaFullInfoResponse, mediaId: string) => {
|
||||||
|
try {
|
||||||
|
await prisma.$transaction(async (tx) => {
|
||||||
|
const createdGenres = await tx.genre.createManyAndReturn({
|
||||||
|
data: mediaData.data.genres.map((genre) => ({
|
||||||
|
name: genre.name,
|
||||||
|
mal_id: genre.mal_id,
|
||||||
|
slug: slugify(genre.name, {
|
||||||
|
lower: true,
|
||||||
|
strict: true,
|
||||||
|
})
|
||||||
|
})),
|
||||||
|
skipDuplicates: true,
|
||||||
|
select: {
|
||||||
|
mal_id: true,
|
||||||
|
id: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await tx.mediaGenre.createMany({
|
||||||
|
data: createdGenres.map((genre) => ({
|
||||||
|
media_id: mediaId,
|
||||||
|
genre_id: genre.id
|
||||||
|
})),
|
||||||
|
skipDuplicates: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
throw new AppError(500, "Failed to bulk insert media genre", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
import {AppError} from "../../../helpers/error/instances/app";
|
||||||
|
import {prisma} from "../../../utils/databases/prisma/connection";
|
||||||
|
|
||||||
|
export const findMediaWithMalIdRepository = async (malId: number) => {
|
||||||
|
try {
|
||||||
|
return await prisma.media.findUnique({
|
||||||
|
where: {
|
||||||
|
mal_id: malId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
throw new AppError(500, "Failed to find media with malId", error)
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -1,63 +1,76 @@
|
|||||||
import { t } from "elysia";
|
import {t} from "elysia";
|
||||||
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
import {AppRouteSchema} from "../../../helpers/types/AppRouteSchema";
|
||||||
|
|
||||||
export const bulkInsertVideoSchema = {
|
export const bulkInsertVideoSchema = {
|
||||||
body: t.Object({
|
body: t.Object({
|
||||||
media_id: t.String({
|
media_id: t.String({
|
||||||
description: "The ID of the media for which episodes will be inserted",
|
description: "The ID of the media for which episodes will be inserted",
|
||||||
}),
|
|
||||||
data: t.Array(
|
|
||||||
t.Object({
|
|
||||||
episode: t.Number({
|
|
||||||
description: "The episode number",
|
|
||||||
}),
|
}),
|
||||||
videos: t.Array(
|
data: t.Array(
|
||||||
t.Object({
|
t.Object({
|
||||||
service_id: t.String({
|
episode: t.Number({
|
||||||
description: "The ID of the video service",
|
description: "The episode number",
|
||||||
|
}),
|
||||||
|
videos: t.Array(
|
||||||
|
t.Object({
|
||||||
|
service_id: t.String({
|
||||||
|
description: "The ID of the video service",
|
||||||
|
}),
|
||||||
|
priority: t.Optional(t.Number({
|
||||||
|
description: "The priority of the video (can't be duplicate)",
|
||||||
|
})),
|
||||||
|
video_code: t.String({
|
||||||
|
description: "The code of the video on the service",
|
||||||
|
}),
|
||||||
|
short_code: t.Optional(
|
||||||
|
t.String({
|
||||||
|
description: "The code of the preview video on the service",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
thumbnail_code: t.Optional(
|
||||||
|
t.String({
|
||||||
|
description: "The code of the thumbnail for the video on the service",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
download_code: t.Optional(
|
||||||
|
t.String({
|
||||||
|
description: "The code of the download link for the video on the service",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
video_code: t.String({
|
|
||||||
description: "The code of the video on the service",
|
|
||||||
}),
|
|
||||||
thumbnail_code: t.Optional(
|
|
||||||
t.String({
|
|
||||||
description: "The code of the thumbnail for the video on the service",
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
),
|
detail: {
|
||||||
}),
|
summary: "Bulk insert videos for a media episode",
|
||||||
detail: {
|
description:
|
||||||
summary: "Bulk insert videos for a media episode",
|
"Perform bulk insert of videos for specific episodes of a media. This operation inserts multiple videos associated with different episodes into the database based on the provided data.",
|
||||||
description:
|
responses: {
|
||||||
"Perform bulk insert of videos for specific episodes of a media. This operation inserts multiple videos associated with different episodes into the database based on the provided data.",
|
201: {
|
||||||
responses: {
|
description: "Videos inserted successfully",
|
||||||
201: {
|
content: {
|
||||||
description: "Videos inserted successfully",
|
"application/json": {
|
||||||
content: {
|
schema: {
|
||||||
"application/json": {
|
type: "object",
|
||||||
schema: {
|
properties: {
|
||||||
type: "object",
|
success: {type: "boolean", default: true},
|
||||||
properties: {
|
status: {type: "integer", default: 201},
|
||||||
success: { type: "boolean", default: true },
|
message: {type: "string", default: "Videos inserted successfully"},
|
||||||
status: { type: "integer", default: 201 },
|
data: {
|
||||||
message: { type: "string", default: "Videos inserted successfully" },
|
type: "array",
|
||||||
data: {
|
default: ["xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"],
|
||||||
type: "array",
|
description: "An array of IDs of the inserted videos",
|
||||||
default: ["xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"],
|
items: {
|
||||||
description: "An array of IDs of the inserted videos",
|
type: "string",
|
||||||
items: {
|
description: "The ID of the inserted video",
|
||||||
type: "string",
|
},
|
||||||
description: "The ID of the inserted video",
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
|
||||||
} satisfies AppRouteSchema;
|
} satisfies AppRouteSchema;
|
||||||
|
|||||||
@ -1,35 +0,0 @@
|
|||||||
import { t } from "elysia";
|
|
||||||
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
|
||||||
|
|
||||||
export const updateAllEpisodeThumbnailSchema = {
|
|
||||||
body: t.Object({
|
|
||||||
service_reference_id: t.String({
|
|
||||||
description: "The ID of the service to which the target of episode thumbnails belong",
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
detail: {
|
|
||||||
summary: "Bulk update episode thumbnails",
|
|
||||||
description:
|
|
||||||
"Perform bulk update of episode thumbnails for all episodes associated with a specific service reference ID. This operation fetches the latest thumbnail data from external sources and updates the existing episode records in the database accordingly.",
|
|
||||||
responses: {
|
|
||||||
204: {
|
|
||||||
description: "Updating episode thumbnails operation completed successfully",
|
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
schema: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
success: { type: "boolean", default: true },
|
|
||||||
status: { type: "integer", default: 204 },
|
|
||||||
message: {
|
|
||||||
type: "string",
|
|
||||||
default: "Updating {newEpisodeThumbnailsCount} episode thumbnails operation completed successfully",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} satisfies AppRouteSchema;
|
|
||||||
@ -4,20 +4,24 @@ import {getContentReferenceAPI} from "../../../../config/apis/jikan/media.refere
|
|||||||
import {bulkInsertMediaCharacterRepository} from "../../repositories/bulkInsertMediaCharacter.repository";
|
import {bulkInsertMediaCharacterRepository} from "../../repositories/bulkInsertMediaCharacter.repository";
|
||||||
import {MediaFullInfoResponse} from "../../types/mediaFullInfo.type";
|
import {MediaFullInfoResponse} from "../../types/mediaFullInfo.type";
|
||||||
import {MediaCharacters} from "../../types/mediaCharacters";
|
import {MediaCharacters} from "../../types/mediaCharacters";
|
||||||
|
import {bulkInsertMediaGenreRepository} from "../../repositories/bulkInsertMediaGenre.repository";
|
||||||
|
|
||||||
export const bulkInsertAnimeService = async (malId: number) => {
|
export const bulkInsertAnimeService = async (malId: number) => {
|
||||||
try {
|
try {
|
||||||
const {baseURL, getMediaFullInfo, getMediaCharacters} = getContentReferenceAPI(malId);
|
const {baseURL, getMediaFullInfo, getMediaCharacters} = getContentReferenceAPI(malId);
|
||||||
const mediaFullInfo = (await fetch(baseURL + getMediaFullInfo).then((res) => res.json())) as MediaFullInfoResponse;
|
const mediaFullInfo = (await fetch(baseURL + getMediaFullInfo).then((res) => res.json())) as MediaFullInfoResponse;
|
||||||
|
|
||||||
|
// Inserting Media and Producers (Producer, Studio, Licensor)
|
||||||
const insertedMedia = await InsertMediaRepository({
|
const insertedMedia = await InsertMediaRepository({
|
||||||
payload: mediaFullInfo.data,
|
payload: mediaFullInfo.data,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Inserting Characters, Staff, and Voice Actors
|
||||||
// await bulkInsertMediaCharacterRepository(insertedMedia.mal_id)
|
|
||||||
const mediaChar = await fetch(baseURL + getMediaCharacters).then((res) => res.json()) as MediaCharacters;
|
const mediaChar = await fetch(baseURL + getMediaCharacters).then((res) => res.json()) as MediaCharacters;
|
||||||
await bulkInsertMediaCharacterRepository(insertedMedia.mal_id, mediaChar.data);
|
await bulkInsertMediaCharacterRepository(insertedMedia.id, mediaChar.data);
|
||||||
|
|
||||||
|
// Inserting Genres and Demographics
|
||||||
|
await bulkInsertMediaGenreRepository(mediaFullInfo, insertedMedia.id)
|
||||||
|
|
||||||
return insertedMedia.id;
|
return insertedMedia.id;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -1,35 +1,37 @@
|
|||||||
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
import {MediaEpisodeInfoResponse} from "../../types/mediaEpisodeInfo.type";
|
||||||
import { MediaEpisodeInfoResponse } from "../../types/mediaEpisodeInfo.type";
|
import {AppError} from "../../../../helpers/error/instances/app";
|
||||||
import { AppError } from "../../../../helpers/error/instances/app";
|
import {SystemAccountId} from "../../../../config/account/system";
|
||||||
import { SystemAccountId } from "../../../../config/account/system";
|
import {ErrorForwarder} from "../../../../helpers/error/instances/forwarder";
|
||||||
import { bulkInsertEpisodesRepository } from "../../repositories/bulkInsertEpisodes.repository";
|
import {bulkInsertEpisodesRepository} from "../../repositories/bulkInsertEpisodes.repository";
|
||||||
import { getEpisodeReferenceAPI } from "../../../../config/apis/jikan/episode.reference";
|
import {getEpisodeReferenceAPI} from "../../../../config/apis/jikan/episode.reference";
|
||||||
import { selectMediaByMalIdRepository } from "../../../media/repositories/SELECT/selectMediaByMalId.repository";
|
import {findMediaWithMalIdRepository} from "../../repositories/findMediaWithMalId.repository";
|
||||||
|
|
||||||
export const bulkInsertEpisodeService = async (mal_id: number, page: number = 1) => {
|
export const bulkInsertEpisodeService = async (mal_id: number, page: number = 1) => {
|
||||||
try {
|
try {
|
||||||
const episodeAPI = getEpisodeReferenceAPI(mal_id);
|
const episodeAPI = getEpisodeReferenceAPI(mal_id);
|
||||||
const episodeData: MediaEpisodeInfoResponse = await fetch(
|
const episodeData: MediaEpisodeInfoResponse = await fetch(
|
||||||
`${episodeAPI.baseURL}${episodeAPI.getEpisodeList}?page=${page}`,
|
`${episodeAPI.baseURL}${episodeAPI.getEpisodeList}?page=${page}`,
|
||||||
).then((res) => res.json());
|
).then((res) => res.json()) as MediaEpisodeInfoResponse;
|
||||||
|
|
||||||
const mediaData = await selectMediaByMalIdRepository(mal_id);
|
const mediaData = await findMediaWithMalIdRepository(mal_id)
|
||||||
if (!mediaData) throw new AppError(404, `Media with Mal ID ${mal_id} not found in database`);
|
if (!mediaData) throw new AppError(404, "Media not found");
|
||||||
|
|
||||||
const insertedEpisodeData = [];
|
const constructedInput = episodeData.data.map(c => ({
|
||||||
episodeData.data.forEach(async (episode) => {
|
media_id: mediaData.id,
|
||||||
insertedEpisodeData.push(
|
episode_number: c.mal_id,
|
||||||
await bulkInsertEpisodesRepository({
|
title: c.title,
|
||||||
mediaId: mediaData.id!,
|
title_romanji: c.title_romanji,
|
||||||
episode: episode.mal_id,
|
title_origin: c.title_japanese,
|
||||||
name: episode.title,
|
aired_at: c.aired,
|
||||||
score: episode.score,
|
score: c.score,
|
||||||
uploadedBy: SystemAccountId,
|
filler: c.filler,
|
||||||
}),
|
recap: c.recap,
|
||||||
);
|
forum_url: c.forum_url,
|
||||||
});
|
created_by_id: SystemAccountId
|
||||||
return episodeData;
|
}))
|
||||||
} catch (err) {
|
const insertedEpisodes = await bulkInsertEpisodesRepository(constructedInput)
|
||||||
ErrorForwarder(err);
|
return episodeData;
|
||||||
}
|
} catch (err) {
|
||||||
|
ErrorForwarder(err);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,35 +1,28 @@
|
|||||||
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,
|
return constructedInput
|
||||||
});
|
} catch (error) {
|
||||||
|
ErrorForwarder(error);
|
||||||
insertedVideos.push(insertedVideo.id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return insertedVideos;
|
|
||||||
} catch (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,13 +1,12 @@
|
|||||||
|
import {character_role} from "@prisma/client";
|
||||||
|
|
||||||
interface StaffVA {
|
interface StaffVA {
|
||||||
mal_id: number;
|
mal_id: number;
|
||||||
url: string;
|
url: string;
|
||||||
|
name: string;
|
||||||
images: {
|
images: {
|
||||||
jpg: {
|
jpg: {
|
||||||
image_url: string;
|
image_url: string;
|
||||||
},
|
|
||||||
webp: {
|
|
||||||
image_url: string;
|
|
||||||
small_image_url: string;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -32,15 +31,9 @@ interface Character {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Role {
|
|
||||||
Main = "Main",
|
|
||||||
Supporting = "Supporting",
|
|
||||||
Background = "Background",
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MediaChar {
|
export interface MediaChar {
|
||||||
character: Character;
|
character: Character;
|
||||||
role: Role;
|
role: character_role;
|
||||||
favorites: number;
|
favorites: number;
|
||||||
voice_actors: voiceActor[];
|
voice_actors: voiceActor[];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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