refactor: media character module
This commit is contained in:
@ -454,13 +454,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 +483,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 {
|
||||||
@ -865,7 +873,7 @@ 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
|
||||||
|
|
||||||
|
|||||||
@ -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 => ({
|
||||||
} catch (error) {
|
mal_id: c.character.mal_id,
|
||||||
throw new AppError(500, "Failed to bulk insert media characters", error);
|
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) {
|
||||||
|
throw new AppError(
|
||||||
|
500,
|
||||||
|
"Failed to bulk insert media characters",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -17,7 +17,7 @@ export const bulkInsertAnimeService = async (malId: number) => {
|
|||||||
|
|
||||||
// await bulkInsertMediaCharacterRepository(insertedMedia.mal_id)
|
// 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);
|
return await bulkInsertMediaCharacterRepository(insertedMedia.id, mediaChar.data);
|
||||||
|
|
||||||
return insertedMedia.id;
|
return insertedMedia.id;
|
||||||
} catch (error) {
|
} catch (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[];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user