@soga/task 0.3.0 → 1.0.0

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.
@@ -0,0 +1,37 @@
1
+ import { DataSource } from 'typeorm';
2
+
3
+ type UploadFileParams = {
4
+ dataSource: DataSource;
5
+ sdk_domain: string;
6
+ paths: string[];
7
+ space_id: number;
8
+ record_id: number;
9
+ is_attachment: boolean;
10
+ };
11
+
12
+ declare const createUploadTask: (params: UploadFileParams) => Promise<void>;
13
+
14
+ declare const runUploadTask: (params: RunnerParams$1) => Promise<true>;
15
+ type RunnerParams$1 = {
16
+ dataSource: DataSource;
17
+ uid: number;
18
+ };
19
+
20
+ type DownloadFileParams = {
21
+ dataSource: DataSource;
22
+ sdk_domain: string;
23
+ space_id: number;
24
+ record_ids: number[];
25
+ };
26
+ type RunnerParams = {
27
+ sdk_domain: string;
28
+ space_id: number;
29
+ dataSource: DataSource;
30
+ uid: number;
31
+ };
32
+
33
+ declare const createDownloadTask: (params: DownloadFileParams) => Promise<void>;
34
+
35
+ declare const runDownloadTask: (params: RunnerParams) => Promise<void>;
36
+
37
+ export { createDownloadTask, createUploadTask, runDownloadTask, runUploadTask };
package/dist/main.d.ts CHANGED
@@ -1,3 +1,37 @@
1
- export * from './upload-task/create';
2
- export * from './upload-task/run';
3
- export * from './upload-task/create-affix';
1
+ import { DataSource } from 'typeorm';
2
+
3
+ type UploadFileParams = {
4
+ dataSource: DataSource;
5
+ sdk_domain: string;
6
+ paths: string[];
7
+ space_id: number;
8
+ record_id: number;
9
+ is_attachment: boolean;
10
+ };
11
+
12
+ declare const createUploadTask: (params: UploadFileParams) => Promise<void>;
13
+
14
+ declare const runUploadTask: (params: RunnerParams$1) => Promise<true>;
15
+ type RunnerParams$1 = {
16
+ dataSource: DataSource;
17
+ uid: number;
18
+ };
19
+
20
+ type DownloadFileParams = {
21
+ dataSource: DataSource;
22
+ sdk_domain: string;
23
+ space_id: number;
24
+ record_ids: number[];
25
+ };
26
+ type RunnerParams = {
27
+ sdk_domain: string;
28
+ space_id: number;
29
+ dataSource: DataSource;
30
+ uid: number;
31
+ };
32
+
33
+ declare const createDownloadTask: (params: DownloadFileParams) => Promise<void>;
34
+
35
+ declare const runDownloadTask: (params: RunnerParams) => Promise<void>;
36
+
37
+ export { createDownloadTask, createUploadTask, runDownloadTask, runUploadTask };
package/dist/main.js CHANGED
@@ -1,19 +1 @@
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);
1
+ var e,t=Object.create,i=Object.defineProperty,a=Object.getOwnPropertyDescriptor,s=Object.getOwnPropertyNames,o=Object.getPrototypeOf,r=Object.prototype.hasOwnProperty,l=(e,t,o,l)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let d of s(t))r.call(e,d)||d===o||i(e,d,{get:()=>t[d],enumerable:!(l=a(t,d))||l.enumerable});return e},d={};((e,t)=>{for(var a in t)i(e,a,{get:t[a],enumerable:!0})})(d,{createDownloadTask:()=>K,createUploadTask:()=>R,runDownloadTask:()=>C,runUploadTask:()=>j}),module.exports=(e=d,l(i({},"__esModule",{value:!0}),e));var n=require("@soga/types"),c=require("path"),p=require("@soga/fileutils"),f=require("@soga/sdk"),_=require("@soga/entities"),h=require("path"),u=((e,a,s)=>(s=null!=e?t(o(e)):{},l(!a&&e&&e.__esModule?s:i(s,"default",{value:e,enumerable:!0}),e)))(require("xregexp")),y=(e,t)=>{const i=t.filter(t=>e.parent_path.startsWith(t.parent_path));if(!i.length)return null;const a=i.map(t=>{const i=(0,h.relative)(t.parent_path,e.parent_path).split(h.sep).filter(e=>!!e).length,a=t.keywords.filter(t=>e.filename.includes(t)).length/t.keywords.length;return{...t,percent:1e3*a/(10*i+1)}}).sort((e,t)=>t.percent-e.percent)[0];return a.percent<1?null:a},m=(e,t)=>{const i=[],a=[...e];let s=[...t];for(const e of s){const t=y(e,a);if(t){const{filepath:i}=t,s=a.find(e=>e.filepath==i);s&&(s.external_texts=s.external_texts||[],s.external_texts.push(e.filepath))}else i.push(e)}return[a,i]},w=e=>{const t=e.split((0,u.default)("[^\\p{L}0-9]","g")).filter(e=>!!e);return[...new Set(t)]},g=require("@soga/error"),R=async e=>{const t=e.dataSource.getRepository(_.UploadFile);let i=[];try{const a=(0,f.getSdk)(e.sdk_domain),s=await a.getUserInfo({refresh:!1}),{id:o}=s,{cloud_info:r,album:l}=await a.getRecordInfo({space_id:e.space_id,record_id:e.record_id,refresh:!0}),d={file_keeps:l.config.file_keeps},_=d.file_keeps==n.RecordFileKeep.SOURCE||d.file_keeps==n.RecordFileKeep.BOTH,h=d.file_keeps==n.RecordFileKeep.PREVIEW||d.file_keeps==n.RecordFileKeep.BOTH,{name:u}=await a.getSpaceInfo({space_id:e.space_id,refresh:!0}),y=l.id;let R=null,b=null;r[n.HostType.ALI]&&(R=r[n.HostType.ALI].id),r[n.HostType.BAIDU]&&(b=r[n.HostType.BAIDU].id);const{paths:O}=e,k=[],F=[],T=[],D=[],{length:E}=O;for(let e=0;e<E;e++){const t=O[e].replace(/[/\\]$/,"");if(!await(0,p.isValidPath)(t))throw(0,g.buildDError)(new Error,{message:`Invalid file path: ${t}`,detail:`Invalid file path: ${t}`});{const e=await(0,p.getFileinfo)(t),{record_type:i,record_ftype:a}=e,{dir:s,base:o,name:r}=(0,c.parse)(t),l={type:i,ftype:a,title:r,filename:o,basepath:(0,c.join)(s,r),filepath:t,filesize:e.size,local_btime:e.local_btime,local_ctime:e.local_ctime,local_mtime:e.local_mtime,parent_path:(0,c.dirname)(t),file_type:"file"};if(i==n.RecordType.FOLDER)F.push(l);else{const e=i==n.RecordType.VIDEO||i==n.RecordType.AUDIO,a=(0,p.isSubtitle)(t);if(e){const e=w(l.title);D.push({...l,file_type:"media",keywords:e})}else a?T.push({...l,file_type:"subtitle"}):k.push(l)}}}const[q,v]=m(D,T),x=[..._?T:v,...h?q:D,...k,...F].map(t=>{const i={input:{filename:t.filename,filepath:t.filepath,filesize:t.filesize,local_btime:t.local_btime,local_ctime:t.local_ctime,local_mtime:t.local_mtime},is_attachment:e.is_attachment,filepath:t.filepath,space_id:e.space_id,space_name:u,aid:y,ali_host_id:R,baidu_host_id:b,config:d,is_paused:!1,is_ready:t.type!=n.RecordType.FOLDER,type:t.type,ftype:t.ftype,task_record_id:e.record_id,uid:o,total_count:t.type==n.RecordType.FOLDER?void 0:1};return"media"==t.file_type&&(i.external_texts=t.external_texts),i});if(!x.length)return;const B=x.filter(e=>e.type!=n.RecordType.FOLDER);if(B.length){const{length:e}=B,a=100;for(let s=0;s<e;s+=a){const e=x.slice(s,s+a),o=await t.insert(e);i=i.concat(o.identifiers.map(e=>e.id))}}const L=x.filter(e=>e.type==n.RecordType.FOLDER);if(L.length){const{length:e}=L,a=100;for(let s=0;s<e;s+=a){const e=L.slice(s,s+a),o=await t.insert(e);i=i.concat(o.identifiers.map(e=>e.id))}}}catch(a){try{i.length&&await t.delete(i)}catch(e){}throw(0,g.buildDError)(a,{message:"create upload task failed",detail:`create upload task failed: [${e.paths.join(", ")}]`})}},b=require("@soga/entities"),O=require("@soga/entities"),k=require("@soga/types"),F=require("fs-extra"),T=require("glob"),D=require("os"),E=require("path"),q=require("typeorm"),v=require("@soga/fileutils"),x=require("@soga/lowdb"),B=require("crypto"),L=require("@soga/error"),S=class{db;file_id;cache_file;dataSource;fileRepository;calculateMd5(e){const t=(0,B.createHash)("md5");return t.update(`${e}`),t.digest("hex")}constructor({dataSource:e,file_id:t}){this.dataSource=e,this.fileRepository=e.getRepository(O.UploadFile),this.file_id=t}async start(){try{await this.init(),await this.parseRawFiles(),await this.insertFolders(),await this.insertFiles(),await this.end(),await this.destroy()}catch(e){throw(0,L.buildDError)(e,{message:"run upload task failed",detail:`run upload task failed, file_id: ${this.file_id}`})}}async end(){const e=await this.fileRepository.findOneBy({id:this.file_id});if(!e)return;const t=await this.fileRepository.countBy({root_id:this.file_id,type:(0,q.Not)(k.RecordType.FOLDER)});e.is_ready=!0,e.total_count=t,await this.fileRepository.save(e)}async insertFiles(){const{files_inserted:e,files:t,medias:i,subtitles:a}=this.db.data;if(e)return;const s=await this.fileRepository.findOneBy({id:this.file_id});if(!s)return;const{config:o}=s,r=!!s.is_attachment||(o.file_keeps==k.RecordFileKeep.SOURCE||o.file_keeps==k.RecordFileKeep.BOTH),l=!!s.is_attachment||(o.file_keeps==k.RecordFileKeep.PREVIEW||o.file_keeps==k.RecordFileKeep.BOTH),[d,n]=m(i,a),c=[...r?a:n,...t,...l?d:i],{length:p}=c;if(!p)return;const f=[];for(let e=0;e<p;e++){const t=c[e],{filepath:i}=t;if(!await(0,v.isValidPath)(i))continue;if(await this.fileRepository.findOneBy({root_id:this.file_id,filepath:i}))continue;const a=(0,E.dirname)(i),r=a==s.filepath?s:await this.fileRepository.findOneBy({root_id:this.file_id,filepath:a});if(!r)continue;const l=r.id,d={is_attachment:s.is_attachment,input:{filename:t.filename,filepath:t.filepath,filesize:t.filesize,local_btime:t.local_btime,local_ctime:t.local_ctime,local_mtime:t.local_mtime},filepath:t.filepath,space_id:s.space_id,space_name:s.space_name,aid:s.aid,ali_host_id:s.ali_host_id,baidu_host_id:s.baidu_host_id,config:o,is_paused:!1,is_ready:t.type!=k.RecordType.FOLDER,type:t.type,ftype:t.ftype,task_record_id:s.task_record_id,uid:s.uid,root_id:s.id,pid:l,total_count:1};"media"==t.file_type&&(d.external_texts=t.external_texts),f.push(d)}const _=this.dataSource.createQueryRunner();await _.connect(),await _.startTransaction();try{const e=_.manager.getRepository(O.UploadFile),{length:t}=f,i=50;for(let a=0;a<t;a+=i){const t=f.slice(a,a+i);await e.createQueryBuilder().insert().into(O.UploadFile).values(t).execute()}await _.commitTransaction()}catch(e){await _.rollbackTransaction()}finally{await _.release()}this.db.data.files_inserted=!0,await this.db.write()}async insertFolders(){const{folders:e,folders_inserted:t}=this.db.data;if(t)return;const{length:i}=e,a=await this.fileRepository.findOneBy({id:this.file_id});if(a){for(let t=0;t<i;t++){const i=(0,E.resolve)(a.filepath,e[t]);if(!await(0,v.isValidPath)(i))continue;if(await this.fileRepository.findOneBy({root_id:this.file_id,filepath:i}))continue;const s=(0,E.resolve)(i,".."),o=s==a.filepath?a:await this.fileRepository.findOneBy({root_id:this.file_id,filepath:s});if(!o)continue;const r=o.id,l=this.file_id,d={is_attachment:a.is_attachment,input:{filename:(0,E.basename)(i),filepath:i,filesize:0,local_btime:0,local_ctime:0,local_mtime:0},aid:a.aid,ali_host_id:a.ali_host_id,baidu_host_id:a.baidu_host_id,config:a.config,filepath:i,is_ready:!1,uid:a.uid,type:k.RecordType.FOLDER,ftype:k.RecordFtype.NONE,task_record_id:a.task_record_id,space_name:a.space_name,space_id:a.space_id,is_paused:a.is_paused,external_texts:[],pid:r,root_id:l};await this.fileRepository.save(this.fileRepository.create(d))}this.db.data.folders_inserted=!0,await this.db.write()}}async parseRawFiles(){if(this.db.data.raw_files_parsed)return;const e=await this.fileRepository.findOneBy({id:this.file_id});if(!e)return;const t=await(0,T.glob)("**/*",{nodir:!0,cwd:e.filepath});let i=[];t.map(e=>{let t=(0,E.dirname)(e);const a=[];for(;"."!=t&&!i.includes(t);)a.unshift(t),t=(0,E.dirname)(t);i=[...i,...a]});const a=[],s=[],o=[],{length:r}=t;for(let i=0;i<r;i++){const r=(0,E.resolve)(e.filepath,t[i]);if(await(0,v.isValidPath)(r)){const e=await(0,v.getFileinfo)(r),{record_type:t,record_ftype:i}=e,{dir:l,base:d,name:n}=(0,E.parse)(r),c={type:t,ftype:i,title:n,filename:d,basepath:(0,E.join)(l,n),filepath:r,filesize:e.size,local_btime:e.local_btime,local_ctime:e.local_ctime,local_mtime:e.local_mtime,parent_path:(0,E.dirname)(r),file_type:"file"},p=t==k.RecordType.VIDEO||t==k.RecordType.AUDIO,f=(0,v.isSubtitle)(r);if(p){const e=w(c.title);o.push({...c,file_type:"media",keywords:e})}else f?s.push({...c,file_type:"subtitle"}):a.push(c)}}this.db.data.folders=i,this.db.data.files=a,this.db.data.medias=o,this.db.data.subtitles=s,this.db.data.raw_files_parsed=!0,await this.db.write()}async destroy(){delete this.db,await(0,F.remove)(this.cache_file)}async init(){const e=await this.fileRepository.findOneBy({id:this.file_id});if(!e)return;const{id:t,input:i}=e,a=this.calculateMd5(`${i.filepath}_${i.filesize}`);this.cache_file=(0,E.resolve)((0,D.homedir)(),".dpan","desktop","json_files",`${t}_${a}.json`);this.db=await(0,x.getDb)(this.cache_file,{folders:[],subtitles:[],medias:[],files:[],status:{}})}},I=require("@soga/error"),U=new Map,j=async e=>{try{const t=U.get(e.uid);if(t)return t;U.set(e.uid,!0);const i=e.dataSource.getRepository(b.UploadFile),a=async()=>{const t=await i.findOneBy({uid:e.uid,root_id:0,is_ready:!1});if(!t)return;const s=new S({dataSource:e.dataSource,file_id:t.id});await s.start(),await a()};await a(),U.delete(e.uid)}catch(e){throw(0,I.buildDError)(e,{message:"run upload task failed",detail:"run upload task failed"})}},P=require("@soga/sdk"),z=require("@soga/types"),$=require("@soga/entities"),H=require("@soga/error"),K=async e=>{const{dataSource:t,sdk_domain:i,record_ids:a,space_id:s}=e,o=(0,P.getSdk)(i),{name:r}=await o.getSpaceInfo({space_id:e.space_id,refresh:!0}),l=await o.getUserInfo({refresh:!1}),{id:d}=l,n=t.getRepository($.DownloadFile);let c=[];try{const{length:e}=a,t=[];for(let i=0;i<e;i++){const e=a[i];i>0&&await new Promise(e=>setTimeout(e,500));const l=await o.getRecordInfo({space_id:s,record_id:e,refresh:!0});if(!l?.manifest)continue;const n={title:l.name,cloud_id:l.id,baidu_host_id:l.cloud_info?.baidu?.id,ali_host_id:l.cloud_info?.ali?.id,type:l.type,ftype:l.ftype,routes:[l.name],root_id:0,space_id:l.space_id,space_name:r,uid:d,detail:l,file_total:l.type==z.RecordType.FOLDER?void 0:1,is_ready:l.type!=z.RecordType.FOLDER,has_attachment:!!l.manifest?.attachments?.length,info:l};t.push(n)}const i=t.filter(e=>e.type!=z.RecordType.FOLDER);if(i.length){const e=i.length;for(let t=0;t<e;t++){const e=i[t],{info:a,...s}=e,o=(await n.save(n.create({...s})))[0];if(o&&c.push(o.id),!e.has_attachment)continue;const r=a;if(e.has_attachment){const e=r.manifest.attachments;for(const t of e){const{uuid:e,type:i,ftype:a,title:o}=t,r={...s,attachment_uuid:e,title:o,type:i,ftype:a},l=await n.save(n.create(r));if(!l)continue;const d=l[0];d&&c.push(d.id)}}}}const l=t.filter(e=>e.type==z.RecordType.FOLDER);if(l.length){const e=l.length;for(let t=0;t<e;t++){const e=l[t],{info:i,...a}=e,s=await n.save(n.create({...a}));if(!s)continue;const o=s[0];if(o&&c.push(o.id),!e.has_attachment)continue;const r=i,d=r.manifest?.attachments;for(const e of d){const{uuid:t,type:i,ftype:s,title:o}=e,r={...a,attachment_uuid:t,has_attachment:!1,title:o,type:i,ftype:s},l=await n.save(n.create(r));if(!l)continue;const d=l[0];d&&c.push(d.id)}}}}catch(e){try{c.length&&await n.delete(c)}catch(e){}throw(0,H.buildDError)(e,{message:"create download task failed",detail:"create download task failed"})}},V=require("@soga/error"),A=require("@soga/entities"),M=require("@soga/types"),N=require("@soga/sdk"),W=require("typeorm"),C=async e=>{const{dataSource:t,sdk_domain:i,space_id:a,uid:s}=e,o=(0,N.getSdk)(i),r=t.getRepository(A.DownloadFile);try{const e=await r.findBy({uid:s,root_id:0,is_ready:!1}),t=async e=>{let i=1,s=1e3,l=[];const d=0==e.root_id?e.id:e.root_id;for(;s>=100;){const t=await o.getRecordList({space_id:a,parent_id:e.detail.id,page:i,pagesize:100});t?(s=t.length,l=l.concat(t),i++):s=0}if(l.length){const i=l.map(t=>({title:t.name,cloud_id:t.id,baidu_host_id:e.baidu_host_id,ali_host_id:e.ali_host_id,pid:e.id,type:t.type,ftype:t.ftype,routes:[...e.routes,t.name],root_id:d,space_id:t.space_id,space_name:e.space_name,uid:e.uid,detail:t,file_total:t.type==M.RecordType.FOLDER?void 0:1})),a=i.filter(e=>e.type!=M.RecordType.FOLDER);for(const e of a){await r.findOneBy({root_id:d,cloud_id:e.cloud_id})||await r.insert(e)}const s=i.filter(e=>e.type==M.RecordType.FOLDER);for(const e of s){const i=await r.findOneBy({root_id:d,cloud_id:e.cloud_id});if(i)await t(i);else{const i=await r.save(r.create(e));await t(i)}}}};for(const i of e){await t(i);const e=await r.countBy({root_id:i.id,type:(0,W.Not)(M.RecordType.FOLDER)});await r.update(i.id,{is_ready:!0,file_total:e})}}catch(e){throw(0,V.buildDError)(e,{message:"run download task failed",detail:"run download task failed"})}};
package/dist/main.mjs ADDED
@@ -0,0 +1 @@
1
+ import{HostType as t,RecordFileKeep as e,RecordType as i}from"@soga/types";import{dirname as a,join as s,parse as o}from"path";import{getFileinfo as r,isSubtitle as l,isValidPath as n}from"@soga/fileutils";import{getSdk as d}from"@soga/sdk";import{UploadFile as c}from"@soga/entities";import{relative as f,sep as p}from"path";import _ from"xregexp";var h=(t,e)=>{const i=e.filter(e=>t.parent_path.startsWith(e.parent_path));if(!i.length)return null;const a=i.map(e=>{const i=f(e.parent_path,t.parent_path).split(p).filter(t=>!!t).length,a=e.keywords.filter(e=>t.filename.includes(e)).length/e.keywords.length;return{...e,percent:1e3*a/(10*i+1)}}).sort((t,e)=>e.percent-t.percent)[0];return a.percent<1?null:a},m=(t,e)=>{const i=[],a=[...t];let s=[...e];for(const t of s){const e=h(t,a);if(e){const{filepath:i}=e,s=a.find(t=>t.filepath==i);s&&(s.external_texts=s.external_texts||[],s.external_texts.push(t.filepath))}else i.push(t)}return[a,i]},u=t=>{const e=t.split(_("[^\\p{L}0-9]","g")).filter(t=>!!t);return[...new Set(e)]};import{buildDError as y}from"@soga/error";var w=async f=>{const p=f.dataSource.getRepository(c);let _=[];try{const c=d(f.sdk_domain),h=await c.getUserInfo({refresh:!1}),{id:w}=h,{cloud_info:g,album:b}=await c.getRecordInfo({space_id:f.space_id,record_id:f.record_id,refresh:!0}),R={file_keeps:b.config.file_keeps},k=R.file_keeps==e.SOURCE||R.file_keeps==e.BOTH,O=R.file_keeps==e.PREVIEW||R.file_keeps==e.BOTH,{name:E}=await c.getSpaceInfo({space_id:f.space_id,refresh:!0}),D=b.id;let F=null,x=null;g[t.ALI]&&(F=g[t.ALI].id),g[t.BAIDU]&&(x=g[t.BAIDU].id);const{paths:B}=f,L=[],v=[],I=[],S=[],{length:z}=B;for(let t=0;t<z;t++){const e=B[t].replace(/[/\\]$/,"");if(!await n(e))throw y(new Error,{message:`Invalid file path: ${e}`,detail:`Invalid file path: ${e}`});{const t=await r(e),{record_type:n,record_ftype:d}=t,{dir:c,base:f,name:p}=o(e),_={type:n,ftype:d,title:p,filename:f,basepath:s(c,p),filepath:e,filesize:t.size,local_btime:t.local_btime,local_ctime:t.local_ctime,local_mtime:t.local_mtime,parent_path:a(e),file_type:"file"};if(n==i.FOLDER)v.push(_);else{const t=n==i.VIDEO||n==i.AUDIO,a=l(e);if(t){const t=u(_.title);S.push({..._,file_type:"media",keywords:t})}else a?I.push({..._,file_type:"subtitle"}):L.push(_)}}}const[T,U]=m(S,I),$=[...k?I:U,...O?T:S,...L,...v].map(t=>{const e={input:{filename:t.filename,filepath:t.filepath,filesize:t.filesize,local_btime:t.local_btime,local_ctime:t.local_ctime,local_mtime:t.local_mtime},is_attachment:f.is_attachment,filepath:t.filepath,space_id:f.space_id,space_name:E,aid:D,ali_host_id:F,baidu_host_id:x,config:R,is_paused:!1,is_ready:t.type!=i.FOLDER,type:t.type,ftype:t.ftype,task_record_id:f.record_id,uid:w,total_count:t.type==i.FOLDER?void 0:1};return"media"==t.file_type&&(e.external_texts=t.external_texts),e});if(!$.length)return;const A=$.filter(t=>t.type!=i.FOLDER);if(A.length){const{length:t}=A,e=100;for(let i=0;i<t;i+=e){const t=$.slice(i,i+e),a=await p.insert(t);_=_.concat(a.identifiers.map(t=>t.id))}}const V=$.filter(t=>t.type==i.FOLDER);if(V.length){const{length:t}=V,e=100;for(let i=0;i<t;i+=e){const t=V.slice(i,i+e),a=await p.insert(t);_=_.concat(a.identifiers.map(t=>t.id))}}}catch(t){try{_.length&&await p.delete(_)}catch(t){}throw y(t,{message:"create upload task failed",detail:`create upload task failed: [${f.paths.join(", ")}]`})}};import{UploadFile as g}from"@soga/entities";import{UploadFile as b}from"@soga/entities";import{RecordFileKeep as R,RecordFtype as k,RecordType as O}from"@soga/types";import{remove as E}from"fs-extra";import{glob as D}from"glob";import{homedir as F}from"os";import{resolve as x,dirname as B,parse as L,join as v,basename as I}from"path";import{Not as S}from"typeorm";import{getFileinfo as z,isSubtitle as T,isValidPath as U}from"@soga/fileutils";import{getDb as $}from"@soga/lowdb";import{createHash as A}from"crypto";import{buildDError as V}from"@soga/error";var j=class{db;file_id;cache_file;dataSource;fileRepository;calculateMd5(t){const e=A("md5");return e.update(`${t}`),e.digest("hex")}constructor({dataSource:t,file_id:e}){this.dataSource=t,this.fileRepository=t.getRepository(b),this.file_id=e}async start(){try{await this.init(),await this.parseRawFiles(),await this.insertFolders(),await this.insertFiles(),await this.end(),await this.destroy()}catch(t){throw V(t,{message:"run upload task failed",detail:`run upload task failed, file_id: ${this.file_id}`})}}async end(){const t=await this.fileRepository.findOneBy({id:this.file_id});if(!t)return;const e=await this.fileRepository.countBy({root_id:this.file_id,type:S(O.FOLDER)});t.is_ready=!0,t.total_count=e,await this.fileRepository.save(t)}async insertFiles(){const{files_inserted:t,files:e,medias:i,subtitles:a}=this.db.data;if(t)return;const s=await this.fileRepository.findOneBy({id:this.file_id});if(!s)return;const{config:o}=s,r=!!s.is_attachment||(o.file_keeps==R.SOURCE||o.file_keeps==R.BOTH),l=!!s.is_attachment||(o.file_keeps==R.PREVIEW||o.file_keeps==R.BOTH),[n,d]=m(i,a),c=[...r?a:d,...e,...l?n:i],{length:f}=c;if(!f)return;const p=[];for(let t=0;t<f;t++){const e=c[t],{filepath:i}=e;if(!await U(i))continue;if(await this.fileRepository.findOneBy({root_id:this.file_id,filepath:i}))continue;const a=B(i),r=a==s.filepath?s:await this.fileRepository.findOneBy({root_id:this.file_id,filepath:a});if(!r)continue;const l=r.id,n={is_attachment:s.is_attachment,input:{filename:e.filename,filepath:e.filepath,filesize:e.filesize,local_btime:e.local_btime,local_ctime:e.local_ctime,local_mtime:e.local_mtime},filepath:e.filepath,space_id:s.space_id,space_name:s.space_name,aid:s.aid,ali_host_id:s.ali_host_id,baidu_host_id:s.baidu_host_id,config:o,is_paused:!1,is_ready:e.type!=O.FOLDER,type:e.type,ftype:e.ftype,task_record_id:s.task_record_id,uid:s.uid,root_id:s.id,pid:l,total_count:1};"media"==e.file_type&&(n.external_texts=e.external_texts),p.push(n)}const _=this.dataSource.createQueryRunner();await _.connect(),await _.startTransaction();try{const t=_.manager.getRepository(b),{length:e}=p,i=50;for(let a=0;a<e;a+=i){const e=p.slice(a,a+i);await t.createQueryBuilder().insert().into(b).values(e).execute()}await _.commitTransaction()}catch(t){await _.rollbackTransaction()}finally{await _.release()}this.db.data.files_inserted=!0,await this.db.write()}async insertFolders(){const{folders:t,folders_inserted:e}=this.db.data;if(e)return;const{length:i}=t,a=await this.fileRepository.findOneBy({id:this.file_id});if(a){for(let e=0;e<i;e++){const i=x(a.filepath,t[e]);if(!await U(i))continue;if(await this.fileRepository.findOneBy({root_id:this.file_id,filepath:i}))continue;const s=x(i,".."),o=s==a.filepath?a:await this.fileRepository.findOneBy({root_id:this.file_id,filepath:s});if(!o)continue;const r=o.id,l=this.file_id,n={is_attachment:a.is_attachment,input:{filename:I(i),filepath:i,filesize:0,local_btime:0,local_ctime:0,local_mtime:0},aid:a.aid,ali_host_id:a.ali_host_id,baidu_host_id:a.baidu_host_id,config:a.config,filepath:i,is_ready:!1,uid:a.uid,type:O.FOLDER,ftype:k.NONE,task_record_id:a.task_record_id,space_name:a.space_name,space_id:a.space_id,is_paused:a.is_paused,external_texts:[],pid:r,root_id:l};await this.fileRepository.save(this.fileRepository.create(n))}this.db.data.folders_inserted=!0,await this.db.write()}}async parseRawFiles(){if(this.db.data.raw_files_parsed)return;const t=await this.fileRepository.findOneBy({id:this.file_id});if(!t)return;const e=await D("**/*",{nodir:!0,cwd:t.filepath});let i=[];e.map(t=>{let e=B(t);const a=[];for(;"."!=e&&!i.includes(e);)a.unshift(e),e=B(e);i=[...i,...a]});const a=[],s=[],o=[],{length:r}=e;for(let i=0;i<r;i++){const r=x(t.filepath,e[i]);if(await U(r)){const t=await z(r),{record_type:e,record_ftype:i}=t,{dir:l,base:n,name:d}=L(r),c={type:e,ftype:i,title:d,filename:n,basepath:v(l,d),filepath:r,filesize:t.size,local_btime:t.local_btime,local_ctime:t.local_ctime,local_mtime:t.local_mtime,parent_path:B(r),file_type:"file"},f=e==O.VIDEO||e==O.AUDIO,p=T(r);if(f){const t=u(c.title);o.push({...c,file_type:"media",keywords:t})}else p?s.push({...c,file_type:"subtitle"}):a.push(c)}}this.db.data.folders=i,this.db.data.files=a,this.db.data.medias=o,this.db.data.subtitles=s,this.db.data.raw_files_parsed=!0,await this.db.write()}async destroy(){delete this.db,await E(this.cache_file)}async init(){const t=await this.fileRepository.findOneBy({id:this.file_id});if(!t)return;const{id:e,input:i}=t,a=this.calculateMd5(`${i.filepath}_${i.filesize}`);this.cache_file=x(F(),".dpan","desktop","json_files",`${e}_${a}.json`);this.db=await $(this.cache_file,{folders:[],subtitles:[],medias:[],files:[],status:{}})}};import{buildDError as H}from"@soga/error";var P=new Map,M=async t=>{try{const e=P.get(t.uid);if(e)return e;P.set(t.uid,!0);const i=t.dataSource.getRepository(g),a=async()=>{const e=await i.findOneBy({uid:t.uid,root_id:0,is_ready:!1});if(!e)return;const s=new j({dataSource:t.dataSource,file_id:e.id});await s.start(),await a()};await a(),P.delete(t.uid)}catch(t){throw H(t,{message:"run upload task failed",detail:"run upload task failed"})}};import{getSdk as N}from"@soga/sdk";import{RecordType as W}from"@soga/types";import{DownloadFile as C}from"@soga/entities";import{buildDError as Q}from"@soga/error";var K=async t=>{const{dataSource:e,sdk_domain:i,record_ids:a,space_id:s}=t,o=N(i),{name:r}=await o.getSpaceInfo({space_id:t.space_id,refresh:!0}),l=await o.getUserInfo({refresh:!1}),{id:n}=l,d=e.getRepository(C);let c=[];try{const{length:t}=a,e=[];for(let i=0;i<t;i++){const t=a[i];i>0&&await new Promise(t=>setTimeout(t,500));const l=await o.getRecordInfo({space_id:s,record_id:t,refresh:!0});if(!l?.manifest)continue;const d={title:l.name,cloud_id:l.id,baidu_host_id:l.cloud_info?.baidu?.id,ali_host_id:l.cloud_info?.ali?.id,type:l.type,ftype:l.ftype,routes:[l.name],root_id:0,space_id:l.space_id,space_name:r,uid:n,detail:l,file_total:l.type==W.FOLDER?void 0:1,is_ready:l.type!=W.FOLDER,has_attachment:!!l.manifest?.attachments?.length,info:l};e.push(d)}const i=e.filter(t=>t.type!=W.FOLDER);if(i.length){const t=i.length;for(let e=0;e<t;e++){const t=i[e],{info:a,...s}=t,o=(await d.save(d.create({...s})))[0];if(o&&c.push(o.id),!t.has_attachment)continue;const r=a;if(t.has_attachment){const t=r.manifest.attachments;for(const e of t){const{uuid:t,type:i,ftype:a,title:o}=e,r={...s,attachment_uuid:t,title:o,type:i,ftype:a},l=await d.save(d.create(r));if(!l)continue;const n=l[0];n&&c.push(n.id)}}}}const l=e.filter(t=>t.type==W.FOLDER);if(l.length){const t=l.length;for(let e=0;e<t;e++){const t=l[e],{info:i,...a}=t,s=await d.save(d.create({...a}));if(!s)continue;const o=s[0];if(o&&c.push(o.id),!t.has_attachment)continue;const r=i,n=r.manifest?.attachments;for(const t of n){const{uuid:e,type:i,ftype:s,title:o}=t,r={...a,attachment_uuid:e,has_attachment:!1,title:o,type:i,ftype:s},l=await d.save(d.create(r));if(!l)continue;const n=l[0];n&&c.push(n.id)}}}}catch(t){try{c.length&&await d.delete(c)}catch(t){}throw Q(t,{message:"create download task failed",detail:"create download task failed"})}};import{buildDError as q}from"@soga/error";import{DownloadFile as G}from"@soga/entities";import{RecordType as J}from"@soga/types";import{getSdk as X}from"@soga/sdk";import{Not as Y}from"typeorm";var Z=async t=>{const{dataSource:e,sdk_domain:i,space_id:a,uid:s}=t,o=X(i),r=e.getRepository(G);try{const t=await r.findBy({uid:s,root_id:0,is_ready:!1}),e=async t=>{let i=1,s=1e3,l=[];const n=0==t.root_id?t.id:t.root_id;for(;s>=100;){const e=await o.getRecordList({space_id:a,parent_id:t.detail.id,page:i,pagesize:100});e?(s=e.length,l=l.concat(e),i++):s=0}if(l.length){const i=l.map(e=>({title:e.name,cloud_id:e.id,baidu_host_id:t.baidu_host_id,ali_host_id:t.ali_host_id,pid:t.id,type:e.type,ftype:e.ftype,routes:[...t.routes,e.name],root_id:n,space_id:e.space_id,space_name:t.space_name,uid:t.uid,detail:e,file_total:e.type==J.FOLDER?void 0:1})),a=i.filter(t=>t.type!=J.FOLDER);for(const t of a){await r.findOneBy({root_id:n,cloud_id:t.cloud_id})||await r.insert(t)}const s=i.filter(t=>t.type==J.FOLDER);for(const t of s){const i=await r.findOneBy({root_id:n,cloud_id:t.cloud_id});if(i)await e(i);else{const i=await r.save(r.create(t));await e(i)}}}};for(const i of t){await e(i);const t=await r.countBy({root_id:i.id,type:Y(J.FOLDER)});await r.update(i.id,{is_ready:!0,file_total:t})}}catch(t){throw q(t,{message:"run download task failed",detail:"run download task failed"})}};export{K as createDownloadTask,w as createUploadTask,Z as runDownloadTask,M as runUploadTask};
package/package.json CHANGED
@@ -1,39 +1,46 @@
1
1
  {
2
2
  "name": "@soga/task",
3
- "version": "0.3.0",
3
+ "version": "1.0.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
7
  "description": "",
8
- "main": "dist/main.js",
9
- "types": "dist/main.d.ts",
8
+ "main": "./dist/main.js",
9
+ "module": "./dist/main.mjs",
10
+ "types": "./dist/main.d.ts",
10
11
  "files": [
11
12
  "dist"
12
13
  ],
14
+ "scripts": {
15
+ "demo": "tsx ./demo/demo.ts",
16
+ "build": "rimraf dist && tsup src/main.ts --format cjs,esm --dts --minify terser",
17
+ "prepublishOnly": "npm run build"
18
+ },
13
19
  "devDependencies": {
14
- "@types/mime": "^4.0.0"
20
+ "@soga/typescript-config": "latest",
21
+ "rimraf": "^6.0.1",
22
+ "terser": "^5.43.1",
23
+ "tsup": "^8.5.0",
24
+ "typescript": "^5.8.3",
25
+ "@types/node": "^24.5.2"
15
26
  },
16
27
  "keywords": [],
17
28
  "author": "",
18
29
  "license": "ISC",
19
30
  "dependencies": {
20
- "@soga/bridge": "^0.3.0",
21
- "@soga/entities": "^0.3.0",
22
- "@soga/sdk": "^0.3.0",
23
- "@soga/types": "^0.3.0",
24
- "@soga/utils": "^0.3.0",
31
+ "@soga/entities": "latest",
32
+ "@soga/fileutils": "latest",
33
+ "@soga/sdk": "latest",
34
+ "@soga/utils": "latest",
35
+ "@soga/types": "latest",
36
+ "@soga/node-types": "latest",
37
+ "@soga/error": "latest",
38
+ "@soga/lowdb": "latest",
39
+ "fs-extra": "^11.3.2",
25
40
  "axios": "^1.9.0",
41
+ "glob": "^11.0.2",
26
42
  "mime": "^4.0.7",
27
- "typeorm": "^0.3.24"
28
- },
29
- "scripts": {
30
- "build": "rimraf dist && tsc && ts-node ./scripts/minify",
31
- "minify": "ts-node ./scripts/minify",
32
- "demo_backup": "ts-node ./demo/demo.ts",
33
- "demo": "ts-node ./demo/demo.ts",
34
- "worker": "tsc && ts-node ./demo/worker.ts",
35
- "test": "jest",
36
- "dev": "ts-node ./src/main.ts",
37
- "lint": "eslint . --ext .ts"
43
+ "typeorm": "^0.3.24",
44
+ "xregexp": "^5.1.2"
38
45
  }
39
- }
46
+ }
@@ -1,2 +0,0 @@
1
- import { UploadFileParams } from './types';
2
- export declare const createUploadAffixTask: (params: UploadFileParams) => Promise<number>;
@@ -1,78 +0,0 @@
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;
@@ -1,2 +0,0 @@
1
- import { UploadFileParams } from './types';
2
- export declare const createUploadTask: (params: UploadFileParams) => Promise<void>;
@@ -1,165 +0,0 @@
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
- throw err;
160
- }
161
- finally {
162
- await queryRunner.release();
163
- }
164
- };
165
- exports.createUploadTask = createUploadTask;
@@ -1,7 +0,0 @@
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 {};
@@ -1,31 +0,0 @@
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;
@@ -1,33 +0,0 @@
1
- import { DataSource } from 'typeorm';
2
- import { FileMeta, MediaMeta, SubtitleMeta } from './types';
3
- import { LowType } from '@soga/bridge';
4
- export declare class SingleRunner {
5
- db: LowType<DbDataType>;
6
- private file_id;
7
- private cache_file;
8
- private dataSource;
9
- private fileRepository;
10
- private calculateMd5;
11
- constructor({ dataSource, file_id, }: {
12
- dataSource: DataSource;
13
- file_id: number;
14
- });
15
- start(): Promise<void>;
16
- private end;
17
- private insertFiles;
18
- private insertFolders;
19
- private parseRawFiles;
20
- private destroy;
21
- private init;
22
- }
23
- type DbDataType = {
24
- raw_files_parsed: boolean;
25
- folders_inserted: boolean;
26
- files_inserted: boolean;
27
- folders: string[];
28
- subtitles: SubtitleMeta[];
29
- medias: MediaMeta[];
30
- files: FileMeta[];
31
- status: Record<string, boolean>;
32
- };
33
- export {};
@@ -1,336 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SingleRunner = void 0;
4
- const entities_1 = require("@soga/entities");
5
- const types_1 = require("@soga/types");
6
- const fs_extra_1 = require("fs-extra");
7
- const glob_1 = require("glob");
8
- const os_1 = require("os");
9
- const path_1 = require("path");
10
- const typeorm_1 = require("typeorm");
11
- const fileinfo_1 = require("../utils/fileinfo");
12
- const utils_1 = require("./utils");
13
- const bridge_1 = require("@soga/bridge");
14
- const crypto_1 = require("crypto");
15
- class SingleRunner {
16
- db;
17
- file_id;
18
- cache_file;
19
- dataSource;
20
- fileRepository;
21
- calculateMd5(text) {
22
- const hash = (0, crypto_1.createHash)('md5');
23
- hash.update(`${text}`);
24
- return hash.digest('hex');
25
- }
26
- constructor({ dataSource, file_id, }) {
27
- this.dataSource = dataSource;
28
- this.fileRepository = dataSource.getRepository(entities_1.UploadFile);
29
- this.file_id = file_id;
30
- }
31
- async start() {
32
- await this.init();
33
- await this.parseRawFiles();
34
- await this.insertFolders();
35
- await this.insertFiles();
36
- await this.end();
37
- await this.destroy();
38
- }
39
- async end() {
40
- const fileitem = await this.fileRepository.findOneBy({
41
- id: this.file_id,
42
- });
43
- if (!fileitem)
44
- return;
45
- const total = await this.fileRepository.countBy({
46
- root_id: this.file_id,
47
- type: (0, typeorm_1.Not)(types_1.RecordType.FOLDER),
48
- });
49
- fileitem.is_ready = true;
50
- fileitem.total_count = total;
51
- await this.fileRepository.save(fileitem);
52
- }
53
- async insertFiles() {
54
- const { files_inserted, files: normal_files, medias, subtitles, } = this.db.data;
55
- if (files_inserted)
56
- return;
57
- const fileitem = await this.fileRepository.findOneBy({
58
- id: this.file_id,
59
- });
60
- if (!fileitem)
61
- return;
62
- const { config } = fileitem;
63
- const keep_source = config.file_keeps == types_1.RecordFileKeep.SOURCE ||
64
- config.file_keeps == types_1.RecordFileKeep.BOTH;
65
- const match_map = {};
66
- let subs = [...subtitles];
67
- medias.forEach((media) => {
68
- const matched = (0, utils_1.matchSubtitles)(media, subs);
69
- if (matched) {
70
- media.external_texts = matched.map((item) => item.filepath);
71
- matched.forEach((item) => (match_map[item.filepath] = true));
72
- subs = subs.filter((item) => !match_map[item.filepath]);
73
- }
74
- });
75
- let subtitle_queues = subtitles;
76
- if (!keep_source) {
77
- subtitle_queues = subtitles.filter((item) => !match_map[item.filepath]);
78
- }
79
- const queues = [...subtitle_queues, ...normal_files, ...medias];
80
- const { length } = queues;
81
- if (!length)
82
- return;
83
- const items = [];
84
- for (let i = 0; i < length; i++) {
85
- const item = queues[i];
86
- const { filepath } = item;
87
- const isValid = await (0, fileinfo_1.isValidPath)(filepath);
88
- if (!isValid)
89
- continue;
90
- const exist = await this.fileRepository.findOneBy({
91
- root_id: this.file_id,
92
- filepath,
93
- });
94
- if (exist)
95
- continue;
96
- const parentPath = (0, path_1.dirname)(filepath);
97
- const parent = parentPath == fileitem.filepath
98
- ? fileitem
99
- : await this.fileRepository.findOneBy({
100
- root_id: this.file_id,
101
- filepath: parentPath,
102
- });
103
- if (!parent) {
104
- continue;
105
- }
106
- const pid = parent.id;
107
- const info = {
108
- inputs: [
109
- {
110
- filename: item.filename,
111
- filepath: item.filepath,
112
- filesize: item.filesize,
113
- local_btime: item.local_btime,
114
- local_ctime: item.local_ctime,
115
- local_mtime: item.local_mtime,
116
- },
117
- ],
118
- filepath: item.filepath,
119
- space_id: fileitem.space_id,
120
- space_name: fileitem.space_name,
121
- aid: fileitem.aid,
122
- ali_host_id: fileitem.ali_host_id,
123
- baidu_host_id: fileitem.baidu_host_id,
124
- config,
125
- is_paused: false,
126
- is_ready: item.type != types_1.RecordType.FOLDER,
127
- type: item.type,
128
- task_record_id: fileitem.task_record_id,
129
- uid: fileitem.uid,
130
- root_id: fileitem.id,
131
- pid,
132
- total_count: 1,
133
- };
134
- if (item.file_type == 'media') {
135
- info.external_texts = item.external_texts;
136
- }
137
- items.push(info);
138
- }
139
- const queryRunner = this.dataSource.createQueryRunner();
140
- await queryRunner.connect();
141
- await queryRunner.startTransaction();
142
- try {
143
- const fileRepository = queryRunner.manager.getRepository(entities_1.UploadFile);
144
- const { length } = items;
145
- const size = 50;
146
- for (let i = 0; i < length; i += size) {
147
- const chunks = items.slice(i, i + size);
148
- await fileRepository
149
- .createQueryBuilder()
150
- .insert()
151
- .into(entities_1.UploadFile)
152
- .values(chunks)
153
- .execute();
154
- }
155
- await queryRunner.commitTransaction();
156
- }
157
- catch (err) {
158
- await queryRunner.rollbackTransaction();
159
- }
160
- finally {
161
- await queryRunner.release();
162
- }
163
- this.db.data.files_inserted = true;
164
- await this.db.write();
165
- }
166
- async insertFolders() {
167
- const { folders, folders_inserted } = this.db.data;
168
- if (folders_inserted)
169
- return;
170
- const { length } = folders;
171
- const fileitem = await this.fileRepository.findOneBy({
172
- id: this.file_id,
173
- });
174
- if (!fileitem)
175
- return;
176
- for (let i = 0; i < length; i++) {
177
- const folderPath = (0, path_1.resolve)(fileitem.filepath, folders[i]);
178
- const isValid = await (0, fileinfo_1.isValidPath)(folderPath);
179
- if (!isValid)
180
- continue;
181
- const exist = await this.fileRepository.findOneBy({
182
- root_id: this.file_id,
183
- filepath: folderPath,
184
- });
185
- if (exist)
186
- continue;
187
- const parentPath = (0, path_1.resolve)(folderPath, '..');
188
- const parent = parentPath == fileitem.filepath
189
- ? fileitem
190
- : await this.fileRepository.findOneBy({
191
- root_id: this.file_id,
192
- filepath: parentPath,
193
- });
194
- if (!parent)
195
- continue;
196
- const pid = parent.id;
197
- const root_id = this.file_id;
198
- const info = {
199
- inputs: [
200
- {
201
- filename: (0, path_1.basename)(folderPath),
202
- filepath: folderPath,
203
- filesize: 0,
204
- local_btime: 0,
205
- local_ctime: 0,
206
- local_mtime: 0,
207
- },
208
- ],
209
- aid: fileitem.aid,
210
- ali_host_id: fileitem.ali_host_id,
211
- baidu_host_id: fileitem.baidu_host_id,
212
- config: fileitem.config,
213
- filepath: folderPath,
214
- is_ready: false,
215
- uid: fileitem.uid,
216
- type: types_1.RecordType.FOLDER,
217
- task_record_id: fileitem.task_record_id,
218
- space_name: fileitem.space_name,
219
- space_id: fileitem.space_id,
220
- is_paused: fileitem.is_paused,
221
- external_texts: [],
222
- pid,
223
- root_id,
224
- };
225
- await this.fileRepository.save(this.fileRepository.create(info));
226
- }
227
- this.db.data.folders_inserted = true;
228
- await this.db.write();
229
- }
230
- async parseRawFiles() {
231
- if (this.db.data.raw_files_parsed) {
232
- return;
233
- }
234
- const fileitem = await this.fileRepository.findOneBy({
235
- id: this.file_id,
236
- });
237
- if (!fileitem)
238
- return;
239
- const paths = await (0, glob_1.glob)('**/*', {
240
- nodir: true,
241
- cwd: fileitem.filepath,
242
- });
243
- let folders = [];
244
- paths.map((item) => {
245
- let parentPath = (0, path_1.dirname)(item);
246
- const arr = [];
247
- while (parentPath != '.') {
248
- if (!folders.includes(parentPath)) {
249
- arr.unshift(parentPath);
250
- }
251
- else {
252
- break;
253
- }
254
- parentPath = (0, path_1.dirname)(parentPath);
255
- }
256
- folders = [...folders, ...arr];
257
- });
258
- const files = [];
259
- const subtitles = [];
260
- const medias = [];
261
- const { length } = paths;
262
- for (let i = 0; i < length; i++) {
263
- const filepath = (0, path_1.resolve)(fileitem.filepath, paths[i]);
264
- const isValid = await (0, fileinfo_1.isValidPath)(filepath);
265
- if (isValid) {
266
- const fileinfo = await (0, fileinfo_1.getFileinfo)(filepath);
267
- const { record_type } = fileinfo;
268
- const { dir, base, name } = (0, path_1.parse)(filepath);
269
- const info = {
270
- type: record_type,
271
- title: name,
272
- filename: base,
273
- basepath: (0, path_1.join)(dir, name),
274
- filepath: filepath,
275
- filesize: fileinfo.size,
276
- local_btime: fileinfo.local_btime,
277
- local_ctime: fileinfo.local_ctime,
278
- local_mtime: fileinfo.local_mtime,
279
- parent_path: (0, path_1.dirname)(filepath),
280
- file_type: 'file',
281
- };
282
- const is_media = record_type == types_1.RecordType.VIDEO || record_type == types_1.RecordType.AUDIO;
283
- const is_subtitle = (0, fileinfo_1.isSubtitle)(filepath);
284
- if (is_media) {
285
- const keywords = info.title
286
- .split(/[ _\-.{}[\]、,,。::!?<>《》【】]+/g)
287
- .filter((k) => k.length >= 2);
288
- medias.push({
289
- ...info,
290
- file_type: 'media',
291
- keywords,
292
- });
293
- }
294
- else if (is_subtitle) {
295
- subtitles.push({
296
- ...info,
297
- file_type: 'subtitle',
298
- });
299
- }
300
- else {
301
- files.push(info);
302
- }
303
- }
304
- }
305
- this.db.data.folders = folders;
306
- this.db.data.files = files;
307
- this.db.data.medias = medias;
308
- this.db.data.subtitles = subtitles;
309
- this.db.data.raw_files_parsed = true;
310
- await this.db.write();
311
- }
312
- async destroy() {
313
- delete this.db;
314
- await (0, fs_extra_1.remove)(this.cache_file);
315
- }
316
- async init() {
317
- const fileitem = await this.fileRepository.findOneBy({
318
- id: this.file_id,
319
- });
320
- if (!fileitem)
321
- return;
322
- const { id, inputs } = fileitem;
323
- const input = inputs[0];
324
- const md5 = this.calculateMd5(`${input.filepath}_${input.filesize}`);
325
- this.cache_file = (0, path_1.resolve)((0, os_1.homedir)(), '.dpan', 'desktop', 'json_files', `${id}_${md5}.json`);
326
- const defaultData = {
327
- folders: [],
328
- subtitles: [],
329
- medias: [],
330
- files: [],
331
- status: {},
332
- };
333
- this.db = await (0, bridge_1.getDb)(this.cache_file, defaultData);
334
- }
335
- }
336
- exports.SingleRunner = SingleRunner;
@@ -1,53 +0,0 @@
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 {};
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,2 +0,0 @@
1
- import { MediaMeta, SubtitleMeta } from './types';
2
- export declare const matchSubtitles: (media: MediaMeta, subtitles: SubtitleMeta[]) => SubtitleMeta[];
@@ -1,29 +0,0 @@
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;
@@ -1,10 +0,0 @@
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>;
@@ -1,108 +0,0 @@
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;