coomer-downloader 3.4.0 → 3.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,13 +2,13 @@ import fs from 'node:fs';
2
2
  import { Readable, Transform } from 'node:stream';
3
3
  import { pipeline } from 'node:stream/promises';
4
4
  import { Subject } from 'rxjs';
5
- import { tryFixCoomerUrl } from '../api/coomer-api';
6
5
  import type { AbortControllerSubject, DownloaderSubject } from '../types';
7
6
  import { deleteFile, getFileSize, mkdir } from '../utils/io';
8
7
  import { sleep } from '../utils/promise';
9
8
  import { fetchByteRange } from '../utils/requests';
10
9
  import { Timer } from '../utils/timer';
11
- import type { CoomerFile, CoomerFileList } from './file';
10
+ import type { CoomerFile } from './file';
11
+ import type { CoomerFileList } from './filelist';
12
12
 
13
13
  export class Downloader {
14
14
  public subject = new Subject<DownloaderSubject>();
@@ -34,7 +34,7 @@ export class Downloader {
34
34
  this.setAbortControllerListener();
35
35
  }
36
36
 
37
- async fetchStream(
37
+ private async fetchStream(
38
38
  file: CoomerFile,
39
39
  stream: Readable,
40
40
  sizeOld = 0,
@@ -99,7 +99,10 @@ export class Downloader {
99
99
  }
100
100
  }
101
101
 
102
- async downloadFile(file: CoomerFile, retries = this.fetchRetries): Promise<void> {
102
+ public async downloadFile(
103
+ file: CoomerFile,
104
+ retries = this.fetchRetries,
105
+ ): Promise<void> {
103
106
  const signal = this.abortController.signal;
104
107
  try {
105
108
  file.downloaded = await getFileSize(file.filepath as string);
@@ -129,8 +132,8 @@ export class Downloader {
129
132
  if (signal.reason === 'FILE_SKIP') return;
130
133
  }
131
134
  if (retries > 0) {
132
- if (/coomer|kemono/.test(file.url)) {
133
- file.url = tryFixCoomerUrl(file.url, retries);
135
+ if (this.filelist.provider?.fixURL) {
136
+ file.url = this.filelist.provider.fixURL(file.url, retries);
134
137
  }
135
138
  await sleep(1000);
136
139
  return await this.downloadFile(file, retries - 1);
@@ -139,7 +142,7 @@ export class Downloader {
139
142
  }
140
143
  }
141
144
 
142
- async downloadFiles(): Promise<void> {
145
+ public async downloadFiles(): Promise<void> {
143
146
  mkdir(this.filelist.dirPath as string);
144
147
 
145
148
  this.subject.next({ type: 'FILES_DOWNLOADING_START' });
@@ -0,0 +1,29 @@
1
+ import { getFileSize } from '../utils/io';
2
+
3
+ export class CoomerFile {
4
+ public active = false;
5
+ public hash?: string;
6
+
7
+ constructor(
8
+ public name: string,
9
+ public url: string,
10
+ public filepath = '',
11
+ public size?: number,
12
+ public downloaded = 0,
13
+ public content?: string,
14
+ ) {}
15
+
16
+ public async calcDownloadedSize() {
17
+ this.downloaded = await getFileSize(this.filepath as string);
18
+ return this;
19
+ }
20
+
21
+ public get textContent() {
22
+ const text = `${this.name || ''} ${this.content || ''}`.toLowerCase();
23
+ return text;
24
+ }
25
+
26
+ public static from(f: Pick<CoomerFile, 'name' | 'url'> & Partial<CoomerFile>) {
27
+ return new CoomerFile(f.name, f.url, f.filepath, f.size, f.downloaded, f.content);
28
+ }
29
+ }
@@ -1,43 +1,17 @@
1
1
  import os from 'node:os';
2
2
  import path from 'node:path';
3
- import logger from '../logger';
3
+ import type { ProviderAPI } from '../api/provider';
4
4
  import type { MediaType } from '../types';
5
5
  import { collectUniquesAndDuplicatesBy, removeDuplicatesBy } from '../utils/duplicates';
6
6
  import { filterString } from '../utils/filters';
7
- import { deleteFile, getFileHash, getFileSize, sanitizeFilename } from '../utils/io';
7
+ import { deleteFile, getFileHash, sanitizeFilename } from '../utils/io';
8
8
  import { testMediaType } from '../utils/mediatypes';
9
-
10
- export class CoomerFile {
11
- public active = false;
12
- public hash?: string;
13
-
14
- constructor(
15
- public name: string,
16
- public url: string,
17
- public filepath = '',
18
- public size?: number,
19
- public downloaded = 0,
20
- public content?: string,
21
- ) {}
22
-
23
- public async getDownloadedSize() {
24
- this.downloaded = await getFileSize(this.filepath as string);
25
- return this;
26
- }
27
-
28
- public get textContent() {
29
- const text = `${this.name || ''} ${this.content || ''}`.toLowerCase();
30
- return text;
31
- }
32
-
33
- public static from(f: Pick<CoomerFile, 'name' | 'url'> & Partial<CoomerFile>) {
34
- return new CoomerFile(f.name, f.url, f.filepath, f.size, f.downloaded, f.content);
35
- }
36
- }
9
+ import type { CoomerFile } from './file';
37
10
 
38
11
  export class CoomerFileList {
39
12
  public dirPath?: string;
40
13
  public dirName?: string;
14
+ public provider?: ProviderAPI;
41
15
 
42
16
  constructor(public files: CoomerFile[] = []) {}
43
17
 
@@ -77,7 +51,7 @@ export class CoomerFileList {
77
51
 
78
52
  public async calculateFileSizes() {
79
53
  for (const file of this.files) {
80
- await file.getDownloadedSize();
54
+ await file.calcDownloadedSize();
81
55
  }
82
56
  return this;
83
57
  }
@@ -97,9 +71,9 @@ export class CoomerFileList {
97
71
 
98
72
  const { duplicates } = collectUniquesAndDuplicatesBy(this.files, 'hash');
99
73
 
100
- console.log({ duplicates });
74
+ // console.log({ duplicates });
101
75
 
102
- logger.debug(`duplicates: ${JSON.stringify(duplicates)}`);
76
+ // logger.debug(`duplicates: ${JSON.stringify(duplicates)}`);
103
77
 
104
78
  duplicates.forEach((f) => {
105
79
  deleteFile(f.filepath);
@@ -0,0 +1,3 @@
1
+ export { Downloader } from './downloader';
2
+ export { CoomerFile } from './file';
3
+ export { CoomerFileList } from './filelist';
package/src/index.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env -S node --no-warnings=ExperimentalWarning
2
2
 
3
3
  import process from 'node:process';
4
- import { apiHandler } from './api';
4
+ import { resolveAPI } from './api';
5
5
  import { argumentHander } from './cli/args-handler';
6
6
  import { createReactInk } from './cli/ui';
7
7
  import { useInkStore } from './cli/ui/store';
8
- import { Downloader } from './services/downloader';
8
+ import { Downloader } from './core';
9
9
  import { parseSizeValue } from './utils/filters';
10
10
  import { setGlobalHeaders } from './utils/requests';
11
11
 
@@ -15,7 +15,7 @@ async function run() {
15
15
  const { url, dir, media, include, exclude, minSize, maxSize, skip, removeDupilicates } =
16
16
  argumentHander();
17
17
 
18
- const filelist = await apiHandler(url);
18
+ const filelist = await resolveAPI(url);
19
19
 
20
20
  filelist
21
21
  .setDirPath(dir)
@@ -1,9 +0,0 @@
1
- import { CoomerFile, CoomerFileList } from '../services/file';
2
-
3
- export async function getPlainFileData(url: string): Promise<CoomerFileList> {
4
- const name = url.split('/').pop() as string;
5
- const file = CoomerFile.from({ name, url });
6
- const filelist = new CoomerFileList([file]);
7
- filelist.dirName = '';
8
- return filelist;
9
- }
File without changes