2023-11-20 01:37:55 +09:00
import fs from "node:fs/promises" ;
import { createWriteStream } from "node:fs" ;
import stream from "node:stream/promises" ;
import { Zip , ZipPassThrough } from "fflate" ;
2023-11-19 02:25:32 +09:00
import { Database } from "./database" ;
2023-12-02 23:22:33 +09:00
import { type TPlatform , site } from "./platform" ;
2023-11-19 02:25:32 +09:00
export type Book = {
id : number ;
2023-12-02 23:22:33 +09:00
platform : TPlatform ;
2023-11-19 02:25:32 +09:00
readerUrl : string ;
2023-11-20 22:56:09 +09:00
title : string ;
authors : Array < string > ;
2023-11-19 02:25:32 +09:00
} ;
export function createLibrary ( db : Database ) {
return {
2023-11-20 22:56:09 +09:00
async add ( readerUrlOrBook : string | Book ) {
if ( typeof readerUrlOrBook === "string" ) {
2023-12-02 23:22:33 +09:00
const platform = site ( readerUrlOrBook ) ;
2023-11-20 22:56:09 +09:00
await db . run (
` insert into books(platform_id, reader_url) values((select id from platforms where name = ?), ?) ` ,
platform ,
readerUrlOrBook ,
) ;
return ;
}
2023-11-19 02:25:32 +09:00
await db . run (
2023-11-20 22:56:09 +09:00
` \
insert into books (
platform_id ,
reader_url ,
title ,
authors )
values ( ( select id from platforms where name = ? ) , ? , ? , ? )
on conflict ( reader_url )
do update set title = excluded . title , authors = excluded . authors
` ,
2023-12-02 23:22:33 +09:00
readerUrlOrBook . platform ,
2023-11-20 22:56:09 +09:00
readerUrlOrBook . readerUrl ,
readerUrlOrBook . title ,
JSON . stringify ( readerUrlOrBook . authors ) ,
2023-11-19 02:25:32 +09:00
) ;
2023-11-19 20:51:29 +09:00
} ,
async delete ( id : number ) {
await db . run ( ` delete from books where id = ? ` , id ) ;
2023-11-19 02:25:32 +09:00
} ,
2023-11-19 22:04:19 +09:00
async get ( id : number ) : Promise < Book | undefined > {
2023-11-20 22:56:09 +09:00
const row = await db . get (
` select books.id, platforms.name as platform, books.reader_url as readerUrl, books.title, books.authors from books left join platforms on books.platform_id = platforms.id where books.id = ? ` ,
2023-11-19 22:04:19 +09:00
id ,
) ;
2023-11-20 22:56:09 +09:00
const book : Book | undefined = row && {
. . . row ,
authors : JSON.parse ( row . authors ) ,
} ;
2023-11-19 22:04:19 +09:00
return book ;
} ,
2023-11-19 02:25:32 +09:00
async getBooks ( ) : Promise < Array < Book > > {
2023-11-20 22:56:09 +09:00
const rows = await db . all (
` select books.id, platforms.name as platform, books.reader_url as readerUrl, books.title, books.authors from books left join platforms on books.platform_id = platforms.id ` ,
2023-11-19 02:25:32 +09:00
) ;
2023-11-20 22:56:09 +09:00
const books : Array < Book > = rows . map ( ( row ) = > ( {
. . . row ,
authors : JSON.parse ( row . authors ) ,
} ) ) ;
2023-11-19 02:25:32 +09:00
return books ;
} ,
2023-12-02 15:56:24 +09:00
async archive (
path : string ,
book : Book ,
opts : {
outDir : string ;
outAuthorsLimit : number ;
} ,
) {
2023-11-23 10:24:08 +09:00
const bookDir = await fs . stat ( path ) ;
2023-11-20 01:37:55 +09:00
2023-11-23 10:24:08 +09:00
if ( ! bookDir . isDirectory ( ) ) {
throw new Error ( ` Not found: ${ path } ` ) ;
}
2023-12-02 15:56:24 +09:00
const title = ` ${ book . authors
. slice ( 0 , opts . outAuthorsLimit )
. join ( "、" ) } 「 $ { book . title } 」 ` .replace(/[/]/g, "%2F");
2023-11-23 10:24:08 +09:00
2023-12-02 15:56:24 +09:00
const out = createWriteStream ( ` ${ opts . outDir } / ${ title } .cbz ` ) ;
2023-11-20 01:37:55 +09:00
2023-11-23 10:24:08 +09:00
const zip = new Zip ( function cb ( err , data , final ) {
if ( err ) {
out . destroy ( err ) ;
return ;
2023-11-20 01:37:55 +09:00
}
2023-11-23 10:24:08 +09:00
out [ final ? "end" : "write" ] ( data ) ;
} ) ;
2023-11-20 01:37:55 +09:00
2023-11-23 10:24:08 +09:00
const files = await fs . readdir ( path ) ;
for ( const file of files ) {
const data = new ZipPassThrough ( file ) ;
zip . add ( data ) ;
const buffer = await fs . readFile ( ` ${ path } / ${ file } ` ) ;
data . push ( buffer , true ) ;
2023-11-20 01:37:55 +09:00
}
2023-11-23 10:24:08 +09:00
zip . end ( ) ;
await stream . finished ( out ) ;
await fs . rm ( path , { recursive : true } ) ;
2023-11-20 01:37:55 +09:00
} ,
2023-11-19 02:25:32 +09:00
} ;
}