feat(l2s): add missing types and fix naming

This commit is contained in:
matt1432 2025-03-29 01:17:43 -04:00
parent 4f2ce0091a
commit 58a7557dc0
2 changed files with 110 additions and 27 deletions
apps/list2series/src

View file

@ -2,19 +2,19 @@ import axios from 'axios';
import { linkSync, mkdirSync, readFileSync, rmSync } from 'fs'; import { linkSync, mkdirSync, readFileSync, rmSync } from 'fs';
import { basename } from 'path'; import { basename } from 'path';
import { type Book } from './types'; import { type Book, type ReadList, type Series } from './types';
const API = JSON.parse(
readFileSync(`${process.env.FLAKE}/apps/list2series/.env`, { encoding: 'utf-8' }),
).API;
// Examples of calling this script: // Examples of calling this script:
// $ just l2s copy 0K65Q482KK7SD // $ just l2s copy 0K65Q482KK7SD
// $ just l2s meta 0K65Q482KK7SD // $ just l2s meta 0K65Q482KK7SD
const API = JSON.parse(
readFileSync(`${process.env.FLAKE}/apps/list2series/.env`, { encoding: 'utf-8' }),
).API;
const LIST_ID = process.argv[3]; const LIST_ID = process.argv[3];
const getListInfo = async() => { const getListInfo = async(): Promise<ReadList> => {
const res = await axios.request({ const res = await axios.request({
method: 'get', method: 'get',
maxBodyLength: Infinity, maxBodyLength: Infinity,
@ -28,8 +28,8 @@ const getListInfo = async() => {
return res.data; return res.data;
}; };
const getSeriesBooks = async(listName: string, seriesPath: string): Promise<Book[]> => { const getSeries = async(seriesTitle: string, operator = true): Promise<Series[]> => {
const series = await axios.request({ return (await axios.request({
method: 'post', method: 'post',
maxBodyLength: Infinity, maxBodyLength: Infinity,
url: 'https://komga.nelim.org/api/v1/series/list?unpaged=true', url: 'https://komga.nelim.org/api/v1/series/list?unpaged=true',
@ -41,14 +41,16 @@ const getSeriesBooks = async(listName: string, seriesPath: string): Promise<Book
data: JSON.stringify({ data: JSON.stringify({
condition: { condition: {
title: { title: {
operator: 'isNot', operator: operator ? 'is' : 'isNot',
value: '', value: seriesTitle,
}, },
}, },
}), }),
}); })).data.content;
};
const thisSeries = (series.data.content as Book[]).find((s) => s.url === seriesPath); const getSeriesBooks = async(listName: string, seriesPath: string): Promise<Book[]> => {
const thisSeries = (await getSeries('', false)).find((s) => s.url === seriesPath);
if (!thisSeries) { if (!thisSeries) {
throw new Error('Series could not be found'); throw new Error('Series could not be found');
@ -115,7 +117,7 @@ const getSeriesBooks = async(listName: string, seriesPath: string): Promise<Book
return books.data.content; return books.data.content;
}; };
const getBookInfo = async(id: string) => { const getBookInfo = async(id: string): Promise<Book> => {
const res = await axios.request({ const res = await axios.request({
method: 'get', method: 'get',
maxBodyLength: Infinity, maxBodyLength: Infinity,
@ -129,8 +131,9 @@ const getBookInfo = async(id: string) => {
return res.data; return res.data;
}; };
const scanLibrary = async() => { // There doesn't seem to be a way to wait for the scan to be done
return await axios.request({ const scanLibrary = (): void => {
axios.request({
method: 'post', method: 'post',
maxBodyLength: Infinity, maxBodyLength: Infinity,
url: 'https://komga.nelim.org/api/v1/libraries/0K4QG58XA29DZ/scan', url: 'https://komga.nelim.org/api/v1/libraries/0K4QG58XA29DZ/scan',
@ -140,14 +143,19 @@ const scanLibrary = async() => {
}); });
}; };
const setBookMetadata = async(i: number, source: Book, target: Book) => { const setBookMetadata = async(i: number, source: Book, target: Book): Promise<void> => {
source.metadata.title = `${source.seriesTitle} Issue #${source.metadata.number}`; const thisSeries = (await getSeries(source.seriesTitle))[0];
source.metadata.title = thisSeries.booksCount !== 1 ?
`${source.seriesTitle} Issue #${source.metadata.number}` :
source.metadata.title = source.seriesTitle;
source.metadata.number = i.toString(); source.metadata.number = i.toString();
source.metadata.numberSort = i; source.metadata.numberSort = i;
const metadata = JSON.stringify(source.metadata); const metadata = JSON.stringify(source.metadata);
const res = await axios.request({ axios.request({
method: 'patch', method: 'patch',
maxBodyLength: Infinity, maxBodyLength: Infinity,
url: `https://komga.nelim.org/api/v1/books/${target.id}/metadata`, url: `https://komga.nelim.org/api/v1/books/${target.id}/metadata`,
@ -157,13 +165,11 @@ const setBookMetadata = async(i: number, source: Book, target: Book) => {
}, },
data: metadata, data: metadata,
}); });
return res;
}; };
const main = async() => { const main = async(): Promise<void> => {
const list = await getListInfo(); const list = await getListInfo();
const ids = list.bookIds as string[]; const ids = list.bookIds;
const seriesPath = `/data/comics/[List] ${list.name}`; const seriesPath = `/data/comics/[List] ${list.name}`;
const listBooks = [] as Book[]; const listBooks = [] as Book[];
@ -186,7 +192,7 @@ const main = async() => {
linkSync(bookPath, inListPath); linkSync(bookPath, inListPath);
} }
await scanLibrary(); scanLibrary();
} }
else if (process.argv[2] === 'meta') { else if (process.argv[2] === 'meta') {

View file

@ -13,7 +13,22 @@ export interface Author {
role: string role: string
} }
export interface Metadata { export interface Link {
label: string
url: string
}
export interface ShortBookMetadata {
authors: Author[]
tags: unknown[]
releaseDate: string
summary: string
summaryNumber: string
created: string
lastModified: string
}
export interface BookMetadata {
title: string title: string
titleLock: boolean titleLock: boolean
summary: string summary: string
@ -26,11 +41,11 @@ export interface Metadata {
releaseDateLock: boolean releaseDateLock: boolean
authors: Author[] authors: Author[]
authorsLock: boolean authorsLock: boolean
tags: [] tags: unknown[]
tagsLock: boolean tagsLock: boolean
isbn: string isbn: string
isbnLock: boolean isbnLock: boolean
links: unknown[] links: Link[]
linksLock: boolean linksLock: boolean
created: string created: string
lastModified: string lastModified: string
@ -50,9 +65,71 @@ export interface Book {
sizeBytes: number sizeBytes: number
size: string size: string
media: Media media: Media
metadata: Metadata metadata: BookMetadata
readProgress: null | unknown readProgress: null | unknown
deleted: boolean deleted: boolean
fileHash: string fileHash: string
oneshot: boolean oneshot: boolean
} }
export interface SeriesMetadata {
status: string
statusLock: boolean
title: string
titleLock: boolean
titleSort: string
titleSortLock: boolean
summary: string
summaryLock: boolean
readingDirection: string
readingDirectionLock: boolean
publisher: string
publisherLock: boolean
ageRating: null | string
ageRatingLock: boolean
language: string
languageLock: boolean
genres: string[]
genresLock: boolean
tags: unknown[]
tagsLock: boolean
totalBookCount: null | number
totalBookCountLock: boolean
sharingLabels: unknown[]
sharingLabelsLock: boolean
links: Link[]
linksLock: boolean
alternateTitles: string[]
alternateTitlesLock: boolean
created: string
lastModified: string
}
export interface Series {
id: string
libraryId: string
name: string
url: string
created: string
lastModified: string
fileLastModified: string
booksCount: number
booksReadCount: number
booksUnreadCount: number
booksInProgressCount: number
metadata: SeriesMetadata
booksMetadata: ShortBookMetadata
deleted: boolean
oneshot: boolean
}
export interface ReadList {
id: string
name: string
summary: string
ordered: boolean
bookIds: string[]
createdDate: string
lastModifiedDate: string
filtered: boolean
}