added local manga, todo: novels
This commit is contained in:
@@ -6,7 +6,8 @@ import fs from "fs";
|
||||
import { PathLike } from "node:fs";
|
||||
import path from "path";
|
||||
import {getAnimeById, searchAnimeLocal} from "../anime/anime.service";
|
||||
import {getBookById, searchBooksLocal} from "../books/books.service";
|
||||
import {getBookById, searchBooksAniList, searchBooksLocal} from "../books/books.service";
|
||||
import AdmZip from 'adm-zip';
|
||||
|
||||
type SetConfigBody = {
|
||||
library?: {
|
||||
@@ -34,7 +35,7 @@ async function resolveEntryMetadata(entry: any, type: string) {
|
||||
|
||||
const results = type === 'anime'
|
||||
? await searchAnimeLocal(query)
|
||||
: await searchBooksLocal(query);
|
||||
: await searchBooksAniList(query);
|
||||
|
||||
const first = results?.[0];
|
||||
|
||||
@@ -245,3 +246,112 @@ export async function matchEntry(
|
||||
|
||||
return { status: 'OK', matched: !!matched_id };
|
||||
}
|
||||
|
||||
export async function getUnits(
|
||||
request: FastifyRequest<{ Params: Params }>,
|
||||
reply: FastifyReply
|
||||
) {
|
||||
try {
|
||||
const { type, id } = request.params as { type: string, id: string };
|
||||
|
||||
// Buscar la entrada por matched_id
|
||||
const entry = await queryOne(
|
||||
`SELECT id, type, matched_id FROM local_entries WHERE matched_id = ? AND type = ?`,
|
||||
[Number(id), type],
|
||||
'local_library'
|
||||
);
|
||||
|
||||
if (!entry) {
|
||||
return reply.status(404).send({ error: 'ENTRY_NOT_FOUND' });
|
||||
}
|
||||
|
||||
// Obtener todos los archivos/unidades ordenados
|
||||
const files = await queryAll(
|
||||
`SELECT id, file_path, unit_number FROM local_files
|
||||
WHERE entry_id = ?
|
||||
ORDER BY unit_number ASC`,
|
||||
[entry.id],
|
||||
'local_library'
|
||||
);
|
||||
|
||||
// Formatear la respuesta según el tipo
|
||||
const units = files.map((file: any) => {
|
||||
const fileName = path.basename(file.file_path);
|
||||
const fileExt = path.extname(file.file_path).toLowerCase();
|
||||
|
||||
// Detectar si es un archivo comprimido (capítulo único) o carpeta
|
||||
const isDirectory = fs.existsSync(file.file_path) &&
|
||||
fs.statSync(file.file_path).isDirectory();
|
||||
|
||||
return {
|
||||
id: file.id,
|
||||
number: file.unit_number,
|
||||
name: fileName,
|
||||
type: type === 'anime' ? 'episode' : 'chapter',
|
||||
format: fileExt === '.cbz' ? 'cbz' : 'file',
|
||||
path: file.file_path
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
entry_id: entry.id,
|
||||
matched_id: entry.matched_id,
|
||||
type: entry.type,
|
||||
total: units.length,
|
||||
units
|
||||
};
|
||||
} catch (err) {
|
||||
console.error('Error getting units:', err);
|
||||
return reply.status(500).send({ error: 'FAILED_TO_GET_UNITS' });
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCbzPages(request: FastifyRequest, reply: FastifyReply) {
|
||||
const { unitId } = request.params as any;
|
||||
|
||||
const file = await queryOne(
|
||||
`SELECT file_path FROM local_files WHERE id = ?`,
|
||||
[unitId],
|
||||
'local_library'
|
||||
);
|
||||
|
||||
if (!file || !fs.existsSync(file.file_path)) {
|
||||
return reply.status(404).send({ error: 'FILE_NOT_FOUND' });
|
||||
}
|
||||
|
||||
const zip = new AdmZip(file.file_path);
|
||||
|
||||
const pages = zip.getEntries()
|
||||
.filter(e => !e.isDirectory && /\.(jpg|jpeg|png|webp)$/i.test(e.entryName))
|
||||
.sort((a, b) => a.entryName.localeCompare(b.entryName, undefined, { numeric: true }))
|
||||
.map((_, i) =>
|
||||
`/api/library/manga/cbz/${unitId}/page/${i}`
|
||||
);
|
||||
|
||||
return { pages };
|
||||
}
|
||||
|
||||
export async function getCbzPage(request: FastifyRequest, reply: FastifyReply) {
|
||||
const { unitId, page } = request.params as any;
|
||||
|
||||
const file = await queryOne(
|
||||
`SELECT file_path FROM local_files WHERE id = ?`,
|
||||
[unitId],
|
||||
'local_library'
|
||||
);
|
||||
|
||||
if (!file) return reply.status(404).send();
|
||||
|
||||
const zip = new AdmZip(file.file_path);
|
||||
|
||||
const images = zip.getEntries()
|
||||
.filter(e => !e.isDirectory && /\.(jpg|jpeg|png|webp)$/i.test(e.entryName))
|
||||
.sort((a, b) => a.entryName.localeCompare(b.entryName, undefined, { numeric: true }));
|
||||
|
||||
const entry = images[page];
|
||||
if (!entry) return reply.status(404).send();
|
||||
|
||||
reply
|
||||
.header('Content-Type', 'image/jpeg')
|
||||
.send(entry.getData());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user