1
1
import { Prisma } from '@prisma/client' ;
2
2
import { Job , Queue , Worker } from 'bullmq' ;
3
3
import { sanitizer } from '../../utils' ;
4
+ import { logger } from '../../utils/logging' ;
4
5
import { prisma } from '../db/client' ;
5
- import { downloadChapter , getChapterFromLocal } from '../utils/mangal' ;
6
+ import { downloadChapter , getChapterFromLocal , getMangaPath , removeManga } from '../utils/mangal' ;
6
7
import { notificationQueue } from './notify' ;
7
8
8
9
const mangaWithLibraryAndMetadata = Prisma . validator < Prisma . MangaArgs > ( ) ( {
9
10
include : { library : true , metadata : true } ,
10
11
} ) ;
11
12
12
- export type MangaWithLibraryAndMetadata = Prisma . MangaGetPayload < typeof mangaWithLibraryAndMetadata > ;
13
+ type MangaWithLibraryAndMetadata = Prisma . MangaGetPayload < typeof mangaWithLibraryAndMetadata > ;
14
+
15
+ const mangaWithChaptersAndLibrary = Prisma . validator < Prisma . MangaArgs > ( ) ( {
16
+ include : { chapters : true , library : true } ,
17
+ } ) ;
18
+
19
+ type MangaWithChaptersAndLibrary = Prisma . MangaGetPayload < typeof mangaWithChaptersAndLibrary > ;
13
20
export interface IDownloadWorkerData {
14
21
manga : MangaWithLibraryAndMetadata ;
15
22
chapterIndex : number ;
@@ -19,8 +26,19 @@ export const downloadWorker = new Worker(
19
26
'downloadQueue' ,
20
27
async ( job : Job ) => {
21
28
const { chapterIndex, manga } : IDownloadWorkerData = job . data ;
29
+ let filePath ;
22
30
try {
23
- const filePath = await downloadChapter ( manga . title , manga . source , chapterIndex , manga . library . path ) ;
31
+ const mangaInDb = await prisma . manga . findUnique ( { where : { id : manga . id } } ) ;
32
+ if ( ! mangaInDb ) {
33
+ job . log ( `Manga ${ manga . title } with id ${ manga . id } is removed from db.` ) ;
34
+ downloadWorker . on ( 'completed' , async ( { id } ) => {
35
+ if ( id === job . id ) {
36
+ await job . remove ( ) ;
37
+ }
38
+ } ) ;
39
+ return ;
40
+ }
41
+ filePath = await downloadChapter ( manga . title , manga . source , chapterIndex , manga . library . path ) ;
24
42
const chapter = await getChapterFromLocal ( filePath ) ;
25
43
26
44
await prisma . chapter . deleteMany ( {
@@ -46,6 +64,10 @@ export const downloadWorker = new Worker(
46
64
await job . updateProgress ( 100 ) ;
47
65
} catch ( err ) {
48
66
await job . log ( `${ err } ` ) ;
67
+ if ( err instanceof Prisma . PrismaClientKnownRequestError && err . code === 'P2003' && filePath ) {
68
+ await removeManga ( getMangaPath ( manga . library . path , manga . title ) ) ;
69
+ await job . log ( `Removed ${ manga . title } folder because it was not found in db` ) ;
70
+ }
49
71
throw err ;
50
72
}
51
73
} ,
@@ -71,3 +93,19 @@ export const downloadQueue = new Queue('downloadQueue', {
71
93
} ,
72
94
} ,
73
95
} ) ;
96
+
97
+ export const removeDownloadJobs = async ( manga : MangaWithChaptersAndLibrary ) => {
98
+ await Promise . all (
99
+ manga . chapters . map ( async ( chapter ) => {
100
+ const jobId = `${ sanitizer ( manga . title ) } _${ chapter . index } _download` ;
101
+ try {
102
+ const job = await downloadQueue . getJob ( jobId ) ;
103
+ if ( job ) {
104
+ await job . remove ( ) ;
105
+ }
106
+ } catch ( err ) {
107
+ logger . error ( `job could not be cancelled. err: ${ err } ` ) ;
108
+ }
109
+ } ) ,
110
+ ) ;
111
+ } ;
0 commit comments