-
Notifications
You must be signed in to change notification settings - Fork 5
/
tools.service.ts
128 lines (117 loc) · 4.17 KB
/
tools.service.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import { LoggerService } from '@/common/logger/logger.service';
import { COOKIE_PATH } from '@/constants/cookie-path';
import { ProxyFetchService } from '@/libs/proxy-fetch';
import { OcrService } from '@/tools/ocr/ocrService';
import type { User } from '@/user/entities/user.entity';
import { Injectable } from '@nestjs/common';
import { sha1 } from '@powerfulyang/node-utils';
import { ensureFileSync } from 'fs-extra';
import { spawn } from 'node:child_process';
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
import { basename, join } from 'node:path';
import process from 'node:process';
import { concatWith, fromEvent, merge, of, switchMap, takeUntil } from 'rxjs';
import sharp from 'sharp';
import type { ImageLike } from 'tesseract.js';
@Injectable()
export class ToolsService {
private readonly proxyUri: string = '';
constructor(
private readonly logger: LoggerService,
private readonly proxyFetchService: ProxyFetchService,
private readonly ocrService: OcrService,
) {
this.logger.setContext(ToolsService.name);
this.proxyUri = this.proxyFetchService.proxyUri;
}
generateVideoDownloadCommand(url: string, user: User) {
const hash = sha1(url);
const downloadPath = join(process.cwd(), `assets/yt-dlp/${hash}.%(ext)s`);
const getFilenameCommand = `yt-dlp ${url} --proxy '${this.proxyUri}' --output '${downloadPath}' --get-filename`;
const cookiesPath = join(COOKIE_PATH, 'yt-dlp', user.id.toString());
let cookiesOption = '';
if (existsSync(cookiesPath)) {
cookiesOption = `--cookies ${cookiesPath}`;
}
const downloadCommand = `yt-dlp ${url} ${cookiesOption} --proxy '${this.proxyUri}' --output '${downloadPath}'`;
return {
getFilenameCommand,
downloadCommand,
};
}
async ocr(imageBuffer: ImageLike) {
const result = await this.ocrService.recognize(imageBuffer);
return result.text;
}
download(videoUrl: string, user: User) {
const { downloadCommand, getFilenameCommand } = this.generateVideoDownloadCommand(
videoUrl,
user,
);
const download = spawn(downloadCommand, {
shell: true,
});
const data$ = fromEvent(download.stdout, 'data', (event: Buffer) => {
return {
data: event.toString('utf8'),
};
});
const error$ = fromEvent(download.stderr, 'data', (event: Buffer) => {
return {
data: event.toString('utf8'),
};
});
const close$ = fromEvent(download, 'close');
const download$ = merge(data$, error$).pipe(takeUntil(close$));
// const filename = basename(event.toString('utf8'));
// const downloadUrl = `https://api.powerfulyang.com/yt-dlp/${filename}`;
// return {
// type: 'done',
// data: downloadUrl,
// };
return download$.pipe(
concatWith(
of(null).pipe(
switchMap(() => {
const getFilename = spawn(getFilenameCommand, {
shell: true,
});
const _data$ = fromEvent(getFilename.stdout, 'data', (event: Buffer) => {
const filename = basename(event.toString('utf8'));
const downloadUrl = `https://api.powerfulyang.com/yt-dlp/${filename}`;
return {
type: 'done',
data: downloadUrl,
};
});
const _close$ = fromEvent(getFilename, 'close');
const _error$ = fromEvent(getFilename.stderr, 'data', (event: Buffer) => {
return {
type: 'error',
data: event.toString('utf8'),
};
});
return merge(_data$, _error$).pipe(takeUntil(_close$));
}),
),
),
);
}
saveCookies(cookies: string, user: User) {
const path = join(COOKIE_PATH, 'yt-dlp', user.id.toString());
ensureFileSync(path);
writeFileSync(path, cookies);
}
readCookies(user: User) {
const path = join(COOKIE_PATH, 'yt-dlp', user.id.toString());
try {
return readFileSync(path, 'utf8');
} catch {
return '';
}
}
compress(data: Buffer) {
const sharpInstance = sharp(data);
return sharpInstance.rotate().webp().resize(300, 300).toBuffer();
}
}