@soga/task 0.0.1 → 0.2.13

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.
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # downloader
package/dist/main.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './upload-task/create';
2
+ export * from './upload-task/run';
3
+ export * from './upload-task/create-affix';
package/dist/main.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./upload-task/create"), exports);
18
+ __exportStar(require("./upload-task/run"), exports);
19
+ __exportStar(require("./upload-task/create-affix"), exports);
@@ -0,0 +1,2 @@
1
+ import { UploadFileParams } from './types';
2
+ export declare const createUploadAffixTask: (params: UploadFileParams) => Promise<number>;
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createUploadAffixTask = void 0;
4
+ const types_1 = require("@soga/types");
5
+ const fileinfo_1 = require("../utils/fileinfo");
6
+ const path_1 = require("path");
7
+ const sdk_1 = require("@soga/sdk");
8
+ const entities_1 = require("@soga/entities");
9
+ const createUploadAffixTask = async (params) => {
10
+ const sdk = (0, sdk_1.getSdk)(params.sdk_domain);
11
+ const userInfo = await sdk.getUserInfo({ refresh: false });
12
+ const { id: uid } = userInfo;
13
+ const { cloud_info, album } = await sdk.getRecordInfo({
14
+ space_id: params.space_id,
15
+ record_id: params.record_id,
16
+ refresh: true,
17
+ });
18
+ const config = {
19
+ file_keeps: album.config.file_keeps,
20
+ };
21
+ const { name: space_name } = await sdk.getSpaceInfo({
22
+ space_id: params.space_id,
23
+ refresh: true,
24
+ });
25
+ const aid = album.id;
26
+ let ali_host_id = 0;
27
+ let baidu_host_id = 0;
28
+ if (cloud_info[types_1.HostType.ALI]) {
29
+ ali_host_id = cloud_info[types_1.HostType.ALI].id;
30
+ }
31
+ if (cloud_info[types_1.HostType.BAIDU]) {
32
+ baidu_host_id = cloud_info[types_1.HostType.BAIDU].id;
33
+ }
34
+ const { paths } = params;
35
+ const { length } = paths;
36
+ const inputs = [];
37
+ for (let i = 0; i < length; i++) {
38
+ const filepath = paths[i];
39
+ const isValid = await (0, fileinfo_1.isValidPath)(filepath);
40
+ if (isValid) {
41
+ const fileinfo = await (0, fileinfo_1.getFileinfo)(filepath);
42
+ const { record_type } = fileinfo;
43
+ if (record_type == types_1.RecordType.FOLDER)
44
+ continue;
45
+ inputs.push({
46
+ filename: (0, path_1.basename)(filepath),
47
+ filepath,
48
+ filesize: fileinfo.size,
49
+ local_btime: fileinfo.local_btime,
50
+ local_ctime: fileinfo.local_ctime,
51
+ local_mtime: fileinfo.local_mtime,
52
+ });
53
+ }
54
+ }
55
+ const file = {
56
+ inputs,
57
+ space_id: params.space_id,
58
+ space_name,
59
+ filepath: '',
60
+ is_ready: true,
61
+ config,
62
+ uid,
63
+ aid,
64
+ baidu_host_id,
65
+ ali_host_id,
66
+ is_paused: false,
67
+ pid: 0,
68
+ root_id: 0,
69
+ total_count: 1,
70
+ type: types_1.RecordType.AFFIX,
71
+ task_record_id: params.record_id,
72
+ external_texts: [],
73
+ };
74
+ const fileRepository = params.dataSource.getRepository(entities_1.UploadFile);
75
+ const res = await fileRepository.save(fileRepository.create(file));
76
+ return res.id;
77
+ };
78
+ exports.createUploadAffixTask = createUploadAffixTask;
@@ -0,0 +1,2 @@
1
+ import { UploadFileParams } from './types';
2
+ export declare const createUploadTask: (params: UploadFileParams) => Promise<void>;
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createUploadTask = void 0;
4
+ const fileinfo_1 = require("../utils/fileinfo");
5
+ const types_1 = require("@soga/types");
6
+ const path_1 = require("path");
7
+ const sdk_1 = require("@soga/sdk");
8
+ const entities_1 = require("@soga/entities");
9
+ const utils_1 = require("./utils");
10
+ const createUploadTask = async (params) => {
11
+ const sdk = (0, sdk_1.getSdk)(params.sdk_domain);
12
+ const userInfo = await sdk.getUserInfo({ refresh: false });
13
+ const { id: uid } = userInfo;
14
+ const { cloud_info, album } = await sdk.getRecordInfo({
15
+ space_id: params.space_id,
16
+ record_id: params.record_id,
17
+ refresh: true,
18
+ });
19
+ const config = {
20
+ file_keeps: album.config.file_keeps,
21
+ };
22
+ const keep_source = config.file_keeps == types_1.RecordFileKeep.SOURCE ||
23
+ config.file_keeps == types_1.RecordFileKeep.BOTH;
24
+ const { name: space_name } = await sdk.getSpaceInfo({
25
+ space_id: params.space_id,
26
+ refresh: true,
27
+ });
28
+ const aid = album.id;
29
+ let ali_host_id = 0;
30
+ let baidu_host_id = 0;
31
+ if (cloud_info[types_1.HostType.ALI]) {
32
+ ali_host_id = cloud_info[types_1.HostType.ALI].id;
33
+ }
34
+ if (cloud_info[types_1.HostType.BAIDU]) {
35
+ baidu_host_id = cloud_info[types_1.HostType.BAIDU].id;
36
+ }
37
+ const { paths } = params;
38
+ const files = [];
39
+ const folders = [];
40
+ const subtitles = [];
41
+ const medias = [];
42
+ const { length } = paths;
43
+ for (let i = 0; i < length; i++) {
44
+ const filepath = paths[i];
45
+ const isValid = await (0, fileinfo_1.isValidPath)(filepath);
46
+ if (isValid) {
47
+ const fileinfo = await (0, fileinfo_1.getFileinfo)(filepath);
48
+ const { record_type } = fileinfo;
49
+ const { dir, base, name } = (0, path_1.parse)(filepath);
50
+ const info = {
51
+ type: record_type,
52
+ title: name,
53
+ filename: base,
54
+ basepath: (0, path_1.join)(dir, name),
55
+ filepath: filepath,
56
+ filesize: fileinfo.size,
57
+ local_btime: fileinfo.local_btime,
58
+ local_ctime: fileinfo.local_ctime,
59
+ local_mtime: fileinfo.local_mtime,
60
+ parent_path: (0, path_1.dirname)(filepath),
61
+ file_type: 'file',
62
+ };
63
+ if (record_type == types_1.RecordType.FOLDER) {
64
+ folders.push(info);
65
+ }
66
+ else {
67
+ const is_media = record_type == types_1.RecordType.VIDEO || record_type == types_1.RecordType.AUDIO;
68
+ const is_subtitle = (0, fileinfo_1.isSubtitle)(filepath);
69
+ if (is_media) {
70
+ const keywords = info.title
71
+ .split(/[ _\-.{}[\]、,,。::!?<>《》【】]+/g)
72
+ .filter((k) => k.length >= 2);
73
+ medias.push({
74
+ ...info,
75
+ file_type: 'media',
76
+ keywords,
77
+ });
78
+ }
79
+ else if (is_subtitle) {
80
+ subtitles.push({
81
+ ...info,
82
+ file_type: 'subtitle',
83
+ });
84
+ }
85
+ else {
86
+ files.push(info);
87
+ }
88
+ }
89
+ }
90
+ }
91
+ const match_map = {};
92
+ let subs = [...subtitles];
93
+ medias.forEach((media) => {
94
+ const matched = (0, utils_1.matchSubtitles)(media, subs);
95
+ if (matched) {
96
+ media.external_texts = matched.map((item) => item.filepath);
97
+ matched.forEach((item) => (match_map[item.filepath] = true));
98
+ subs = subs.filter((item) => !match_map[item.filepath]);
99
+ }
100
+ });
101
+ let subtitle_queues = subtitles;
102
+ if (!keep_source) {
103
+ subtitle_queues = subtitles.filter((item) => !match_map[item.filepath]);
104
+ }
105
+ const queues = [...subtitle_queues, ...medias, ...files, ...folders].map((item) => {
106
+ const info = {
107
+ inputs: [
108
+ {
109
+ filename: item.filename,
110
+ filepath: item.filepath,
111
+ filesize: item.filesize,
112
+ local_btime: item.local_btime,
113
+ local_ctime: item.local_ctime,
114
+ local_mtime: item.local_mtime,
115
+ },
116
+ ],
117
+ filepath: item.filepath,
118
+ space_id: params.space_id,
119
+ space_name,
120
+ aid,
121
+ ali_host_id,
122
+ baidu_host_id,
123
+ config,
124
+ is_paused: false,
125
+ is_ready: item.type != types_1.RecordType.FOLDER,
126
+ type: item.type,
127
+ task_record_id: params.record_id,
128
+ uid,
129
+ total_count: item.type == types_1.RecordType.FOLDER ? undefined : 1,
130
+ };
131
+ if (item.file_type == 'media') {
132
+ info.external_texts = item.external_texts;
133
+ }
134
+ return info;
135
+ });
136
+ if (!queues.length) {
137
+ return;
138
+ }
139
+ const queryRunner = params.dataSource.createQueryRunner();
140
+ await queryRunner.connect();
141
+ await queryRunner.startTransaction();
142
+ try {
143
+ const fileRepository = queryRunner.manager.getRepository(entities_1.UploadFile);
144
+ const { length } = queues;
145
+ const size = 50;
146
+ for (let i = 0; i < length; i += size) {
147
+ const items = queues.slice(i, i + size);
148
+ await fileRepository
149
+ .createQueryBuilder()
150
+ .insert()
151
+ .into(entities_1.UploadFile)
152
+ .values(items)
153
+ .execute();
154
+ }
155
+ await queryRunner.commitTransaction();
156
+ }
157
+ catch (err) {
158
+ await queryRunner.rollbackTransaction();
159
+ }
160
+ finally {
161
+ await queryRunner.release();
162
+ }
163
+ };
164
+ exports.createUploadTask = createUploadTask;
@@ -0,0 +1,7 @@
1
+ import { DataSource } from 'typeorm';
2
+ export declare const runUploadTask: (params: RunnerParams) => Promise<true>;
3
+ type RunnerParams = {
4
+ dataSource: DataSource;
5
+ uid: number;
6
+ };
7
+ export {};
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runUploadTask = void 0;
4
+ const entities_1 = require("@soga/entities");
5
+ const single_runner_1 = require("./single-runner");
6
+ const processMap = new Map();
7
+ const runUploadTask = async (params) => {
8
+ const cache = processMap.get(params.uid);
9
+ if (cache)
10
+ return cache;
11
+ processMap.set(params.uid, true);
12
+ const fileRepository = params.dataSource.getRepository(entities_1.UploadFile);
13
+ const loop = async () => {
14
+ const fileitem = await fileRepository.findOneBy({
15
+ uid: params.uid,
16
+ root_id: 0,
17
+ is_ready: false,
18
+ });
19
+ if (!fileitem)
20
+ return;
21
+ const st = new single_runner_1.SingleRunner({
22
+ dataSource: params.dataSource,
23
+ file_id: fileitem.id,
24
+ });
25
+ await st.start();
26
+ await loop();
27
+ };
28
+ await loop();
29
+ processMap.delete(params.uid);
30
+ };
31
+ exports.runUploadTask = runUploadTask;
@@ -0,0 +1,23 @@
1
+ import { FileCache } from '@soga/file-cache';
2
+ import { DataSource } from 'typeorm';
3
+ export declare class SingleRunner {
4
+ protected fc: FileCache;
5
+ private file_id;
6
+ private cache_file;
7
+ private dataSource;
8
+ private fileRepository;
9
+ private PARSED_FILES_KEY;
10
+ private INSERT_FOLDERS_KEY;
11
+ private INSERT_FILES_KEY;
12
+ constructor({ dataSource, file_id, }: {
13
+ dataSource: DataSource;
14
+ file_id: number;
15
+ });
16
+ start(): Promise<void>;
17
+ private end;
18
+ private insertFiles;
19
+ private insertFolders;
20
+ private parseRawFiles;
21
+ private destroy;
22
+ private init;
23
+ }
@@ -0,0 +1,337 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SingleRunner = void 0;
4
+ const entities_1 = require("@soga/entities");
5
+ const file_cache_1 = require("@soga/file-cache");
6
+ const types_1 = require("@soga/types");
7
+ const fs_extra_1 = require("fs-extra");
8
+ const glob_1 = require("glob");
9
+ const os_1 = require("os");
10
+ const path_1 = require("path");
11
+ const typeorm_1 = require("typeorm");
12
+ const fileinfo_1 = require("../utils/fileinfo");
13
+ const utils_1 = require("./utils");
14
+ class SingleRunner {
15
+ fc;
16
+ file_id;
17
+ cache_file;
18
+ dataSource;
19
+ fileRepository;
20
+ PARSED_FILES_KEY = 'parsed_files';
21
+ INSERT_FOLDERS_KEY = 'insert_folders';
22
+ INSERT_FILES_KEY = 'insert_files';
23
+ constructor({ dataSource, file_id, }) {
24
+ this.dataSource = dataSource;
25
+ this.fileRepository = dataSource.getRepository(entities_1.UploadFile);
26
+ this.file_id = file_id;
27
+ }
28
+ async start() {
29
+ await this.init();
30
+ await this.parseRawFiles();
31
+ await this.insertFolders();
32
+ await this.insertFiles();
33
+ await this.end();
34
+ await this.destroy();
35
+ }
36
+ async end() {
37
+ const fileitem = await this.fileRepository.findOneBy({
38
+ id: this.file_id,
39
+ });
40
+ if (!fileitem)
41
+ return;
42
+ const total = await this.fileRepository.countBy({
43
+ root_id: this.file_id,
44
+ type: (0, typeorm_1.Not)(types_1.RecordType.FOLDER),
45
+ });
46
+ fileitem.is_ready = true;
47
+ fileitem.total_count = total;
48
+ await this.fileRepository.save(fileitem);
49
+ }
50
+ async insertFiles() {
51
+ const key = this.INSERT_FILES_KEY;
52
+ const cache = await this.fc.get(key);
53
+ if (cache)
54
+ return cache;
55
+ const data = await this.fc.get(this.PARSED_FILES_KEY);
56
+ if (!data)
57
+ return;
58
+ const fileitem = await this.fileRepository.findOneBy({
59
+ id: this.file_id,
60
+ });
61
+ if (!fileitem)
62
+ return;
63
+ const { config } = fileitem;
64
+ const keep_source = config.file_keeps == types_1.RecordFileKeep.SOURCE ||
65
+ config.file_keeps == types_1.RecordFileKeep.BOTH;
66
+ const { subtitles, medias, files: normal_files } = data;
67
+ const match_map = {};
68
+ let subs = [...subtitles];
69
+ medias.forEach((media) => {
70
+ const matched = (0, utils_1.matchSubtitles)(media, subs);
71
+ if (matched) {
72
+ media.external_texts = matched.map((item) => item.filepath);
73
+ matched.forEach((item) => (match_map[item.filepath] = true));
74
+ subs = subs.filter((item) => !match_map[item.filepath]);
75
+ }
76
+ });
77
+ let subtitle_queues = subtitles;
78
+ if (!keep_source) {
79
+ subtitle_queues = subtitles.filter((item) => !match_map[item.filepath]);
80
+ }
81
+ const queues = [...subtitle_queues, ...normal_files, ...medias];
82
+ const { length } = queues;
83
+ if (!length)
84
+ return;
85
+ const items = [];
86
+ for (let i = 0; i < length; i++) {
87
+ const item = queues[i];
88
+ const { filepath } = item;
89
+ const isValid = await (0, fileinfo_1.isValidPath)(filepath);
90
+ if (!isValid)
91
+ continue;
92
+ const exist = await this.fileRepository.findOneBy({
93
+ root_id: this.file_id,
94
+ filepath,
95
+ });
96
+ if (exist)
97
+ continue;
98
+ const parentPath = (0, path_1.dirname)(filepath);
99
+ const parent = parentPath == fileitem.filepath
100
+ ? fileitem
101
+ : await this.fileRepository.findOneBy({
102
+ root_id: this.file_id,
103
+ filepath: parentPath,
104
+ });
105
+ if (!parent) {
106
+ continue;
107
+ }
108
+ const pid = parent.id;
109
+ const info = {
110
+ inputs: [
111
+ {
112
+ filename: item.filename,
113
+ filepath: item.filepath,
114
+ filesize: item.filesize,
115
+ local_btime: item.local_btime,
116
+ local_ctime: item.local_ctime,
117
+ local_mtime: item.local_mtime,
118
+ },
119
+ ],
120
+ filepath: item.filepath,
121
+ space_id: fileitem.space_id,
122
+ space_name: fileitem.space_name,
123
+ aid: fileitem.aid,
124
+ ali_host_id: fileitem.ali_host_id,
125
+ baidu_host_id: fileitem.baidu_host_id,
126
+ config,
127
+ is_paused: false,
128
+ is_ready: item.type != types_1.RecordType.FOLDER,
129
+ type: item.type,
130
+ task_record_id: fileitem.task_record_id,
131
+ uid: fileitem.uid,
132
+ root_id: fileitem.id,
133
+ pid,
134
+ total_count: 1,
135
+ };
136
+ if (item.file_type == 'media') {
137
+ info.external_texts = item.external_texts;
138
+ }
139
+ items.push(info);
140
+ }
141
+ const queryRunner = this.dataSource.createQueryRunner();
142
+ await queryRunner.connect();
143
+ await queryRunner.startTransaction();
144
+ try {
145
+ const fileRepository = queryRunner.manager.getRepository(entities_1.UploadFile);
146
+ const { length } = items;
147
+ const size = 50;
148
+ for (let i = 0; i < length; i += size) {
149
+ const chunks = items.slice(i, i + size);
150
+ await fileRepository
151
+ .createQueryBuilder()
152
+ .insert()
153
+ .into(entities_1.UploadFile)
154
+ .values(chunks)
155
+ .execute();
156
+ }
157
+ await queryRunner.commitTransaction();
158
+ }
159
+ catch (err) {
160
+ await queryRunner.rollbackTransaction();
161
+ }
162
+ finally {
163
+ await queryRunner.release();
164
+ }
165
+ await this.fc.set(key, true);
166
+ }
167
+ async insertFolders() {
168
+ const key = this.INSERT_FOLDERS_KEY;
169
+ const cache = await this.fc.get(key);
170
+ if (cache)
171
+ return cache;
172
+ const data = await this.fc.get(this.PARSED_FILES_KEY);
173
+ if (!data)
174
+ return;
175
+ const { folders } = data;
176
+ const { length } = folders;
177
+ const fileitem = await this.fileRepository.findOneBy({
178
+ id: this.file_id,
179
+ });
180
+ if (!fileitem)
181
+ return;
182
+ for (let i = 0; i < length; i++) {
183
+ const folderPath = (0, path_1.resolve)(fileitem.filepath, folders[i]);
184
+ const isValid = await (0, fileinfo_1.isValidPath)(folderPath);
185
+ if (!isValid)
186
+ continue;
187
+ const exist = await this.fileRepository.findOneBy({
188
+ root_id: this.file_id,
189
+ filepath: folderPath,
190
+ });
191
+ if (exist)
192
+ continue;
193
+ const parentPath = (0, path_1.resolve)(folderPath, '..');
194
+ const parent = parentPath == fileitem.filepath
195
+ ? fileitem
196
+ : await this.fileRepository.findOneBy({
197
+ root_id: this.file_id,
198
+ filepath: parentPath,
199
+ });
200
+ if (!parent)
201
+ continue;
202
+ const pid = parent.id;
203
+ const root_id = this.file_id;
204
+ const info = {
205
+ inputs: [
206
+ {
207
+ filename: (0, path_1.basename)(folderPath),
208
+ filepath: folderPath,
209
+ filesize: 0,
210
+ local_btime: 0,
211
+ local_ctime: 0,
212
+ local_mtime: 0,
213
+ },
214
+ ],
215
+ aid: fileitem.aid,
216
+ ali_host_id: fileitem.ali_host_id,
217
+ baidu_host_id: fileitem.baidu_host_id,
218
+ config: fileitem.config,
219
+ filepath: folderPath,
220
+ is_ready: false,
221
+ uid: fileitem.uid,
222
+ type: types_1.RecordType.FOLDER,
223
+ task_record_id: fileitem.task_record_id,
224
+ space_name: fileitem.space_name,
225
+ space_id: fileitem.space_id,
226
+ is_paused: fileitem.is_paused,
227
+ external_texts: [],
228
+ pid,
229
+ root_id,
230
+ };
231
+ await this.fileRepository.save(this.fileRepository.create(info));
232
+ }
233
+ await this.fc.set(key, true);
234
+ }
235
+ async parseRawFiles() {
236
+ const key = this.PARSED_FILES_KEY;
237
+ const cache = await this.fc.get(key);
238
+ if (cache)
239
+ return cache;
240
+ const fileitem = await this.fileRepository.findOneBy({
241
+ id: this.file_id,
242
+ });
243
+ if (!fileitem)
244
+ return;
245
+ const paths = await (0, glob_1.glob)('**/*', {
246
+ nodir: true,
247
+ cwd: fileitem.filepath,
248
+ });
249
+ let folders = [];
250
+ paths.map((item) => {
251
+ let parentPath = (0, path_1.dirname)(item);
252
+ const arr = [];
253
+ while (parentPath != '.') {
254
+ if (!folders.includes(parentPath)) {
255
+ arr.unshift(parentPath);
256
+ }
257
+ else {
258
+ break;
259
+ }
260
+ parentPath = (0, path_1.dirname)(parentPath);
261
+ }
262
+ folders = [...folders, ...arr];
263
+ });
264
+ const files = [];
265
+ const subtitles = [];
266
+ const medias = [];
267
+ const { length } = paths;
268
+ for (let i = 0; i < length; i++) {
269
+ const filepath = (0, path_1.resolve)(fileitem.filepath, paths[i]);
270
+ const isValid = await (0, fileinfo_1.isValidPath)(filepath);
271
+ if (isValid) {
272
+ const fileinfo = await (0, fileinfo_1.getFileinfo)(filepath);
273
+ const { record_type } = fileinfo;
274
+ const { dir, base, name } = (0, path_1.parse)(filepath);
275
+ const info = {
276
+ type: record_type,
277
+ title: name,
278
+ filename: base,
279
+ basepath: (0, path_1.join)(dir, name),
280
+ filepath: filepath,
281
+ filesize: fileinfo.size,
282
+ local_btime: fileinfo.local_btime,
283
+ local_ctime: fileinfo.local_ctime,
284
+ local_mtime: fileinfo.local_mtime,
285
+ parent_path: (0, path_1.dirname)(filepath),
286
+ file_type: 'file',
287
+ };
288
+ const is_media = record_type == types_1.RecordType.VIDEO || record_type == types_1.RecordType.AUDIO;
289
+ const is_subtitle = (0, fileinfo_1.isSubtitle)(filepath);
290
+ if (is_media) {
291
+ const keywords = info.title
292
+ .split(/[ _\-.{}[\]、,,。::!?<>《》【】]+/g)
293
+ .filter((k) => k.length >= 2);
294
+ medias.push({
295
+ ...info,
296
+ file_type: 'media',
297
+ keywords,
298
+ });
299
+ }
300
+ else if (is_subtitle) {
301
+ subtitles.push({
302
+ ...info,
303
+ file_type: 'subtitle',
304
+ });
305
+ }
306
+ else {
307
+ files.push(info);
308
+ }
309
+ }
310
+ }
311
+ await this.fc.set(key, {
312
+ files,
313
+ folders,
314
+ medias,
315
+ subtitles,
316
+ });
317
+ return {
318
+ files,
319
+ folders,
320
+ };
321
+ }
322
+ async destroy() {
323
+ await this.fc?.destroy();
324
+ await (0, fs_extra_1.remove)(this.cache_file);
325
+ }
326
+ async init() {
327
+ const fileitem = await this.fileRepository.findOneBy({
328
+ id: this.file_id,
329
+ });
330
+ if (!fileitem)
331
+ return;
332
+ const { id } = fileitem;
333
+ this.cache_file = (0, path_1.resolve)((0, os_1.homedir)(), '.dpan', 'desktop', 'json_files', `upload_task_single_${id}.json`);
334
+ this.fc = await (0, file_cache_1.getFileCache)(this.cache_file);
335
+ }
336
+ }
337
+ exports.SingleRunner = SingleRunner;
@@ -0,0 +1,53 @@
1
+ import { RecordType, UploadInputItem } from '@soga/types';
2
+ import { DataSource } from 'typeorm';
3
+ export type UploadFileParams = {
4
+ dataSource: DataSource;
5
+ sdk_domain: string;
6
+ paths: string[];
7
+ space_id: number;
8
+ record_id: number;
9
+ };
10
+ interface CommonMeta {
11
+ type: RecordType;
12
+ filename: string;
13
+ filepath: string;
14
+ filesize: number;
15
+ local_btime: number;
16
+ local_ctime: number;
17
+ local_mtime: number;
18
+ parent_path: string;
19
+ title: string;
20
+ basepath: string;
21
+ file_type: 'media' | 'subtitle' | 'folder' | 'file';
22
+ }
23
+ export interface FileMeta extends CommonMeta {
24
+ file_type: 'file';
25
+ }
26
+ export interface MediaMeta extends CommonMeta {
27
+ keywords: string[];
28
+ external_texts?: string[];
29
+ file_type: 'media';
30
+ }
31
+ export interface SubtitleMeta extends CommonMeta {
32
+ file_type: 'subtitle';
33
+ }
34
+ export interface FileItem {
35
+ inputs: UploadInputItem[];
36
+ space_id: number;
37
+ space_name: string;
38
+ filepath: string;
39
+ is_ready: boolean;
40
+ config: object;
41
+ uid: number;
42
+ aid: number;
43
+ baidu_host_id: number;
44
+ ali_host_id: number;
45
+ is_paused: boolean;
46
+ type: RecordType;
47
+ task_record_id: number;
48
+ external_texts: string[];
49
+ root_id?: number;
50
+ pid?: number;
51
+ total_count?: number;
52
+ }
53
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ import { MediaMeta, SubtitleMeta } from './types';
2
+ export declare const matchSubtitles: (media: MediaMeta, subtitles: SubtitleMeta[]) => SubtitleMeta[];
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.matchSubtitles = void 0;
4
+ const path_1 = require("path");
5
+ const matchSubtitles = (media, subtitles) => {
6
+ const first_match = subtitles.filter((item) => item.parent_path.includes(media.parent_path));
7
+ if (!first_match.length)
8
+ return null;
9
+ const { keywords } = media;
10
+ const matched = [];
11
+ first_match.forEach((item) => {
12
+ if (item.basepath == media.basepath) {
13
+ matched.unshift(item);
14
+ }
15
+ else {
16
+ const relative_uri = (0, path_1.relative)(media.parent_path, item.parent_path);
17
+ const level = relative_uri.split(path_1.sep).filter((i) => !!i).length;
18
+ if (level < 2) {
19
+ const matched_keywords = keywords.filter((keyword) => item.title.includes(keyword));
20
+ if (matched_keywords.length &&
21
+ matched_keywords.join('').length / keywords.length > 0.15) {
22
+ matched.push(item);
23
+ }
24
+ }
25
+ }
26
+ });
27
+ return matched;
28
+ };
29
+ exports.matchSubtitles = matchSubtitles;
@@ -0,0 +1,10 @@
1
+ import { RecordType } from '@soga/types';
2
+ export declare const getFileinfo: (filepath: string) => Promise<{
3
+ local_ctime: number;
4
+ local_mtime: number;
5
+ local_btime: number;
6
+ record_type: RecordType;
7
+ size: number;
8
+ }>;
9
+ export declare const isSubtitle: (filepath: string) => boolean;
10
+ export declare const isValidPath: (filepath: string) => Promise<boolean>;
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.isValidPath = exports.isSubtitle = exports.getFileinfo = void 0;
7
+ const types_1 = require("@soga/types");
8
+ const mime_1 = __importDefault(require("mime"));
9
+ const fs_extra_1 = require("fs-extra");
10
+ const promises_1 = require("fs/promises");
11
+ const path_1 = require("path");
12
+ const isTextFile = async (filepath, length = 1024 * 5) => {
13
+ const fd = await (0, promises_1.open)(filepath, 'r');
14
+ for (let i = 0; i < length; i++) {
15
+ const buf = Buffer.alloc(1);
16
+ const { bytesRead } = await fd.read(buf, 0, 1, i);
17
+ const char = buf.toString().charCodeAt(0);
18
+ if (bytesRead === 0) {
19
+ await fd.close();
20
+ return true;
21
+ }
22
+ else if (bytesRead === 1 && char === 0) {
23
+ await fd.close();
24
+ return false;
25
+ }
26
+ }
27
+ await fd.close();
28
+ return true;
29
+ };
30
+ const getRecordType = async (filepath) => {
31
+ const mimetype = mime_1.default.getType(filepath);
32
+ if (!mimetype) {
33
+ return types_1.RecordType.OTHER;
34
+ }
35
+ if (mimetype.startsWith('video/')) {
36
+ if (filepath.endsWith('.ts')) {
37
+ if (await isTextFile(filepath)) {
38
+ return types_1.RecordType.OTHER;
39
+ }
40
+ else {
41
+ return types_1.RecordType.VIDEO;
42
+ }
43
+ }
44
+ else {
45
+ return types_1.RecordType.VIDEO;
46
+ }
47
+ }
48
+ else if (mimetype.startsWith('audio/')) {
49
+ return types_1.RecordType.AUDIO;
50
+ }
51
+ else if (mimetype.startsWith('image/')) {
52
+ return types_1.RecordType.IMAGE;
53
+ }
54
+ else if (mimetype.startsWith('text/')) {
55
+ return types_1.RecordType.TXT;
56
+ }
57
+ else if (mimetype.startsWith('application/vnd.rn-realmedia')) {
58
+ return types_1.RecordType.VIDEO;
59
+ }
60
+ return types_1.RecordType.OTHER;
61
+ };
62
+ const getFileinfo = async (filepath) => {
63
+ try {
64
+ const stats = await (0, fs_extra_1.stat)(filepath);
65
+ const isFolder = stats.isDirectory();
66
+ const record_type = isFolder
67
+ ? types_1.RecordType.FOLDER
68
+ : await getRecordType(filepath);
69
+ return {
70
+ local_ctime: Math.floor(stats.ctimeMs),
71
+ local_mtime: Math.floor(stats.mtimeMs),
72
+ local_btime: Math.floor(stats.birthtimeMs),
73
+ record_type,
74
+ size: isFolder ? 0 : stats.size,
75
+ };
76
+ }
77
+ catch (err) {
78
+ const now = Date.now();
79
+ return {
80
+ local_ctime: now,
81
+ local_mtime: now,
82
+ local_btime: now,
83
+ record_type: types_1.RecordType.OTHER,
84
+ size: 0,
85
+ };
86
+ }
87
+ };
88
+ exports.getFileinfo = getFileinfo;
89
+ const isSubtitle = (filepath) => {
90
+ const parsed = (0, path_1.parse)(filepath);
91
+ const ext = parsed.ext;
92
+ const types = ['.srt', '.vtt', '.ass', '.ssa', '.sbv', '.lrc'];
93
+ if (types.includes(ext)) {
94
+ return true;
95
+ }
96
+ else {
97
+ return false;
98
+ }
99
+ };
100
+ exports.isSubtitle = isSubtitle;
101
+ const isValidPath = async (filepath) => {
102
+ const exists = await (0, fs_extra_1.pathExists)(filepath);
103
+ if (!exists) {
104
+ return false;
105
+ }
106
+ return true;
107
+ };
108
+ exports.isValidPath = isValidPath;
package/package.json CHANGED
@@ -1,15 +1,64 @@
1
1
  {
2
2
  "name": "@soga/task",
3
- "version": "0.0.1",
4
- "main": "index.js",
3
+ "version": "0.2.13",
5
4
  "publishConfig": {
6
5
  "access": "public"
7
6
  },
7
+ "description": "",
8
+ "main": "dist/main.js",
9
+ "types": "dist/main.d.ts",
10
+ "files": [
11
+ "dist"
12
+ ],
8
13
  "scripts": {
9
- "test": "echo \"Error: no test specified\" && exit 1"
14
+ "build": "rimraf dist && tsc && ts-node ./scripts/minify",
15
+ "minify": "ts-node ./scripts/minify",
16
+ "demo_backup": "ts-node ./demo/demo.ts",
17
+ "demo": "ts-node ./demo/demo.ts",
18
+ "worker": "tsc && ts-node ./demo/worker.ts",
19
+ "test": "jest",
20
+ "dev": "ts-node ./src/main.ts",
21
+ "lint": "eslint . --ext .ts",
22
+ "prepublishOnly": "npm run build"
23
+ },
24
+ "devDependencies": {
25
+ "@soga/types": "file:../types",
26
+ "@types/fs-extra": "^11.0.4",
27
+ "@types/glob": "^8.1.0",
28
+ "@types/jest": "^29.5.14",
29
+ "@types/mime": "^3.0.4",
30
+ "@types/node": "^20.8.7",
31
+ "@typescript-eslint/eslint-plugin": "^6.4.1",
32
+ "@typescript-eslint/parser": "^6.4.1",
33
+ "eslint": "^8.47.0",
34
+ "eslint-config-prettier": "^9.1.0",
35
+ "eslint-plugin-jest": "^27.9.0",
36
+ "eslint-plugin-prettier": "^5.2.3",
37
+ "glob": "^10.4.5",
38
+ "jest": "^29.7.0",
39
+ "prettier": "^3.0.2",
40
+ "reflect-metadata": "^0.2.2",
41
+ "rimraf": "^6.0.1",
42
+ "terser": "^5.19.2",
43
+ "ts-jest": "^29.2.5",
44
+ "ts-node": "^10.9.1",
45
+ "typescript": "^5.1.6"
10
46
  },
11
47
  "keywords": [],
12
48
  "author": "",
13
49
  "license": "ISC",
14
- "description": ""
50
+ "peerDependencies": {
51
+ "level": "*",
52
+ "typeorm": "*"
53
+ },
54
+ "dependencies": {
55
+ "@soga/entities": "^0.2.8",
56
+ "@soga/file-cache": "^0.2.13",
57
+ "@soga/sdk": "^0.2.13",
58
+ "@soga/types": "^0.2.8",
59
+ "@soga/utils": "^0.2.8",
60
+ "axios": "^1.8.4",
61
+ "mime": "^3.0.0"
62
+ },
63
+ "gitHead": "6835bf7d5150fe9805b2a66b3c4cb608e408234d"
15
64
  }
package/index.js DELETED
@@ -1 +0,0 @@
1
- console.log("cache");