@soga/file-encoder 1.3.14 → 1.3.16

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/dist/index.d.mts CHANGED
@@ -7,6 +7,7 @@ import * as lowdb_lib from 'lowdb/lib';
7
7
 
8
8
  interface Params {
9
9
  is_shop_space: boolean;
10
+ is_attachment: boolean;
10
11
  id: number;
11
12
  input: UploadInputItem;
12
13
  type: RecordType;
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@ import * as lowdb_lib from 'lowdb/lib';
7
7
 
8
8
  interface Params {
9
9
  is_shop_space: boolean;
10
+ is_attachment: boolean;
10
11
  id: number;
11
12
  input: UploadInputItem;
12
13
  type: RecordType;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- var t,e=Object.create,a=Object.defineProperty,i=Object.getOwnPropertyDescriptor,s=Object.getOwnPropertyNames,r=Object.getPrototypeOf,o=Object.prototype.hasOwnProperty,n=(t,e,r,n)=>{if(e&&"object"==typeof e||"function"==typeof e)for(let h of s(e))o.call(t,h)||h===r||a(t,h,{get:()=>e[h],enumerable:!(n=i(e,h))||n.enumerable});return t},h=(t,i,s)=>(s=null!=t?e(r(t)):{},n(!i&&t&&t.__esModule?s:a(s,"default",{value:t,enumerable:!0}),t)),d={};((t,e)=>{for(var i in e)a(t,i,{get:e[i],enumerable:!0})})(d,{encode:()=>qe,getPrepare:()=>Ie}),module.exports=(t=d,n(a({},"__esModule",{value:!0}),t));var c=require("@soga/error"),l=require("@soga/lowdb"),u=require("crypto"),p=require("fs-extra"),g=require("fs/promises"),w=require("path"),m=require("stream/promises");function f(t){const e=(0,u.createHash)("md5");return e.update(`${t}`),e.digest("hex")}async function _(t){await new Promise((e,a)=>{(async()=>{const i=(0,w.resolve)(t.outputRoot,t.filename);await(0,p.remove)(i);let s=!1;const r=(0,p.createWriteStream)(i);r.on("open",()=>{s=!0}).on("error",async t=>{s&&r.close(),await(0,p.remove)(i),a(t)});const{length:o}=t.files,n=async(e=0)=>{if(e<o){const a=t.files[e],o=t.files.length;await new Promise((t,e)=>{const n=(0,p.createReadStream)(a);n.pipe(r,{end:!o}),n.on("end",()=>{n.close(),t(!0)}),n.on("error",async t=>{n.destroy(),s&&r.close(),await(0,p.remove)(i),e(t)})}),await n(e+1)}};await n(0),s&&r.end(),e(!0)})()})}async function y(t,e){const a=f(JSON.stringify({...t,dbName:e})),i="db_unique_key",s=(0,w.resolve)(t.outputRoot,e),r=await(0,l.getDb)(s,{});return r.data[i]?r.data[i]!=a&&(r.data={[i]:a},await r.write()):(r.data[i]=a,await r.write()),r}async function b(t){return await y({file_id:t.id,input:{filepath:t.input.filepath,filesize:t.input.filesize},outputRoot:t.outputRoot},"encoder_store.json")}async function v({input_path:t,target_path:e,start:a,end:i}){const s=(0,p.createReadStream)(t,{start:a,end:i,highWaterMark:65536}),r=(0,p.createWriteStream)(e);try{await(0,m.pipeline)(s,r)}catch(t){try{(0,p.existsSync)(e)&&await(0,p.remove)(e)}catch(t){console.warn("Failed to clean up incomplete file:",t.message)}throw t}}var P=require("path"),x=require("@soga/utils"),z=require("@soga/fileutils"),T=require("@soga/error"),R=require("@soga/node-types"),S=require("fs-extra"),D=require("@soga/types"),I=2097152,M={[D.HostType.BAIDU]:52428800,[D.HostType.ALI]:4294967296},F={[D.HostType.BAIDU]:2147483648,[D.HostType.ALI]:4294967296},$=(D.HostType.BAIDU,D.HostType.ALI,require("@soga/types")),k=require("@soga/utils"),q=require("worker_threads"),E=class{segmentNames={};params;id;port=null;db;get lowData(){return this.db.data}get isVideo(){return this.params.type==$.RecordType.VIDEO}get isAudio(){return this.params.type==$.RecordType.AUDIO}get isMedia(){return this.isAudio||this.isVideo}get isTxt(){return this.params.type==$.RecordType.DOC&&this.params.ftype==$.RecordFtype.DOC_TXT}get isImg(){return this.params.type==$.RecordType.IMAGE}getSizeLimit(t){return this.params.is_shop_space?F[t]||2147483648:M[t]||52428800}getFilesize(){return this.params.input.filesize}constructor(t){this.params=t,this.id=t.id,this.port=t.port??null,this.db=t.db}async getPartInfo({host_type:t,filepath:e,start:a,end:i,filename:s,index:r},o=!0){const n={start:a,end:i,size:i-a+1,path:e,index:r,file:s,md5:o?await(0,k.calculateMd5)({file:e,start:a,end:i}):""};if(o){if(t===$.HostType.BAIDU){const t=await(0,k.calculateMd4)({file:e,start:a,end:i});n.md4=t}if(t===$.HostType.ALI){const t=await(0,k.calculateSha1)({file:e,start:a,end:i});n.sha1=t}}return n}async getStore(t){const{id:e,input:a,outputRoot:i}=this.params;return await y({file_id:e,input:{filepath:a.filepath,filesize:a.filesize},outputRoot:i},t)}async postProgress(t){const e={step:t.type,percent:t.percent};await this.postMessage({id:this.id,type:"percent",data:e})}async postMessage(t){this.port?this.port.postMessage(t):q.parentPort&&q.parentPort.postMessage(t)}async setKeeps(t){this.lowData.keeps=t,await this.db.write()}get keeps(){return this.lowData.keeps}async setMeta(t){this.lowData.meta=t,await this.db.write()}get meta(){return this.lowData.meta}async setSourceResult(t){this.lowData.source_result=t,await this.db.write()}get sourceResult(){return this.lowData.source_result}async setPrepareResult(t){this.lowData.prepare_result=t,await this.db.write()}get prepareResult(){return this.lowData.prepare_result}async setMd5(t){this.lowData.meta.md5=t,await this.db.write()}get md5(){return this.lowData.meta.md5}async setSubtitleEncoderResult(t){this.lowData.subtitle_encoder_result=t,await this.db.write()}get subtitleEncoderResult(){return this.lowData.subtitle_encoder_result}async setAudioSeparatorResult(t){this.lowData.audio_separator_result=t,await this.db.write()}get audioSeparatorResult(){return this.lowData.audio_separator_result}async setAudioTranscoderResult(t){this.lowData.audio_transcoder_result=t,await this.db.write()}get audioTranscoderResult(){return this.lowData.audio_transcoder_result}async setCoverResult(t){this.lowData.cover_result=t,await this.db.write()}get coverResult(){return this.lowData.cover_result}async setVideoTranscoderResult(t){this.lowData.video_transcoder_result=t,await this.db.write()}get videoTranscoderResult(){return this.lowData.video_transcoder_result}async setVideoThumbnailerResult(t){this.lowData.video_thumbnailer_result=t,await this.db.write()}get videoThumbnailerResult(){return this.lowData.video_thumbnailer_result}async setGrouperResult(t){this.lowData.grouper_result=t,await this.db.write()}get grouperResult(){return this.lowData.grouper_result}async setImgResult(t){this.lowData.img_result=t,await this.db.write()}get imgResult(){return this.lowData.img_result}async setTxtResult(t){this.lowData.txt_result=t,await this.db.write()}get txtResult(){return this.lowData.txt_result}async setResult(t){this.lowData.result=t,await this.db.write()}get result(){return this.lowData.result}_syncGetId({file:t,start:e,end:a},i){const s=`${i}_key_index`,r=`${i}_key_map`,o=`${t}_${e||0}_${a||0}`,n=this.db.data[r]||{};if(n[o])return n[o];this.db.data[s]=this.db.data[s]||0,this.db.data[r]=this.db.data[r]||{};const h=this.db.data[s]+1,d=`id_${h}`;return this.db.data[r][o]=d,this.db.data[s]=h,d}_syncSetIdMap({id:t,file:e,start:a,end:i},s,r){const o=`${s}_${r}_id_map`;this.db.data[o]=this.db.data[o]||{},this.db.data[o][t]={f:e,s:a,e:i}}},N=class extends E{syncGetSourceId(t){return this._syncGetId(t,"source")}async getSourceId(t){const e=this.syncGetSourceId(t);return await this.db.write(),e}getSourceIdMap(t){return this.db.data[`source_${t}_id_map`]||{}}syncSetSourceIdMap(t,e){this._syncSetIdMap(t,"source",e)}async setSourceIdMap(t,e){this.syncSetSourceIdMap(t,e),await this.db.write()}getSourceSegmentName=(t,e)=>{const a=`source_${e}_${t}`;if(this.segmentNames[a])return this.segmentNames[a];const i=`s-${f(`source-${e}-${this.md5}-${t}`)}`;return this.segmentNames[a]=i,i}},U=class extends N{head_size=32;getZipFilePath(){return(0,P.resolve)(this.params.outputRoot,"souce_zip.bin")}getDownloadListFileName(t){return`source_${t}_download_list.json`}getPartName(t,e){return this.getSourceSegmentName(e,t)}getPartPath(t,e){return(0,P.resolve)(this.params.outputRoot,this.getPartName(t,e))}get dbData(){return this.db.data}async setPartList(t,e){const a=`source_${t}_part_list`;this.dbData[a]=e,await this.params.db.write()}getPartList(t){const e=`source_${t}_part_list`;return this.dbData[e]}async setDownloadMap(t,e){const a=`source_${t}_download_map`;this.dbData[a]=e,await this.params.db.write()}getDownloadMap(t){const e=`source_${t}_download_map`;return this.dbData[e]}async sendProgress(t){await this.postProgress({type:R.UploadProgress.transcode_source,percent:t})}async setDownloadList(t,e){const a=`source_${t}_download_list`;this.dbData[a]=e,await this.params.db.write()}getDownloadList(t){const e=`source_${t}_download_list`;return this.dbData[e]}async start(){try{if(this.sourceResult)return await this.sendProgress(1),this.sourceResult;await this.gzip();const{length:t}=this.params.hosts;for(let e=0;e<t;e++){const t=this.params.hosts[e];await this.calculatePartList(t),await this.processDownloadMap(t)}await this.sendProgress(.9);const e=await this.getResult();return await this.sendProgress(1),e}catch(t){throw(0,T.buildDError)(t,{message:"Error occurred during source encoding",detail:`Error occurred during source encoding: ${this.params.input.filepath}`})}}async gzip(){if(this.dbData.source_gziped)return;const t=this.params.input.filepath,e=this.getZipFilePath();await(0,x.gzip)(t,e,async({percent:t})=>{await this.sendProgress(.6*t)}),this.dbData.source_gziped=!0,await this.params.db.write()}async getResult(){if(this.sourceResult)return this.sourceResult;const t={meta:await this.getMetaData(),data:{}},{length:e}=this.params.hosts;for(let a=0;a<e;a++){const e=this.params.hosts[a],i=this.getPartList(e),s=this.getDownloadMap(e);t.data[e]={download:s,parts:i}}return await this.setSourceResult(t),t}async getMetaData(){const t="source_meta",e=this.dbData[t];if(e)return e;const a=this.getZipFilePath(),i=await(0,z.getFileSize)(a),s={path:a,start:0,end:0},{head_size:r}=this;s.end=i<=r?i-1:r-1;const o={head:(await(0,x.getFileBufferSlice)(s.path,s.start,s.end)).toString("base64")};return this.dbData[t]=o,await this.params.db.write(),o}async writeDownloadListFile(t,e){const a=this.getDownloadListFileName(t),i=(0,P.resolve)(this.params.outputRoot,a);await(0,S.writeFile)(i,e,"utf-8");return{file_path:i,size:await(0,z.getFileSize)(i)}}async processDownloadMap(t){const e=this.getDownloadMap(t);if(e)return e;const a=this.getDownloadList(t);let i;const{file_path:s,size:r}=await this.writeDownloadListFile(t,JSON.stringify(a)),o=this.getSizeLimit(t),n=this.getPartList(t);if(n.length){const e=n[n.length-1],{path:a,size:h,file:d,index:c,end:l,start:u}=e,g=(0,P.resolve)(this.params.outputRoot,d);if(h+r<=o){await async function({source1:t,source2:e,target:a}){const i=(0,p.createReadStream)(t.filepath,{start:t.start,end:t.end}),s=(0,p.createWriteStream)(a);await(0,m.pipeline)(i,s);const r=(0,p.createReadStream)(e),o=(0,p.createWriteStream)(a,{flags:"a"});await(0,m.pipeline)(r,o)}({source1:{filepath:a,start:u,end:l},source2:s,target:g});const e=(await(0,S.stat)(g)).size,o=e-1,h=e-r,w=await this.getPartInfo({host_type:t,filepath:g,start:0,end:e-1,filename:d,index:c});n[n.length-1]=w;i={id:await this.getSourceId({file:d,start:h,end:o}),file:d,start:h,end:o}}else{const e=c+1,a=this.getPartName(t,e),o=this.getPartPath(t,e);await(0,S.rename)(s,o);const h=await this.getSourceId({file:a,start:0,end:r-1}),d=await this.getPartInfo({host_type:t,filepath:o,start:0,end:r-1,filename:a,index:e});n.push(d),i={id:h,file:a,start:0,end:r-1}}return await this.setPartList(t,n),await this.setDownloadMap(t,i),i}}async calculatePartList(t){const e=`source_${t}_list_calculated`;if(this.dbData[e])return;const a=this.getZipFilePath(),i=await(0,z.getFileSize)(a),s=[],r=this.getSizeLimit(t),{head_size:o}=this,n=[];if(i>o){let e=0;for(let h=o;h<=i-1;h+=r){const o=Math.min(h+r-1,i-1),d=this.getPartName(t,e),c=await this.getPartInfo({host_type:t,filepath:a,start:h,end:o,filename:d,index:e});let l=0;for(let t=h;t<o;t+=I){const e=Math.min(t+I-1,o),a=e-t+1,i=l+a-1,s=await this.getSourceId({file:"source_zip",start:t,end:e});n.push({id:s,file:d,start:l,end:i}),l+=a}s.push(c),e++}}await this.setPartList(t,s),await this.setDownloadList(t,n),this.dbData[e]=!0,await this.db.write()}},L=require("path"),C=require("fs-extra"),A=require("@soga/utils"),O=h(require("zlib")),V=require("@soga/utils"),G=require("@soga/error"),B=require("@soga/node-types"),j=require("path"),H=require("@soga/fileutils"),X=require("fs-extra"),W=class extends E{get preview_common_db_data(){return this.db.data}async getCurrentFileIndex(t){const e=this.db.data[`preview_${t}_current_index`];return"number"!=typeof e?(this.db.data[`preview_${t}_current_index`]=0,await this.db.write(),0):e}async increaseCurrentFileIndex(t){const e=await this.getCurrentFileIndex(t)+1;return this.db.data[`preview_${t}_current_index`]=e,await this.db.write(),e}getPartName(t,e){return this.getPreviewSegmentName(e,t)}getPartPath(t,e){return(0,j.resolve)(this.params.outputRoot,this.getPartName(t,e))}syncGetPreviewId(t){return this._syncGetId(t,"preview")}async getPreviewId(t){const e=this.syncGetPreviewId(t);return await this.db.write(),e}getPreviewIdMap(t){return this.db.data[`preview_${t}_id_map`]||{}}syncSetPreviewIdMap(t,e){this._syncSetIdMap(t,"preview",e)}async setPreviewIdMap(t,e){this.syncSetPreviewIdMap(t,e),await this.db.write()}getPreviewSegmentName=(t,e)=>{const a=`preview_${e}_${t}`;if(this.segmentNames[a])return this.segmentNames[a];const i=`p-${f(`preview-${e}-${this.md5}-${t}`)}`;return this.segmentNames[a]=i,i};async calculatePartList(t,e){const a=[],i=await this.getCurrentFileIndex(t);for(let s=0;s<i+1;s++){const i=this.getPartName(t,s),r=this.getPartPath(t,s),o=await(0,H.getFileSize)(r),n=await this.getPartInfo({host_type:t,filename:i,filepath:r,index:s,start:0,end:o-1},e);a.push(n)}return a}getPartListKey(t){return`preview_${t}_part_list`}async completePartList(t){const e=await this.getPartList(t);if(e){const a=[];for(const i of e)if(i.md5)a.push(i);else{const e=await this.getPartInfo({filename:i.file,filepath:i.path,start:i.start,end:i.end,host_type:t,index:i.index},!0);a.push(e)}await this.setPartList(t,a)}}async getPartList(t){const e=this.getPartListKey(t),a=this.preview_common_db_data[e];if(a)return a}async setPartList(t,e){const a=this.getPartListKey(t);this.preview_common_db_data[a]=e,await this.db.write()}async attachCacheData(){const{hosts:t}=this.params;for(const e of t)await this.attachHostCacheData(e),await this.completePartList(e)}getCacheInfo(t){const e=`preview_${t}_cache_info`;return this.preview_common_db_data[e]}async writeCacheFile(t,e){const a=`preview_${t}_cache_info.txt`,i=(0,j.resolve)(this.params.outputRoot,a);await(0,X.writeFile)(i,e,"utf-8");return{file_path:i,size:await(0,H.getFileSize)(i)}}async setCacheInfo(t,e){const a=`preview_${t}_cache_info`;this.preview_common_db_data[a]=e,await this.db.write()}async attachHostCacheData(t){if(this.getCacheInfo(t))return;const e=await this.getPartList(t),a=this.getPreviewIdMap(t),{file_path:i,size:s}=await this.writeCacheFile(t,JSON.stringify(a)),r=this.getSizeLimit(t);if(e.length){const a=e[e.length-1],{path:o,size:n,file:h,index:d,end:c}=a;let l;if(n+s<=r){await async function({filepath:t,size:e},a){(await(0,p.stat)(t)).size>e&&await(0,g.truncate)(t,e);const i=(0,p.createReadStream)(a),s=(0,p.createWriteStream)(t,{flags:"a"});await(0,m.pipeline)(i,s)}({filepath:o,size:n},i);const a=await(0,H.getFileSize)(o),r=await this.getPartInfo({host_type:t,filename:h,filepath:o,index:d,start:0,end:a-1});e[e.length-1]=r;const u=c+1,w=c+s;l={id:await this.getPreviewId({file:h,start:u,end:w}),file:h,start:u,end:w}}else{const a=d+1,r=this.getPartName(t,a),o=this.getPartPath(t,a);await(0,X.copy)(i,o);const n=await this.getPreviewId({file:r,start:0,end:s-1}),h=await this.getPartInfo({host_type:t,filename:r,filepath:o,index:a,start:0,end:s-1},!1);e.push(h),await this.setPartList(t,e),l={id:n,file:r,start:0,end:s-1}}l&&await this.setCacheInfo(t,l)}}},K=class extends W{content_size_1=81920;content_size_2=102400;totalPage=1;hashBuffer=Buffer.from("dpan");get hashBufferLength(){return this.hashBuffer.length}getU8FileName(){return`text_utf8_${this.params.id}.txt`}getU8FilePath(){return(0,L.resolve)(this.params.outputRoot,this.getU8FileName())}async sendProgress(t){await this.postProgress({type:B.UploadProgress.transcode_txt,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.dbData.txt_result)return await this.sendProgress(1),this.dbData.txt_result;await this.txtConvertToUtf8File(),await this.sendProgress(.2);const{length:t}=this.params.hosts;for(let e=0;e<t;e++){const a=this.params.hosts[e];await this.txtConvertToGzipFile(a),await this.sendProgress(.2+(e+1)/t*.6)}await this.attachCacheData();const e=await this.getResult();return await this.clean(),await this.sendProgress(1),e}catch(t){throw(0,G.buildDError)(t,{message:"Error occurred during txt encoding",detail:`Error occurred during txt encoding: ${this.params.input.filepath}`})}}async getResult(){if(this.txtResult)return this.txtResult;const t={meta:{pad:this.hashBufferLength,pages:this.totalPage},data:{}};for(const e of this.params.hosts)t.data[e]={cache:this.getCacheInfo(e),parts:await this.getPartList(e),entrance:await this.getEntranceInfo(e)};return await this.setTxtResult(t),t}async clean(){try{if(this.params.debug)return;const t=this.getU8FilePath();await(0,C.remove)(t)}catch(t){}}async setEntranceInfo(t,e){const a=`txt_${t}_entrance`;this.dbData[a]=e,await this.db.write()}async getEntranceInfo(t){const e=`txt_${t}_entrance`,a=this.dbData[e];if(a)return a}async txtConvertToUtf8File(){if(this.dbData.txt_utf8_converted)return;const t=this.params.input.filepath,e=this.getU8FilePath();await(0,V.saveFileAsUtf8)(t,e),this.dbData.txt_utf8_converted=!0,await this.db.write()}async txtConvertToGzipFile(t){if(await this.getEntranceInfo(t))return;const e=this.getSizeLimit(t),a=this.getU8FilePath(),i=await this.calculateSlice(),{length:s}=i,r={};let o=0,n=(0,C.createWriteStream)(this.getPartPath(t,await this.getCurrentFileIndex(t)));for(let h=0;h<s;h++){const d=h==s-1?0:h+1,c=i[d],{index:l,start:u,end:p}=c,g={page:l+1,text:(await(0,A.getFileBufferSlice)(a,u,p)).toString("utf8")},w=JSON.stringify(g);let m=Buffer.from(w,"utf8");if(0==d){const t={...g,map:r};m=Buffer.from(JSON.stringify(t),"utf8")}const f=await this.getPreviewId({file:"u8zip",start:u,end:p});await new Promise((a,i)=>{O.default.gzip(m,async(s,h)=>{if(s)return i(s);const c=h.length<this.hashBufferLength?this.hashBuffer:h.subarray(0,this.hashBufferLength),l=Buffer.concat([c,h]),u=l.length;if(o+u>e){n.end();const e=await this.increaseCurrentFileIndex(t);n=(0,C.createWriteStream)(this.getPartPath(t,e)),o=0}const p=o,g=o+u-1;if(n.write(l),o+=u,0==d){n.end();const e={id:f,start:p,end:g,file:this.getPartName(t,await this.getCurrentFileIndex(t))};await this.setEntranceInfo(t,e)}else r[`p_${d+1}`]={id:f,f:this.getPartName(t,await this.getCurrentFileIndex(t)),s:p,e:g};this.syncSetPreviewIdMap({id:f,file:this.getPartName(t,await this.getCurrentFileIndex(t)),start:p,end:g},t),a(!0)})})}await this.db.write();const h=await this.calculatePartList(t,!1);await this.setPartList(t,h)}async calculateSlice(){if(this.dbData.txt_slice_list)return this.dbData.txt_slice_list;const t=this.getU8FilePath(),e=await new Promise((e,a)=>{(0,C.readFile)(t,"utf8",(t,i)=>{if(t)return void a(t);const s=this.content_size_1,r=this.content_size_2,o=[];let n=0,h=0,d=0;for(;h<i.length;){let t=Math.min(h+r,i.length);const e=Math.min(h+s,i.length),a=i.slice(e,t-1).indexOf("#");-1!==a&&(t=e+a);const c=i.slice(h,t),l=Buffer.byteLength(c);o.push({index:n++,start:d,end:d+l-1}),this.totalPage=n,h=t,d+=l}e(o)})});return this.dbData.txt_slice_list=e,await this.db.write(),e}},J=require("path"),Q=require("@soga/imgutils"),Z=require("@soga/utils"),Y=require("@soga/fileutils"),tt=require("@soga/error"),et=require("@soga/node-types"),at=require("fs-extra"),it=class extends W{getCompressFileName(){return"img_compress.jpg"}getCompressFilePath(){return(0,J.resolve)(this.params.outputRoot,this.getCompressFileName())}getGzFileName(){return"compressed_img.zip"}getGzFilePath(){return(0,J.resolve)(this.params.outputRoot,this.getGzFileName())}async sendProgress(t){await this.postProgress({type:et.UploadProgress.transcode_img,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.imgResult)return await this.sendProgress(1),this.imgResult;await this.compress(),await this.sendProgress(.1),await this.gzip(),await this.sendProgress(.4);const{hosts:t}=this.params,{length:e}=t;for(let a=0;a<e;a++){const e=t[a];await this.splitFile(e),await this.calculatePartList(e,!1)}await this.attachCacheData(),await this.sendProgress(.9);const a=await this.getResult();return await this.clean(),await this.sendProgress(1),a}catch(t){throw(0,tt.buildDError)(t,{message:"Error occurred during image encoding",detail:`Error occurred during image encoding: ${this.params.input.filepath}`})}}getCacheInfoFileName(t){return`img_${t}_cache.json`}async getResult(){if(this.imgResult)return this.imgResult;const{input:t}=this.params,e=t.filepath,{width:a,height:i}=await(0,Q.getMetadata)(e),s=this.getCompressFilePath(),{width:r,height:o}=await(0,Q.getMetadata)(s),n=await(0,Y.getFileSize)(s),h={meta:{width:a,height:i,size:t.filesize,t_width:r,t_height:o,t_size:n},data:{}},{length:d}=this.params.hosts;for(let t=0;t<d;t++){const e=this.params.hosts[t],a=await this.getPartList(e),i=this.getPreviewList(e);h.data[e]={img:{preview:i},cache:this.getCacheInfo(e),parts:a}}return await this.setImgResult(h),h}async clean(){try{if(this.params.debug)return;const t=this.getCompressFilePath();await(0,at.remove)(t)}catch(t){}}async compress(){if(this.dbData.img_compressed)return;const t=this.getCompressFilePath();await(0,Q.compress)({ffmpeg_path:this.params.ffmpegPath,input_path:this.params.input.filepath,output_path:t}),this.dbData.img_compressed=!0,await this.db.write()}async gzip(){if(this.dbData.img_gziped)return;const t=this.getCompressFilePath(),e=this.getGzFilePath();await(0,Z.gzip)(t,e),this.dbData.img_gziped=!0,await this.db.write()}async setPreviewList(t,e){const a=`img_${t}_preview_list`;this.dbData[a]=e,await this.db.write()}getPreviewList(t){const e=`img_${t}_preview_list`;return this.dbData[e]}async splitFile(t){if(this.getPreviewList(t))return;const e=this.getGzFilePath(),a=await(0,Y.getFileSize)(e),i=this.getSizeLimit(t),s=[],r=[];for(let o=0;o<=a-1;o+=i){0!=o&&await this.increaseCurrentFileIndex(t);const n=Math.min(o+i-1,a-1),h=await this.getCurrentFileIndex(t),d=this.getPartName(t,h),c=this.getPartPath(t,h);await v({input_path:e,target_path:c,start:o,end:n});const l=0,u=n-o,p=await this.getPartInfo({host_type:t,filepath:c,filename:d,start:l,end:u,index:h},!1);s.push(p);const g=await this.getPreviewId({file:d,start:l,end:u});r.push({id:g,file:d,start:l,end:u}),await this.setPreviewIdMap({id:g,file:d,start:l,end:u},t)}await this.setPartList(t,s),await this.setPreviewList(t,r)}},st=h(require("fluent-ffmpeg")),rt=require("child_process"),ot=require("@soga/mediainfo"),nt=class extends W{async getMediainfo(){const{mediainfo:t}=this.db.data;if(t)return t;const e=this.params.input.filepath,a=await(0,ot.parseMediaInfo)(e);return this.db.data.mediainfo=a,await this.params.db.write(),a}constructor(t){super(t),st.default.setFfmpegPath(t.ffmpegPath)}getFluent(){return(0,st.default)()}async ffmpeg(t,e){const a=this.params.ffmpegPath;return await new Promise((i,s)=>{const r=(0,rt.spawn)(a,t,Object.assign({stdio:"ignore"},e));r.on("close",t=>{i(t)}),r.on("error",t=>{s(t)})})}},ht=require("path"),dt=require("@soga/fileutils"),ct=require("@soga/node-types"),lt=require("@soga/error"),ut=({type:t,track_order:e,quality:a})=>`audio-${e}-${a}-${t}.${"manifest"===t?"m3u8":"mp4"}`,pt=({width:t,height:e})=>`video-formatted-${t}-${e}.mp4`,gt=t=>`grouper_result_${t}`,wt=t=>{let e=0,a=0,i=0;t.segments.forEach(t=>{a+=t.duration,e+=t.size;const s=8*t.size/t.duration;s>i&&(i=s)});const s=8*e/a;return{bandwidth:Math.ceil(i),average_bandwidth:Math.ceil(s)}},mt=(t,e)=>{if("number"==typeof t.percent)return t.percent/100;return function(t){const e=t.split(":").map(parseFloat),[a=0,i=0,s=0]=e.reverse();return 3600*s+60*i+a}(t.timemark)/e};var ft=class extends nt{async start(){try{await this.separateVideo(),await this.postProgress({type:ct.UploadProgress.separate_video,percent:1})}catch(t){throw(0,lt.buildDError)(t,{message:"Error occurred during video separation",detail:`Error occurred during video separation: ${this.params.input.filepath}`})}}async separateVideo(){const t="video_separated";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],i=pt({width:a.width,height:a.height}),s=(0,ht.resolve)(this.params.outputRoot,i),r=(0,dt.isVideoSupport)(a.codec),o=["-sn","-an","-map","0:v:0"];let n="copy";r||(n=a.width*a.height>=2073600?"libx265":"libx264","libx265"==n&&o.push("-pix_fmt","yuv420p")),o.push("-c:v",n);const h=a.duration;o.push("-y"),await new Promise((t,e)=>{const a=this.getFluent().input(this.params.input.filepath).outputOptions(o).on("progress",async t=>{if(!r&&t.frames){const e=mt(t,h);await this.postProgress({type:ct.UploadProgress.separate_video,percent:e})}}).on("end",async()=>{t("end"),a.kill("SIGKILL")}).on("error",async t=>{e(t)}).output(s);a.run()});if(!await(0,dt.isValidFile)(s))throw new Error("Separate Video track failed");this.db.data[t]=!0,await this.params.db.write()}},_t=require("path"),yt=require("@soga/fileutils"),bt=require("@soga/node-types"),vt=require("@soga/error"),Pt=class extends nt{async start(){try{await this.separateTracks(),await this.postProgress({type:bt.UploadProgress.separate_audio,percent:1})}catch(t){throw(0,vt.buildDError)(t,{message:"Error occurred during audio separation",detail:`Error occurred during audio separation: ${this.params.input.filepath}`})}}async separateTracks(){if(this.audioSeparatorResult)return;const t=await this.getMediainfo();if(!t?.audio?.length)return;const{audio:e}=t,a=e.length,i=[];for(let t=0;t<a;t++){const s=e[t],{codec:r,channels:o,lossless:n}=s,h={adapt:{need:!0,codec:"",channels:Math.min(o,2)},high:{need:!1,codec:"flac",channels:0}};(0,yt.isAudioAdapt)(r)?o>2?(h.high.need=!0,h.high.codec="copy",h.adapt.codec=r,h.adapt.need=!0):(h.adapt.need=!0,h.adapt.codec="copy",h.adapt.channels=0):(0,yt.isAudioHigh)(r)?(h.high.need=!0,h.high.codec="copy",h.adapt.need=!0,h.adapt.codec="aac"):(h.adapt.need=!0,h.adapt.codec="aac",n&&(h.high.need=!0,h.high.codec="flac")),h.adapt.need&&await this.separateAudioTrack(t,{type:"adapt",codec:h.adapt.codec,tracks:a,channels:h.adapt.channels,need_adapt:!0,need_high:h.high.need}),h.high.need&&await this.separateAudioTrack(t,{type:"high",codec:h.high.codec,tracks:a,channels:h.high.channels,need_adapt:h.adapt.need,need_high:!0}),i.push(h)}await this.setAudioSeparatorResult(i)}async separateAudioTrack(t,e){const a=`audio_separated_${t}_${e.type}`;if(this.db.data[a])return;const i=await this.getMediainfo();if(!i?.audio?.length)return;const s=i.audio[t];if(!s)return;const r=s?.duration??i.general?.duration,o=ut({type:"formatted",track_order:t,quality:e.type}),n=(0,_t.resolve)(this.params.outputRoot,o),h=["-sn","-vn","-map",`0:a:${t}`];e.codec&&h.push("-c:a",e.codec),e.channels&&h.push("-ac",e.channels.toString()),h.push("-y"),await new Promise((a,i)=>{const s=this.getFluent().input(this.params.input.filepath).outputOptions(h).on("progress",async a=>{if("copy"!=e.codec){const i=mt(a,r);let s=t;"adapt"==e.type?e.need_high?s+=1/3*i:s+=i:e.need_adapt?(s+=1/3,s+=2/3*i):s+=i;const o=s/e.tracks;await this.postProgress({type:bt.UploadProgress.separate_audio,percent:o})}}).on("end",async()=>{a("end"),s.kill("SIGKILL")}).on("error",async t=>{i(t)}).output(n);s.run()});if(!await(0,yt.isValidFile)(n))throw new Error(`Separate audio track failed: [track_order:${t}, track_quality ${e.type}] `);if("copy"==e.codec){let a=t;"adapt"==e.type&&e.need_high?a+=1/3:a+=1;const i=a/e.tracks;await this.postProgress({type:bt.UploadProgress.separate_audio,percent:i})}this.db.data[a]=!0,await this.params.db.write()}},xt=require("path"),zt=require("@soga/mediainfo"),Tt=require("@soga/mp4box"),Rt=require("@soga/m3u8"),St=require("@soga/node-types"),Dt=require("@soga/fileutils"),It=require("fs-extra"),Mt=require("@soga/error"),Ft=class extends nt{getVideoInitName({width:t,height:e}){return`video-init-${t}-${e}.mp4`}getVideoManifestName({width:t,height:e}){return`video-hls-${t}-${e}.m3u8`}async start(){try{await this.transcodeVideo(),await this.saveData(),await this.postProgress({type:St.UploadProgress.transcode_video,percent:1})}catch(t){throw(0,Mt.buildDError)(t,{message:"Error occurred during video transcoding",detail:`Error occurred during video transcoding: ${this.params.input.filepath}`})}}async saveData(){const t=await this.getMediainfo();if(!t?.video?.length)return;if(this.videoTranscoderResult)return;const{width:e,height:a}=t.video[0],i=pt({width:e,height:a}),s=(0,xt.resolve)(this.params.outputRoot,i),r=this.getVideoManifestName({width:e,height:a}),o=(0,xt.resolve)(this.params.outputRoot,r),n=await(0,Rt.parseM3U8)(o),{videos:h}=await(0,Tt.getMp4boxInfo)(s),{codec:d}=h[0],{bandwidth:c,average_bandwidth:l}=wt(n),u=(await(0,zt.parseMediaInfo)(s)).video[0],p=(0,Dt.getStandardInfo)(e,a),g={m3u8:n,m3u8_path:o,codec:d,width:e,height:a,bandwidth:c,average_bandwidth:l,bitdepth:u?.bitdepth,bitrate:u?.bitrate,codec_name:u?.codec??"",framerate:u?.framerate,label:p?.label??"unknown"};await this.setVideoTranscoderResult(g),this.params.debug||await(0,It.remove)(s)}async transcodeVideo(){const t="video_transcode_state";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],i={width:a.width,height:a.height},s=pt(i),r=this.getVideoInitName(i),o=this.getVideoManifestName({width:a.width,height:a.height}),n=["-i",s,"-an","-sn","-c:v","copy","-hls_list_size","0","-hls_time","6","-hls_segment_type","fmp4","-hls_fmp4_init_filename",r,"-y",o];await this.ffmpeg(n,{cwd:this.params.outputRoot});const h=(0,xt.resolve)(this.params.outputRoot,o);if(!await(0,Dt.isValidFile)(h))throw new Error("Transcode video track failed");this.db.data[t]=!0,await this.db.write()}},$t=require("path"),kt=require("@soga/fileutils"),qt=require("@soga/mp4box"),Et=require("@soga/m3u8"),Nt=require("@soga/mediainfo"),Ut=require("fs-extra"),Lt=require("@soga/error"),Ct=require("@soga/node-types"),At=class extends nt{async start(){try{await this.transcodeAudios(),await this.saveData()}catch(t){throw(0,Lt.buildDError)(t,{message:"Error occurred during audio transcoding",detail:`Error occurred during audio transcoding: ${this.params.input.filepath}`})}}async saveData(){if(this.audioTranscoderResult)return;const t=await this.getMediainfo();if(!t?.audio?.length)return;const e=t.audio.length,a=this.audioSeparatorResult,i=[],s={};for(let t=0;t<e;t++){const e=a[t];e.adapt.need&&(s.adapt=await this.getQualityData({track_order:t,quality:"adapt"})),e.high.need&&(s.high=await this.getQualityData({track_order:t,quality:"high"})),i.push(s)}await this.setAudioTranscoderResult(i);try{if(this.params.debug)return;for(let t=0;t<e;t++){const e=a[t];if(e.adapt.need){const e=ut({type:"formatted",track_order:t,quality:"adapt"}),a=(0,$t.resolve)(this.params.outputRoot,e);await(0,Ut.remove)(a)}if(e.high.need){const e=ut({type:"formatted",track_order:t,quality:"high"}),a=(0,$t.resolve)(this.params.outputRoot,e);await(0,Ut.remove)(a)}}}catch(t){}}async getQualityData({track_order:t,quality:e}){const a=ut({type:"formatted",track_order:t,quality:e}),i=(0,$t.resolve)(this.params.outputRoot,a),s=await(0,Nt.parseMediaInfo)(i);if(!s.audio?.length)throw new Error("parse mediainfo failed!");const r=s.audio[0],o=ut({type:"manifest",track_order:t,quality:e}),n=await(0,kt.getFileSize)(i),h=(0,$t.resolve)(this.params.outputRoot,o),d=await(0,qt.getMp4boxInfo)(i),{audios:c}=d,{language:l,codec:u}=c[0],p=l&&!l.startsWith("un")?{language:l}:void 0,g=await(0,Et.parseM3U8)(h),{bandwidth:w,average_bandwidth:m}=wt(g);return{m3u8:g,m3u8_path:h,codec:u,codec_name:r.codec,...p,order:t,lossless:r.lossless,channels:r.channels,bandwidth:w,size:n,average_bandwidth:m}}async transcodeAudios(){const t="audio_transcoded";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.audio?.length)return;const a=e.audio.length,i=this.audioSeparatorResult;for(let t=0;t<a;t++){const e=i[t];e.adapt.need&&await this.transcodeAudio(t,{...e.adapt,type:"adapt"}),e.high.need&&await this.transcodeAudio(t,{...e.high,type:"high"});const s=(t+1)/a;await this.postProgress({type:Ct.UploadProgress.transcode_audio,percent:s})}await this.postProgress({type:Ct.UploadProgress.transcode_audio,percent:1}),this.db.data[t]=!0,await this.db.write()}async transcodeAudio(t,e){const a=`audio-transcoded-${t}-${e.type}`;if(this.db.data[a])return;const i=ut({type:"formatted",track_order:t,quality:e.type}),s=ut({type:"init",track_order:t,quality:e.type}),r=ut({type:"manifest",track_order:t,quality:e.type}),o=["-i",i,"-vn","-sn","-c:a","copy","-hls_list_size","0","-hls_time","6","-hls_segment_type","fmp4","-hls_fmp4_init_filename",s,"-y",r];await this.ffmpeg(o,{cwd:this.params.outputRoot});const n=(0,$t.resolve)(this.params.outputRoot,r);if(!await(0,kt.isValidFile)(n))throw new Error(`Transcode audio track failed: [track_order:${t}, track_quality ${e.type}] `);this.db.data[a]=!0,await this.db.write()}},Ot=require("path"),Vt=require("@soga/fileutils"),Gt=require("@soga/imgutils"),Bt=require("fs-extra"),jt=require("@soga/node-types"),Ht=require("@soga/error"),Xt=class extends nt{m3u8_data=null;thumbnail_duration=30;thumbnail_group=[];row=8;col=8;screenshot_width=480;screenshot_height=270;getScreenshotName(t){return`video_screenshot_${t}.jpg`}getTileName(t){return`video_tile_${t}.jpg`}getCoverName(){return"video_cover.jpg"}async updateImagePercent(t,e){const a="screenshot"==e?6*t/7:t/7+6/7;await this.postProgress({type:jt.UploadProgress.transcode_thumbnail,percent:a})}store;async initStore(){this.store=await this.getStore("thumbnail_store.json")}async start(){if(!this.videoThumbnailerResult)try{const t=await this.getMediainfo();if(!t?.video?.length)return;if(await this.init(),!this.m3u8_data)return;await this.generateScreenshots(),await this.generateTiles(),await this.saveCoverInfo(),await this.saveThumbnailInfo()}catch(t){throw(0,Ht.buildDError)(t,{message:"Error occurred during video thumbnail generation",detail:`Error occurred during video thumbnail generation: ${this.params.input.filepath}`})}}async init(){await this.initStore(),await this.initScreenshotSize(),await this.initM3U8Data(),await this.initThumbnailDuration(),await this.initThumbnailGroup()}async saveThumbnailInfo(){if(this.videoThumbnailerResult)return;const{col:t,row:e,thumbnail_group:a,screenshot_width:i,screenshot_height:s}=this,r=a.length,o=[],n=[];for(let h=0;h<r;h++){const r=a[h],d=r.start_time,c=r.end_time,l=Math.floor(h/(e*t)),u=h%e*i,p=Math.floor(h%(t*e)/e)*s,g=this.getTileName(l);n.push(g),o.push({file:g,st:d,et:c,x:u,y:p,w:i,h:s})}const h=[...new Set(n)],d=h.length,c=[];for(let t=0;t<d;t++){const e=h[t],a=(0,Ot.resolve)(this.params.outputRoot,e),i=await(0,Vt.getFileSize)(a);c.push({file:e,file_path:a,size:i})}const l={width:this.screenshot_width,height:this.screenshot_height,row:this.row,col:this.col,tile_list:c,sprite_list:o};await this.setVideoThumbnailerResult(l)}async saveCoverInfo(){if(this.coverResult)return;const t=this.store.data.thumbnail_screenshot_largest,e=t?.index||0,{screenshot_width:a,screenshot_height:i}=this,s=this.getScreenshotName(e),r=(0,Ot.resolve)(this.params.outputRoot,s),o=this.getCoverName(),n=(0,Ot.resolve)(this.params.outputRoot,o);await(0,Bt.copy)(r,n);const h={file:o,path:n,size:await(0,Vt.getFileSize)(n),width:a,height:i};await this.setCoverResult(h)}async generateTiles(){const t=this.store.data.thumbnail_tile_index||0,{length:e}=this.thumbnail_group,a=this.col*this.row,i=Math.ceil(e/a);for(let e=t;e<i;e++)await this.generateOneTile(e),await this.updateImagePercent((e+1)/i,"tile")}async generateOneTile(t){const{col:e,row:a}=this,i=this.thumbnail_group.length,s=a*e,r=t*s,o=Math.min(s,i-r),n=[];for(let t=0;t<o;t++){const e=this.getScreenshotName(r+t),a=(0,Ot.resolve)(this.params.outputRoot,e);n.push(a)}const h=this.getTileName(t),d=(0,Ot.resolve)(this.params.outputRoot,h);await this.createSpriteSheet(n,d),this.store.data.thumbnail_tile_index=t+1,await this.store.write()}async createSpriteSheet(t,e){await(0,Gt.combine)({col:this.col,inputs:t,output_path:e,width:this.screenshot_width,height:this.screenshot_height})}getKeyFrameParams(t,e=0){if(t<1)return["-vframes","1"];{const a=Math.max(t-e-.3,.1);if(a<1)return["-vframes","1"];return["-ss",`${a.toFixed(3)}`,"-vframes","1"]}}async generateScreenshots(){if(this.store.data.thumbnail_screenshot_state)return;this.store.data.thumbnail_screenshot_index||=0;const t=this.store.data.thumbnail_screenshot_index,e=this.store.data.thumbnail_screenshot_largest,a={index:0,size:0};if(e){const t=e;a.index=t.index,a.size=t.size}const{segments:i}=this.m3u8_data,{thumbnail_group:s,screenshot_width:r}=this,{length:o}=s,n=async(t,{errorTimes:e,fixedSeconds:o})=>{const h=s[t].item.index,d=i[h];try{const e=this.getScreenshotName(t),i=`concat:${d.init_uri}|${d.uri}`,s=this.getKeyFrameParams(d.duration,o),n=r>this.screenshot_height?`${r}:-2`:`-2:${this.screenshot_height}`,h=["-i",i,...s,"-vf",`scale=${n}:flags=lanczos`,"-y",e];await this.ffmpeg(h,{cwd:this.params.outputRoot});const c=(0,Ot.resolve)(this.params.outputRoot,e),l=await(0,Vt.getFileSize)(c);if(0===l)throw new Error(`Generate video thumbnail error: [index: ${t}, start_time: ${d.start_time}, end_time: ${d.end_time}]`);l>=a.size&&(a.index=t,a.size=l,this.store.data.thumbnail_screenshot_largest=a,await this.store.write()),this.store.data.thumbnail_screenshot_index=t+1,await this.store.write()}catch(a){const i=Math.max(10,d.duration);if(!(e<3))throw a;await n(t,{errorTimes:e+1,fixedSeconds:o+i/5})}};for(let e=t;e<o;e++)await n(e,{errorTimes:0,fixedSeconds:0}),await this.updateImagePercent((e+1)/o,"screenshot");this.store.data.thumbnail_screenshot_state=!0,await this.store.write()}async initScreenshotSize(){const{thumbnail_screenshot_size:t}=this.store.data;if(t)return this.screenshot_width=t.width,void(this.screenshot_height=t.height);const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],{width:i,height:s}=a,r=i>s?480:270;this.screenshot_width=2*Math.floor(Math.min(r,i)/2),this.screenshot_height=2*Math.floor(this.screenshot_width*(s/i)/2),this.store.data.thumbnail_screenshot_size={width:this.screenshot_width,height:this.screenshot_height}}async initThumbnailGroup(){if(this.store.data.thumbnail_group)return void(this.thumbnail_group=this.store.data.thumbnail_group);const t=[],{segments:e}=this.m3u8_data,{length:a}=e,i=this.thumbnail_duration;let s=0,r=[];for(let o=0;o<a;o++){const n=e[o];if(s+=n.duration,r.push(n),s>=i||o===a-1){const e=r.length,a=r[0],i=r[e-1];t.push({duration:s,start_time:a.start_time,end_time:i.end_time,items:r,item:i}),s=0,r=[]}}if(t.length>1){if(t[t.length-1].duration<1){const e=t.pop(),a=t[t.length-2];a.duration=a.duration+e.duration,a.end_time=e.end_time,a.items=a.items.concat(e.items),a.item=e.item,e.items}}t.forEach(t=>{const{items:e}=t;for(let a=e.length-1;a>=0;a--)if(e[a].duration>1){t.item=e[a];break}}),this.thumbnail_group=t,this.store.data.thumbnail_group=t,await this.store.write()}getVideoM3U8Info(){return this.videoTranscoderResult?.m3u8}async initM3U8Data(){this.m3u8_data=this.getVideoM3U8Info()}async initThumbnailDuration(){if(this.store.data.thumbnail_duration)return this.thumbnail_duration=this.store.data.thumbnail_duration,this.thumbnail_duration;let t=30;const e=await this.getMediainfo(),a=e?.video;if(!a?.length)return t;const i=a[0],s=i.duration||e?.general?.duration,{width:r,height:o}=i;r*o>=518400&&(t=10),r*o>=921600&&(t=20),r*o>=2073600&&(t=30),r*o>=3686400&&(t=40),r*o>=8294400&&(t=60);const n=s??0;if(n&&(n<60&&(t=0),n<300&&(t=Math.ceil(t/4)),n<600&&(t=Math.ceil(t/2)),n>3600)){const e=n/3600;t=Math.ceil(t*e)}return t=Math.min(60,t),this.thumbnail_duration=t,this.store.data.thumbnail_duration=t,await this.store.write(),t}},Wt=require("path"),Kt=require("fs-extra"),Jt=require("@soga/imgutils"),Qt=require("@soga/fileutils"),Zt=require("@soga/node-types"),Yt=require("@soga/error"),te=class extends nt{get cover_name(){return"audio_cover.png"}async start(){try{await this.generateCover(),this.isAudio&&await this.postProgress({type:Zt.UploadProgress.transcode_thumbnail,percent:1})}catch(t){throw(0,Yt.buildDError)(t,{message:"Error occurred during audio cover generation",detail:`Error occurred during audio cover generation: ${this.params.input.filepath}`})}}async generateCover(){const t=await this.getMediainfo();if(t.video?.length)return;const e="audio-covered";try{if(this.coverResult)return this.coverResult;if(this.db.data[e])return;const{cover_name:t}=this,a=["-i",this.params.input.filepath,"-map","0:v","-y",t];await this.ffmpeg(a,{cwd:this.params.outputRoot});const i=(0,Wt.resolve)(this.params.outputRoot,t),s=await(0,Kt.pathExists)(i),r=await(0,Jt.getMetadata)(i);if(s){const e={file:t,path:i,size:await(0,Qt.getFileSize)(i),width:r.width??0,height:r.height??0};await this.setCoverResult(e)}}catch(t){throw t}finally{this.db.data[e]=!0,await this.db.write()}}},ee=require("path"),ae=require("@soga/utils"),ie=require("@soga/fileutils"),se=require("fs-extra"),re=require("@soga/error"),oe=require("@soga/node-types"),ne=class extends nt{builtin_tracks=0;external_tracks=0;get tracks(){return this.builtin_tracks+this.external_tracks}async sendProgress(t){await this.postProgress({type:oe.UploadProgress.separate_subtitle,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.subtitleEncoderResult)return;const t=await this.getMediainfo();if(this.builtin_tracks=t?.text?.length||0,this.external_tracks=this.params.subtitles?.length||0,!this.tracks)return await this.setSubtitleEncoderResult([]),void await this.sendProgress(1);const e=await this.parseBuiltinTextTracks();await this.sendProgress(this.builtin_tracks/this.tracks);const a=await this.parseExternalTextTracks(),i=[...e,...a];await this.setSubtitleEncoderResult(i),await this.sendProgress(1)}catch(t){throw(0,re.buildDError)(t,{message:"Error occurred while process subtitle track",detail:`Error occurred while process subtitle track: ${this.params.input.filepath}`})}}async parseBuiltinTextTracks(){const t=await this.getMediainfo(),e=t?.text;if(!e?.length)return[];const{subtitle_builtin_tracks:a}=this.dbData;if(a)return a;const i=e.length,s=[];for(let t=0;t<i;t++){const e=await this.parseBuiltinTextTrack(t);e&&s.push(e),await this.sendProgress((t+1)/this.tracks)}return this.dbData.subtitle_builtin_tracks=s,await this.params.db.write(),s}async parseBuiltinTextTrack(t){const e=this.params.outputRoot,a=`subtitle-builtin-${t}.zip`,i=(0,ee.resolve)(e,a),s=`subtitle-temp-${t}.vtt`,r=(0,ee.resolve)(e,s),o=`subtitle-builtin-u8-${t}.vtt`,n=(0,ee.resolve)(e,o),h=["-i",this.params.input.filepath,"-vn","-an","-map",`0:s:${t}`,"-c","webvtt","-y",s];await this.ffmpeg(h,{cwd:this.params.outputRoot});if(await(0,ie.isValidFile)(r)){if(await(0,ae.isUtf8File)(r))await(0,se.copy)(r,n);else{await(0,ae.saveFileAsUtf8)(r,n);await(0,ie.isValidFile)(n)||await(0,se.copy)(r,n)}const e=await(0,ae.getFileLanguage)(n),{label:s,lang:o}=e;await(0,ae.gzip)(n,i);return{file:a,file_path:i,size:await(0,ie.getFileSize)(i),lang:o,name:s||`builtin_${t+1}`,title:s||`builtin_${t+1}`,builtin:!0,source:null}}return!1}async parseExternalTextTracks(){const{subtitles:t}=this.params;if(!t?.length)return[];const{subtitle_external_tracks:e}=this.dbData;if(e)return e;const a=[],i=t.length;for(let e=0;e<i;e++){const i=await this.parseExternalTextTrack(e,t[e]);i&&a.push(i),await this.sendProgress((this.builtin_tracks+(e+1))/this.tracks)}return this.dbData.subtitle_external_tracks=a,await this.params.db.write(),a}async parseExternalTextTrack(t,e){const{ext:a}=(0,ee.parse)(e),i=this.params.outputRoot,s=`subtitle-external-${t}.vtt`,r=(0,ee.resolve)(i,s),o=`subtitle-external-${t}.zip`,n=(0,ee.resolve)(i,o),h=`subtitle-external-u8-${t}${a}`,d=(0,ee.resolve)(i,h),c=`subtitle-external-source-${t}.zip`,l=(0,ee.resolve)(i,c);if(!await(0,ie.isValidPath)(e))return!1;if(await(0,ae.isUtf8File)(e))await(0,se.copy)(e,d);else{await(0,ae.saveFileAsUtf8)(e,d);if(!await(0,ie.isValidFile)(d))return!1}const u=["-i",d,"-c","webvtt","-y",s];await this.ffmpeg(u,{cwd:this.params.outputRoot});if(await(0,ie.isValidFile)(r)){const i=await(0,ae.getFileLanguage)(r),{label:s,lang:h}=i;await(0,ae.gzip)(e,l),await(0,ae.gzip)(r,n);const d=await(0,ie.getFileSize)(l);return{file:o,size:await(0,ie.getFileSize)(n),file_path:n,lang:h,name:s||`external_${t+1}`,title:s||`external_${t+1}`,builtin:!1,source:{file:c,file_path:l,size:d,ext:a}}}return!1}},he=require("@soga/error"),de=require("path"),ce=require("fs-extra"),le=require("@soga/node-types"),ue=require("@soga/fileutils"),pe=require("@soga/utils"),ge=require("@soga/error"),we=require("path"),me=require("@soga/fileutils"),fe=class extends nt{hostType;safe_index=0;file_map={};completed_percent=0;total_percent=0;store;async initStore(t){this.store=await this.getStore(`${t}_grouper_store.json`)}getFileName=t=>this.getPreviewSegmentName(t,this.hostType);getGroupedVideoManifestName(t){return`grouper_video_${this.hostType}_${t}.m3u8`}getAudioManifestName(t,e){return`grouper_audio_${this.hostType}_${e}_${t}.m3u8`}getThumbnailInfoFilename(){return`grouper_thumbnail_${this.hostType}.json`}getCacheInfoFilename(){return`grouper_cache_${this.hostType}.json`}constructor(t){super(t),this.hostType=t.host_type,this.completed_percent=t.completed_percent,this.total_percent=1/t.hosts.length}async generateSafeFile(t){return await async function(t){const e=`safe_${t.type}_${t.file_index}.txt`,a=f(t.filesize),i=(0,w.resolve)(t.outputRoot,e);return await(0,p.writeFile)(i,a),{file_path:i,size:a.length}}({type:t,file_index:this.safe_index++,outputRoot:this.params.outputRoot,filesize:this.params.input.filesize})}readAudioTracks(){return this.audioTranscoderResult??[]}readVideoTracks(){return this.videoTranscoderResult?[this.videoTranscoderResult]:[]}readThumbnailInfo(){return this.videoThumbnailerResult}readCoverInfo(){return this.coverResult}readSubtitleInfo(){return this.subtitleEncoderResult}async getPartData(){const t=this.store.data.grouper_part_names??[],e=[];for(let a=0;a<t.length;a++){const i=t[a],s=(0,we.resolve)(this.params.outputRoot,i),r=await(0,me.getFileSize)(s),o=await this.getPartInfo({host_type:this.hostType,filepath:s,start:0,end:r-1,filename:i});e.push(o)}return e}async getAudioData(){const t=this.readAudioTracks();if(!t?.length)return;const e=[];for(let a=0;a<t.length;a++){const i=t[a];if(i.adapt){const{average_bandwidth:t,bandwidth:s,channels:r,codec:o,codec_name:n,language:h,order:d}=i.adapt,c=this.getAudioManifestName("adapt",a),l=this.file_map[c],{file_index:u,start:p,end:g,size:w,hash:m}=l,f=this.getFileName(u),_=await this.getPreviewId({file:c});await this.setPreviewIdMap({id:_,file:f,start:p,end:g},this.hostType);const y={id:_,average_band:t,band:s,channels:r,codec:o,codec_name:n,language:h,order:d,file:f,start:p,end:g,size:w,hash:m};if(i.high){const{average_bandwidth:t,bandwidth:e,channels:s,codec:r,codec_name:o,language:n,order:h}=i.high,d=this.getAudioManifestName("high",a),c=this.file_map[d],{file_index:l,start:u,end:p,size:g,hash:w}=c,m=this.getFileName(l),f=await this.getPreviewId({file:d});await this.setPreviewIdMap({id:f,file:m,start:u,end:p},this.hostType),y.high={id:f,average_band:t,band:e,channels:s,codec:r,codec_name:o,language:n,order:h,file:m,start:u,end:p,size:g,hash:w}}e.push(y)}}return e}async getVideoData(){const t=this.readVideoTracks();if(!t?.length)return;const e=[];for(let a=0;a<t.length;a++){const i=t[a],s=this.getGroupedVideoManifestName(a),r=await this.getPreviewId({file:s}),o=this.file_map[s],{file_index:n,start:h,end:d,size:c,hash:l}=o,u=this.getFileName(n);await this.setPreviewIdMap({id:r,file:u,start:h,end:d},this.hostType);const{average_bandwidth:p,bandwidth:g,codec:w,width:m,height:f,label:_,codec_name:y,bitdepth:b,framerate:v}=i,P={id:r,average_band:p,band:g,codec:w,codec_name:y,bitdepth:b,framerate:Math.round(v),width:m,height:f,file:u,start:h,end:d,size:c,label:_,hash:l};e.push(P)}return e}async getSubtitleData(){const t=this.readSubtitleInfo();if(!t?.length)return;const e=[],{length:a}=t;for(let i=0;i<a;i++){const a=t[i],{builtin:s,file:r,lang:o,title:n,name:h,source:d}=a,c=this.file_map[r],{file_index:l,start:u,end:p,size:g}=c,w=this.getFileName(l),m={uuid:await this.getPreviewId({file:r,start:u,end:p}),builtin:s,lang:o,name:h,title:n,file:w,start:u,end:p,size:g};if(d){const{file:t,ext:e}=d,a=this.file_map[t],{file_index:i,start:s,end:r,size:o}=a,n=this.getFileName(i);m.source={size:o,file:n,start:s,end:r,ext:e}}e.push(m)}return e}async getThumbnailData(){const t=this.readThumbnailInfo();if(!t)return;const{row:e,col:a,width:i,height:s}=t,r=this.getThumbnailInfoFilename(),o=this.file_map[r],{file_index:n,start:h,end:d,size:c}=o,l=this.getFileName(n),u=await this.getPreviewId({file:r});await this.setPreviewIdMap({id:u,file:l,start:h,end:d},this.hostType);return{id:u,row:e,col:a,width:i,height:s,file:l,start:h,end:d,size:c}}async getCoverData(){const t=this.readCoverInfo();if(!t)return;const e=t,{file:a,width:i,height:s}=e,r=this.file_map[a],{file_index:o,start:n,end:h,size:d}=r,c=this.getFileName(o),l=await this.getPreviewId({file:e.path});await this.setPreviewIdMap({id:l,file:c,start:n,end:h},this.hostType);return{id:l,width:i,height:s,file:c,start:n,end:h,size:d}}async getCacheData(){const t=this.getCacheInfoFilename(),e=await this.getPreviewId({file:t}),a=this.file_map[t],{file_index:i,start:s,end:r,size:o}=a,n=this.getFileName(i);await this.setPreviewIdMap({id:e,file:n,start:s,end:r},this.hostType);return{id:e,file:n,start:s,end:r}}async saveData(){const t=gt(this.hostType);if(this.db.data[t])return;const e={},a=await this.getAudioData();a&&(e.audios=a);const i=await this.getVideoData();i&&(e.videos=i);const s=await this.getSubtitleData();s&&(e.subtitles=s);const r=await this.getThumbnailData();r&&(e.thumbnail=r);const o=await this.getCoverData();o&&(e.cover=o),e.parts=await this.getPartData(),e.cache=await this.getCacheData(),this.db.data[t]=e,await this.db.write()}},_e=class extends fe{current_position=0;current_index=0;group_data=[];async start(){const t=gt(this.hostType);if(this.db.data[t])return this.db.data[t];try{return await this.initStore(this.hostType),await this.calculateData(),await this.postProgress({type:le.UploadProgress.group_media,percent:this.completed_percent+.5*this.total_percent}),await this.processGroups(),await this.postProgress({type:le.UploadProgress.group_media,percent:this.completed_percent+.9*this.total_percent}),await this.saveData(),await this.postProgress({type:le.UploadProgress.group_media,percent:this.completed_percent+this.total_percent}),this.db.data[t]}catch(t){throw(0,ge.buildDError)(t,{message:`Error occurred during media grouping ${this.hostType}`,detail:`Error occurred during media grouping ${this.hostType}: ${this.params.input.filepath}`})}}async processGroups(){const t="grouper_process_state";if(this.store.data[t])return;this.store.data.grouper_process_map||={},this.store.data.grouper_process_index||=0;const{length:e}=this.group_data;for(let t=0;t<e;t++){const a=this.group_data[t];this.store.data.grouper_process_map[a.filename]||(await _({outputRoot:this.params.outputRoot,files:a.files,filename:a.filename}),this.store.data.grouper_process_map[a.filename]=!0,await this.store.write(),await this.postProgress({type:le.UploadProgress.group_media,percent:this.completed_percent+.5*this.total_percent+this.total_percent*(.4*(t+1)/e)}))}this.store.data[t]=!0,await this.store.write()}async insertSafeFile(){const t=await this.generateSafeFile(this.hostType);this.addOne(t,!0)}async calculateData(){this.store.data.grouper_group_list||=[],this.store.data.grouper_file_map||={},await this.insertSafeFile(),await this.calculateMediaTracks(),await this.calculateThumbnails(),await this.calculateCovers(),await this.calculateCaches(),this.current_index+=1,this.current_position=0,await this.calculateSubtitles(),this.store.data.grouper_group_list=this.group_data,this.store.data.grouper_file_map=this.file_map;const t=this.group_data.map(t=>t.filename);this.store.data.grouper_part_names=t,this.store.data.grouper_calculate_state=!0,await this.store.write()}async calculateSubtitles(){const t=this.readSubtitleInfo();if(!t?.length)return;await this.insertSafeFile();const{length:e}=t;for(let a=0;a<e;a++){const e=t[a],{file:i,file_path:s,size:r}=e,o=this.addOne({file_path:s,size:r});if(this.file_map[i]=o,e.source){const{file:t,file_path:a,size:i}=e.source,s=this.addOne({file_path:a,size:i});this.file_map[t]=s}}}async calculateCaches(){await this.getAudioData(),await this.getVideoData(),await this.getThumbnailData(),await this.getCoverData();const t=this.getPreviewIdMap(this.hostType),e=this.getCacheInfoFilename(),a=await this.writeText(e,JSON.stringify(t));this.file_map[e]=a}async calculateCovers(){const t=this.readCoverInfo();if(!t)return;const{file:e,path:a,size:i}=t,s=this.addOne({file_path:a,size:i});this.file_map[e]=s}async calculateMediaTracks(){const t=this.readAudioTracks(),e=this.readVideoTracks(),a=t?.length;for(let e=0;e<a;e++){const i=t[e];if(i.adapt){const t=await this.calculateOneTrack(i.adapt.m3u8),a=this.getAudioManifestName("adapt",e),s=await this.writeTrackText(a,t);this.file_map[a]=s}if(i.high){const t=await this.calculateOneTrack(i.high.m3u8),a=this.getAudioManifestName("high",e),s=await this.writeTrackText(a,t);this.file_map[a]=s}await this.postProgress({type:le.UploadProgress.group_media,percent:this.completed_percent+.4*this.total_percent*((e+1)/a)})}const i=e.length;for(let t=0;t<i;t++){const a=e[t],s=await this.calculateOneTrack(a.m3u8),r=this.getGroupedVideoManifestName(t),o=await this.writeTrackText(r,s);this.file_map[r]=o,await this.postProgress({type:le.UploadProgress.group_media,percent:this.completed_percent+.2*this.total_percent+.2*this.total_percent*((t+1)/i)})}}async calculateThumbnails(){const t=this.readThumbnailInfo();if(!t)return;if(!t)return;const{tile_list:e}=t,{length:a}=e;let i=[...t.sprite_list];for(let t=0;t<a;t++){const a=e[t],s=a.file,r=await this.safelyAddOne({file_path:a.file_path,size:a.size}),o=await this.getPreviewId({file:s}),n=this.getFileName(r.file_index);await this.setPreviewIdMap({id:o,file:n,start:r.start,end:r.end},this.hostType),this.file_map[s]=r,i=i.map(t=>t.file===s?{...t,file:n,id:o,s:r.start,e:r.end}:t)}const s=this.getThumbnailInfoFilename(),r=await this.writeText(s,JSON.stringify(i));this.file_map[s]=r}async calculateOneTrack(t){const{segments:e,init:a,version:i,targetDuration:s,mediaSequence:r,endList:o}=t,n={},h=this.addOne({size:a.size,file_path:a.file_path}),d=await this.getPreviewId({file:a.uri}),c=this.getFileName(h.file_index),l=`${c}?id=${d}`;await this.setPreviewIdMap({id:d,file:c,start:h.start,end:h.end},this.hostType);const u=["#EXTM3U",`#EXT-X-VERSION:${i}`,`#EXT-X-TARGETDURATION:${s}`,`#EXT-X-MEDIA-SEQUENCE:${r}`,`#EXT-X-MAP:URI=${l},BYTERANGE="${h.size}@${h.start}"`];[...e].forEach(t=>{const{uri:e,size:a,duration:i,file_path:s}=t;n[e]=this.addOne({size:a,duration:i,file_path:s})});for(const[t,e]of Object.entries(n)){const a=await this.getPreviewId({file:t}),i=this.getFileName(e.file_index);await this.setPreviewIdMap({id:a,file:i,start:e.start,end:e.end},this.hostType),u.push(`#EXTINF:${e.duration},`),u.push(`#EXT-X-BYTERANGE:${e.size}@${e.start}`),u.push(`${i}?id=${a}`)}o&&u.push("#EXT-X-ENDLIST");return u.join("\n")}async writeTrackText(t,e){const a=(0,de.resolve)(this.params.outputRoot,t),i=(0,de.resolve)(this.params.outputRoot,`${t}.gz`),s=(0,de.resolve)(this.params.outputRoot,`${t}.bin`);await(0,ce.writeFile)(a,e,"utf-8"),await(0,pe.gzip)(a,i);if(await(0,ue.getFileSize)(i)>16){const t=(await(0,pe.getFileBufferSlice)(i,0,15)).toString("base64");await async function(t,e){await new Promise((a,i)=>{const s=(0,p.createReadStream)(t,{start:16}),r=(0,p.createWriteStream)(e);s.pipe(r),r.on("finish",()=>{a(!0)}),s.on("error",t=>{i(t)}),r.on("error",t=>{i(t)})})}(i,s);return{...this.addOne({file_path:s,size:await(0,ue.getFileSize)(s)}),hash:t}}return{...this.addOne({file_path:a,size:await(0,ue.getFileSize)(a)}),hash:""}}async writeText(t,e){const a=(0,de.resolve)(this.params.outputRoot,t);await(0,ce.writeFile)(a,e,"utf-8");return this.addOne({file_path:a,size:await(0,ue.getFileSize)(a)})}addOne({file_path:t,size:e,duration:a=0},i=!1){const s=this.getSizeLimit(this.hostType),{current_position:r,group_data:o}=this;if(i&&o[this.current_index]||!(r+e<=s)){this.current_index+=1;const{current_index:i}=this;o[i]?o[i].files.push(t):o[i]={filename:this.getFileName(i),files:[t]};const s=0,r=e-1;return this.current_position=e,{file_index:i,start:s,end:r,duration:a,size:r-s+1}}{const{current_index:i}=this,s=r,n=r+e-1;return this.current_position=n+1,o[i]?o[i].files.push(t):o[i]={filename:this.getFileName(i),files:[t]},{file_index:i,start:s,end:n,duration:a,size:n-s+1}}}async safelyAddOne(t){const e=this.getSizeLimit(this.hostType),{current_position:a}=this;return a+t.size<=e?0===a?(await this.insertSafeFile(),this.addOne(t)):this.addOne(t):(await this.insertSafeFile(),this.addOne(t))}},ye=class extends nt{async start(){try{if(this.grouperResult)return this.grouperResult;const t={meta:await this.getMetaData(),data:{}},{length:e}=this.params.hosts;for(let a=0;a<e;a++){const i=this.params.hosts[a],s=this.getSizeLimit(i),r=new _e({...this.params,host_type:i,file_size_limit:s,completed_percent:a/e}),o=await r.start();t.data[i]=o}return await this.setGrouperResult(t),t}catch(t){throw(0,he.buildDError)(t,{message:t.message||"Error occurred during media grouping",detail:t.detail||`Error occurred during media grouping: ${this.params.input.filepath}`})}}async getMetaData(){const t={},e=this.audioTranscoderResult??[],a=this.videoTranscoderResult?[this.videoTranscoderResult]:[];if(a?.length){const e=await this.getMediainfo(),{duration:i}=e?.general;if(a?.length){const{width:e,height:s,framerate:r,bitdepth:o,label:n,codec:h,codec_name:d}=a[0];t.videos=[{duration:i,bitdepth:o,width:e,height:s,framerate:r,label:n,codec:h,codec_name:d}]}}if(e?.length)for(const a of e){const{high:e,adapt:i}=a,{channels:s,lossless:r}=i,o=await this.getMediainfo(),{duration:n}=o?.general,{codec:h,codec_name:d}=i,c={duration:n,channels:s,lossless:r,codec:h,codec_name:d};e&&(c.high={channels:e.channels,codec:e.codec,codec_name:e.codec_name,lossless:e.lossless}),t.audios=t.audios||[],t.audios.push(c)}return t}},be=class extends nt{async start(){if(this.db.data.grouper_result)return this.db.data.grouper_result;const t=await this.getMediainfo();if(!t)return;const e=t.video,a=e?.length,i=t.audio,s=i?.length;if(!s&&!a)return;const r=new ne(this.params);if(await r.start(),s){const t=new Pt(this.params);await t.start();const e=new At(this.params);await e.start();const a=new te(this.params);await a.start()}if(a){const t=new ft(this.params);await t.start();const e=new Ft(this.params);await e.start();const a=new Xt(this.params);await a.start()}const o=new ye(this.params);await o.start()}async getResult(){return this.db.data.grouper_result}},ve=require("@soga/types"),Pe=require("@soga/node-types"),xe=require("@soga/mediainfo"),ze=require("@soga/fileutils"),Te=require("fs-extra"),Re=h(require("check-disk-space")),Se=require("@soga/error"),De=class extends E{async start(){this.prepareResult||(await this.checkStorage(),await this.calculateMeta(),await this.calculateProgress())}async checkStorage(){const{length:t}=this.params.hosts,e=await(0,Re.default)(this.params.outputRoot),a=e.free,i=e.diskPath;if((3+t)*this.params.input.filesize>a)throw(0,Se.buildDError)(new Error(`${i} have no enough computer disk space, please adjust the temporary path in user settings.`),{message:`${i} have no enough computer disk space, please adjust the temporary path in user settings.`,detail:`${i} have no enough computer disk space to process ${this.params.input.filepath}`})}async calculateMeta(){if(this.meta)return this.meta;const{filename:t,local_btime:e,local_ctime:a,local_mtime:i,filesize:s}=this.params.input,r={file:t,size:s,btime:e,ctime:a,mtime:i,md5:""};return await this.setMeta(r),r}async calculateProgress(){if(this.prepareResult)return;const t={[Pe.UploadProgress.prepare]:{weight:0,percent:1},[Pe.UploadProgress.calculate_md5]:{weight:0,percent:0},[Pe.UploadProgress.separate_video]:{weight:0,percent:0},[Pe.UploadProgress.separate_audio]:{weight:0,percent:0},[Pe.UploadProgress.separate_subtitle]:{weight:0,percent:0},[Pe.UploadProgress.transcode_video]:{weight:0,percent:0},[Pe.UploadProgress.transcode_audio]:{weight:0,percent:0},[Pe.UploadProgress.transcode_thumbnail]:{weight:0,percent:0},[Pe.UploadProgress.transcode_source]:{weight:0,percent:0},[Pe.UploadProgress.transcode_txt]:{weight:0,percent:0},[Pe.UploadProgress.transcode_img]:{weight:0,percent:0},[Pe.UploadProgress.group_media]:{weight:0,percent:0},[Pe.UploadProgress.upload_baidu]:{weight:0,percent:0},[Pe.UploadProgress.upload_ali]:{weight:0,percent:0},[Pe.UploadProgress.end]:{weight:0,percent:0}},e={keep_preview:this.params.keepPreview,keep_source:this.params.keepSource},a=await(0,ze.getFileSize)(this.params.input.filepath);t[Pe.UploadProgress.prepare].weight=t[Pe.UploadProgress.end].weight=Math.ceil(a/1024/1024/500),t[Pe.UploadProgress.calculate_md5].weight=Math.ceil(a/1024/1024/200);let i=0;if(this.isMedia)if(this.params.keepPreview){const s=await(0,xe.parseMediaInfo)(this.params.input.filepath),r=s?.general?.duration??0;if(s.video?.length){const e=s.video[0],{width:a,height:i,codec:r}=e,o=(0,ze.isVideoSupport)(r),{duration:n}=s.general,h=o?n/400:n*(a*i)/1920/1080;t[Pe.UploadProgress.separate_video].weight=Math.ceil(h),t[Pe.UploadProgress.transcode_video].weight=Math.ceil(.01*n)}if(s.audio?.length){const{duration:e}=s.general;let a=0;s.audio.forEach(t=>{const{codec:i,lossless:s,channels:r}=t,o={high_need:!1,high_transcode:!1,adapt_need:!1,adapt_transcode:!1};(0,ze.isAudioAdapt)(i)?r>2?(o.high_need=!0,o.high_transcode=!1,o.adapt_need=!0,o.adapt_transcode=!0):(o.high_need=!1,o.adapt_need=!0,o.adapt_transcode=!1):(0,ze.isAudioHigh)(i)?(o.high_need=!0,o.high_transcode=!1,o.adapt_need=!0,o.adapt_transcode=!0):(o.high_need=!1,o.adapt_need=!0,o.adapt_transcode=!1,s&&(o.high_need=!0,o.high_transcode=!0)),o.adapt_need&&(a+=o.adapt_transcode?e/40:5),o.high_need&&(a+=o.high_transcode?e/20:10)}),t[Pe.UploadProgress.separate_audio].weight=Math.ceil(a),t[Pe.UploadProgress.transcode_audio].weight=Math.ceil(.01*e)}const o=s.video?.length??0,n=s.audio?.length??0;if(o||n){e.keep_preview=!0;const o=(s.text?.length||0)+(this.params.subtitles?.length||0);t[Pe.UploadProgress.separate_subtitle].weight=Math.ceil(o),t[Pe.UploadProgress.transcode_thumbnail].weight=Math.ceil(.08*r),i+=a,t[Pe.UploadProgress.group_media].weight=Math.ceil(a/1024/1024/10)}else e.keep_preview=!1,e.keep_source=!0,i+=a}else e.keep_source=!0,i+=a;else this.isTxt?e.keep_preview?(t[Pe.UploadProgress.transcode_txt].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a):this.isImg?e.keep_preview&&(t[Pe.UploadProgress.transcode_img].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a);e.keep_source&&(t[Pe.UploadProgress.transcode_source].weight=Math.ceil(a/1024/1024/30)),this.params.hosts.includes(ve.HostType.BAIDU)&&(t[Pe.UploadProgress.upload_baidu].weight=Math.ceil(i/1024/1024/1)),this.params.hosts.includes(ve.HostType.ALI)&&(t[Pe.UploadProgress.upload_ali].weight=Math.ceil(i/1024/1024/2));const s={preview:e.keep_preview,source:e.keep_source};await this.setKeeps(s),await this.setPrepareResult(t)}},Ie=async t=>{await(0,Te.ensureDir)(t.outputRoot);const e=await b(t);try{const a=new De({...t,db:e});return await a.start(),a}catch(t){}},Me=require("@soga/node-types"),Fe=require("crypto"),$e=require("fs-extra"),ke=class extends E{async start(){await this.processFile();return await this.getResult()}async calculateMd5(){if(this.md5)return this.md5;const t=this.params.input.filepath,e=this.params.input.filesize;let a=0;const i=await new Promise((i,s)=>{let r=0;const o=(0,Fe.createHash)("md5"),n=(0,$e.createReadStream)(t,{highWaterMark:4194304});n.on("data",async t=>{o.update(t),r+=t.length;const i=r/e;r-a>104857600&&(a=r,await this.postProgress({type:Me.UploadProgress.calculate_md5,percent:Math.min(i,1)}))}),n.on("end",()=>{const t=o.digest("hex");i(t)}),n.on("error",t=>{s(t)})});return i&&await this.setMd5(i),await this.postProgress({type:Me.UploadProgress.calculate_md5,percent:1}),i}async getResult(){if(this.result)return this.result;const{sourceResult:t,grouperResult:e,imgResult:a,txtResult:i,meta:s,keeps:r}=this,{length:o}=this.params.hosts,n={meta:{preview:r.preview,source:r.source,file:s}};for(let s=0;s<o;s++){const r=this.params.hosts[s];n[r]={max_size:0,parts:[]};const o=t=>{n[r].parts=[...n[r].parts,...t]},h=a?.data[r];if(h){h.cache&&(n[r].cache=h?.cache);const t=h.parts?.map(t=>({...t,preview:!0,source:!1}));t&&o(t),n.meta.img=a.meta,h.img&&(n[r].img=h.img)}const d=i?.data[r];if(d){o((d.parts||[]).map(t=>({...t,preview:!0,source:!1}))),n[r].cache=d.cache,n[r].txt={entrance:d.entrance,pad:i?.meta.pad,pages:i?.meta.pages}}const c=e?.data[r];if(c?.parts){o(c.parts.map(t=>({...t,preview:!0,source:!1}))),n.meta.audios=e.meta.audios,n.meta.videos=e.meta.videos,n[r].cache=c.cache,n[r].media={audios:c.audios,videos:c.videos,subtitles:c.subtitles,thumbnail:c.thumbnail,cover:c.cover}}const l=t?.data[r];if(l?.parts){o(l.parts.map(t=>{let e=!0;return(this.isMedia||this.isTxt)&&(e=!1),{...t,preview:e,source:!0}})),n[r].source={head:t.meta.head,download:l.download}}[...n[r]?.parts].forEach(t=>{t.size>n[r].max_size&&(n[r].max_size=t.size)})}return await this.setResult(n),n}async processFile(){const t="encoder_processed";if(this.db.data[t])return;const e=await Ie(this.params),{keeps:a}=e,i={...this.params,keepPreview:a.preview,keepSource:a.source},s=await this.calculateMd5();if(await this.setMd5(s),i.keepSource){const t=new U(this.params);await t.start()}if(e.isMedia&&i.keepPreview){const t=new be(this.params);await t.start()}if(e.isTxt&&i.keepPreview){const t=new K(this.params);await t.start()}if(e.isImg){const t=new it(this.params);await t.start()}this.db.data[t]=!0,await this.db.write()}},qe=async t=>{try{const e=await b(t),a=new ke({...t,db:e});return a.start()}catch(e){throw(0,c.buildDError)(e,{message:"Error occurred during file encoding",detail:`Error occurred during file encoding: ${t.input.filepath}`})}};
1
+ var t,e=Object.create,a=Object.defineProperty,i=Object.getOwnPropertyDescriptor,s=Object.getOwnPropertyNames,r=Object.getPrototypeOf,o=Object.prototype.hasOwnProperty,n=(t,e,r,n)=>{if(e&&"object"==typeof e||"function"==typeof e)for(let h of s(e))o.call(t,h)||h===r||a(t,h,{get:()=>e[h],enumerable:!(n=i(e,h))||n.enumerable});return t},h=(t,i,s)=>(s=null!=t?e(r(t)):{},n(!i&&t&&t.__esModule?s:a(s,"default",{value:t,enumerable:!0}),t)),d={};((t,e)=>{for(var i in e)a(t,i,{get:e[i],enumerable:!0})})(d,{encode:()=>Ee,getPrepare:()=>Ie}),module.exports=(t=d,n(a({},"__esModule",{value:!0}),t));var c=require("@soga/error"),l=require("@soga/lowdb"),u=require("crypto"),p=require("fs-extra"),g=require("fs/promises"),w=require("path"),m=require("stream/promises");function f(t){const e=(0,u.createHash)("md5");return e.update(`${t}`),e.digest("hex")}async function _(t){await new Promise((e,a)=>{(async()=>{const i=(0,w.resolve)(t.outputRoot,t.filename);await(0,p.remove)(i);let s=!1;const r=(0,p.createWriteStream)(i);r.on("open",()=>{s=!0}).on("error",async t=>{s&&r.close(),await(0,p.remove)(i),a(t)});const{length:o}=t.files,n=async(e=0)=>{if(e<o){const a=t.files[e],o=t.files.length;await new Promise((t,e)=>{const n=(0,p.createReadStream)(a);n.pipe(r,{end:!o}),n.on("end",()=>{n.close(),t(!0)}),n.on("error",async t=>{n.destroy(),s&&r.close(),await(0,p.remove)(i),e(t)})}),await n(e+1)}};await n(0),s&&r.end(),e(!0)})()})}async function y(t,e){const a=f(JSON.stringify({...t,dbName:e})),i="db_unique_key",s=(0,w.resolve)(t.outputRoot,e),r=await(0,l.getDb)(s,{});return r.data[i]?r.data[i]!=a&&(r.data={[i]:a},await r.write()):(r.data[i]=a,await r.write()),r}async function b(t){return await y({file_id:t.id,input:{filepath:t.input.filepath,filesize:t.input.filesize},outputRoot:t.outputRoot},"encoder_store.json")}async function v({input_path:t,target_path:e,start:a,end:i}){const s=(0,p.createReadStream)(t,{start:a,end:i,highWaterMark:65536}),r=(0,p.createWriteStream)(e);try{await(0,m.pipeline)(s,r)}catch(t){try{(0,p.existsSync)(e)&&await(0,p.remove)(e)}catch(t){console.warn("Failed to clean up incomplete file:",t.message)}throw t}}var P=require("path"),x=require("@soga/utils"),T=require("@soga/fileutils"),z=require("@soga/error"),R=require("@soga/node-types"),S=require("fs-extra"),D=require("@soga/types"),I=2097152,M={[D.HostType.BAIDU]:52428800,[D.HostType.ALI]:4294967296},$={[D.HostType.BAIDU]:2147483648,[D.HostType.ALI]:4294967296},F=(D.HostType.BAIDU,D.HostType.ALI,require("@soga/types")),k=require("@soga/utils"),q=require("worker_threads"),E=class{segmentNames={};params;id;port=null;db;get lowData(){return this.db.data}get isVideo(){return this.params.type==F.RecordType.VIDEO}get isAudio(){return this.params.type==F.RecordType.AUDIO}get isMedia(){return this.isAudio||this.isVideo}get isTxt(){return this.params.type==F.RecordType.DOC&&this.params.ftype==F.RecordFtype.DOC_TXT}get isImg(){return this.params.type==F.RecordType.IMAGE}getSizeLimit(t){return this.params.is_shop_space?$[t]||2147483648:M[t]||52428800}getFilesize(){return this.params.input.filesize}constructor(t){this.params=t,this.id=t.id,this.port=t.port??null,this.db=t.db}async getPartInfo({host_type:t,filepath:e,start:a,end:i,filename:s,index:r},o=!0){const n={start:a,end:i,size:i-a+1,path:e,index:r,file:s,md5:o?await(0,k.calculateMd5)({file:e,start:a,end:i}):""};if(o){if(t===F.HostType.BAIDU){const t=await(0,k.calculateMd4)({file:e,start:a,end:i});n.md4=t}if(t===F.HostType.ALI){const t=await(0,k.calculateSha1)({file:e,start:a,end:i});n.sha1=t}}return n}async getStore(t){const{id:e,input:a,outputRoot:i}=this.params;return await y({file_id:e,input:{filepath:a.filepath,filesize:a.filesize},outputRoot:i},t)}async postProgress(t){const e={step:t.type,percent:t.percent};await this.postMessage({id:this.id,type:"percent",data:e})}async postMessage(t){this.port?this.port.postMessage(t):q.parentPort&&q.parentPort.postMessage(t)}async setKeeps(t){this.lowData.keeps=t,await this.db.write()}get keeps(){return this.lowData.keeps}async setMeta(t){this.lowData.meta=t,await this.db.write()}get meta(){return this.lowData.meta}async setSourceResult(t){this.lowData.source_result=t,await this.db.write()}get sourceResult(){return this.lowData.source_result}async setPrepareResult(t){this.lowData.prepare_result=t,await this.db.write()}get prepareResult(){return this.lowData.prepare_result}async setMd5(t){this.lowData.meta.md5=t,await this.db.write()}get md5(){return this.lowData.meta.md5}async setSubtitleEncoderResult(t){this.lowData.subtitle_encoder_result=t,await this.db.write()}get subtitleEncoderResult(){return this.lowData.subtitle_encoder_result}async setAudioSeparatorResult(t){this.lowData.audio_separator_result=t,await this.db.write()}get audioSeparatorResult(){return this.lowData.audio_separator_result}async setAudioTranscoderResult(t){this.lowData.audio_transcoder_result=t,await this.db.write()}get audioTranscoderResult(){return this.lowData.audio_transcoder_result}async setCoverResult(t){this.lowData.cover_result=t,await this.db.write()}get coverResult(){return this.lowData.cover_result}async setVideoTranscoderResult(t){this.lowData.video_transcoder_result=t,await this.db.write()}get videoTranscoderResult(){return this.lowData.video_transcoder_result}async setVideoThumbnailerResult(t){this.lowData.video_thumbnailer_result=t,await this.db.write()}get videoThumbnailerResult(){return this.lowData.video_thumbnailer_result}async setGrouperResult(t){this.lowData.grouper_result=t,await this.db.write()}get grouperResult(){return this.lowData.grouper_result}async setImgResult(t){this.lowData.img_result=t,await this.db.write()}get imgResult(){return this.lowData.img_result}async setTxtResult(t){this.lowData.txt_result=t,await this.db.write()}get txtResult(){return this.lowData.txt_result}async setResult(t){this.lowData.result=t,await this.db.write()}get result(){return this.lowData.result}_syncGetId({file:t,start:e,end:a},i){const s=`${i}_key_index`,r=`${i}_key_map`,o=`${t}_${e||0}_${a||0}`,n=this.db.data[r]||{};if(n[o])return n[o];this.db.data[s]=this.db.data[s]||0,this.db.data[r]=this.db.data[r]||{};const h=this.db.data[s]+1,d=`id_${h}`;return this.db.data[r][o]=d,this.db.data[s]=h,d}_syncSetIdMap({id:t,file:e,start:a,end:i},s,r){const o=`${s}_${r}_id_map`;this.db.data[o]=this.db.data[o]||{},this.db.data[o][t]={f:e,s:a,e:i}}},N=class extends E{syncGetSourceId(t){return this._syncGetId(t,"source")}async getSourceId(t){const e=this.syncGetSourceId(t);return await this.db.write(),e}getSourceIdMap(t){return this.db.data[`source_${t}_id_map`]||{}}syncSetSourceIdMap(t,e){this._syncSetIdMap(t,"source",e)}async setSourceIdMap(t,e){this.syncSetSourceIdMap(t,e),await this.db.write()}getSourceSegmentName=(t,e)=>{const a=this.params.is_attachment?"attachment":"file",i=`source_${e}_${a}_${t}`;if(this.segmentNames[i])return this.segmentNames[i];const s=`s-${f(`source-${e}-${a}-${this.md5}-${t}`)}`;return this.segmentNames[i]=s,s}},U=class extends N{head_size=32;getZipFilePath(){return(0,P.resolve)(this.params.outputRoot,"souce_zip.bin")}getDownloadListFileName(t){return`source_${t}_download_list.json`}getPartName(t,e){return this.getSourceSegmentName(e,t)}getPartPath(t,e){return(0,P.resolve)(this.params.outputRoot,this.getPartName(t,e))}get dbData(){return this.db.data}async setPartList(t,e){const a=`source_${t}_part_list`;this.dbData[a]=e,await this.params.db.write()}getPartList(t){const e=`source_${t}_part_list`;return this.dbData[e]}async setDownloadMap(t,e){const a=`source_${t}_download_map`;this.dbData[a]=e,await this.params.db.write()}getDownloadMap(t){const e=`source_${t}_download_map`;return this.dbData[e]}async sendProgress(t){await this.postProgress({type:R.UploadProgress.transcode_source,percent:t})}async setDownloadList(t,e){const a=`source_${t}_download_list`;this.dbData[a]=e,await this.params.db.write()}getDownloadList(t){const e=`source_${t}_download_list`;return this.dbData[e]}async start(){try{if(this.sourceResult)return await this.sendProgress(1),this.sourceResult;await this.gzip();const{length:t}=this.params.hosts;for(let e=0;e<t;e++){const t=this.params.hosts[e];await this.calculatePartList(t),await this.processDownloadMap(t)}await this.sendProgress(.9);const e=await this.getResult();return await this.sendProgress(1),e}catch(t){throw(0,z.buildDError)(t,{message:"Error occurred during source encoding",detail:`Error occurred during source encoding: ${this.params.input.filepath}`})}}async gzip(){if(this.dbData.source_gziped)return;const t=this.params.input.filepath,e=this.getZipFilePath();await(0,x.gzip)(t,e,async({percent:t})=>{await this.sendProgress(.6*t)}),this.dbData.source_gziped=!0,await this.params.db.write()}async getResult(){if(this.sourceResult)return this.sourceResult;const t={meta:await this.getMetaData(),data:{}},{length:e}=this.params.hosts;for(let a=0;a<e;a++){const e=this.params.hosts[a],i=this.getPartList(e),s=this.getDownloadMap(e);t.data[e]={download:s,parts:i}}return await this.setSourceResult(t),t}async getMetaData(){const t="source_meta",e=this.dbData[t];if(e)return e;const a=this.getZipFilePath(),i=await(0,T.getFileSize)(a),s={path:a,start:0,end:0},{head_size:r}=this;s.end=i<=r?i-1:r-1;const o={head:(await(0,x.getFileBufferSlice)(s.path,s.start,s.end)).toString("base64")};return this.dbData[t]=o,await this.params.db.write(),o}async writeDownloadListFile(t,e){const a=this.getDownloadListFileName(t),i=(0,P.resolve)(this.params.outputRoot,a);await(0,S.writeFile)(i,e,"utf-8");return{file_path:i,size:await(0,T.getFileSize)(i)}}async processDownloadMap(t){const e=this.getDownloadMap(t);if(e)return e;const a=this.getDownloadList(t);let i;const{file_path:s,size:r}=await this.writeDownloadListFile(t,JSON.stringify(a)),o=this.getSizeLimit(t),n=this.getPartList(t);if(n.length){const e=n[n.length-1],{path:a,size:h,file:d,index:c,end:l,start:u}=e,g=(0,P.resolve)(this.params.outputRoot,d);if(h+r<=o){await async function({source1:t,source2:e,target:a}){const i=(0,p.createReadStream)(t.filepath,{start:t.start,end:t.end}),s=(0,p.createWriteStream)(a);await(0,m.pipeline)(i,s);const r=(0,p.createReadStream)(e),o=(0,p.createWriteStream)(a,{flags:"a"});await(0,m.pipeline)(r,o)}({source1:{filepath:a,start:u,end:l},source2:s,target:g});const e=(await(0,S.stat)(g)).size,o=e-1,h=e-r,w=await this.getPartInfo({host_type:t,filepath:g,start:0,end:e-1,filename:d,index:c});n[n.length-1]=w;i={id:await this.getSourceId({file:d,start:h,end:o}),file:d,start:h,end:o}}else{const e=c+1,a=this.getPartName(t,e),o=this.getPartPath(t,e);await(0,S.rename)(s,o);const h=await this.getSourceId({file:a,start:0,end:r-1}),d=await this.getPartInfo({host_type:t,filepath:o,start:0,end:r-1,filename:a,index:e});n.push(d),i={id:h,file:a,start:0,end:r-1}}return await this.setPartList(t,n),await this.setDownloadMap(t,i),i}}async calculatePartList(t){const e=`source_${t}_list_calculated`;if(this.dbData[e])return;const a=this.getZipFilePath(),i=await(0,T.getFileSize)(a),s=[],r=this.getSizeLimit(t),{head_size:o}=this,n=[];if(i>o){let e=0;for(let h=o;h<=i-1;h+=r){const o=Math.min(h+r-1,i-1),d=this.getPartName(t,e),c=await this.getPartInfo({host_type:t,filepath:a,start:h,end:o,filename:d,index:e});let l=0;for(let t=h;t<o;t+=I){const e=Math.min(t+I-1,o),a=e-t+1,i=l+a-1,s=await this.getSourceId({file:"source_zip",start:t,end:e});n.push({id:s,file:d,start:l,end:i}),l+=a}s.push(c),e++}}await this.setPartList(t,s),await this.setDownloadList(t,n),this.dbData[e]=!0,await this.db.write()}},L=require("path"),C=require("fs-extra"),A=require("@soga/utils"),O=h(require("zlib")),V=require("@soga/utils"),G=require("@soga/error"),B=require("@soga/node-types"),j=require("path"),H=require("@soga/fileutils"),X=require("fs-extra"),W=class extends E{get preview_common_db_data(){return this.db.data}async getCurrentFileIndex(t){const e=this.db.data[`preview_${t}_current_index`];return"number"!=typeof e?(this.db.data[`preview_${t}_current_index`]=0,await this.db.write(),0):e}async increaseCurrentFileIndex(t){const e=await this.getCurrentFileIndex(t)+1;return this.db.data[`preview_${t}_current_index`]=e,await this.db.write(),e}getPartName(t,e){return this.getPreviewSegmentName(e,t)}getPartPath(t,e){return(0,j.resolve)(this.params.outputRoot,this.getPartName(t,e))}syncGetPreviewId(t){return this._syncGetId(t,"preview")}async getPreviewId(t){const e=this.syncGetPreviewId(t);return await this.db.write(),e}getPreviewIdMap(t){return this.db.data[`preview_${t}_id_map`]||{}}syncSetPreviewIdMap(t,e){this._syncSetIdMap(t,"preview",e)}async setPreviewIdMap(t,e){this.syncSetPreviewIdMap(t,e),await this.db.write()}getPreviewSegmentName=(t,e)=>{const a=this.params.is_attachment?"attachment":"file",i=`preview_${e}_${a}_${t}`;if(this.segmentNames[i])return this.segmentNames[i];const s=`p-${f(`preview-${e}-${a}-${this.md5}-${t}`)}`;return this.segmentNames[i]=s,s};async calculatePartList(t,e){const a=[],i=await this.getCurrentFileIndex(t);for(let s=0;s<i+1;s++){const i=this.getPartName(t,s),r=this.getPartPath(t,s),o=await(0,H.getFileSize)(r),n=await this.getPartInfo({host_type:t,filename:i,filepath:r,index:s,start:0,end:o-1},e);a.push(n)}return a}getPartListKey(t){return`preview_${t}_part_list`}async completePartList(t){const e=await this.getPartList(t);if(e){const a=[];for(const i of e)if(i.md5)a.push(i);else{const e=await this.getPartInfo({filename:i.file,filepath:i.path,start:i.start,end:i.end,host_type:t,index:i.index},!0);a.push(e)}await this.setPartList(t,a)}}async getPartList(t){const e=this.getPartListKey(t),a=this.preview_common_db_data[e];if(a)return a}async setPartList(t,e){const a=this.getPartListKey(t);this.preview_common_db_data[a]=e,await this.db.write()}async attachCacheData(){const{hosts:t}=this.params;for(const e of t)await this.attachHostCacheData(e),await this.completePartList(e)}getCacheInfo(t){const e=`preview_${t}_cache_info`;return this.preview_common_db_data[e]}async writeCacheFile(t,e){const a=`preview_${t}_cache_info.txt`,i=(0,j.resolve)(this.params.outputRoot,a);await(0,X.writeFile)(i,e,"utf-8");return{file_path:i,size:await(0,H.getFileSize)(i)}}async setCacheInfo(t,e){const a=`preview_${t}_cache_info`;this.preview_common_db_data[a]=e,await this.db.write()}async attachHostCacheData(t){if(this.getCacheInfo(t))return;const e=await this.getPartList(t),a=this.getPreviewIdMap(t),{file_path:i,size:s}=await this.writeCacheFile(t,JSON.stringify(a)),r=this.getSizeLimit(t);if(e.length){const a=e[e.length-1],{path:o,size:n,file:h,index:d,end:c}=a;let l;if(n+s<=r){await async function({filepath:t,size:e},a){(await(0,p.stat)(t)).size>e&&await(0,g.truncate)(t,e);const i=(0,p.createReadStream)(a),s=(0,p.createWriteStream)(t,{flags:"a"});await(0,m.pipeline)(i,s)}({filepath:o,size:n},i);const a=await(0,H.getFileSize)(o),r=await this.getPartInfo({host_type:t,filename:h,filepath:o,index:d,start:0,end:a-1});e[e.length-1]=r;const u=c+1,w=c+s;l={id:await this.getPreviewId({file:h,start:u,end:w}),file:h,start:u,end:w}}else{const a=d+1,r=this.getPartName(t,a),o=this.getPartPath(t,a);await(0,X.copy)(i,o);const n=await this.getPreviewId({file:r,start:0,end:s-1}),h=await this.getPartInfo({host_type:t,filename:r,filepath:o,index:a,start:0,end:s-1},!1);e.push(h),await this.setPartList(t,e),l={id:n,file:r,start:0,end:s-1}}l&&await this.setCacheInfo(t,l)}}},K=class extends W{content_size_1=81920;content_size_2=102400;totalPage=1;hashBuffer=Buffer.from("dpan");get hashBufferLength(){return this.hashBuffer.length}getU8FileName(){return`text_utf8_${this.params.id}.txt`}getU8FilePath(){return(0,L.resolve)(this.params.outputRoot,this.getU8FileName())}async sendProgress(t){await this.postProgress({type:B.UploadProgress.transcode_txt,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.dbData.txt_result)return await this.sendProgress(1),this.dbData.txt_result;await this.txtConvertToUtf8File(),await this.sendProgress(.2);const{length:t}=this.params.hosts;for(let e=0;e<t;e++){const a=this.params.hosts[e];await this.txtConvertToGzipFile(a),await this.sendProgress(.2+(e+1)/t*.6)}await this.attachCacheData();const e=await this.getResult();return await this.clean(),await this.sendProgress(1),e}catch(t){throw(0,G.buildDError)(t,{message:"Error occurred during txt encoding",detail:`Error occurred during txt encoding: ${this.params.input.filepath}`})}}async getResult(){if(this.txtResult)return this.txtResult;const t={meta:{pad:this.hashBufferLength,pages:this.totalPage},data:{}};for(const e of this.params.hosts)t.data[e]={cache:this.getCacheInfo(e),parts:await this.getPartList(e),entrance:await this.getEntranceInfo(e)};return await this.setTxtResult(t),t}async clean(){try{if(this.params.debug)return;const t=this.getU8FilePath();await(0,C.remove)(t)}catch(t){}}async setEntranceInfo(t,e){const a=`txt_${t}_entrance`;this.dbData[a]=e,await this.db.write()}async getEntranceInfo(t){const e=`txt_${t}_entrance`,a=this.dbData[e];if(a)return a}async txtConvertToUtf8File(){if(this.dbData.txt_utf8_converted)return;const t=this.params.input.filepath,e=this.getU8FilePath();await(0,V.saveFileAsUtf8)(t,e),this.dbData.txt_utf8_converted=!0,await this.db.write()}async txtConvertToGzipFile(t){if(await this.getEntranceInfo(t))return;const e=this.getSizeLimit(t),a=this.getU8FilePath(),i=await this.calculateSlice(),{length:s}=i,r={};let o=0,n=(0,C.createWriteStream)(this.getPartPath(t,await this.getCurrentFileIndex(t)));for(let h=0;h<s;h++){const d=h==s-1?0:h+1,c=i[d],{index:l,start:u,end:p}=c,g={page:l+1,text:(await(0,A.getFileBufferSlice)(a,u,p)).toString("utf8")},w=JSON.stringify(g);let m=Buffer.from(w,"utf8");if(0==d){const t={...g,map:r};m=Buffer.from(JSON.stringify(t),"utf8")}const f=await this.getPreviewId({file:"u8zip",start:u,end:p});await new Promise((a,i)=>{O.default.gzip(m,async(s,h)=>{if(s)return i(s);const c=h.length<this.hashBufferLength?this.hashBuffer:h.subarray(0,this.hashBufferLength),l=Buffer.concat([c,h]),u=l.length;if(o+u>e){n.end();const e=await this.increaseCurrentFileIndex(t);n=(0,C.createWriteStream)(this.getPartPath(t,e)),o=0}const p=o,g=o+u-1;if(n.write(l),o+=u,0==d){n.end();const e={id:f,start:p,end:g,file:this.getPartName(t,await this.getCurrentFileIndex(t))};await this.setEntranceInfo(t,e)}else r[`p_${d+1}`]={id:f,f:this.getPartName(t,await this.getCurrentFileIndex(t)),s:p,e:g};this.syncSetPreviewIdMap({id:f,file:this.getPartName(t,await this.getCurrentFileIndex(t)),start:p,end:g},t),a(!0)})})}await this.db.write();const h=await this.calculatePartList(t,!1);await this.setPartList(t,h)}async calculateSlice(){if(this.dbData.txt_slice_list)return this.dbData.txt_slice_list;const t=this.getU8FilePath(),e=await new Promise((e,a)=>{(0,C.readFile)(t,"utf8",(t,i)=>{if(t)return void a(t);const s=this.content_size_1,r=this.content_size_2,o=[];let n=0,h=0,d=0;for(;h<i.length;){let t=Math.min(h+r,i.length);const e=Math.min(h+s,i.length),a=i.slice(e,t-1).indexOf("#");-1!==a&&(t=e+a);const c=i.slice(h,t),l=Buffer.byteLength(c);o.push({index:n++,start:d,end:d+l-1}),this.totalPage=n,h=t,d+=l}e(o)})});return this.dbData.txt_slice_list=e,await this.db.write(),e}},J=require("path"),Q=require("@soga/imgutils"),Z=require("@soga/utils"),Y=require("@soga/fileutils"),tt=require("@soga/error"),et=require("@soga/node-types"),at=require("fs-extra"),it=class extends W{getCompressFileName(){return"img_compress.jpg"}getCompressFilePath(){return(0,J.resolve)(this.params.outputRoot,this.getCompressFileName())}getGzFileName(){return"compressed_img.zip"}getGzFilePath(){return(0,J.resolve)(this.params.outputRoot,this.getGzFileName())}async sendProgress(t){await this.postProgress({type:et.UploadProgress.transcode_img,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.imgResult)return await this.sendProgress(1),this.imgResult;await this.compress(),await this.sendProgress(.1),await this.gzip(),await this.sendProgress(.4);const{hosts:t}=this.params,{length:e}=t;for(let a=0;a<e;a++){const e=t[a];await this.splitFile(e),await this.calculatePartList(e,!1)}await this.attachCacheData(),await this.sendProgress(.9);const a=await this.getResult();return await this.clean(),await this.sendProgress(1),a}catch(t){throw(0,tt.buildDError)(t,{message:"Error occurred during image encoding",detail:`Error occurred during image encoding: ${this.params.input.filepath}`})}}getCacheInfoFileName(t){return`img_${t}_cache.json`}async getResult(){if(this.imgResult)return this.imgResult;const{input:t}=this.params,e=t.filepath,{width:a,height:i}=await(0,Q.getMetadata)(e),s=this.getCompressFilePath(),{width:r,height:o}=await(0,Q.getMetadata)(s),n=await(0,Y.getFileSize)(s),h={meta:{width:a,height:i,size:t.filesize,t_width:r,t_height:o,t_size:n},data:{}},{length:d}=this.params.hosts;for(let t=0;t<d;t++){const e=this.params.hosts[t],a=await this.getPartList(e),i=this.getPreviewList(e);h.data[e]={img:{preview:i},cache:this.getCacheInfo(e),parts:a}}return await this.setImgResult(h),h}async clean(){try{if(this.params.debug)return;const t=this.getCompressFilePath();await(0,at.remove)(t)}catch(t){}}async compress(){if(this.dbData.img_compressed)return;const t=this.getCompressFilePath();await(0,Q.compress)({ffmpeg_path:this.params.ffmpegPath,input_path:this.params.input.filepath,output_path:t}),this.dbData.img_compressed=!0,await this.db.write()}async gzip(){if(this.dbData.img_gziped)return;const t=this.getCompressFilePath(),e=this.getGzFilePath();await(0,Z.gzip)(t,e),this.dbData.img_gziped=!0,await this.db.write()}async setPreviewList(t,e){const a=`img_${t}_preview_list`;this.dbData[a]=e,await this.db.write()}getPreviewList(t){const e=`img_${t}_preview_list`;return this.dbData[e]}async splitFile(t){if(this.getPreviewList(t))return;const e=this.getGzFilePath(),a=await(0,Y.getFileSize)(e),i=this.getSizeLimit(t),s=[],r=[];for(let o=0;o<=a-1;o+=i){0!=o&&await this.increaseCurrentFileIndex(t);const n=Math.min(o+i-1,a-1),h=await this.getCurrentFileIndex(t),d=this.getPartName(t,h),c=this.getPartPath(t,h);await v({input_path:e,target_path:c,start:o,end:n});const l=0,u=n-o,p=await this.getPartInfo({host_type:t,filepath:c,filename:d,start:l,end:u,index:h},!1);s.push(p);const g=await this.getPreviewId({file:d,start:l,end:u});r.push({id:g,file:d,start:l,end:u}),await this.setPreviewIdMap({id:g,file:d,start:l,end:u},t)}await this.setPartList(t,s),await this.setPreviewList(t,r)}},st=h(require("fluent-ffmpeg")),rt=require("child_process"),ot=require("@soga/mediainfo"),nt=class extends W{async getMediainfo(){const{mediainfo:t}=this.db.data;if(t)return t;const e=this.params.input.filepath,a=await(0,ot.parseMediaInfo)(e);return this.db.data.mediainfo=a,await this.params.db.write(),a}constructor(t){super(t),st.default.setFfmpegPath(t.ffmpegPath)}getFluent(){return(0,st.default)()}async ffmpeg(t,e){const a=this.params.ffmpegPath;return await new Promise((i,s)=>{const r=(0,rt.spawn)(a,t,Object.assign({stdio:"ignore"},e));r.on("close",t=>{i(t)}),r.on("error",t=>{s(t)})})}},ht=require("path"),dt=require("@soga/fileutils"),ct=require("@soga/node-types"),lt=require("@soga/error"),ut=({type:t,track_order:e,quality:a})=>`audio-${e}-${a}-${t}.${"manifest"===t?"m3u8":"mp4"}`,pt=({width:t,height:e})=>`video-formatted-${t}-${e}.mp4`,gt=t=>`grouper_result_${t}`,wt=t=>{let e=0,a=0,i=0;t.segments.forEach(t=>{a+=t.duration,e+=t.size;const s=8*t.size/t.duration;s>i&&(i=s)});const s=8*e/a;return{bandwidth:Math.ceil(i),average_bandwidth:Math.ceil(s)}},mt=(t,e)=>{if("number"==typeof t.percent)return t.percent/100;return function(t){const e=t.split(":").map(parseFloat),[a=0,i=0,s=0]=e.reverse();return 3600*s+60*i+a}(t.timemark)/e};var ft=class extends nt{async start(){try{await this.separateVideo(),await this.postProgress({type:ct.UploadProgress.separate_video,percent:1})}catch(t){throw(0,lt.buildDError)(t,{message:"Error occurred during video separation",detail:`Error occurred during video separation: ${this.params.input.filepath}`})}}async separateVideo(){const t="video_separated";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],i=pt({width:a.width,height:a.height}),s=(0,ht.resolve)(this.params.outputRoot,i),r=(0,dt.isVideoSupport)(a.codec),o=["-sn","-an","-map","0:v:0"];let n="copy";r||(n=a.width*a.height>=2073600?"libx265":"libx264","libx265"==n&&o.push("-pix_fmt","yuv420p")),o.push("-c:v",n);const h=a.duration;o.push("-y"),await new Promise((t,e)=>{const a=this.getFluent().input(this.params.input.filepath).outputOptions(o).on("progress",async t=>{if(!r&&t.frames){const e=mt(t,h);await this.postProgress({type:ct.UploadProgress.separate_video,percent:e})}}).on("end",async()=>{t("end"),a.kill("SIGKILL")}).on("error",async t=>{e(t)}).output(s);a.run()});if(!await(0,dt.isValidFile)(s))throw new Error("Separate Video track failed");this.db.data[t]=!0,await this.params.db.write()}},_t=require("path"),yt=require("@soga/fileutils"),bt=require("@soga/node-types"),vt=require("@soga/error"),Pt=class extends nt{async start(){try{await this.separateTracks(),await this.postProgress({type:bt.UploadProgress.separate_audio,percent:1})}catch(t){throw(0,vt.buildDError)(t,{message:"Error occurred during audio separation",detail:`Error occurred during audio separation: ${this.params.input.filepath}`})}}async separateTracks(){if(this.audioSeparatorResult)return;const t=await this.getMediainfo();if(!t?.audio?.length)return;const{audio:e}=t,a=e.length,i=[];for(let t=0;t<a;t++){const s=e[t],{codec:r,channels:o,lossless:n}=s,h={adapt:{need:!0,codec:"",channels:Math.min(o,2)},high:{need:!1,codec:"flac",channels:0}};(0,yt.isAudioAdapt)(r)?o>2?(h.high.need=!0,h.high.codec="copy",h.adapt.codec=r,h.adapt.need=!0):(h.adapt.need=!0,h.adapt.codec="copy",h.adapt.channels=0):(0,yt.isAudioHigh)(r)?(h.high.need=!0,h.high.codec="copy",h.adapt.need=!0,h.adapt.codec="aac"):(h.adapt.need=!0,h.adapt.codec="aac",n&&(h.high.need=!0,h.high.codec="flac")),h.adapt.need&&await this.separateAudioTrack(t,{type:"adapt",codec:h.adapt.codec,tracks:a,channels:h.adapt.channels,need_adapt:!0,need_high:h.high.need}),h.high.need&&await this.separateAudioTrack(t,{type:"high",codec:h.high.codec,tracks:a,channels:h.high.channels,need_adapt:h.adapt.need,need_high:!0}),i.push(h)}await this.setAudioSeparatorResult(i)}async separateAudioTrack(t,e){const a=`audio_separated_${t}_${e.type}`;if(this.db.data[a])return;const i=await this.getMediainfo();if(!i?.audio?.length)return;const s=i.audio[t];if(!s)return;const r=s?.duration??i.general?.duration,o=ut({type:"formatted",track_order:t,quality:e.type}),n=(0,_t.resolve)(this.params.outputRoot,o),h=["-sn","-vn","-map",`0:a:${t}`];e.codec&&h.push("-c:a",e.codec),e.channels&&h.push("-ac",e.channels.toString()),h.push("-y"),await new Promise((a,i)=>{const s=this.getFluent().input(this.params.input.filepath).outputOptions(h).on("progress",async a=>{if("copy"!=e.codec){const i=mt(a,r);let s=t;"adapt"==e.type?e.need_high?s+=1/3*i:s+=i:e.need_adapt?(s+=1/3,s+=2/3*i):s+=i;const o=s/e.tracks;await this.postProgress({type:bt.UploadProgress.separate_audio,percent:o})}}).on("end",async()=>{a("end"),s.kill("SIGKILL")}).on("error",async t=>{i(t)}).output(n);s.run()});if(!await(0,yt.isValidFile)(n))throw new Error(`Separate audio track failed: [track_order:${t}, track_quality ${e.type}] `);if("copy"==e.codec){let a=t;"adapt"==e.type&&e.need_high?a+=1/3:a+=1;const i=a/e.tracks;await this.postProgress({type:bt.UploadProgress.separate_audio,percent:i})}this.db.data[a]=!0,await this.params.db.write()}},xt=require("path"),Tt=require("@soga/mediainfo"),zt=require("@soga/mp4box"),Rt=require("@soga/m3u8"),St=require("@soga/node-types"),Dt=require("@soga/fileutils"),It=require("fs-extra"),Mt=require("@soga/error"),$t=class extends nt{getVideoInitName({width:t,height:e}){return`video-init-${t}-${e}.mp4`}getVideoManifestName({width:t,height:e}){return`video-hls-${t}-${e}.m3u8`}async start(){try{await this.transcodeVideo(),await this.saveData(),await this.postProgress({type:St.UploadProgress.transcode_video,percent:1})}catch(t){throw(0,Mt.buildDError)(t,{message:"Error occurred during video transcoding",detail:`Error occurred during video transcoding: ${this.params.input.filepath}`})}}async saveData(){const t=await this.getMediainfo();if(!t?.video?.length)return;if(this.videoTranscoderResult)return;const{width:e,height:a}=t.video[0],i=pt({width:e,height:a}),s=(0,xt.resolve)(this.params.outputRoot,i),r=this.getVideoManifestName({width:e,height:a}),o=(0,xt.resolve)(this.params.outputRoot,r),n=await(0,Rt.parseM3U8)(o),{videos:h}=await(0,zt.getMp4boxInfo)(s),{codec:d}=h[0],{bandwidth:c,average_bandwidth:l}=wt(n),u=(await(0,Tt.parseMediaInfo)(s)).video[0],p=(0,Dt.getStandardInfo)(e,a),g={m3u8:n,m3u8_path:o,codec:d,width:e,height:a,bandwidth:c,average_bandwidth:l,bitdepth:u?.bitdepth,bitrate:u?.bitrate,codec_name:u?.codec??"",framerate:u?.framerate,label:p?.label??"unknown"};await this.setVideoTranscoderResult(g),this.params.debug||await(0,It.remove)(s)}async transcodeVideo(){const t="video_transcode_state";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],i={width:a.width,height:a.height},s=pt(i),r=this.getVideoInitName(i),o=this.getVideoManifestName({width:a.width,height:a.height}),n=["-i",s,"-an","-sn","-c:v","copy","-hls_list_size","0","-hls_time","6","-hls_segment_type","fmp4","-hls_fmp4_init_filename",r,"-y",o];await this.ffmpeg(n,{cwd:this.params.outputRoot});const h=(0,xt.resolve)(this.params.outputRoot,o);if(!await(0,Dt.isValidFile)(h))throw new Error("Transcode video track failed");this.db.data[t]=!0,await this.db.write()}},Ft=require("path"),kt=require("@soga/fileutils"),qt=require("@soga/mp4box"),Et=require("@soga/m3u8"),Nt=require("@soga/mediainfo"),Ut=require("fs-extra"),Lt=require("@soga/error"),Ct=require("@soga/node-types"),At=class extends nt{async start(){try{await this.transcodeAudios(),await this.saveData()}catch(t){throw(0,Lt.buildDError)(t,{message:"Error occurred during audio transcoding",detail:`Error occurred during audio transcoding: ${this.params.input.filepath}`})}}async saveData(){if(this.audioTranscoderResult)return;const t=await this.getMediainfo();if(!t?.audio?.length)return;const e=t.audio.length,a=this.audioSeparatorResult,i=[],s={};for(let t=0;t<e;t++){const e=a[t];e.adapt.need&&(s.adapt=await this.getQualityData({track_order:t,quality:"adapt"})),e.high.need&&(s.high=await this.getQualityData({track_order:t,quality:"high"})),i.push(s)}await this.setAudioTranscoderResult(i);try{if(this.params.debug)return;for(let t=0;t<e;t++){const e=a[t];if(e.adapt.need){const e=ut({type:"formatted",track_order:t,quality:"adapt"}),a=(0,Ft.resolve)(this.params.outputRoot,e);await(0,Ut.remove)(a)}if(e.high.need){const e=ut({type:"formatted",track_order:t,quality:"high"}),a=(0,Ft.resolve)(this.params.outputRoot,e);await(0,Ut.remove)(a)}}}catch(t){}}async getQualityData({track_order:t,quality:e}){const a=ut({type:"formatted",track_order:t,quality:e}),i=(0,Ft.resolve)(this.params.outputRoot,a),s=await(0,Nt.parseMediaInfo)(i);if(!s.audio?.length)throw new Error("parse mediainfo failed!");const r=s.audio[0],o=ut({type:"manifest",track_order:t,quality:e}),n=await(0,kt.getFileSize)(i),h=(0,Ft.resolve)(this.params.outputRoot,o),d=await(0,qt.getMp4boxInfo)(i),{audios:c}=d,{language:l,codec:u}=c[0],p=l&&!l.startsWith("un")?{language:l}:void 0,g=await(0,Et.parseM3U8)(h),{bandwidth:w,average_bandwidth:m}=wt(g);return{m3u8:g,m3u8_path:h,codec:u,codec_name:r.codec,...p,order:t,lossless:r.lossless,channels:r.channels,bandwidth:w,size:n,average_bandwidth:m}}async transcodeAudios(){const t="audio_transcoded";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.audio?.length)return;const a=e.audio.length,i=this.audioSeparatorResult;for(let t=0;t<a;t++){const e=i[t];e.adapt.need&&await this.transcodeAudio(t,{...e.adapt,type:"adapt"}),e.high.need&&await this.transcodeAudio(t,{...e.high,type:"high"});const s=(t+1)/a;await this.postProgress({type:Ct.UploadProgress.transcode_audio,percent:s})}await this.postProgress({type:Ct.UploadProgress.transcode_audio,percent:1}),this.db.data[t]=!0,await this.db.write()}async transcodeAudio(t,e){const a=`audio-transcoded-${t}-${e.type}`;if(this.db.data[a])return;const i=ut({type:"formatted",track_order:t,quality:e.type}),s=ut({type:"init",track_order:t,quality:e.type}),r=ut({type:"manifest",track_order:t,quality:e.type}),o=["-i",i,"-vn","-sn","-c:a","copy","-hls_list_size","0","-hls_time","6","-hls_segment_type","fmp4","-hls_fmp4_init_filename",s,"-y",r];await this.ffmpeg(o,{cwd:this.params.outputRoot});const n=(0,Ft.resolve)(this.params.outputRoot,r);if(!await(0,kt.isValidFile)(n))throw new Error(`Transcode audio track failed: [track_order:${t}, track_quality ${e.type}] `);this.db.data[a]=!0,await this.db.write()}},Ot=require("path"),Vt=require("@soga/fileutils"),Gt=require("@soga/imgutils"),Bt=require("fs-extra"),jt=require("@soga/node-types"),Ht=require("@soga/error"),Xt=class extends nt{m3u8_data=null;thumbnail_duration=30;thumbnail_group=[];row=8;col=8;screenshot_width=480;screenshot_height=270;getScreenshotName(t){return`video_screenshot_${t}.jpg`}getTileName(t){return`video_tile_${t}.jpg`}getCoverName(){return"video_cover.jpg"}async updateImagePercent(t,e){const a="screenshot"==e?6*t/7:t/7+6/7;await this.postProgress({type:jt.UploadProgress.transcode_thumbnail,percent:a})}store;async initStore(){this.store=await this.getStore("thumbnail_store.json")}async start(){if(!this.videoThumbnailerResult)try{const t=await this.getMediainfo();if(!t?.video?.length)return;if(await this.init(),!this.m3u8_data)return;await this.generateScreenshots(),await this.generateTiles(),await this.saveCoverInfo(),await this.saveThumbnailInfo()}catch(t){throw(0,Ht.buildDError)(t,{message:"Error occurred during video thumbnail generation",detail:`Error occurred during video thumbnail generation: ${this.params.input.filepath}`})}}async init(){await this.initStore(),await this.initScreenshotSize(),await this.initM3U8Data(),await this.initThumbnailDuration(),await this.initThumbnailGroup()}async saveThumbnailInfo(){if(this.videoThumbnailerResult)return;const{col:t,row:e,thumbnail_group:a,screenshot_width:i,screenshot_height:s}=this,r=a.length,o=[],n=[];for(let h=0;h<r;h++){const r=a[h],d=r.start_time,c=r.end_time,l=Math.floor(h/(e*t)),u=h%e*i,p=Math.floor(h%(t*e)/e)*s,g=this.getTileName(l);n.push(g),o.push({file:g,st:d,et:c,x:u,y:p,w:i,h:s})}const h=[...new Set(n)],d=h.length,c=[];for(let t=0;t<d;t++){const e=h[t],a=(0,Ot.resolve)(this.params.outputRoot,e),i=await(0,Vt.getFileSize)(a);c.push({file:e,file_path:a,size:i})}const l={width:this.screenshot_width,height:this.screenshot_height,row:this.row,col:this.col,tile_list:c,sprite_list:o};await this.setVideoThumbnailerResult(l)}async saveCoverInfo(){if(this.coverResult)return;const t=this.store.data.thumbnail_screenshot_largest,e=t?.index||0,{screenshot_width:a,screenshot_height:i}=this,s=this.getScreenshotName(e),r=(0,Ot.resolve)(this.params.outputRoot,s),o=this.getCoverName(),n=(0,Ot.resolve)(this.params.outputRoot,o);await(0,Bt.copy)(r,n);const h={file:o,path:n,size:await(0,Vt.getFileSize)(n),width:a,height:i};await this.setCoverResult(h)}async generateTiles(){const t=this.store.data.thumbnail_tile_index||0,{length:e}=this.thumbnail_group,a=this.col*this.row,i=Math.ceil(e/a);for(let e=t;e<i;e++)await this.generateOneTile(e),await this.updateImagePercent((e+1)/i,"tile")}async generateOneTile(t){const{col:e,row:a}=this,i=this.thumbnail_group.length,s=a*e,r=t*s,o=Math.min(s,i-r),n=[];for(let t=0;t<o;t++){const e=this.getScreenshotName(r+t),a=(0,Ot.resolve)(this.params.outputRoot,e);n.push(a)}const h=this.getTileName(t),d=(0,Ot.resolve)(this.params.outputRoot,h);await this.createSpriteSheet(n,d),this.store.data.thumbnail_tile_index=t+1,await this.store.write()}async createSpriteSheet(t,e){await(0,Gt.combine)({col:this.col,inputs:t,output_path:e,width:this.screenshot_width,height:this.screenshot_height})}getKeyFrameParams(t,e=0){if(t<1)return["-vframes","1"];{const a=Math.max(t-e-.3,.1);if(a<1)return["-vframes","1"];return["-ss",`${a.toFixed(3)}`,"-vframes","1"]}}async generateScreenshots(){if(this.store.data.thumbnail_screenshot_state)return;this.store.data.thumbnail_screenshot_index||=0;const t=this.store.data.thumbnail_screenshot_index,e=this.store.data.thumbnail_screenshot_largest,a={index:0,size:0};if(e){const t=e;a.index=t.index,a.size=t.size}const{segments:i}=this.m3u8_data,{thumbnail_group:s,screenshot_width:r}=this,{length:o}=s,n=async(t,{errorTimes:e,fixedSeconds:o})=>{const h=s[t].item.index,d=i[h];try{const e=this.getScreenshotName(t),i=`concat:${d.init_uri}|${d.uri}`,s=this.getKeyFrameParams(d.duration,o),n=r>this.screenshot_height?`${r}:-2`:`-2:${this.screenshot_height}`,h=["-i",i,...s,"-vf",`scale=${n}:flags=lanczos`,"-y",e];await this.ffmpeg(h,{cwd:this.params.outputRoot});const c=(0,Ot.resolve)(this.params.outputRoot,e),l=await(0,Vt.getFileSize)(c);if(0===l)throw new Error(`Generate video thumbnail error: [index: ${t}, start_time: ${d.start_time}, end_time: ${d.end_time}]`);l>=a.size&&(a.index=t,a.size=l,this.store.data.thumbnail_screenshot_largest=a,await this.store.write()),this.store.data.thumbnail_screenshot_index=t+1,await this.store.write()}catch(a){const i=Math.max(10,d.duration);if(!(e<3))throw a;await n(t,{errorTimes:e+1,fixedSeconds:o+i/5})}};for(let e=t;e<o;e++)await n(e,{errorTimes:0,fixedSeconds:0}),await this.updateImagePercent((e+1)/o,"screenshot");this.store.data.thumbnail_screenshot_state=!0,await this.store.write()}async initScreenshotSize(){const{thumbnail_screenshot_size:t}=this.store.data;if(t)return this.screenshot_width=t.width,void(this.screenshot_height=t.height);const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],{width:i,height:s}=a,r=i>s?480:270;this.screenshot_width=2*Math.floor(Math.min(r,i)/2),this.screenshot_height=2*Math.floor(this.screenshot_width*(s/i)/2),this.store.data.thumbnail_screenshot_size={width:this.screenshot_width,height:this.screenshot_height}}async initThumbnailGroup(){if(this.store.data.thumbnail_group)return void(this.thumbnail_group=this.store.data.thumbnail_group);const t=[],{segments:e}=this.m3u8_data,{length:a}=e,i=this.thumbnail_duration;let s=0,r=[];for(let o=0;o<a;o++){const n=e[o];if(s+=n.duration,r.push(n),s>=i||o===a-1){const e=r.length,a=r[0],i=r[e-1];t.push({duration:s,start_time:a.start_time,end_time:i.end_time,items:r,item:i}),s=0,r=[]}}if(t.length>1){if(t[t.length-1].duration<1){const e=t.pop(),a=t[t.length-2];a.duration=a.duration+e.duration,a.end_time=e.end_time,a.items=a.items.concat(e.items),a.item=e.item,e.items}}t.forEach(t=>{const{items:e}=t;for(let a=e.length-1;a>=0;a--)if(e[a].duration>1){t.item=e[a];break}}),this.thumbnail_group=t,this.store.data.thumbnail_group=t,await this.store.write()}getVideoM3U8Info(){return this.videoTranscoderResult?.m3u8}async initM3U8Data(){this.m3u8_data=this.getVideoM3U8Info()}async initThumbnailDuration(){if(this.store.data.thumbnail_duration)return this.thumbnail_duration=this.store.data.thumbnail_duration,this.thumbnail_duration;let t=30;const e=await this.getMediainfo(),a=e?.video;if(!a?.length)return t;const i=a[0],s=i.duration||e?.general?.duration,{width:r,height:o}=i;r*o>=518400&&(t=10),r*o>=921600&&(t=20),r*o>=2073600&&(t=30),r*o>=3686400&&(t=40),r*o>=8294400&&(t=60);const n=s??0;if(n&&(n<60&&(t=0),n<300&&(t=Math.ceil(t/4)),n<600&&(t=Math.ceil(t/2)),n>3600)){const e=n/3600;t=Math.ceil(t*e)}return t=Math.min(60,t),this.thumbnail_duration=t,this.store.data.thumbnail_duration=t,await this.store.write(),t}},Wt=require("path"),Kt=require("fs-extra"),Jt=require("@soga/imgutils"),Qt=require("@soga/fileutils"),Zt=require("@soga/node-types"),Yt=require("@soga/error"),te=class extends nt{get cover_name(){return"audio_cover.png"}async start(){try{await this.generateCover(),this.isAudio&&await this.postProgress({type:Zt.UploadProgress.transcode_thumbnail,percent:1})}catch(t){throw(0,Yt.buildDError)(t,{message:"Error occurred during audio cover generation",detail:`Error occurred during audio cover generation: ${this.params.input.filepath}`})}}async generateCover(){const t=await this.getMediainfo();if(t.video?.length)return;const e="audio-covered";try{if(this.coverResult)return this.coverResult;if(this.db.data[e])return;const{cover_name:t}=this,a=["-i",this.params.input.filepath,"-map","0:v","-y",t];await this.ffmpeg(a,{cwd:this.params.outputRoot});const i=(0,Wt.resolve)(this.params.outputRoot,t),s=await(0,Kt.pathExists)(i),r=await(0,Jt.getMetadata)(i);if(s){const e={file:t,path:i,size:await(0,Qt.getFileSize)(i),width:r.width??0,height:r.height??0};await this.setCoverResult(e)}}catch(t){throw t}finally{this.db.data[e]=!0,await this.db.write()}}},ee=require("path"),ae=require("@soga/utils"),ie=require("@soga/fileutils"),se=require("fs-extra"),re=require("@soga/error"),oe=require("@soga/node-types"),ne=class extends nt{builtin_tracks=0;external_tracks=0;get tracks(){return this.builtin_tracks+this.external_tracks}async sendProgress(t){await this.postProgress({type:oe.UploadProgress.separate_subtitle,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.subtitleEncoderResult)return;const t=await this.getMediainfo();if(this.builtin_tracks=t?.text?.length||0,this.external_tracks=this.params.subtitles?.length||0,!this.tracks)return await this.setSubtitleEncoderResult([]),void await this.sendProgress(1);const e=await this.parseBuiltinTextTracks();await this.sendProgress(this.builtin_tracks/this.tracks);const a=await this.parseExternalTextTracks(),i=[...e,...a];await this.setSubtitleEncoderResult(i),await this.sendProgress(1)}catch(t){throw(0,re.buildDError)(t,{message:"Error occurred while process subtitle track",detail:`Error occurred while process subtitle track: ${this.params.input.filepath}`})}}async parseBuiltinTextTracks(){const t=await this.getMediainfo(),e=t?.text;if(!e?.length)return[];const{subtitle_builtin_tracks:a}=this.dbData;if(a)return a;const i=e.length,s=[];for(let t=0;t<i;t++){const e=await this.parseBuiltinTextTrack(t);e&&s.push(e),await this.sendProgress((t+1)/this.tracks)}return this.dbData.subtitle_builtin_tracks=s,await this.params.db.write(),s}async parseBuiltinTextTrack(t){const e=this.params.outputRoot,a=`subtitle-builtin-${t}.zip`,i=(0,ee.resolve)(e,a),s=`subtitle-temp-${t}.vtt`,r=(0,ee.resolve)(e,s),o=`subtitle-builtin-u8-${t}.vtt`,n=(0,ee.resolve)(e,o),h=["-i",this.params.input.filepath,"-vn","-an","-map",`0:s:${t}`,"-c","webvtt","-y",s];await this.ffmpeg(h,{cwd:this.params.outputRoot});if(await(0,ie.isValidFile)(r)){if(await(0,ae.isUtf8File)(r))await(0,se.copy)(r,n);else{await(0,ae.saveFileAsUtf8)(r,n);await(0,ie.isValidFile)(n)||await(0,se.copy)(r,n)}const e=await(0,ae.getFileLanguage)(n),{label:s,lang:o}=e;await(0,ae.gzip)(n,i);return{file:a,file_path:i,size:await(0,ie.getFileSize)(i),lang:o,name:s||`builtin_${t+1}`,title:s||`builtin_${t+1}`,builtin:!0,source:null}}return!1}async parseExternalTextTracks(){const{subtitles:t}=this.params;if(!t?.length)return[];const{subtitle_external_tracks:e}=this.dbData;if(e)return e;const a=[],i=t.length;for(let e=0;e<i;e++){const i=await this.parseExternalTextTrack(e,t[e]);i&&a.push(i),await this.sendProgress((this.builtin_tracks+(e+1))/this.tracks)}return this.dbData.subtitle_external_tracks=a,await this.params.db.write(),a}async parseExternalTextTrack(t,e){const{ext:a}=(0,ee.parse)(e),i=this.params.outputRoot,s=`subtitle-external-${t}.vtt`,r=(0,ee.resolve)(i,s),o=`subtitle-external-${t}.zip`,n=(0,ee.resolve)(i,o),h=`subtitle-external-u8-${t}${a}`,d=(0,ee.resolve)(i,h),c=`subtitle-external-source-${t}.zip`,l=(0,ee.resolve)(i,c);if(!await(0,ie.isValidPath)(e))return!1;if(await(0,ae.isUtf8File)(e))await(0,se.copy)(e,d);else{await(0,ae.saveFileAsUtf8)(e,d);if(!await(0,ie.isValidFile)(d))return!1}const u=["-i",d,"-c","webvtt","-y",s];await this.ffmpeg(u,{cwd:this.params.outputRoot});if(await(0,ie.isValidFile)(r)){const i=await(0,ae.getFileLanguage)(r),{label:s,lang:h}=i;await(0,ae.gzip)(e,l),await(0,ae.gzip)(r,n);const d=await(0,ie.getFileSize)(l);return{file:o,size:await(0,ie.getFileSize)(n),file_path:n,lang:h,name:s||`external_${t+1}`,title:s||`external_${t+1}`,builtin:!1,source:{file:c,file_path:l,size:d,ext:a}}}return!1}},he=require("@soga/error"),de=require("path"),ce=require("fs-extra"),le=require("@soga/node-types"),ue=require("@soga/fileutils"),pe=require("@soga/utils"),ge=require("@soga/error"),we=require("path"),me=require("@soga/fileutils"),fe=class extends nt{hostType;safe_index=0;file_map={};completed_percent=0;total_percent=0;store;async initStore(t){this.store=await this.getStore(`${t}_grouper_store.json`)}getFileName=t=>this.getPreviewSegmentName(t,this.hostType);getGroupedVideoManifestName(t){return`grouper_video_${this.hostType}_${t}.m3u8`}getAudioManifestName(t,e){return`grouper_audio_${this.hostType}_${e}_${t}.m3u8`}getThumbnailInfoFilename(){return`grouper_thumbnail_${this.hostType}.json`}getCacheInfoFilename(){return`grouper_cache_${this.hostType}.json`}constructor(t){super(t),this.hostType=t.host_type,this.completed_percent=t.completed_percent,this.total_percent=1/t.hosts.length}async generateSafeFile(t){return await async function(t){const e=`safe_${t.type}_${t.file_index}.txt`,a=f(t.filesize),i=(0,w.resolve)(t.outputRoot,e);return await(0,p.writeFile)(i,a),{file_path:i,size:a.length}}({type:t,file_index:this.safe_index++,outputRoot:this.params.outputRoot,filesize:this.params.input.filesize})}readAudioTracks(){return this.audioTranscoderResult??[]}readVideoTracks(){return this.videoTranscoderResult?[this.videoTranscoderResult]:[]}readThumbnailInfo(){return this.videoThumbnailerResult}readCoverInfo(){return this.coverResult}readSubtitleInfo(){return this.subtitleEncoderResult}async getPartData(){const t=this.store.data.grouper_part_names??[],e=[];for(let a=0;a<t.length;a++){const i=t[a],s=(0,we.resolve)(this.params.outputRoot,i),r=await(0,me.getFileSize)(s),o=await this.getPartInfo({host_type:this.hostType,filepath:s,start:0,end:r-1,filename:i});e.push(o)}return e}async getAudioData(){const t=this.readAudioTracks();if(!t?.length)return;const e=[];for(let a=0;a<t.length;a++){const i=t[a];if(i.adapt){const{average_bandwidth:t,bandwidth:s,channels:r,codec:o,codec_name:n,language:h,order:d}=i.adapt,c=this.getAudioManifestName("adapt",a),l=this.file_map[c],{file_index:u,start:p,end:g,size:w,hash:m}=l,f=this.getFileName(u),_=await this.getPreviewId({file:c});await this.setPreviewIdMap({id:_,file:f,start:p,end:g},this.hostType);const y={id:_,average_band:t,band:s,channels:r,codec:o,codec_name:n,language:h,order:d,file:f,start:p,end:g,size:w,hash:m};if(i.high){const{average_bandwidth:t,bandwidth:e,channels:s,codec:r,codec_name:o,language:n,order:h}=i.high,d=this.getAudioManifestName("high",a),c=this.file_map[d],{file_index:l,start:u,end:p,size:g,hash:w}=c,m=this.getFileName(l),f=await this.getPreviewId({file:d});await this.setPreviewIdMap({id:f,file:m,start:u,end:p},this.hostType),y.high={id:f,average_band:t,band:e,channels:s,codec:r,codec_name:o,language:n,order:h,file:m,start:u,end:p,size:g,hash:w}}e.push(y)}}return e}async getVideoData(){const t=this.readVideoTracks();if(!t?.length)return;const e=[];for(let a=0;a<t.length;a++){const i=t[a],s=this.getGroupedVideoManifestName(a),r=await this.getPreviewId({file:s}),o=this.file_map[s],{file_index:n,start:h,end:d,size:c,hash:l}=o,u=this.getFileName(n);await this.setPreviewIdMap({id:r,file:u,start:h,end:d},this.hostType);const{average_bandwidth:p,bandwidth:g,codec:w,width:m,height:f,label:_,codec_name:y,bitdepth:b,framerate:v}=i,P={id:r,average_band:p,band:g,codec:w,codec_name:y,bitdepth:b,framerate:Math.round(v),width:m,height:f,file:u,start:h,end:d,size:c,label:_,hash:l};e.push(P)}return e}async getSubtitleData(){const t=this.readSubtitleInfo();if(!t?.length)return;const e=[],{length:a}=t;for(let i=0;i<a;i++){const a=t[i],{builtin:s,file:r,lang:o,title:n,name:h,source:d}=a,c=this.file_map[r],{file_index:l,start:u,end:p,size:g}=c,w=this.getFileName(l),m={uuid:await this.getPreviewId({file:r,start:u,end:p}),builtin:s,lang:o,name:h,title:n,file:w,start:u,end:p,size:g};if(d){const{file:t,ext:e}=d,a=this.file_map[t],{file_index:i,start:s,end:r,size:o}=a,n=this.getFileName(i);m.source={size:o,file:n,start:s,end:r,ext:e}}e.push(m)}return e}async getThumbnailData(){const t=this.readThumbnailInfo();if(!t)return;const{row:e,col:a,width:i,height:s}=t,r=this.getThumbnailInfoFilename(),o=this.file_map[r],{file_index:n,start:h,end:d,size:c}=o,l=this.getFileName(n),u=await this.getPreviewId({file:r});await this.setPreviewIdMap({id:u,file:l,start:h,end:d},this.hostType);return{id:u,row:e,col:a,width:i,height:s,file:l,start:h,end:d,size:c}}async getCoverData(){const t=this.readCoverInfo();if(!t)return;const e=t,{file:a,width:i,height:s}=e,r=this.file_map[a],{file_index:o,start:n,end:h,size:d}=r,c=this.getFileName(o),l=await this.getPreviewId({file:e.path});await this.setPreviewIdMap({id:l,file:c,start:n,end:h},this.hostType);return{id:l,width:i,height:s,file:c,start:n,end:h,size:d}}async getCacheData(){const t=this.getCacheInfoFilename(),e=await this.getPreviewId({file:t}),a=this.file_map[t],{file_index:i,start:s,end:r,size:o}=a,n=this.getFileName(i);await this.setPreviewIdMap({id:e,file:n,start:s,end:r},this.hostType);return{id:e,file:n,start:s,end:r}}async saveData(){const t=gt(this.hostType);if(this.db.data[t])return;const e={},a=await this.getAudioData();a&&(e.audios=a);const i=await this.getVideoData();i&&(e.videos=i);const s=await this.getSubtitleData();s&&(e.subtitles=s);const r=await this.getThumbnailData();r&&(e.thumbnail=r);const o=await this.getCoverData();o&&(e.cover=o),e.parts=await this.getPartData(),e.cache=await this.getCacheData(),this.db.data[t]=e,await this.db.write()}},_e=class extends fe{current_position=0;current_index=0;group_data=[];async start(){const t=gt(this.hostType);if(this.db.data[t])return this.db.data[t];try{return await this.initStore(this.hostType),await this.calculateData(),await this.postProgress({type:le.UploadProgress.group_media,percent:this.completed_percent+.5*this.total_percent}),await this.processGroups(),await this.postProgress({type:le.UploadProgress.group_media,percent:this.completed_percent+.9*this.total_percent}),await this.saveData(),await this.postProgress({type:le.UploadProgress.group_media,percent:this.completed_percent+this.total_percent}),this.db.data[t]}catch(t){throw(0,ge.buildDError)(t,{message:`Error occurred during media grouping ${this.hostType}`,detail:`Error occurred during media grouping ${this.hostType}: ${this.params.input.filepath}`})}}async processGroups(){const t="grouper_process_state";if(this.store.data[t])return;this.store.data.grouper_process_map||={},this.store.data.grouper_process_index||=0;const{length:e}=this.group_data;for(let t=0;t<e;t++){const a=this.group_data[t];this.store.data.grouper_process_map[a.filename]||(await _({outputRoot:this.params.outputRoot,files:a.files,filename:a.filename}),this.store.data.grouper_process_map[a.filename]=!0,await this.store.write(),await this.postProgress({type:le.UploadProgress.group_media,percent:this.completed_percent+.5*this.total_percent+this.total_percent*(.4*(t+1)/e)}))}this.store.data[t]=!0,await this.store.write()}async insertSafeFile(){const t=await this.generateSafeFile(this.hostType);this.addOne(t,!0)}async calculateData(){this.store.data.grouper_group_list||=[],this.store.data.grouper_file_map||={},await this.insertSafeFile(),await this.calculateMediaTracks(),await this.calculateThumbnails(),await this.calculateCovers(),await this.calculateCaches(),this.current_index+=1,this.current_position=0,await this.calculateSubtitles(),this.store.data.grouper_group_list=this.group_data,this.store.data.grouper_file_map=this.file_map;const t=this.group_data.map(t=>t.filename);this.store.data.grouper_part_names=t,this.store.data.grouper_calculate_state=!0,await this.store.write()}async calculateSubtitles(){const t=this.readSubtitleInfo();if(!t?.length)return;await this.insertSafeFile();const{length:e}=t;for(let a=0;a<e;a++){const e=t[a],{file:i,file_path:s,size:r}=e,o=this.addOne({file_path:s,size:r});if(this.file_map[i]=o,e.source){const{file:t,file_path:a,size:i}=e.source,s=this.addOne({file_path:a,size:i});this.file_map[t]=s}}}async calculateCaches(){await this.getAudioData(),await this.getVideoData(),await this.getThumbnailData(),await this.getCoverData();const t=this.getPreviewIdMap(this.hostType),e=this.getCacheInfoFilename(),a=await this.writeText(e,JSON.stringify(t));this.file_map[e]=a}async calculateCovers(){const t=this.readCoverInfo();if(!t)return;const{file:e,path:a,size:i}=t,s=this.addOne({file_path:a,size:i});this.file_map[e]=s}async calculateMediaTracks(){const t=this.readAudioTracks(),e=this.readVideoTracks(),a=t?.length;for(let e=0;e<a;e++){const i=t[e];if(i.adapt){const t=await this.calculateOneTrack(i.adapt.m3u8),a=this.getAudioManifestName("adapt",e),s=await this.writeTrackText(a,t);this.file_map[a]=s}if(i.high){const t=await this.calculateOneTrack(i.high.m3u8),a=this.getAudioManifestName("high",e),s=await this.writeTrackText(a,t);this.file_map[a]=s}await this.postProgress({type:le.UploadProgress.group_media,percent:this.completed_percent+.4*this.total_percent*((e+1)/a)})}const i=e.length;for(let t=0;t<i;t++){const a=e[t],s=await this.calculateOneTrack(a.m3u8),r=this.getGroupedVideoManifestName(t),o=await this.writeTrackText(r,s);this.file_map[r]=o,await this.postProgress({type:le.UploadProgress.group_media,percent:this.completed_percent+.2*this.total_percent+.2*this.total_percent*((t+1)/i)})}}async calculateThumbnails(){const t=this.readThumbnailInfo();if(!t)return;if(!t)return;const{tile_list:e}=t,{length:a}=e;let i=[...t.sprite_list];for(let t=0;t<a;t++){const a=e[t],s=a.file,r=await this.safelyAddOne({file_path:a.file_path,size:a.size}),o=await this.getPreviewId({file:s}),n=this.getFileName(r.file_index);await this.setPreviewIdMap({id:o,file:n,start:r.start,end:r.end},this.hostType),this.file_map[s]=r,i=i.map(t=>t.file===s?{...t,file:n,id:o,s:r.start,e:r.end}:t)}const s=this.getThumbnailInfoFilename(),r=await this.writeText(s,JSON.stringify(i));this.file_map[s]=r}async calculateOneTrack(t){const{segments:e,init:a,version:i,targetDuration:s,mediaSequence:r,endList:o}=t,n={},h=this.addOne({size:a.size,file_path:a.file_path}),d=await this.getPreviewId({file:a.uri}),c=this.getFileName(h.file_index),l=`${c}?id=${d}`;await this.setPreviewIdMap({id:d,file:c,start:h.start,end:h.end},this.hostType);const u=["#EXTM3U",`#EXT-X-VERSION:${i}`,`#EXT-X-TARGETDURATION:${s}`,`#EXT-X-MEDIA-SEQUENCE:${r}`,`#EXT-X-MAP:URI=${l},BYTERANGE="${h.size}@${h.start}"`];[...e].forEach(t=>{const{uri:e,size:a,duration:i,file_path:s}=t;n[e]=this.addOne({size:a,duration:i,file_path:s})});for(const[t,e]of Object.entries(n)){const a=await this.getPreviewId({file:t}),i=this.getFileName(e.file_index);await this.setPreviewIdMap({id:a,file:i,start:e.start,end:e.end},this.hostType),u.push(`#EXTINF:${e.duration},`),u.push(`#EXT-X-BYTERANGE:${e.size}@${e.start}`),u.push(`${i}?id=${a}`)}o&&u.push("#EXT-X-ENDLIST");return u.join("\n")}async writeTrackText(t,e){const a=(0,de.resolve)(this.params.outputRoot,t),i=(0,de.resolve)(this.params.outputRoot,`${t}.gz`),s=(0,de.resolve)(this.params.outputRoot,`${t}.bin`);await(0,ce.writeFile)(a,e,"utf-8"),await(0,pe.gzip)(a,i);if(await(0,ue.getFileSize)(i)>16){const t=(await(0,pe.getFileBufferSlice)(i,0,15)).toString("base64");await async function(t,e){await new Promise((a,i)=>{const s=(0,p.createReadStream)(t,{start:16}),r=(0,p.createWriteStream)(e);s.pipe(r),r.on("finish",()=>{a(!0)}),s.on("error",t=>{i(t)}),r.on("error",t=>{i(t)})})}(i,s);return{...this.addOne({file_path:s,size:await(0,ue.getFileSize)(s)}),hash:t}}return{...this.addOne({file_path:a,size:await(0,ue.getFileSize)(a)}),hash:""}}async writeText(t,e){const a=(0,de.resolve)(this.params.outputRoot,t);await(0,ce.writeFile)(a,e,"utf-8");return this.addOne({file_path:a,size:await(0,ue.getFileSize)(a)})}addOne({file_path:t,size:e,duration:a=0},i=!1){const s=this.getSizeLimit(this.hostType),{current_position:r,group_data:o}=this;if(i&&o[this.current_index]||!(r+e<=s)){this.current_index+=1;const{current_index:i}=this;o[i]?o[i].files.push(t):o[i]={filename:this.getFileName(i),files:[t]};const s=0,r=e-1;return this.current_position=e,{file_index:i,start:s,end:r,duration:a,size:r-s+1}}{const{current_index:i}=this,s=r,n=r+e-1;return this.current_position=n+1,o[i]?o[i].files.push(t):o[i]={filename:this.getFileName(i),files:[t]},{file_index:i,start:s,end:n,duration:a,size:n-s+1}}}async safelyAddOne(t){const e=this.getSizeLimit(this.hostType),{current_position:a}=this;return a+t.size<=e?0===a?(await this.insertSafeFile(),this.addOne(t)):this.addOne(t):(await this.insertSafeFile(),this.addOne(t))}},ye=class extends nt{async start(){try{if(this.grouperResult)return this.grouperResult;const t={meta:await this.getMetaData(),data:{}},{length:e}=this.params.hosts;for(let a=0;a<e;a++){const i=this.params.hosts[a],s=this.getSizeLimit(i),r=new _e({...this.params,host_type:i,file_size_limit:s,completed_percent:a/e}),o=await r.start();t.data[i]=o}return await this.setGrouperResult(t),t}catch(t){throw(0,he.buildDError)(t,{message:t.message||"Error occurred during media grouping",detail:t.detail||`Error occurred during media grouping: ${this.params.input.filepath}`})}}async getMetaData(){const t={},e=this.audioTranscoderResult??[],a=this.videoTranscoderResult?[this.videoTranscoderResult]:[];if(a?.length){const e=await this.getMediainfo(),{duration:i}=e?.general;if(a?.length){const{width:e,height:s,framerate:r,bitdepth:o,label:n,codec:h,codec_name:d}=a[0];t.videos=[{duration:i,bitdepth:o,width:e,height:s,framerate:r,label:n,codec:h,codec_name:d}]}}if(e?.length)for(const a of e){const{high:e,adapt:i}=a,{channels:s,lossless:r}=i,o=await this.getMediainfo(),{duration:n}=o?.general,{codec:h,codec_name:d}=i,c={duration:n,channels:s,lossless:r,codec:h,codec_name:d};e&&(c.high={channels:e.channels,codec:e.codec,codec_name:e.codec_name,lossless:e.lossless}),t.audios=t.audios||[],t.audios.push(c)}return t}},be=class extends nt{async start(){if(this.db.data.grouper_result)return this.db.data.grouper_result;const t=await this.getMediainfo();if(!t)return;const e=t.video,a=e?.length,i=t.audio,s=i?.length;if(!s&&!a)return;const r=new ne(this.params);if(await r.start(),s){const t=new Pt(this.params);await t.start();const e=new At(this.params);await e.start();const a=new te(this.params);await a.start()}if(a){const t=new ft(this.params);await t.start();const e=new $t(this.params);await e.start();const a=new Xt(this.params);await a.start()}const o=new ye(this.params);await o.start()}async getResult(){return this.db.data.grouper_result}},ve=require("@soga/types"),Pe=require("@soga/node-types"),xe=require("@soga/mediainfo"),Te=require("@soga/fileutils"),ze=require("fs-extra"),Re=h(require("check-disk-space")),Se=require("@soga/error"),De=class extends E{async start(){this.prepareResult||(await this.checkStorage(),await this.calculateMeta(),await this.calculateProgress())}async checkStorage(){const{length:t}=this.params.hosts,e=await(0,Re.default)(this.params.outputRoot),a=e.free,i=e.diskPath;if((3+t)*this.params.input.filesize>a)throw(0,Se.buildDError)(new Error(`${i} have no enough computer disk space, please adjust the temporary path in user settings.`),{message:`${i} have no enough computer disk space, please adjust the temporary path in user settings.`,detail:`${i} have no enough computer disk space to process ${this.params.input.filepath}`})}async calculateMeta(){if(this.meta)return this.meta;const{filename:t,local_btime:e,local_ctime:a,local_mtime:i,filesize:s}=this.params.input,r={file:t,size:s,btime:e,ctime:a,mtime:i,md5:""};return await this.setMeta(r),r}async calculateProgress(){if(this.prepareResult)return;const t={[Pe.UploadProgress.prepare]:{weight:0,percent:1},[Pe.UploadProgress.calculate_md5]:{weight:0,percent:0},[Pe.UploadProgress.separate_video]:{weight:0,percent:0},[Pe.UploadProgress.separate_audio]:{weight:0,percent:0},[Pe.UploadProgress.separate_subtitle]:{weight:0,percent:0},[Pe.UploadProgress.transcode_video]:{weight:0,percent:0},[Pe.UploadProgress.transcode_audio]:{weight:0,percent:0},[Pe.UploadProgress.transcode_thumbnail]:{weight:0,percent:0},[Pe.UploadProgress.transcode_source]:{weight:0,percent:0},[Pe.UploadProgress.transcode_txt]:{weight:0,percent:0},[Pe.UploadProgress.transcode_img]:{weight:0,percent:0},[Pe.UploadProgress.group_media]:{weight:0,percent:0},[Pe.UploadProgress.upload_baidu]:{weight:0,percent:0},[Pe.UploadProgress.upload_ali]:{weight:0,percent:0},[Pe.UploadProgress.end]:{weight:0,percent:0}},e={keep_preview:this.params.keepPreview,keep_source:this.params.keepSource},a=await(0,Te.getFileSize)(this.params.input.filepath);t[Pe.UploadProgress.prepare].weight=t[Pe.UploadProgress.end].weight=Math.ceil(a/1024/1024/500),t[Pe.UploadProgress.calculate_md5].weight=Math.ceil(a/1024/1024/200);let i=0;if(this.isMedia)if(this.params.keepPreview){const s=await(0,xe.parseMediaInfo)(this.params.input.filepath),r=s?.general?.duration??0;if(s.video?.length){const e=s.video[0],{width:a,height:i,codec:r}=e,o=(0,Te.isVideoSupport)(r),{duration:n}=s.general,h=o?n/400:n*(a*i)/1920/1080;t[Pe.UploadProgress.separate_video].weight=Math.ceil(h),t[Pe.UploadProgress.transcode_video].weight=Math.ceil(.01*n)}if(s.audio?.length){const{duration:e}=s.general;let a=0;s.audio.forEach(t=>{const{codec:i,lossless:s,channels:r}=t,o={high_need:!1,high_transcode:!1,adapt_need:!1,adapt_transcode:!1};(0,Te.isAudioAdapt)(i)?r>2?(o.high_need=!0,o.high_transcode=!1,o.adapt_need=!0,o.adapt_transcode=!0):(o.high_need=!1,o.adapt_need=!0,o.adapt_transcode=!1):(0,Te.isAudioHigh)(i)?(o.high_need=!0,o.high_transcode=!1,o.adapt_need=!0,o.adapt_transcode=!0):(o.high_need=!1,o.adapt_need=!0,o.adapt_transcode=!1,s&&(o.high_need=!0,o.high_transcode=!0)),o.adapt_need&&(a+=o.adapt_transcode?e/40:5),o.high_need&&(a+=o.high_transcode?e/20:10)}),t[Pe.UploadProgress.separate_audio].weight=Math.ceil(a),t[Pe.UploadProgress.transcode_audio].weight=Math.ceil(.01*e)}const o=s.video?.length??0,n=s.audio?.length??0;if(o||n){e.keep_preview=!0;const o=(s.text?.length||0)+(this.params.subtitles?.length||0);t[Pe.UploadProgress.separate_subtitle].weight=Math.ceil(o),t[Pe.UploadProgress.transcode_thumbnail].weight=Math.ceil(.08*r),i+=a,t[Pe.UploadProgress.group_media].weight=Math.ceil(a/1024/1024/10)}else e.keep_preview=!1,e.keep_source=!0,i+=a}else e.keep_source=!0,i+=a;else this.isTxt?e.keep_preview?(t[Pe.UploadProgress.transcode_txt].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a):this.isImg?e.keep_preview&&(t[Pe.UploadProgress.transcode_img].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a);e.keep_source&&(t[Pe.UploadProgress.transcode_source].weight=Math.ceil(a/1024/1024/30)),this.params.hosts.includes(ve.HostType.BAIDU)&&(t[Pe.UploadProgress.upload_baidu].weight=Math.ceil(i/1024/1024/1)),this.params.hosts.includes(ve.HostType.ALI)&&(t[Pe.UploadProgress.upload_ali].weight=Math.ceil(i/1024/1024/2));const s={preview:e.keep_preview,source:e.keep_source};await this.setKeeps(s),await this.setPrepareResult(t)}},Ie=async t=>{await(0,ze.ensureDir)(t.outputRoot);const e=await b(t);try{const a=new De({...t,db:e});return await a.start(),a}catch(t){}},Me=require("@soga/node-types"),$e=require("crypto"),Fe=require("fs-extra"),ke=require("@soga/types"),qe=class extends E{async start(){await this.processFile();return await this.getResult()}async calculateMd5(){if(this.md5)return this.md5;const t=this.params.input.filepath,e=this.params.input.filesize;let a=0;const i=await new Promise((i,s)=>{let r=0;const o=(0,$e.createHash)("md5"),n=(0,Fe.createReadStream)(t,{highWaterMark:4194304});n.on("data",async t=>{o.update(t),r+=t.length;const i=r/e;r-a>104857600&&(a=r,await this.postProgress({type:Me.UploadProgress.calculate_md5,percent:Math.min(i,1)}))}),n.on("end",()=>{const t=o.digest("hex");i(t)}),n.on("error",t=>{s(t)})});return i&&await this.setMd5(i),await this.postProgress({type:Me.UploadProgress.calculate_md5,percent:1}),i}getCloudName({host_type:t,md5:e,is_attachment:a}){const i=a?"a":"f";return t==ke.HostType.BAIDU?`dpan_${i}-${e}.bin`:`dpan_${i}_${e}.txt`}async getResult(){if(this.result)return this.result;const{sourceResult:t,grouperResult:e,imgResult:a,txtResult:i,meta:s,keeps:r}=this,{length:o}=this.params.hosts,n={meta:{preview:r.preview,source:r.source,file:s}};for(let s=0;s<o;s++){const r=this.params.hosts[s];n[r]={max_size:0,parts:[]};const o=t=>{const e=t.map(t=>{const e=this.getCloudName({host_type:r,md5:t.md5,is_attachment:this.params.is_attachment});return{...t,name:e}});n[r].parts=[...n[r].parts,...e]},h=a?.data[r];if(h){h.cache&&(n[r].cache=h?.cache);const t=h.parts?.map(t=>({...t,preview:!0,source:!1}));t&&o(t),n.meta.img=a.meta,h.img&&(n[r].img=h.img)}const d=i?.data[r];if(d){o((d.parts||[]).map(t=>({...t,preview:!0,source:!1}))),n[r].cache=d.cache,n[r].txt={entrance:d.entrance,pad:i?.meta.pad,pages:i?.meta.pages}}const c=e?.data[r];if(c?.parts){o(c.parts.map(t=>({...t,preview:!0,source:!1}))),n.meta.audios=e.meta.audios,n.meta.videos=e.meta.videos,n[r].cache=c.cache,n[r].media={audios:c.audios,videos:c.videos,subtitles:c.subtitles,thumbnail:c.thumbnail,cover:c.cover}}const l=t?.data[r];if(l?.parts){o(l.parts.map(t=>{let e=!0;return(this.isMedia||this.isTxt)&&(e=!1),{...t,preview:e,source:!0}})),n[r].source={head:t.meta.head,download:l.download}}[...n[r]?.parts].forEach(t=>{t.size>n[r].max_size&&(n[r].max_size=t.size)})}return await this.setResult(n),n}async processFile(){const t="encoder_processed";if(this.db.data[t])return;const e=await Ie(this.params),{keeps:a}=e,i={...this.params,keepPreview:a.preview,keepSource:a.source},s=await this.calculateMd5();if(await this.setMd5(s),i.keepSource){const t=new U(this.params);await t.start()}if(e.isMedia&&i.keepPreview){const t=new be(this.params);await t.start()}if(e.isTxt&&i.keepPreview){const t=new K(this.params);await t.start()}if(e.isImg){const t=new it(this.params);await t.start()}this.db.data[t]=!0,await this.db.write()}},Ee=async t=>{try{const e=await b(t),a=new qe({...t,db:e});return a.start()}catch(e){throw(0,c.buildDError)(e,{message:"Error occurred during file encoding",detail:`Error occurred during file encoding: ${t.input.filepath}`})}};
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{buildDError as t}from"@soga/error";import{getDb as e}from"@soga/lowdb";import{createHash as a}from"crypto";import{createReadStream as i,createWriteStream as s,existsSync as r,remove as o,stat as n,writeFile as h}from"fs-extra";import{truncate as d}from"fs/promises";import{resolve as c}from"path";import{pipeline as l}from"stream/promises";function u(t){const e=a("md5");return e.update(`${t}`),e.digest("hex")}async function p(t){await new Promise((e,a)=>{(async()=>{const r=c(t.outputRoot,t.filename);await o(r);let n=!1;const h=s(r);h.on("open",()=>{n=!0}).on("error",async t=>{n&&h.close(),await o(r),a(t)});const{length:d}=t.files,l=async(e=0)=>{if(e<d){const a=t.files[e],s=t.files.length;await new Promise((t,e)=>{const d=i(a);d.pipe(h,{end:!s}),d.on("end",()=>{d.close(),t(!0)}),d.on("error",async t=>{d.destroy(),n&&h.close(),await o(r),e(t)})}),await l(e+1)}};await l(0),n&&h.end(),e(!0)})()})}async function g(t,a){const i=u(JSON.stringify({...t,dbName:a})),s="db_unique_key",r=c(t.outputRoot,a),o=await e(r,{});return o.data[s]?o.data[s]!=i&&(o.data={[s]:i},await o.write()):(o.data[s]=i,await o.write()),o}async function m(t){return await g({file_id:t.id,input:{filepath:t.input.filepath,filesize:t.input.filesize},outputRoot:t.outputRoot},"encoder_store.json")}async function w({input_path:t,target_path:e,start:a,end:n}){const h=i(t,{start:a,end:n,highWaterMark:65536}),d=s(e);try{await l(h,d)}catch(t){try{r(e)&&await o(e)}catch(t){console.warn("Failed to clean up incomplete file:",t.message)}throw t}}import{resolve as f}from"path";import{gzip as _,getFileBufferSlice as y}from"@soga/utils";import{getFileSize as b}from"@soga/fileutils";import{buildDError as v}from"@soga/error";import{UploadProgress as P}from"@soga/node-types";import{rename as x,stat as D,writeFile as T}from"fs-extra";import{HostType as z}from"@soga/types";var R=2097152,I={[z.BAIDU]:52428800,[z.ALI]:4294967296},M={[z.BAIDU]:2147483648,[z.ALI]:4294967296};z.BAIDU,z.ALI;import{HostType as $,RecordFtype as S,RecordType as k}from"@soga/types";import{calculateMd4 as F,calculateMd5 as E,calculateSha1 as N}from"@soga/utils";import{parentPort as L}from"worker_threads";var C=class{segmentNames={};params;id;port=null;db;get lowData(){return this.db.data}get isVideo(){return this.params.type==k.VIDEO}get isAudio(){return this.params.type==k.AUDIO}get isMedia(){return this.isAudio||this.isVideo}get isTxt(){return this.params.type==k.DOC&&this.params.ftype==S.DOC_TXT}get isImg(){return this.params.type==k.IMAGE}getSizeLimit(t){return this.params.is_shop_space?M[t]||2147483648:I[t]||52428800}getFilesize(){return this.params.input.filesize}constructor(t){this.params=t,this.id=t.id,this.port=t.port??null,this.db=t.db}async getPartInfo({host_type:t,filepath:e,start:a,end:i,filename:s,index:r},o=!0){const n={start:a,end:i,size:i-a+1,path:e,index:r,file:s,md5:o?await E({file:e,start:a,end:i}):""};if(o){if(t===$.BAIDU){const t=await F({file:e,start:a,end:i});n.md4=t}if(t===$.ALI){const t=await N({file:e,start:a,end:i});n.sha1=t}}return n}async getStore(t){const{id:e,input:a,outputRoot:i}=this.params;return await g({file_id:e,input:{filepath:a.filepath,filesize:a.filesize},outputRoot:i},t)}async postProgress(t){const e={step:t.type,percent:t.percent};await this.postMessage({id:this.id,type:"percent",data:e})}async postMessage(t){this.port?this.port.postMessage(t):L&&L.postMessage(t)}async setKeeps(t){this.lowData.keeps=t,await this.db.write()}get keeps(){return this.lowData.keeps}async setMeta(t){this.lowData.meta=t,await this.db.write()}get meta(){return this.lowData.meta}async setSourceResult(t){this.lowData.source_result=t,await this.db.write()}get sourceResult(){return this.lowData.source_result}async setPrepareResult(t){this.lowData.prepare_result=t,await this.db.write()}get prepareResult(){return this.lowData.prepare_result}async setMd5(t){this.lowData.meta.md5=t,await this.db.write()}get md5(){return this.lowData.meta.md5}async setSubtitleEncoderResult(t){this.lowData.subtitle_encoder_result=t,await this.db.write()}get subtitleEncoderResult(){return this.lowData.subtitle_encoder_result}async setAudioSeparatorResult(t){this.lowData.audio_separator_result=t,await this.db.write()}get audioSeparatorResult(){return this.lowData.audio_separator_result}async setAudioTranscoderResult(t){this.lowData.audio_transcoder_result=t,await this.db.write()}get audioTranscoderResult(){return this.lowData.audio_transcoder_result}async setCoverResult(t){this.lowData.cover_result=t,await this.db.write()}get coverResult(){return this.lowData.cover_result}async setVideoTranscoderResult(t){this.lowData.video_transcoder_result=t,await this.db.write()}get videoTranscoderResult(){return this.lowData.video_transcoder_result}async setVideoThumbnailerResult(t){this.lowData.video_thumbnailer_result=t,await this.db.write()}get videoThumbnailerResult(){return this.lowData.video_thumbnailer_result}async setGrouperResult(t){this.lowData.grouper_result=t,await this.db.write()}get grouperResult(){return this.lowData.grouper_result}async setImgResult(t){this.lowData.img_result=t,await this.db.write()}get imgResult(){return this.lowData.img_result}async setTxtResult(t){this.lowData.txt_result=t,await this.db.write()}get txtResult(){return this.lowData.txt_result}async setResult(t){this.lowData.result=t,await this.db.write()}get result(){return this.lowData.result}_syncGetId({file:t,start:e,end:a},i){const s=`${i}_key_index`,r=`${i}_key_map`,o=`${t}_${e||0}_${a||0}`,n=this.db.data[r]||{};if(n[o])return n[o];this.db.data[s]=this.db.data[s]||0,this.db.data[r]=this.db.data[r]||{};const h=this.db.data[s]+1,d=`id_${h}`;return this.db.data[r][o]=d,this.db.data[s]=h,d}_syncSetIdMap({id:t,file:e,start:a,end:i},s,r){const o=`${s}_${r}_id_map`;this.db.data[o]=this.db.data[o]||{},this.db.data[o][t]={f:e,s:a,e:i}}},A=class extends C{syncGetSourceId(t){return this._syncGetId(t,"source")}async getSourceId(t){const e=this.syncGetSourceId(t);return await this.db.write(),e}getSourceIdMap(t){return this.db.data[`source_${t}_id_map`]||{}}syncSetSourceIdMap(t,e){this._syncSetIdMap(t,"source",e)}async setSourceIdMap(t,e){this.syncSetSourceIdMap(t,e),await this.db.write()}getSourceSegmentName=(t,e)=>{const a=`source_${e}_${t}`;if(this.segmentNames[a])return this.segmentNames[a];const i=`s-${u(`source-${e}-${this.md5}-${t}`)}`;return this.segmentNames[a]=i,i}},O=class extends A{head_size=32;getZipFilePath(){return f(this.params.outputRoot,"souce_zip.bin")}getDownloadListFileName(t){return`source_${t}_download_list.json`}getPartName(t,e){return this.getSourceSegmentName(e,t)}getPartPath(t,e){return f(this.params.outputRoot,this.getPartName(t,e))}get dbData(){return this.db.data}async setPartList(t,e){const a=`source_${t}_part_list`;this.dbData[a]=e,await this.params.db.write()}getPartList(t){const e=`source_${t}_part_list`;return this.dbData[e]}async setDownloadMap(t,e){const a=`source_${t}_download_map`;this.dbData[a]=e,await this.params.db.write()}getDownloadMap(t){const e=`source_${t}_download_map`;return this.dbData[e]}async sendProgress(t){await this.postProgress({type:P.transcode_source,percent:t})}async setDownloadList(t,e){const a=`source_${t}_download_list`;this.dbData[a]=e,await this.params.db.write()}getDownloadList(t){const e=`source_${t}_download_list`;return this.dbData[e]}async start(){try{if(this.sourceResult)return await this.sendProgress(1),this.sourceResult;await this.gzip();const{length:t}=this.params.hosts;for(let e=0;e<t;e++){const t=this.params.hosts[e];await this.calculatePartList(t),await this.processDownloadMap(t)}await this.sendProgress(.9);const e=await this.getResult();return await this.sendProgress(1),e}catch(t){throw v(t,{message:"Error occurred during source encoding",detail:`Error occurred during source encoding: ${this.params.input.filepath}`})}}async gzip(){if(this.dbData.source_gziped)return;const t=this.params.input.filepath,e=this.getZipFilePath();await _(t,e,async({percent:t})=>{await this.sendProgress(.6*t)}),this.dbData.source_gziped=!0,await this.params.db.write()}async getResult(){if(this.sourceResult)return this.sourceResult;const t={meta:await this.getMetaData(),data:{}},{length:e}=this.params.hosts;for(let a=0;a<e;a++){const e=this.params.hosts[a],i=this.getPartList(e),s=this.getDownloadMap(e);t.data[e]={download:s,parts:i}}return await this.setSourceResult(t),t}async getMetaData(){const t="source_meta",e=this.dbData[t];if(e)return e;const a=this.getZipFilePath(),i=await b(a),s={path:a,start:0,end:0},{head_size:r}=this;s.end=i<=r?i-1:r-1;const o={head:(await y(s.path,s.start,s.end)).toString("base64")};return this.dbData[t]=o,await this.params.db.write(),o}async writeDownloadListFile(t,e){const a=this.getDownloadListFileName(t),i=f(this.params.outputRoot,a);await T(i,e,"utf-8");return{file_path:i,size:await b(i)}}async processDownloadMap(t){const e=this.getDownloadMap(t);if(e)return e;const a=this.getDownloadList(t);let r;const{file_path:o,size:n}=await this.writeDownloadListFile(t,JSON.stringify(a)),h=this.getSizeLimit(t),d=this.getPartList(t);if(d.length){const e=d[d.length-1],{path:a,size:c,file:u,index:p,end:g,start:m}=e,w=f(this.params.outputRoot,u);if(c+n<=h){await async function({source1:t,source2:e,target:a}){const r=i(t.filepath,{start:t.start,end:t.end}),o=s(a);await l(r,o);const n=i(e),h=s(a,{flags:"a"});await l(n,h)}({source1:{filepath:a,start:m,end:g},source2:o,target:w});const e=(await D(w)).size,h=e-1,c=e-n,f=await this.getPartInfo({host_type:t,filepath:w,start:0,end:e-1,filename:u,index:p});d[d.length-1]=f;r={id:await this.getSourceId({file:u,start:c,end:h}),file:u,start:c,end:h}}else{const e=p+1,a=this.getPartName(t,e),i=this.getPartPath(t,e);await x(o,i);const s=await this.getSourceId({file:a,start:0,end:n-1}),h=await this.getPartInfo({host_type:t,filepath:i,start:0,end:n-1,filename:a,index:e});d.push(h),r={id:s,file:a,start:0,end:n-1}}return await this.setPartList(t,d),await this.setDownloadMap(t,r),r}}async calculatePartList(t){const e=`source_${t}_list_calculated`;if(this.dbData[e])return;const a=this.getZipFilePath(),i=await b(a),s=[],r=this.getSizeLimit(t),{head_size:o}=this,n=[];if(i>o){let e=0;for(let h=o;h<=i-1;h+=r){const o=Math.min(h+r-1,i-1),d=this.getPartName(t,e),c=await this.getPartInfo({host_type:t,filepath:a,start:h,end:o,filename:d,index:e});let l=0;for(let t=h;t<o;t+=R){const e=Math.min(t+R-1,o),a=e-t+1,i=l+a-1,s=await this.getSourceId({file:"source_zip",start:t,end:e});n.push({id:s,file:d,start:l,end:i}),l+=a}s.push(c),e++}}await this.setPartList(t,s),await this.setDownloadList(t,n),this.dbData[e]=!0,await this.db.write()}};import{resolve as U}from"path";import{createWriteStream as V,readFile as G,remove as B}from"fs-extra";import{getFileBufferSlice as j}from"@soga/utils";import q from"zlib";import{saveFileAsUtf8 as X}from"@soga/utils";import{buildDError as K}from"@soga/error";import{UploadProgress as J}from"@soga/node-types";import{resolve as H}from"path";import{getFileSize as Q}from"@soga/fileutils";import{copy as W,writeFile as Z}from"fs-extra";var Y=class extends C{get preview_common_db_data(){return this.db.data}async getCurrentFileIndex(t){const e=this.db.data[`preview_${t}_current_index`];return"number"!=typeof e?(this.db.data[`preview_${t}_current_index`]=0,await this.db.write(),0):e}async increaseCurrentFileIndex(t){const e=await this.getCurrentFileIndex(t)+1;return this.db.data[`preview_${t}_current_index`]=e,await this.db.write(),e}getPartName(t,e){return this.getPreviewSegmentName(e,t)}getPartPath(t,e){return H(this.params.outputRoot,this.getPartName(t,e))}syncGetPreviewId(t){return this._syncGetId(t,"preview")}async getPreviewId(t){const e=this.syncGetPreviewId(t);return await this.db.write(),e}getPreviewIdMap(t){return this.db.data[`preview_${t}_id_map`]||{}}syncSetPreviewIdMap(t,e){this._syncSetIdMap(t,"preview",e)}async setPreviewIdMap(t,e){this.syncSetPreviewIdMap(t,e),await this.db.write()}getPreviewSegmentName=(t,e)=>{const a=`preview_${e}_${t}`;if(this.segmentNames[a])return this.segmentNames[a];const i=`p-${u(`preview-${e}-${this.md5}-${t}`)}`;return this.segmentNames[a]=i,i};async calculatePartList(t,e){const a=[],i=await this.getCurrentFileIndex(t);for(let s=0;s<i+1;s++){const i=this.getPartName(t,s),r=this.getPartPath(t,s),o=await Q(r),n=await this.getPartInfo({host_type:t,filename:i,filepath:r,index:s,start:0,end:o-1},e);a.push(n)}return a}getPartListKey(t){return`preview_${t}_part_list`}async completePartList(t){const e=await this.getPartList(t);if(e){const a=[];for(const i of e)if(i.md5)a.push(i);else{const e=await this.getPartInfo({filename:i.file,filepath:i.path,start:i.start,end:i.end,host_type:t,index:i.index},!0);a.push(e)}await this.setPartList(t,a)}}async getPartList(t){const e=this.getPartListKey(t),a=this.preview_common_db_data[e];if(a)return a}async setPartList(t,e){const a=this.getPartListKey(t);this.preview_common_db_data[a]=e,await this.db.write()}async attachCacheData(){const{hosts:t}=this.params;for(const e of t)await this.attachHostCacheData(e),await this.completePartList(e)}getCacheInfo(t){const e=`preview_${t}_cache_info`;return this.preview_common_db_data[e]}async writeCacheFile(t,e){const a=`preview_${t}_cache_info.txt`,i=H(this.params.outputRoot,a);await Z(i,e,"utf-8");return{file_path:i,size:await Q(i)}}async setCacheInfo(t,e){const a=`preview_${t}_cache_info`;this.preview_common_db_data[a]=e,await this.db.write()}async attachHostCacheData(t){if(this.getCacheInfo(t))return;const e=await this.getPartList(t),a=this.getPreviewIdMap(t),{file_path:r,size:o}=await this.writeCacheFile(t,JSON.stringify(a)),h=this.getSizeLimit(t);if(e.length){const a=e[e.length-1],{path:c,size:u,file:p,index:g,end:m}=a;let w;if(u+o<=h){await async function({filepath:t,size:e},a){(await n(t)).size>e&&await d(t,e);const r=i(a),o=s(t,{flags:"a"});await l(r,o)}({filepath:c,size:u},r);const a=await Q(c),h=await this.getPartInfo({host_type:t,filename:p,filepath:c,index:g,start:0,end:a-1});e[e.length-1]=h;const f=m+1,_=m+o;w={id:await this.getPreviewId({file:p,start:f,end:_}),file:p,start:f,end:_}}else{const a=g+1,i=this.getPartName(t,a),s=this.getPartPath(t,a);await W(r,s);const n=await this.getPreviewId({file:i,start:0,end:o-1}),h=await this.getPartInfo({host_type:t,filename:i,filepath:s,index:a,start:0,end:o-1},!1);e.push(h),await this.setPartList(t,e),w={id:n,file:i,start:0,end:o-1}}w&&await this.setCacheInfo(t,w)}}},tt=class extends Y{content_size_1=81920;content_size_2=102400;totalPage=1;hashBuffer=Buffer.from("dpan");get hashBufferLength(){return this.hashBuffer.length}getU8FileName(){return`text_utf8_${this.params.id}.txt`}getU8FilePath(){return U(this.params.outputRoot,this.getU8FileName())}async sendProgress(t){await this.postProgress({type:J.transcode_txt,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.dbData.txt_result)return await this.sendProgress(1),this.dbData.txt_result;await this.txtConvertToUtf8File(),await this.sendProgress(.2);const{length:t}=this.params.hosts;for(let e=0;e<t;e++){const a=this.params.hosts[e];await this.txtConvertToGzipFile(a),await this.sendProgress(.2+(e+1)/t*.6)}await this.attachCacheData();const e=await this.getResult();return await this.clean(),await this.sendProgress(1),e}catch(t){throw K(t,{message:"Error occurred during txt encoding",detail:`Error occurred during txt encoding: ${this.params.input.filepath}`})}}async getResult(){if(this.txtResult)return this.txtResult;const t={meta:{pad:this.hashBufferLength,pages:this.totalPage},data:{}};for(const e of this.params.hosts)t.data[e]={cache:this.getCacheInfo(e),parts:await this.getPartList(e),entrance:await this.getEntranceInfo(e)};return await this.setTxtResult(t),t}async clean(){try{if(this.params.debug)return;const t=this.getU8FilePath();await B(t)}catch(t){}}async setEntranceInfo(t,e){const a=`txt_${t}_entrance`;this.dbData[a]=e,await this.db.write()}async getEntranceInfo(t){const e=`txt_${t}_entrance`,a=this.dbData[e];if(a)return a}async txtConvertToUtf8File(){if(this.dbData.txt_utf8_converted)return;const t=this.params.input.filepath,e=this.getU8FilePath();await X(t,e),this.dbData.txt_utf8_converted=!0,await this.db.write()}async txtConvertToGzipFile(t){if(await this.getEntranceInfo(t))return;const e=this.getSizeLimit(t),a=this.getU8FilePath(),i=await this.calculateSlice(),{length:s}=i,r={};let o=0,n=V(this.getPartPath(t,await this.getCurrentFileIndex(t)));for(let h=0;h<s;h++){const d=h==s-1?0:h+1,c=i[d],{index:l,start:u,end:p}=c,g={page:l+1,text:(await j(a,u,p)).toString("utf8")},m=JSON.stringify(g);let w=Buffer.from(m,"utf8");if(0==d){const t={...g,map:r};w=Buffer.from(JSON.stringify(t),"utf8")}const f=await this.getPreviewId({file:"u8zip",start:u,end:p});await new Promise((a,i)=>{q.gzip(w,async(s,h)=>{if(s)return i(s);const c=h.length<this.hashBufferLength?this.hashBuffer:h.subarray(0,this.hashBufferLength),l=Buffer.concat([c,h]),u=l.length;if(o+u>e){n.end();const e=await this.increaseCurrentFileIndex(t);n=V(this.getPartPath(t,e)),o=0}const p=o,g=o+u-1;if(n.write(l),o+=u,0==d){n.end();const e={id:f,start:p,end:g,file:this.getPartName(t,await this.getCurrentFileIndex(t))};await this.setEntranceInfo(t,e)}else r[`p_${d+1}`]={id:f,f:this.getPartName(t,await this.getCurrentFileIndex(t)),s:p,e:g};this.syncSetPreviewIdMap({id:f,file:this.getPartName(t,await this.getCurrentFileIndex(t)),start:p,end:g},t),a(!0)})})}await this.db.write();const h=await this.calculatePartList(t,!1);await this.setPartList(t,h)}async calculateSlice(){if(this.dbData.txt_slice_list)return this.dbData.txt_slice_list;const t=this.getU8FilePath(),e=await new Promise((e,a)=>{G(t,"utf8",(t,i)=>{if(t)return void a(t);const s=this.content_size_1,r=this.content_size_2,o=[];let n=0,h=0,d=0;for(;h<i.length;){let t=Math.min(h+r,i.length);const e=Math.min(h+s,i.length),a=i.slice(e,t-1).indexOf("#");-1!==a&&(t=e+a);const c=i.slice(h,t),l=Buffer.byteLength(c);o.push({index:n++,start:d,end:d+l-1}),this.totalPage=n,h=t,d+=l}e(o)})});return this.dbData.txt_slice_list=e,await this.db.write(),e}};import{resolve as et}from"path";import{getMetadata as at,compress as it}from"@soga/imgutils";import{gzip as st}from"@soga/utils";import{getFileSize as rt}from"@soga/fileutils";import{buildDError as ot}from"@soga/error";import{UploadProgress as nt}from"@soga/node-types";import{remove as ht}from"fs-extra";var dt=class extends Y{getCompressFileName(){return"img_compress.jpg"}getCompressFilePath(){return et(this.params.outputRoot,this.getCompressFileName())}getGzFileName(){return"compressed_img.zip"}getGzFilePath(){return et(this.params.outputRoot,this.getGzFileName())}async sendProgress(t){await this.postProgress({type:nt.transcode_img,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.imgResult)return await this.sendProgress(1),this.imgResult;await this.compress(),await this.sendProgress(.1),await this.gzip(),await this.sendProgress(.4);const{hosts:t}=this.params,{length:e}=t;for(let a=0;a<e;a++){const e=t[a];await this.splitFile(e),await this.calculatePartList(e,!1)}await this.attachCacheData(),await this.sendProgress(.9);const a=await this.getResult();return await this.clean(),await this.sendProgress(1),a}catch(t){throw ot(t,{message:"Error occurred during image encoding",detail:`Error occurred during image encoding: ${this.params.input.filepath}`})}}getCacheInfoFileName(t){return`img_${t}_cache.json`}async getResult(){if(this.imgResult)return this.imgResult;const{input:t}=this.params,e=t.filepath,{width:a,height:i}=await at(e),s=this.getCompressFilePath(),{width:r,height:o}=await at(s),n=await rt(s),h={meta:{width:a,height:i,size:t.filesize,t_width:r,t_height:o,t_size:n},data:{}},{length:d}=this.params.hosts;for(let t=0;t<d;t++){const e=this.params.hosts[t],a=await this.getPartList(e),i=this.getPreviewList(e);h.data[e]={img:{preview:i},cache:this.getCacheInfo(e),parts:a}}return await this.setImgResult(h),h}async clean(){try{if(this.params.debug)return;const t=this.getCompressFilePath();await ht(t)}catch(t){}}async compress(){if(this.dbData.img_compressed)return;const t=this.getCompressFilePath();await it({ffmpeg_path:this.params.ffmpegPath,input_path:this.params.input.filepath,output_path:t}),this.dbData.img_compressed=!0,await this.db.write()}async gzip(){if(this.dbData.img_gziped)return;const t=this.getCompressFilePath(),e=this.getGzFilePath();await st(t,e),this.dbData.img_gziped=!0,await this.db.write()}async setPreviewList(t,e){const a=`img_${t}_preview_list`;this.dbData[a]=e,await this.db.write()}getPreviewList(t){const e=`img_${t}_preview_list`;return this.dbData[e]}async splitFile(t){if(this.getPreviewList(t))return;const e=this.getGzFilePath(),a=await rt(e),i=this.getSizeLimit(t),s=[],r=[];for(let o=0;o<=a-1;o+=i){0!=o&&await this.increaseCurrentFileIndex(t);const n=Math.min(o+i-1,a-1),h=await this.getCurrentFileIndex(t),d=this.getPartName(t,h),c=this.getPartPath(t,h);await w({input_path:e,target_path:c,start:o,end:n});const l=0,u=n-o,p=await this.getPartInfo({host_type:t,filepath:c,filename:d,start:l,end:u,index:h},!1);s.push(p);const g=await this.getPreviewId({file:d,start:l,end:u});r.push({id:g,file:d,start:l,end:u}),await this.setPreviewIdMap({id:g,file:d,start:l,end:u},t)}await this.setPartList(t,s),await this.setPreviewList(t,r)}};import ct from"fluent-ffmpeg";import{spawn as lt}from"child_process";import{parseMediaInfo as ut}from"@soga/mediainfo";var pt=class extends Y{async getMediainfo(){const{mediainfo:t}=this.db.data;if(t)return t;const e=this.params.input.filepath,a=await ut(e);return this.db.data.mediainfo=a,await this.params.db.write(),a}constructor(t){super(t),ct.setFfmpegPath(t.ffmpegPath)}getFluent(){return ct()}async ffmpeg(t,e){const a=this.params.ffmpegPath;return await new Promise((i,s)=>{const r=lt(a,t,Object.assign({stdio:"ignore"},e));r.on("close",t=>{i(t)}),r.on("error",t=>{s(t)})})}};import{resolve as gt}from"path";import{isValidFile as mt,isVideoSupport as wt}from"@soga/fileutils";import{UploadProgress as ft}from"@soga/node-types";import{buildDError as _t}from"@soga/error";var yt=({type:t,track_order:e,quality:a})=>`audio-${e}-${a}-${t}.${"manifest"===t?"m3u8":"mp4"}`,bt=({width:t,height:e})=>`video-formatted-${t}-${e}.mp4`,vt=t=>`grouper_result_${t}`,Pt=t=>{let e=0,a=0,i=0;t.segments.forEach(t=>{a+=t.duration,e+=t.size;const s=8*t.size/t.duration;s>i&&(i=s)});const s=8*e/a;return{bandwidth:Math.ceil(i),average_bandwidth:Math.ceil(s)}},xt=(t,e)=>{if("number"==typeof t.percent)return t.percent/100;return function(t){const e=t.split(":").map(parseFloat),[a=0,i=0,s=0]=e.reverse();return 3600*s+60*i+a}(t.timemark)/e};var Dt=class extends pt{async start(){try{await this.separateVideo(),await this.postProgress({type:ft.separate_video,percent:1})}catch(t){throw _t(t,{message:"Error occurred during video separation",detail:`Error occurred during video separation: ${this.params.input.filepath}`})}}async separateVideo(){const t="video_separated";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],i=bt({width:a.width,height:a.height}),s=gt(this.params.outputRoot,i),r=wt(a.codec),o=["-sn","-an","-map","0:v:0"];let n="copy";r||(n=a.width*a.height>=2073600?"libx265":"libx264","libx265"==n&&o.push("-pix_fmt","yuv420p")),o.push("-c:v",n);const h=a.duration;o.push("-y"),await new Promise((t,e)=>{const a=this.getFluent().input(this.params.input.filepath).outputOptions(o).on("progress",async t=>{if(!r&&t.frames){const e=xt(t,h);await this.postProgress({type:ft.separate_video,percent:e})}}).on("end",async()=>{t("end"),a.kill("SIGKILL")}).on("error",async t=>{e(t)}).output(s);a.run()});if(!await mt(s))throw new Error("Separate Video track failed");this.db.data[t]=!0,await this.params.db.write()}};import{resolve as Tt}from"path";import{isValidFile as zt,isAudioAdapt as Rt,isAudioHigh as It}from"@soga/fileutils";import{UploadProgress as Mt}from"@soga/node-types";import{buildDError as $t}from"@soga/error";var St=class extends pt{async start(){try{await this.separateTracks(),await this.postProgress({type:Mt.separate_audio,percent:1})}catch(t){throw $t(t,{message:"Error occurred during audio separation",detail:`Error occurred during audio separation: ${this.params.input.filepath}`})}}async separateTracks(){if(this.audioSeparatorResult)return;const t=await this.getMediainfo();if(!t?.audio?.length)return;const{audio:e}=t,a=e.length,i=[];for(let t=0;t<a;t++){const s=e[t],{codec:r,channels:o,lossless:n}=s,h={adapt:{need:!0,codec:"",channels:Math.min(o,2)},high:{need:!1,codec:"flac",channels:0}};Rt(r)?o>2?(h.high.need=!0,h.high.codec="copy",h.adapt.codec=r,h.adapt.need=!0):(h.adapt.need=!0,h.adapt.codec="copy",h.adapt.channels=0):It(r)?(h.high.need=!0,h.high.codec="copy",h.adapt.need=!0,h.adapt.codec="aac"):(h.adapt.need=!0,h.adapt.codec="aac",n&&(h.high.need=!0,h.high.codec="flac")),h.adapt.need&&await this.separateAudioTrack(t,{type:"adapt",codec:h.adapt.codec,tracks:a,channels:h.adapt.channels,need_adapt:!0,need_high:h.high.need}),h.high.need&&await this.separateAudioTrack(t,{type:"high",codec:h.high.codec,tracks:a,channels:h.high.channels,need_adapt:h.adapt.need,need_high:!0}),i.push(h)}await this.setAudioSeparatorResult(i)}async separateAudioTrack(t,e){const a=`audio_separated_${t}_${e.type}`;if(this.db.data[a])return;const i=await this.getMediainfo();if(!i?.audio?.length)return;const s=i.audio[t];if(!s)return;const r=s?.duration??i.general?.duration,o=yt({type:"formatted",track_order:t,quality:e.type}),n=Tt(this.params.outputRoot,o),h=["-sn","-vn","-map",`0:a:${t}`];e.codec&&h.push("-c:a",e.codec),e.channels&&h.push("-ac",e.channels.toString()),h.push("-y"),await new Promise((a,i)=>{const s=this.getFluent().input(this.params.input.filepath).outputOptions(h).on("progress",async a=>{if("copy"!=e.codec){const i=xt(a,r);let s=t;"adapt"==e.type?e.need_high?s+=1/3*i:s+=i:e.need_adapt?(s+=1/3,s+=2/3*i):s+=i;const o=s/e.tracks;await this.postProgress({type:Mt.separate_audio,percent:o})}}).on("end",async()=>{a("end"),s.kill("SIGKILL")}).on("error",async t=>{i(t)}).output(n);s.run()});if(!await zt(n))throw new Error(`Separate audio track failed: [track_order:${t}, track_quality ${e.type}] `);if("copy"==e.codec){let a=t;"adapt"==e.type&&e.need_high?a+=1/3:a+=1;const i=a/e.tracks;await this.postProgress({type:Mt.separate_audio,percent:i})}this.db.data[a]=!0,await this.params.db.write()}};import{resolve as kt}from"path";import{parseMediaInfo as Ft}from"@soga/mediainfo";import{getMp4boxInfo as Et}from"@soga/mp4box";import{parseM3U8 as Nt}from"@soga/m3u8";import{UploadProgress as Lt}from"@soga/node-types";import{isValidFile as Ct,getStandardInfo as At}from"@soga/fileutils";import{remove as Ot}from"fs-extra";import{buildDError as Ut}from"@soga/error";var Vt=class extends pt{getVideoInitName({width:t,height:e}){return`video-init-${t}-${e}.mp4`}getVideoManifestName({width:t,height:e}){return`video-hls-${t}-${e}.m3u8`}async start(){try{await this.transcodeVideo(),await this.saveData(),await this.postProgress({type:Lt.transcode_video,percent:1})}catch(t){throw Ut(t,{message:"Error occurred during video transcoding",detail:`Error occurred during video transcoding: ${this.params.input.filepath}`})}}async saveData(){const t=await this.getMediainfo();if(!t?.video?.length)return;if(this.videoTranscoderResult)return;const{width:e,height:a}=t.video[0],i=bt({width:e,height:a}),s=kt(this.params.outputRoot,i),r=this.getVideoManifestName({width:e,height:a}),o=kt(this.params.outputRoot,r),n=await Nt(o),{videos:h}=await Et(s),{codec:d}=h[0],{bandwidth:c,average_bandwidth:l}=Pt(n),u=(await Ft(s)).video[0],p=At(e,a),g={m3u8:n,m3u8_path:o,codec:d,width:e,height:a,bandwidth:c,average_bandwidth:l,bitdepth:u?.bitdepth,bitrate:u?.bitrate,codec_name:u?.codec??"",framerate:u?.framerate,label:p?.label??"unknown"};await this.setVideoTranscoderResult(g),this.params.debug||await Ot(s)}async transcodeVideo(){const t="video_transcode_state";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],i={width:a.width,height:a.height},s=bt(i),r=this.getVideoInitName(i),o=this.getVideoManifestName({width:a.width,height:a.height}),n=["-i",s,"-an","-sn","-c:v","copy","-hls_list_size","0","-hls_time","6","-hls_segment_type","fmp4","-hls_fmp4_init_filename",r,"-y",o];await this.ffmpeg(n,{cwd:this.params.outputRoot});const h=kt(this.params.outputRoot,o);if(!await Ct(h))throw new Error("Transcode video track failed");this.db.data[t]=!0,await this.db.write()}};import{resolve as Gt}from"path";import{getFileSize as Bt,isValidFile as jt}from"@soga/fileutils";import{getMp4boxInfo as qt}from"@soga/mp4box";import{parseM3U8 as Xt}from"@soga/m3u8";import{parseMediaInfo as Kt}from"@soga/mediainfo";import{remove as Jt}from"fs-extra";import{buildDError as Ht}from"@soga/error";import{UploadProgress as Qt}from"@soga/node-types";var Wt=class extends pt{async start(){try{await this.transcodeAudios(),await this.saveData()}catch(t){throw Ht(t,{message:"Error occurred during audio transcoding",detail:`Error occurred during audio transcoding: ${this.params.input.filepath}`})}}async saveData(){if(this.audioTranscoderResult)return;const t=await this.getMediainfo();if(!t?.audio?.length)return;const e=t.audio.length,a=this.audioSeparatorResult,i=[],s={};for(let t=0;t<e;t++){const e=a[t];e.adapt.need&&(s.adapt=await this.getQualityData({track_order:t,quality:"adapt"})),e.high.need&&(s.high=await this.getQualityData({track_order:t,quality:"high"})),i.push(s)}await this.setAudioTranscoderResult(i);try{if(this.params.debug)return;for(let t=0;t<e;t++){const e=a[t];if(e.adapt.need){const e=yt({type:"formatted",track_order:t,quality:"adapt"}),a=Gt(this.params.outputRoot,e);await Jt(a)}if(e.high.need){const e=yt({type:"formatted",track_order:t,quality:"high"}),a=Gt(this.params.outputRoot,e);await Jt(a)}}}catch(t){}}async getQualityData({track_order:t,quality:e}){const a=yt({type:"formatted",track_order:t,quality:e}),i=Gt(this.params.outputRoot,a),s=await Kt(i);if(!s.audio?.length)throw new Error("parse mediainfo failed!");const r=s.audio[0],o=yt({type:"manifest",track_order:t,quality:e}),n=await Bt(i),h=Gt(this.params.outputRoot,o),d=await qt(i),{audios:c}=d,{language:l,codec:u}=c[0],p=l&&!l.startsWith("un")?{language:l}:void 0,g=await Xt(h),{bandwidth:m,average_bandwidth:w}=Pt(g);return{m3u8:g,m3u8_path:h,codec:u,codec_name:r.codec,...p,order:t,lossless:r.lossless,channels:r.channels,bandwidth:m,size:n,average_bandwidth:w}}async transcodeAudios(){const t="audio_transcoded";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.audio?.length)return;const a=e.audio.length,i=this.audioSeparatorResult;for(let t=0;t<a;t++){const e=i[t];e.adapt.need&&await this.transcodeAudio(t,{...e.adapt,type:"adapt"}),e.high.need&&await this.transcodeAudio(t,{...e.high,type:"high"});const s=(t+1)/a;await this.postProgress({type:Qt.transcode_audio,percent:s})}await this.postProgress({type:Qt.transcode_audio,percent:1}),this.db.data[t]=!0,await this.db.write()}async transcodeAudio(t,e){const a=`audio-transcoded-${t}-${e.type}`;if(this.db.data[a])return;const i=yt({type:"formatted",track_order:t,quality:e.type}),s=yt({type:"init",track_order:t,quality:e.type}),r=yt({type:"manifest",track_order:t,quality:e.type}),o=["-i",i,"-vn","-sn","-c:a","copy","-hls_list_size","0","-hls_time","6","-hls_segment_type","fmp4","-hls_fmp4_init_filename",s,"-y",r];await this.ffmpeg(o,{cwd:this.params.outputRoot});const n=Gt(this.params.outputRoot,r);if(!await jt(n))throw new Error(`Transcode audio track failed: [track_order:${t}, track_quality ${e.type}] `);this.db.data[a]=!0,await this.db.write()}};import{resolve as Zt}from"path";import{getFileSize as Yt}from"@soga/fileutils";import{combine as te}from"@soga/imgutils";import{copy as ee}from"fs-extra";import{UploadProgress as ae}from"@soga/node-types";import{buildDError as ie}from"@soga/error";var se=class extends pt{m3u8_data=null;thumbnail_duration=30;thumbnail_group=[];row=8;col=8;screenshot_width=480;screenshot_height=270;getScreenshotName(t){return`video_screenshot_${t}.jpg`}getTileName(t){return`video_tile_${t}.jpg`}getCoverName(){return"video_cover.jpg"}async updateImagePercent(t,e){const a="screenshot"==e?6*t/7:t/7+6/7;await this.postProgress({type:ae.transcode_thumbnail,percent:a})}store;async initStore(){this.store=await this.getStore("thumbnail_store.json")}async start(){if(!this.videoThumbnailerResult)try{const t=await this.getMediainfo();if(!t?.video?.length)return;if(await this.init(),!this.m3u8_data)return;await this.generateScreenshots(),await this.generateTiles(),await this.saveCoverInfo(),await this.saveThumbnailInfo()}catch(t){throw ie(t,{message:"Error occurred during video thumbnail generation",detail:`Error occurred during video thumbnail generation: ${this.params.input.filepath}`})}}async init(){await this.initStore(),await this.initScreenshotSize(),await this.initM3U8Data(),await this.initThumbnailDuration(),await this.initThumbnailGroup()}async saveThumbnailInfo(){if(this.videoThumbnailerResult)return;const{col:t,row:e,thumbnail_group:a,screenshot_width:i,screenshot_height:s}=this,r=a.length,o=[],n=[];for(let h=0;h<r;h++){const r=a[h],d=r.start_time,c=r.end_time,l=Math.floor(h/(e*t)),u=h%e*i,p=Math.floor(h%(t*e)/e)*s,g=this.getTileName(l);n.push(g),o.push({file:g,st:d,et:c,x:u,y:p,w:i,h:s})}const h=[...new Set(n)],d=h.length,c=[];for(let t=0;t<d;t++){const e=h[t],a=Zt(this.params.outputRoot,e),i=await Yt(a);c.push({file:e,file_path:a,size:i})}const l={width:this.screenshot_width,height:this.screenshot_height,row:this.row,col:this.col,tile_list:c,sprite_list:o};await this.setVideoThumbnailerResult(l)}async saveCoverInfo(){if(this.coverResult)return;const t=this.store.data.thumbnail_screenshot_largest,e=t?.index||0,{screenshot_width:a,screenshot_height:i}=this,s=this.getScreenshotName(e),r=Zt(this.params.outputRoot,s),o=this.getCoverName(),n=Zt(this.params.outputRoot,o);await ee(r,n);const h={file:o,path:n,size:await Yt(n),width:a,height:i};await this.setCoverResult(h)}async generateTiles(){const t=this.store.data.thumbnail_tile_index||0,{length:e}=this.thumbnail_group,a=this.col*this.row,i=Math.ceil(e/a);for(let e=t;e<i;e++)await this.generateOneTile(e),await this.updateImagePercent((e+1)/i,"tile")}async generateOneTile(t){const{col:e,row:a}=this,i=this.thumbnail_group.length,s=a*e,r=t*s,o=Math.min(s,i-r),n=[];for(let t=0;t<o;t++){const e=this.getScreenshotName(r+t),a=Zt(this.params.outputRoot,e);n.push(a)}const h=this.getTileName(t),d=Zt(this.params.outputRoot,h);await this.createSpriteSheet(n,d),this.store.data.thumbnail_tile_index=t+1,await this.store.write()}async createSpriteSheet(t,e){await te({col:this.col,inputs:t,output_path:e,width:this.screenshot_width,height:this.screenshot_height})}getKeyFrameParams(t,e=0){if(t<1)return["-vframes","1"];{const a=Math.max(t-e-.3,.1);if(a<1)return["-vframes","1"];return["-ss",`${a.toFixed(3)}`,"-vframes","1"]}}async generateScreenshots(){if(this.store.data.thumbnail_screenshot_state)return;this.store.data.thumbnail_screenshot_index||=0;const t=this.store.data.thumbnail_screenshot_index,e=this.store.data.thumbnail_screenshot_largest,a={index:0,size:0};if(e){const t=e;a.index=t.index,a.size=t.size}const{segments:i}=this.m3u8_data,{thumbnail_group:s,screenshot_width:r}=this,{length:o}=s,n=async(t,{errorTimes:e,fixedSeconds:o})=>{const h=s[t].item.index,d=i[h];try{const e=this.getScreenshotName(t),i=`concat:${d.init_uri}|${d.uri}`,s=this.getKeyFrameParams(d.duration,o),n=r>this.screenshot_height?`${r}:-2`:`-2:${this.screenshot_height}`,h=["-i",i,...s,"-vf",`scale=${n}:flags=lanczos`,"-y",e];await this.ffmpeg(h,{cwd:this.params.outputRoot});const c=Zt(this.params.outputRoot,e),l=await Yt(c);if(0===l)throw new Error(`Generate video thumbnail error: [index: ${t}, start_time: ${d.start_time}, end_time: ${d.end_time}]`);l>=a.size&&(a.index=t,a.size=l,this.store.data.thumbnail_screenshot_largest=a,await this.store.write()),this.store.data.thumbnail_screenshot_index=t+1,await this.store.write()}catch(a){const i=Math.max(10,d.duration);if(!(e<3))throw a;await n(t,{errorTimes:e+1,fixedSeconds:o+i/5})}};for(let e=t;e<o;e++)await n(e,{errorTimes:0,fixedSeconds:0}),await this.updateImagePercent((e+1)/o,"screenshot");this.store.data.thumbnail_screenshot_state=!0,await this.store.write()}async initScreenshotSize(){const{thumbnail_screenshot_size:t}=this.store.data;if(t)return this.screenshot_width=t.width,void(this.screenshot_height=t.height);const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],{width:i,height:s}=a,r=i>s?480:270;this.screenshot_width=2*Math.floor(Math.min(r,i)/2),this.screenshot_height=2*Math.floor(this.screenshot_width*(s/i)/2),this.store.data.thumbnail_screenshot_size={width:this.screenshot_width,height:this.screenshot_height}}async initThumbnailGroup(){if(this.store.data.thumbnail_group)return void(this.thumbnail_group=this.store.data.thumbnail_group);const t=[],{segments:e}=this.m3u8_data,{length:a}=e,i=this.thumbnail_duration;let s=0,r=[];for(let o=0;o<a;o++){const n=e[o];if(s+=n.duration,r.push(n),s>=i||o===a-1){const e=r.length,a=r[0],i=r[e-1];t.push({duration:s,start_time:a.start_time,end_time:i.end_time,items:r,item:i}),s=0,r=[]}}if(t.length>1){if(t[t.length-1].duration<1){const e=t.pop(),a=t[t.length-2];a.duration=a.duration+e.duration,a.end_time=e.end_time,a.items=a.items.concat(e.items),a.item=e.item,e.items}}t.forEach(t=>{const{items:e}=t;for(let a=e.length-1;a>=0;a--)if(e[a].duration>1){t.item=e[a];break}}),this.thumbnail_group=t,this.store.data.thumbnail_group=t,await this.store.write()}getVideoM3U8Info(){return this.videoTranscoderResult?.m3u8}async initM3U8Data(){this.m3u8_data=this.getVideoM3U8Info()}async initThumbnailDuration(){if(this.store.data.thumbnail_duration)return this.thumbnail_duration=this.store.data.thumbnail_duration,this.thumbnail_duration;let t=30;const e=await this.getMediainfo(),a=e?.video;if(!a?.length)return t;const i=a[0],s=i.duration||e?.general?.duration,{width:r,height:o}=i;r*o>=518400&&(t=10),r*o>=921600&&(t=20),r*o>=2073600&&(t=30),r*o>=3686400&&(t=40),r*o>=8294400&&(t=60);const n=s??0;if(n&&(n<60&&(t=0),n<300&&(t=Math.ceil(t/4)),n<600&&(t=Math.ceil(t/2)),n>3600)){const e=n/3600;t=Math.ceil(t*e)}return t=Math.min(60,t),this.thumbnail_duration=t,this.store.data.thumbnail_duration=t,await this.store.write(),t}};import{resolve as re}from"path";import{pathExists as oe}from"fs-extra";import{getMetadata as ne}from"@soga/imgutils";import{getFileSize as he}from"@soga/fileutils";import{UploadProgress as de}from"@soga/node-types";import{buildDError as ce}from"@soga/error";var le=class extends pt{get cover_name(){return"audio_cover.png"}async start(){try{await this.generateCover(),this.isAudio&&await this.postProgress({type:de.transcode_thumbnail,percent:1})}catch(t){throw ce(t,{message:"Error occurred during audio cover generation",detail:`Error occurred during audio cover generation: ${this.params.input.filepath}`})}}async generateCover(){const t=await this.getMediainfo();if(t.video?.length)return;const e="audio-covered";try{if(this.coverResult)return this.coverResult;if(this.db.data[e])return;const{cover_name:t}=this,a=["-i",this.params.input.filepath,"-map","0:v","-y",t];await this.ffmpeg(a,{cwd:this.params.outputRoot});const i=re(this.params.outputRoot,t),s=await oe(i),r=await ne(i);if(s){const e={file:t,path:i,size:await he(i),width:r.width??0,height:r.height??0};await this.setCoverResult(e)}}catch(t){throw t}finally{this.db.data[e]=!0,await this.db.write()}}};import{parse as ue,resolve as pe}from"path";import{getFileLanguage as ge,isUtf8File as me,saveFileAsUtf8 as we,gzip as fe}from"@soga/utils";import{isValidFile as _e,getFileSize as ye,isValidPath as be}from"@soga/fileutils";import{copy as ve}from"fs-extra";import{buildDError as Pe}from"@soga/error";import{UploadProgress as xe}from"@soga/node-types";var De=class extends pt{builtin_tracks=0;external_tracks=0;get tracks(){return this.builtin_tracks+this.external_tracks}async sendProgress(t){await this.postProgress({type:xe.separate_subtitle,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.subtitleEncoderResult)return;const t=await this.getMediainfo();if(this.builtin_tracks=t?.text?.length||0,this.external_tracks=this.params.subtitles?.length||0,!this.tracks)return await this.setSubtitleEncoderResult([]),void await this.sendProgress(1);const e=await this.parseBuiltinTextTracks();await this.sendProgress(this.builtin_tracks/this.tracks);const a=await this.parseExternalTextTracks(),i=[...e,...a];await this.setSubtitleEncoderResult(i),await this.sendProgress(1)}catch(t){throw Pe(t,{message:"Error occurred while process subtitle track",detail:`Error occurred while process subtitle track: ${this.params.input.filepath}`})}}async parseBuiltinTextTracks(){const t=await this.getMediainfo(),e=t?.text;if(!e?.length)return[];const{subtitle_builtin_tracks:a}=this.dbData;if(a)return a;const i=e.length,s=[];for(let t=0;t<i;t++){const e=await this.parseBuiltinTextTrack(t);e&&s.push(e),await this.sendProgress((t+1)/this.tracks)}return this.dbData.subtitle_builtin_tracks=s,await this.params.db.write(),s}async parseBuiltinTextTrack(t){const e=this.params.outputRoot,a=`subtitle-builtin-${t}.zip`,i=pe(e,a),s=`subtitle-temp-${t}.vtt`,r=pe(e,s),o=pe(e,`subtitle-builtin-u8-${t}.vtt`),n=["-i",this.params.input.filepath,"-vn","-an","-map",`0:s:${t}`,"-c","webvtt","-y",s];await this.ffmpeg(n,{cwd:this.params.outputRoot});if(await _e(r)){if(await me(r))await ve(r,o);else{await we(r,o);await _e(o)||await ve(r,o)}const e=await ge(o),{label:s,lang:n}=e;await fe(o,i);return{file:a,file_path:i,size:await ye(i),lang:n,name:s||`builtin_${t+1}`,title:s||`builtin_${t+1}`,builtin:!0,source:null}}return!1}async parseExternalTextTracks(){const{subtitles:t}=this.params;if(!t?.length)return[];const{subtitle_external_tracks:e}=this.dbData;if(e)return e;const a=[],i=t.length;for(let e=0;e<i;e++){const i=await this.parseExternalTextTrack(e,t[e]);i&&a.push(i),await this.sendProgress((this.builtin_tracks+(e+1))/this.tracks)}return this.dbData.subtitle_external_tracks=a,await this.params.db.write(),a}async parseExternalTextTrack(t,e){const{ext:a}=ue(e),i=this.params.outputRoot,s=`subtitle-external-${t}.vtt`,r=pe(i,s),o=`subtitle-external-${t}.zip`,n=pe(i,o),h=pe(i,`subtitle-external-u8-${t}${a}`),d=`subtitle-external-source-${t}.zip`,c=pe(i,d);if(!await be(e))return!1;if(await me(e))await ve(e,h);else{await we(e,h);if(!await _e(h))return!1}const l=["-i",h,"-c","webvtt","-y",s];await this.ffmpeg(l,{cwd:this.params.outputRoot});if(await _e(r)){const i=await ge(r),{label:s,lang:h}=i;await fe(e,c),await fe(r,n);const l=await ye(c);return{file:o,size:await ye(n),file_path:n,lang:h,name:s||`external_${t+1}`,title:s||`external_${t+1}`,builtin:!1,source:{file:d,file_path:c,size:l,ext:a}}}return!1}};import{buildDError as Te}from"@soga/error";import{resolve as ze}from"path";import{writeFile as Re}from"fs-extra";import{UploadProgress as Ie}from"@soga/node-types";import{getFileSize as Me}from"@soga/fileutils";import{gzip as $e,getFileBufferSlice as Se}from"@soga/utils";import{buildDError as ke}from"@soga/error";import{resolve as Fe}from"path";import{getFileSize as Ee}from"@soga/fileutils";var Ne=class extends pt{hostType;safe_index=0;file_map={};completed_percent=0;total_percent=0;store;async initStore(t){this.store=await this.getStore(`${t}_grouper_store.json`)}getFileName=t=>this.getPreviewSegmentName(t,this.hostType);getGroupedVideoManifestName(t){return`grouper_video_${this.hostType}_${t}.m3u8`}getAudioManifestName(t,e){return`grouper_audio_${this.hostType}_${e}_${t}.m3u8`}getThumbnailInfoFilename(){return`grouper_thumbnail_${this.hostType}.json`}getCacheInfoFilename(){return`grouper_cache_${this.hostType}.json`}constructor(t){super(t),this.hostType=t.host_type,this.completed_percent=t.completed_percent,this.total_percent=1/t.hosts.length}async generateSafeFile(t){return await async function(t){const e=`safe_${t.type}_${t.file_index}.txt`,a=u(t.filesize),i=c(t.outputRoot,e);return await h(i,a),{file_path:i,size:a.length}}({type:t,file_index:this.safe_index++,outputRoot:this.params.outputRoot,filesize:this.params.input.filesize})}readAudioTracks(){return this.audioTranscoderResult??[]}readVideoTracks(){return this.videoTranscoderResult?[this.videoTranscoderResult]:[]}readThumbnailInfo(){return this.videoThumbnailerResult}readCoverInfo(){return this.coverResult}readSubtitleInfo(){return this.subtitleEncoderResult}async getPartData(){const t=this.store.data.grouper_part_names??[],e=[];for(let a=0;a<t.length;a++){const i=t[a],s=Fe(this.params.outputRoot,i),r=await Ee(s),o=await this.getPartInfo({host_type:this.hostType,filepath:s,start:0,end:r-1,filename:i});e.push(o)}return e}async getAudioData(){const t=this.readAudioTracks();if(!t?.length)return;const e=[];for(let a=0;a<t.length;a++){const i=t[a];if(i.adapt){const{average_bandwidth:t,bandwidth:s,channels:r,codec:o,codec_name:n,language:h,order:d}=i.adapt,c=this.getAudioManifestName("adapt",a),l=this.file_map[c],{file_index:u,start:p,end:g,size:m,hash:w}=l,f=this.getFileName(u),_=await this.getPreviewId({file:c});await this.setPreviewIdMap({id:_,file:f,start:p,end:g},this.hostType);const y={id:_,average_band:t,band:s,channels:r,codec:o,codec_name:n,language:h,order:d,file:f,start:p,end:g,size:m,hash:w};if(i.high){const{average_bandwidth:t,bandwidth:e,channels:s,codec:r,codec_name:o,language:n,order:h}=i.high,d=this.getAudioManifestName("high",a),c=this.file_map[d],{file_index:l,start:u,end:p,size:g,hash:m}=c,w=this.getFileName(l),f=await this.getPreviewId({file:d});await this.setPreviewIdMap({id:f,file:w,start:u,end:p},this.hostType),y.high={id:f,average_band:t,band:e,channels:s,codec:r,codec_name:o,language:n,order:h,file:w,start:u,end:p,size:g,hash:m}}e.push(y)}}return e}async getVideoData(){const t=this.readVideoTracks();if(!t?.length)return;const e=[];for(let a=0;a<t.length;a++){const i=t[a],s=this.getGroupedVideoManifestName(a),r=await this.getPreviewId({file:s}),o=this.file_map[s],{file_index:n,start:h,end:d,size:c,hash:l}=o,u=this.getFileName(n);await this.setPreviewIdMap({id:r,file:u,start:h,end:d},this.hostType);const{average_bandwidth:p,bandwidth:g,codec:m,width:w,height:f,label:_,codec_name:y,bitdepth:b,framerate:v}=i,P={id:r,average_band:p,band:g,codec:m,codec_name:y,bitdepth:b,framerate:Math.round(v),width:w,height:f,file:u,start:h,end:d,size:c,label:_,hash:l};e.push(P)}return e}async getSubtitleData(){const t=this.readSubtitleInfo();if(!t?.length)return;const e=[],{length:a}=t;for(let i=0;i<a;i++){const a=t[i],{builtin:s,file:r,lang:o,title:n,name:h,source:d}=a,c=this.file_map[r],{file_index:l,start:u,end:p,size:g}=c,m=this.getFileName(l),w={uuid:await this.getPreviewId({file:r,start:u,end:p}),builtin:s,lang:o,name:h,title:n,file:m,start:u,end:p,size:g};if(d){const{file:t,ext:e}=d,a=this.file_map[t],{file_index:i,start:s,end:r,size:o}=a,n=this.getFileName(i);w.source={size:o,file:n,start:s,end:r,ext:e}}e.push(w)}return e}async getThumbnailData(){const t=this.readThumbnailInfo();if(!t)return;const{row:e,col:a,width:i,height:s}=t,r=this.getThumbnailInfoFilename(),o=this.file_map[r],{file_index:n,start:h,end:d,size:c}=o,l=this.getFileName(n),u=await this.getPreviewId({file:r});await this.setPreviewIdMap({id:u,file:l,start:h,end:d},this.hostType);return{id:u,row:e,col:a,width:i,height:s,file:l,start:h,end:d,size:c}}async getCoverData(){const t=this.readCoverInfo();if(!t)return;const e=t,{file:a,width:i,height:s}=e,r=this.file_map[a],{file_index:o,start:n,end:h,size:d}=r,c=this.getFileName(o),l=await this.getPreviewId({file:e.path});await this.setPreviewIdMap({id:l,file:c,start:n,end:h},this.hostType);return{id:l,width:i,height:s,file:c,start:n,end:h,size:d}}async getCacheData(){const t=this.getCacheInfoFilename(),e=await this.getPreviewId({file:t}),a=this.file_map[t],{file_index:i,start:s,end:r,size:o}=a,n=this.getFileName(i);await this.setPreviewIdMap({id:e,file:n,start:s,end:r},this.hostType);return{id:e,file:n,start:s,end:r}}async saveData(){const t=vt(this.hostType);if(this.db.data[t])return;const e={},a=await this.getAudioData();a&&(e.audios=a);const i=await this.getVideoData();i&&(e.videos=i);const s=await this.getSubtitleData();s&&(e.subtitles=s);const r=await this.getThumbnailData();r&&(e.thumbnail=r);const o=await this.getCoverData();o&&(e.cover=o),e.parts=await this.getPartData(),e.cache=await this.getCacheData(),this.db.data[t]=e,await this.db.write()}},Le=class extends Ne{current_position=0;current_index=0;group_data=[];async start(){const t=vt(this.hostType);if(this.db.data[t])return this.db.data[t];try{return await this.initStore(this.hostType),await this.calculateData(),await this.postProgress({type:Ie.group_media,percent:this.completed_percent+.5*this.total_percent}),await this.processGroups(),await this.postProgress({type:Ie.group_media,percent:this.completed_percent+.9*this.total_percent}),await this.saveData(),await this.postProgress({type:Ie.group_media,percent:this.completed_percent+this.total_percent}),this.db.data[t]}catch(t){throw ke(t,{message:`Error occurred during media grouping ${this.hostType}`,detail:`Error occurred during media grouping ${this.hostType}: ${this.params.input.filepath}`})}}async processGroups(){const t="grouper_process_state";if(this.store.data[t])return;this.store.data.grouper_process_map||={},this.store.data.grouper_process_index||=0;const{length:e}=this.group_data;for(let t=0;t<e;t++){const a=this.group_data[t];this.store.data.grouper_process_map[a.filename]||(await p({outputRoot:this.params.outputRoot,files:a.files,filename:a.filename}),this.store.data.grouper_process_map[a.filename]=!0,await this.store.write(),await this.postProgress({type:Ie.group_media,percent:this.completed_percent+.5*this.total_percent+this.total_percent*(.4*(t+1)/e)}))}this.store.data[t]=!0,await this.store.write()}async insertSafeFile(){const t=await this.generateSafeFile(this.hostType);this.addOne(t,!0)}async calculateData(){this.store.data.grouper_group_list||=[],this.store.data.grouper_file_map||={},await this.insertSafeFile(),await this.calculateMediaTracks(),await this.calculateThumbnails(),await this.calculateCovers(),await this.calculateCaches(),this.current_index+=1,this.current_position=0,await this.calculateSubtitles(),this.store.data.grouper_group_list=this.group_data,this.store.data.grouper_file_map=this.file_map;const t=this.group_data.map(t=>t.filename);this.store.data.grouper_part_names=t,this.store.data.grouper_calculate_state=!0,await this.store.write()}async calculateSubtitles(){const t=this.readSubtitleInfo();if(!t?.length)return;await this.insertSafeFile();const{length:e}=t;for(let a=0;a<e;a++){const e=t[a],{file:i,file_path:s,size:r}=e,o=this.addOne({file_path:s,size:r});if(this.file_map[i]=o,e.source){const{file:t,file_path:a,size:i}=e.source,s=this.addOne({file_path:a,size:i});this.file_map[t]=s}}}async calculateCaches(){await this.getAudioData(),await this.getVideoData(),await this.getThumbnailData(),await this.getCoverData();const t=this.getPreviewIdMap(this.hostType),e=this.getCacheInfoFilename(),a=await this.writeText(e,JSON.stringify(t));this.file_map[e]=a}async calculateCovers(){const t=this.readCoverInfo();if(!t)return;const{file:e,path:a,size:i}=t,s=this.addOne({file_path:a,size:i});this.file_map[e]=s}async calculateMediaTracks(){const t=this.readAudioTracks(),e=this.readVideoTracks(),a=t?.length;for(let e=0;e<a;e++){const i=t[e];if(i.adapt){const t=await this.calculateOneTrack(i.adapt.m3u8),a=this.getAudioManifestName("adapt",e),s=await this.writeTrackText(a,t);this.file_map[a]=s}if(i.high){const t=await this.calculateOneTrack(i.high.m3u8),a=this.getAudioManifestName("high",e),s=await this.writeTrackText(a,t);this.file_map[a]=s}await this.postProgress({type:Ie.group_media,percent:this.completed_percent+.4*this.total_percent*((e+1)/a)})}const i=e.length;for(let t=0;t<i;t++){const a=e[t],s=await this.calculateOneTrack(a.m3u8),r=this.getGroupedVideoManifestName(t),o=await this.writeTrackText(r,s);this.file_map[r]=o,await this.postProgress({type:Ie.group_media,percent:this.completed_percent+.2*this.total_percent+.2*this.total_percent*((t+1)/i)})}}async calculateThumbnails(){const t=this.readThumbnailInfo();if(!t)return;if(!t)return;const{tile_list:e}=t,{length:a}=e;let i=[...t.sprite_list];for(let t=0;t<a;t++){const a=e[t],s=a.file,r=await this.safelyAddOne({file_path:a.file_path,size:a.size}),o=await this.getPreviewId({file:s}),n=this.getFileName(r.file_index);await this.setPreviewIdMap({id:o,file:n,start:r.start,end:r.end},this.hostType),this.file_map[s]=r,i=i.map(t=>t.file===s?{...t,file:n,id:o,s:r.start,e:r.end}:t)}const s=this.getThumbnailInfoFilename(),r=await this.writeText(s,JSON.stringify(i));this.file_map[s]=r}async calculateOneTrack(t){const{segments:e,init:a,version:i,targetDuration:s,mediaSequence:r,endList:o}=t,n={},h=this.addOne({size:a.size,file_path:a.file_path}),d=await this.getPreviewId({file:a.uri}),c=this.getFileName(h.file_index),l=`${c}?id=${d}`;await this.setPreviewIdMap({id:d,file:c,start:h.start,end:h.end},this.hostType);const u=["#EXTM3U",`#EXT-X-VERSION:${i}`,`#EXT-X-TARGETDURATION:${s}`,`#EXT-X-MEDIA-SEQUENCE:${r}`,`#EXT-X-MAP:URI=${l},BYTERANGE="${h.size}@${h.start}"`];[...e].forEach(t=>{const{uri:e,size:a,duration:i,file_path:s}=t;n[e]=this.addOne({size:a,duration:i,file_path:s})});for(const[t,e]of Object.entries(n)){const a=await this.getPreviewId({file:t}),i=this.getFileName(e.file_index);await this.setPreviewIdMap({id:a,file:i,start:e.start,end:e.end},this.hostType),u.push(`#EXTINF:${e.duration},`),u.push(`#EXT-X-BYTERANGE:${e.size}@${e.start}`),u.push(`${i}?id=${a}`)}o&&u.push("#EXT-X-ENDLIST");return u.join("\n")}async writeTrackText(t,e){const a=ze(this.params.outputRoot,t),r=ze(this.params.outputRoot,`${t}.gz`),o=ze(this.params.outputRoot,`${t}.bin`);await Re(a,e,"utf-8"),await $e(a,r);if(await Me(r)>16){const t=(await Se(r,0,15)).toString("base64");await async function(t,e){await new Promise((a,r)=>{const o=i(t,{start:16}),n=s(e);o.pipe(n),n.on("finish",()=>{a(!0)}),o.on("error",t=>{r(t)}),n.on("error",t=>{r(t)})})}(r,o);return{...this.addOne({file_path:o,size:await Me(o)}),hash:t}}return{...this.addOne({file_path:a,size:await Me(a)}),hash:""}}async writeText(t,e){const a=ze(this.params.outputRoot,t);await Re(a,e,"utf-8");return this.addOne({file_path:a,size:await Me(a)})}addOne({file_path:t,size:e,duration:a=0},i=!1){const s=this.getSizeLimit(this.hostType),{current_position:r,group_data:o}=this;if(i&&o[this.current_index]||!(r+e<=s)){this.current_index+=1;const{current_index:i}=this;o[i]?o[i].files.push(t):o[i]={filename:this.getFileName(i),files:[t]};const s=0,r=e-1;return this.current_position=e,{file_index:i,start:s,end:r,duration:a,size:r-s+1}}{const{current_index:i}=this,s=r,n=r+e-1;return this.current_position=n+1,o[i]?o[i].files.push(t):o[i]={filename:this.getFileName(i),files:[t]},{file_index:i,start:s,end:n,duration:a,size:n-s+1}}}async safelyAddOne(t){const e=this.getSizeLimit(this.hostType),{current_position:a}=this;return a+t.size<=e?0===a?(await this.insertSafeFile(),this.addOne(t)):this.addOne(t):(await this.insertSafeFile(),this.addOne(t))}},Ce=class extends pt{async start(){try{if(this.grouperResult)return this.grouperResult;const t={meta:await this.getMetaData(),data:{}},{length:e}=this.params.hosts;for(let a=0;a<e;a++){const i=this.params.hosts[a],s=this.getSizeLimit(i),r=new Le({...this.params,host_type:i,file_size_limit:s,completed_percent:a/e}),o=await r.start();t.data[i]=o}return await this.setGrouperResult(t),t}catch(t){throw Te(t,{message:t.message||"Error occurred during media grouping",detail:t.detail||`Error occurred during media grouping: ${this.params.input.filepath}`})}}async getMetaData(){const t={},e=this.audioTranscoderResult??[],a=this.videoTranscoderResult?[this.videoTranscoderResult]:[];if(a?.length){const e=await this.getMediainfo(),{duration:i}=e?.general;if(a?.length){const{width:e,height:s,framerate:r,bitdepth:o,label:n,codec:h,codec_name:d}=a[0];t.videos=[{duration:i,bitdepth:o,width:e,height:s,framerate:r,label:n,codec:h,codec_name:d}]}}if(e?.length)for(const a of e){const{high:e,adapt:i}=a,{channels:s,lossless:r}=i,o=await this.getMediainfo(),{duration:n}=o?.general,{codec:h,codec_name:d}=i,c={duration:n,channels:s,lossless:r,codec:h,codec_name:d};e&&(c.high={channels:e.channels,codec:e.codec,codec_name:e.codec_name,lossless:e.lossless}),t.audios=t.audios||[],t.audios.push(c)}return t}},Ae=class extends pt{async start(){if(this.db.data.grouper_result)return this.db.data.grouper_result;const t=await this.getMediainfo();if(!t)return;const e=t.video,a=e?.length,i=t.audio,s=i?.length;if(!s&&!a)return;const r=new De(this.params);if(await r.start(),s){const t=new St(this.params);await t.start();const e=new Wt(this.params);await e.start();const a=new le(this.params);await a.start()}if(a){const t=new Dt(this.params);await t.start();const e=new Vt(this.params);await e.start();const a=new se(this.params);await a.start()}const o=new Ce(this.params);await o.start()}async getResult(){return this.db.data.grouper_result}};import{HostType as Oe}from"@soga/types";import{UploadProgress as Ue}from"@soga/node-types";import{parseMediaInfo as Ve}from"@soga/mediainfo";import{getFileSize as Ge,isAudioAdapt as Be,isAudioHigh as je,isVideoSupport as qe}from"@soga/fileutils";import{ensureDir as Xe}from"fs-extra";import Ke from"check-disk-space";import{buildDError as Je}from"@soga/error";var He=class extends C{async start(){this.prepareResult||(await this.checkStorage(),await this.calculateMeta(),await this.calculateProgress())}async checkStorage(){const{length:t}=this.params.hosts,e=await Ke(this.params.outputRoot),a=e.free,i=e.diskPath;if((3+t)*this.params.input.filesize>a)throw Je(new Error(`${i} have no enough computer disk space, please adjust the temporary path in user settings.`),{message:`${i} have no enough computer disk space, please adjust the temporary path in user settings.`,detail:`${i} have no enough computer disk space to process ${this.params.input.filepath}`})}async calculateMeta(){if(this.meta)return this.meta;const{filename:t,local_btime:e,local_ctime:a,local_mtime:i,filesize:s}=this.params.input,r={file:t,size:s,btime:e,ctime:a,mtime:i,md5:""};return await this.setMeta(r),r}async calculateProgress(){if(this.prepareResult)return;const t={[Ue.prepare]:{weight:0,percent:1},[Ue.calculate_md5]:{weight:0,percent:0},[Ue.separate_video]:{weight:0,percent:0},[Ue.separate_audio]:{weight:0,percent:0},[Ue.separate_subtitle]:{weight:0,percent:0},[Ue.transcode_video]:{weight:0,percent:0},[Ue.transcode_audio]:{weight:0,percent:0},[Ue.transcode_thumbnail]:{weight:0,percent:0},[Ue.transcode_source]:{weight:0,percent:0},[Ue.transcode_txt]:{weight:0,percent:0},[Ue.transcode_img]:{weight:0,percent:0},[Ue.group_media]:{weight:0,percent:0},[Ue.upload_baidu]:{weight:0,percent:0},[Ue.upload_ali]:{weight:0,percent:0},[Ue.end]:{weight:0,percent:0}},e={keep_preview:this.params.keepPreview,keep_source:this.params.keepSource},a=await Ge(this.params.input.filepath);t[Ue.prepare].weight=t[Ue.end].weight=Math.ceil(a/1024/1024/500),t[Ue.calculate_md5].weight=Math.ceil(a/1024/1024/200);let i=0;if(this.isMedia)if(this.params.keepPreview){const s=await Ve(this.params.input.filepath),r=s?.general?.duration??0;if(s.video?.length){const e=s.video[0],{width:a,height:i,codec:r}=e,o=qe(r),{duration:n}=s.general,h=o?n/400:n*(a*i)/1920/1080;t[Ue.separate_video].weight=Math.ceil(h),t[Ue.transcode_video].weight=Math.ceil(.01*n)}if(s.audio?.length){const{duration:e}=s.general;let a=0;s.audio.forEach(t=>{const{codec:i,lossless:s,channels:r}=t,o={high_need:!1,high_transcode:!1,adapt_need:!1,adapt_transcode:!1};Be(i)?r>2?(o.high_need=!0,o.high_transcode=!1,o.adapt_need=!0,o.adapt_transcode=!0):(o.high_need=!1,o.adapt_need=!0,o.adapt_transcode=!1):je(i)?(o.high_need=!0,o.high_transcode=!1,o.adapt_need=!0,o.adapt_transcode=!0):(o.high_need=!1,o.adapt_need=!0,o.adapt_transcode=!1,s&&(o.high_need=!0,o.high_transcode=!0)),o.adapt_need&&(a+=o.adapt_transcode?e/40:5),o.high_need&&(a+=o.high_transcode?e/20:10)}),t[Ue.separate_audio].weight=Math.ceil(a),t[Ue.transcode_audio].weight=Math.ceil(.01*e)}const o=s.video?.length??0,n=s.audio?.length??0;if(o||n){e.keep_preview=!0;const o=(s.text?.length||0)+(this.params.subtitles?.length||0);t[Ue.separate_subtitle].weight=Math.ceil(o),t[Ue.transcode_thumbnail].weight=Math.ceil(.08*r),i+=a,t[Ue.group_media].weight=Math.ceil(a/1024/1024/10)}else e.keep_preview=!1,e.keep_source=!0,i+=a}else e.keep_source=!0,i+=a;else this.isTxt?e.keep_preview?(t[Ue.transcode_txt].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a):this.isImg?e.keep_preview&&(t[Ue.transcode_img].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a);e.keep_source&&(t[Ue.transcode_source].weight=Math.ceil(a/1024/1024/30)),this.params.hosts.includes(Oe.BAIDU)&&(t[Ue.upload_baidu].weight=Math.ceil(i/1024/1024/1)),this.params.hosts.includes(Oe.ALI)&&(t[Ue.upload_ali].weight=Math.ceil(i/1024/1024/2));const s={preview:e.keep_preview,source:e.keep_source};await this.setKeeps(s),await this.setPrepareResult(t)}},Qe=async t=>{await Xe(t.outputRoot);const e=await m(t);try{const a=new He({...t,db:e});return await a.start(),a}catch(t){}};import{UploadProgress as We}from"@soga/node-types";import{createHash as Ze}from"crypto";import{createReadStream as Ye}from"fs-extra";var ta=class extends C{async start(){await this.processFile();return await this.getResult()}async calculateMd5(){if(this.md5)return this.md5;const t=this.params.input.filepath,e=this.params.input.filesize;let a=0;const i=await new Promise((i,s)=>{let r=0;const o=Ze("md5"),n=Ye(t,{highWaterMark:4194304});n.on("data",async t=>{o.update(t),r+=t.length;const i=r/e;r-a>104857600&&(a=r,await this.postProgress({type:We.calculate_md5,percent:Math.min(i,1)}))}),n.on("end",()=>{const t=o.digest("hex");i(t)}),n.on("error",t=>{s(t)})});return i&&await this.setMd5(i),await this.postProgress({type:We.calculate_md5,percent:1}),i}async getResult(){if(this.result)return this.result;const{sourceResult:t,grouperResult:e,imgResult:a,txtResult:i,meta:s,keeps:r}=this,{length:o}=this.params.hosts,n={meta:{preview:r.preview,source:r.source,file:s}};for(let s=0;s<o;s++){const r=this.params.hosts[s];n[r]={max_size:0,parts:[]};const o=t=>{n[r].parts=[...n[r].parts,...t]},h=a?.data[r];if(h){h.cache&&(n[r].cache=h?.cache);const t=h.parts?.map(t=>({...t,preview:!0,source:!1}));t&&o(t),n.meta.img=a.meta,h.img&&(n[r].img=h.img)}const d=i?.data[r];if(d){o((d.parts||[]).map(t=>({...t,preview:!0,source:!1}))),n[r].cache=d.cache,n[r].txt={entrance:d.entrance,pad:i?.meta.pad,pages:i?.meta.pages}}const c=e?.data[r];if(c?.parts){o(c.parts.map(t=>({...t,preview:!0,source:!1}))),n.meta.audios=e.meta.audios,n.meta.videos=e.meta.videos,n[r].cache=c.cache,n[r].media={audios:c.audios,videos:c.videos,subtitles:c.subtitles,thumbnail:c.thumbnail,cover:c.cover}}const l=t?.data[r];if(l?.parts){o(l.parts.map(t=>{let e=!0;return(this.isMedia||this.isTxt)&&(e=!1),{...t,preview:e,source:!0}})),n[r].source={head:t.meta.head,download:l.download}}[...n[r]?.parts].forEach(t=>{t.size>n[r].max_size&&(n[r].max_size=t.size)})}return await this.setResult(n),n}async processFile(){const t="encoder_processed";if(this.db.data[t])return;const e=await Qe(this.params),{keeps:a}=e,i={...this.params,keepPreview:a.preview,keepSource:a.source},s=await this.calculateMd5();if(await this.setMd5(s),i.keepSource){const t=new O(this.params);await t.start()}if(e.isMedia&&i.keepPreview){const t=new Ae(this.params);await t.start()}if(e.isTxt&&i.keepPreview){const t=new tt(this.params);await t.start()}if(e.isImg){const t=new dt(this.params);await t.start()}this.db.data[t]=!0,await this.db.write()}},ea=async e=>{try{const t=await m(e),a=new ta({...e,db:t});return a.start()}catch(a){throw t(a,{message:"Error occurred during file encoding",detail:`Error occurred during file encoding: ${e.input.filepath}`})}};export{ea as encode,Qe as getPrepare};
1
+ import{buildDError as t}from"@soga/error";import{getDb as e}from"@soga/lowdb";import{createHash as a}from"crypto";import{createReadStream as i,createWriteStream as s,existsSync as r,remove as o,stat as n,writeFile as h}from"fs-extra";import{truncate as d}from"fs/promises";import{resolve as c}from"path";import{pipeline as l}from"stream/promises";function p(t){const e=a("md5");return e.update(`${t}`),e.digest("hex")}async function u(t){await new Promise((e,a)=>{(async()=>{const r=c(t.outputRoot,t.filename);await o(r);let n=!1;const h=s(r);h.on("open",()=>{n=!0}).on("error",async t=>{n&&h.close(),await o(r),a(t)});const{length:d}=t.files,l=async(e=0)=>{if(e<d){const a=t.files[e],s=t.files.length;await new Promise((t,e)=>{const d=i(a);d.pipe(h,{end:!s}),d.on("end",()=>{d.close(),t(!0)}),d.on("error",async t=>{d.destroy(),n&&h.close(),await o(r),e(t)})}),await l(e+1)}};await l(0),n&&h.end(),e(!0)})()})}async function g(t,a){const i=p(JSON.stringify({...t,dbName:a})),s="db_unique_key",r=c(t.outputRoot,a),o=await e(r,{});return o.data[s]?o.data[s]!=i&&(o.data={[s]:i},await o.write()):(o.data[s]=i,await o.write()),o}async function m(t){return await g({file_id:t.id,input:{filepath:t.input.filepath,filesize:t.input.filesize},outputRoot:t.outputRoot},"encoder_store.json")}async function w({input_path:t,target_path:e,start:a,end:n}){const h=i(t,{start:a,end:n,highWaterMark:65536}),d=s(e);try{await l(h,d)}catch(t){try{r(e)&&await o(e)}catch(t){console.warn("Failed to clean up incomplete file:",t.message)}throw t}}import{resolve as f}from"path";import{gzip as _,getFileBufferSlice as y}from"@soga/utils";import{getFileSize as b}from"@soga/fileutils";import{buildDError as v}from"@soga/error";import{UploadProgress as P}from"@soga/node-types";import{rename as x,stat as D,writeFile as T}from"fs-extra";import{HostType as z}from"@soga/types";var R=2097152,I={[z.BAIDU]:52428800,[z.ALI]:4294967296},$={[z.BAIDU]:2147483648,[z.ALI]:4294967296};z.BAIDU,z.ALI;import{HostType as M,RecordFtype as S,RecordType as k}from"@soga/types";import{calculateMd4 as F,calculateMd5 as E,calculateSha1 as N}from"@soga/utils";import{parentPort as C}from"worker_threads";var L=class{segmentNames={};params;id;port=null;db;get lowData(){return this.db.data}get isVideo(){return this.params.type==k.VIDEO}get isAudio(){return this.params.type==k.AUDIO}get isMedia(){return this.isAudio||this.isVideo}get isTxt(){return this.params.type==k.DOC&&this.params.ftype==S.DOC_TXT}get isImg(){return this.params.type==k.IMAGE}getSizeLimit(t){return this.params.is_shop_space?$[t]||2147483648:I[t]||52428800}getFilesize(){return this.params.input.filesize}constructor(t){this.params=t,this.id=t.id,this.port=t.port??null,this.db=t.db}async getPartInfo({host_type:t,filepath:e,start:a,end:i,filename:s,index:r},o=!0){const n={start:a,end:i,size:i-a+1,path:e,index:r,file:s,md5:o?await E({file:e,start:a,end:i}):""};if(o){if(t===M.BAIDU){const t=await F({file:e,start:a,end:i});n.md4=t}if(t===M.ALI){const t=await N({file:e,start:a,end:i});n.sha1=t}}return n}async getStore(t){const{id:e,input:a,outputRoot:i}=this.params;return await g({file_id:e,input:{filepath:a.filepath,filesize:a.filesize},outputRoot:i},t)}async postProgress(t){const e={step:t.type,percent:t.percent};await this.postMessage({id:this.id,type:"percent",data:e})}async postMessage(t){this.port?this.port.postMessage(t):C&&C.postMessage(t)}async setKeeps(t){this.lowData.keeps=t,await this.db.write()}get keeps(){return this.lowData.keeps}async setMeta(t){this.lowData.meta=t,await this.db.write()}get meta(){return this.lowData.meta}async setSourceResult(t){this.lowData.source_result=t,await this.db.write()}get sourceResult(){return this.lowData.source_result}async setPrepareResult(t){this.lowData.prepare_result=t,await this.db.write()}get prepareResult(){return this.lowData.prepare_result}async setMd5(t){this.lowData.meta.md5=t,await this.db.write()}get md5(){return this.lowData.meta.md5}async setSubtitleEncoderResult(t){this.lowData.subtitle_encoder_result=t,await this.db.write()}get subtitleEncoderResult(){return this.lowData.subtitle_encoder_result}async setAudioSeparatorResult(t){this.lowData.audio_separator_result=t,await this.db.write()}get audioSeparatorResult(){return this.lowData.audio_separator_result}async setAudioTranscoderResult(t){this.lowData.audio_transcoder_result=t,await this.db.write()}get audioTranscoderResult(){return this.lowData.audio_transcoder_result}async setCoverResult(t){this.lowData.cover_result=t,await this.db.write()}get coverResult(){return this.lowData.cover_result}async setVideoTranscoderResult(t){this.lowData.video_transcoder_result=t,await this.db.write()}get videoTranscoderResult(){return this.lowData.video_transcoder_result}async setVideoThumbnailerResult(t){this.lowData.video_thumbnailer_result=t,await this.db.write()}get videoThumbnailerResult(){return this.lowData.video_thumbnailer_result}async setGrouperResult(t){this.lowData.grouper_result=t,await this.db.write()}get grouperResult(){return this.lowData.grouper_result}async setImgResult(t){this.lowData.img_result=t,await this.db.write()}get imgResult(){return this.lowData.img_result}async setTxtResult(t){this.lowData.txt_result=t,await this.db.write()}get txtResult(){return this.lowData.txt_result}async setResult(t){this.lowData.result=t,await this.db.write()}get result(){return this.lowData.result}_syncGetId({file:t,start:e,end:a},i){const s=`${i}_key_index`,r=`${i}_key_map`,o=`${t}_${e||0}_${a||0}`,n=this.db.data[r]||{};if(n[o])return n[o];this.db.data[s]=this.db.data[s]||0,this.db.data[r]=this.db.data[r]||{};const h=this.db.data[s]+1,d=`id_${h}`;return this.db.data[r][o]=d,this.db.data[s]=h,d}_syncSetIdMap({id:t,file:e,start:a,end:i},s,r){const o=`${s}_${r}_id_map`;this.db.data[o]=this.db.data[o]||{},this.db.data[o][t]={f:e,s:a,e:i}}},A=class extends L{syncGetSourceId(t){return this._syncGetId(t,"source")}async getSourceId(t){const e=this.syncGetSourceId(t);return await this.db.write(),e}getSourceIdMap(t){return this.db.data[`source_${t}_id_map`]||{}}syncSetSourceIdMap(t,e){this._syncSetIdMap(t,"source",e)}async setSourceIdMap(t,e){this.syncSetSourceIdMap(t,e),await this.db.write()}getSourceSegmentName=(t,e)=>{const a=this.params.is_attachment?"attachment":"file",i=`source_${e}_${a}_${t}`;if(this.segmentNames[i])return this.segmentNames[i];const s=`s-${p(`source-${e}-${a}-${this.md5}-${t}`)}`;return this.segmentNames[i]=s,s}},O=class extends A{head_size=32;getZipFilePath(){return f(this.params.outputRoot,"souce_zip.bin")}getDownloadListFileName(t){return`source_${t}_download_list.json`}getPartName(t,e){return this.getSourceSegmentName(e,t)}getPartPath(t,e){return f(this.params.outputRoot,this.getPartName(t,e))}get dbData(){return this.db.data}async setPartList(t,e){const a=`source_${t}_part_list`;this.dbData[a]=e,await this.params.db.write()}getPartList(t){const e=`source_${t}_part_list`;return this.dbData[e]}async setDownloadMap(t,e){const a=`source_${t}_download_map`;this.dbData[a]=e,await this.params.db.write()}getDownloadMap(t){const e=`source_${t}_download_map`;return this.dbData[e]}async sendProgress(t){await this.postProgress({type:P.transcode_source,percent:t})}async setDownloadList(t,e){const a=`source_${t}_download_list`;this.dbData[a]=e,await this.params.db.write()}getDownloadList(t){const e=`source_${t}_download_list`;return this.dbData[e]}async start(){try{if(this.sourceResult)return await this.sendProgress(1),this.sourceResult;await this.gzip();const{length:t}=this.params.hosts;for(let e=0;e<t;e++){const t=this.params.hosts[e];await this.calculatePartList(t),await this.processDownloadMap(t)}await this.sendProgress(.9);const e=await this.getResult();return await this.sendProgress(1),e}catch(t){throw v(t,{message:"Error occurred during source encoding",detail:`Error occurred during source encoding: ${this.params.input.filepath}`})}}async gzip(){if(this.dbData.source_gziped)return;const t=this.params.input.filepath,e=this.getZipFilePath();await _(t,e,async({percent:t})=>{await this.sendProgress(.6*t)}),this.dbData.source_gziped=!0,await this.params.db.write()}async getResult(){if(this.sourceResult)return this.sourceResult;const t={meta:await this.getMetaData(),data:{}},{length:e}=this.params.hosts;for(let a=0;a<e;a++){const e=this.params.hosts[a],i=this.getPartList(e),s=this.getDownloadMap(e);t.data[e]={download:s,parts:i}}return await this.setSourceResult(t),t}async getMetaData(){const t="source_meta",e=this.dbData[t];if(e)return e;const a=this.getZipFilePath(),i=await b(a),s={path:a,start:0,end:0},{head_size:r}=this;s.end=i<=r?i-1:r-1;const o={head:(await y(s.path,s.start,s.end)).toString("base64")};return this.dbData[t]=o,await this.params.db.write(),o}async writeDownloadListFile(t,e){const a=this.getDownloadListFileName(t),i=f(this.params.outputRoot,a);await T(i,e,"utf-8");return{file_path:i,size:await b(i)}}async processDownloadMap(t){const e=this.getDownloadMap(t);if(e)return e;const a=this.getDownloadList(t);let r;const{file_path:o,size:n}=await this.writeDownloadListFile(t,JSON.stringify(a)),h=this.getSizeLimit(t),d=this.getPartList(t);if(d.length){const e=d[d.length-1],{path:a,size:c,file:p,index:u,end:g,start:m}=e,w=f(this.params.outputRoot,p);if(c+n<=h){await async function({source1:t,source2:e,target:a}){const r=i(t.filepath,{start:t.start,end:t.end}),o=s(a);await l(r,o);const n=i(e),h=s(a,{flags:"a"});await l(n,h)}({source1:{filepath:a,start:m,end:g},source2:o,target:w});const e=(await D(w)).size,h=e-1,c=e-n,f=await this.getPartInfo({host_type:t,filepath:w,start:0,end:e-1,filename:p,index:u});d[d.length-1]=f;r={id:await this.getSourceId({file:p,start:c,end:h}),file:p,start:c,end:h}}else{const e=u+1,a=this.getPartName(t,e),i=this.getPartPath(t,e);await x(o,i);const s=await this.getSourceId({file:a,start:0,end:n-1}),h=await this.getPartInfo({host_type:t,filepath:i,start:0,end:n-1,filename:a,index:e});d.push(h),r={id:s,file:a,start:0,end:n-1}}return await this.setPartList(t,d),await this.setDownloadMap(t,r),r}}async calculatePartList(t){const e=`source_${t}_list_calculated`;if(this.dbData[e])return;const a=this.getZipFilePath(),i=await b(a),s=[],r=this.getSizeLimit(t),{head_size:o}=this,n=[];if(i>o){let e=0;for(let h=o;h<=i-1;h+=r){const o=Math.min(h+r-1,i-1),d=this.getPartName(t,e),c=await this.getPartInfo({host_type:t,filepath:a,start:h,end:o,filename:d,index:e});let l=0;for(let t=h;t<o;t+=R){const e=Math.min(t+R-1,o),a=e-t+1,i=l+a-1,s=await this.getSourceId({file:"source_zip",start:t,end:e});n.push({id:s,file:d,start:l,end:i}),l+=a}s.push(c),e++}}await this.setPartList(t,s),await this.setDownloadList(t,n),this.dbData[e]=!0,await this.db.write()}};import{resolve as U}from"path";import{createWriteStream as V,readFile as G,remove as B}from"fs-extra";import{getFileBufferSlice as j}from"@soga/utils";import q from"zlib";import{saveFileAsUtf8 as X}from"@soga/utils";import{buildDError as K}from"@soga/error";import{UploadProgress as H}from"@soga/node-types";import{resolve as J}from"path";import{getFileSize as Q}from"@soga/fileutils";import{copy as W,writeFile as Z}from"fs-extra";var Y=class extends L{get preview_common_db_data(){return this.db.data}async getCurrentFileIndex(t){const e=this.db.data[`preview_${t}_current_index`];return"number"!=typeof e?(this.db.data[`preview_${t}_current_index`]=0,await this.db.write(),0):e}async increaseCurrentFileIndex(t){const e=await this.getCurrentFileIndex(t)+1;return this.db.data[`preview_${t}_current_index`]=e,await this.db.write(),e}getPartName(t,e){return this.getPreviewSegmentName(e,t)}getPartPath(t,e){return J(this.params.outputRoot,this.getPartName(t,e))}syncGetPreviewId(t){return this._syncGetId(t,"preview")}async getPreviewId(t){const e=this.syncGetPreviewId(t);return await this.db.write(),e}getPreviewIdMap(t){return this.db.data[`preview_${t}_id_map`]||{}}syncSetPreviewIdMap(t,e){this._syncSetIdMap(t,"preview",e)}async setPreviewIdMap(t,e){this.syncSetPreviewIdMap(t,e),await this.db.write()}getPreviewSegmentName=(t,e)=>{const a=this.params.is_attachment?"attachment":"file",i=`preview_${e}_${a}_${t}`;if(this.segmentNames[i])return this.segmentNames[i];const s=`p-${p(`preview-${e}-${a}-${this.md5}-${t}`)}`;return this.segmentNames[i]=s,s};async calculatePartList(t,e){const a=[],i=await this.getCurrentFileIndex(t);for(let s=0;s<i+1;s++){const i=this.getPartName(t,s),r=this.getPartPath(t,s),o=await Q(r),n=await this.getPartInfo({host_type:t,filename:i,filepath:r,index:s,start:0,end:o-1},e);a.push(n)}return a}getPartListKey(t){return`preview_${t}_part_list`}async completePartList(t){const e=await this.getPartList(t);if(e){const a=[];for(const i of e)if(i.md5)a.push(i);else{const e=await this.getPartInfo({filename:i.file,filepath:i.path,start:i.start,end:i.end,host_type:t,index:i.index},!0);a.push(e)}await this.setPartList(t,a)}}async getPartList(t){const e=this.getPartListKey(t),a=this.preview_common_db_data[e];if(a)return a}async setPartList(t,e){const a=this.getPartListKey(t);this.preview_common_db_data[a]=e,await this.db.write()}async attachCacheData(){const{hosts:t}=this.params;for(const e of t)await this.attachHostCacheData(e),await this.completePartList(e)}getCacheInfo(t){const e=`preview_${t}_cache_info`;return this.preview_common_db_data[e]}async writeCacheFile(t,e){const a=`preview_${t}_cache_info.txt`,i=J(this.params.outputRoot,a);await Z(i,e,"utf-8");return{file_path:i,size:await Q(i)}}async setCacheInfo(t,e){const a=`preview_${t}_cache_info`;this.preview_common_db_data[a]=e,await this.db.write()}async attachHostCacheData(t){if(this.getCacheInfo(t))return;const e=await this.getPartList(t),a=this.getPreviewIdMap(t),{file_path:r,size:o}=await this.writeCacheFile(t,JSON.stringify(a)),h=this.getSizeLimit(t);if(e.length){const a=e[e.length-1],{path:c,size:p,file:u,index:g,end:m}=a;let w;if(p+o<=h){await async function({filepath:t,size:e},a){(await n(t)).size>e&&await d(t,e);const r=i(a),o=s(t,{flags:"a"});await l(r,o)}({filepath:c,size:p},r);const a=await Q(c),h=await this.getPartInfo({host_type:t,filename:u,filepath:c,index:g,start:0,end:a-1});e[e.length-1]=h;const f=m+1,_=m+o;w={id:await this.getPreviewId({file:u,start:f,end:_}),file:u,start:f,end:_}}else{const a=g+1,i=this.getPartName(t,a),s=this.getPartPath(t,a);await W(r,s);const n=await this.getPreviewId({file:i,start:0,end:o-1}),h=await this.getPartInfo({host_type:t,filename:i,filepath:s,index:a,start:0,end:o-1},!1);e.push(h),await this.setPartList(t,e),w={id:n,file:i,start:0,end:o-1}}w&&await this.setCacheInfo(t,w)}}},tt=class extends Y{content_size_1=81920;content_size_2=102400;totalPage=1;hashBuffer=Buffer.from("dpan");get hashBufferLength(){return this.hashBuffer.length}getU8FileName(){return`text_utf8_${this.params.id}.txt`}getU8FilePath(){return U(this.params.outputRoot,this.getU8FileName())}async sendProgress(t){await this.postProgress({type:H.transcode_txt,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.dbData.txt_result)return await this.sendProgress(1),this.dbData.txt_result;await this.txtConvertToUtf8File(),await this.sendProgress(.2);const{length:t}=this.params.hosts;for(let e=0;e<t;e++){const a=this.params.hosts[e];await this.txtConvertToGzipFile(a),await this.sendProgress(.2+(e+1)/t*.6)}await this.attachCacheData();const e=await this.getResult();return await this.clean(),await this.sendProgress(1),e}catch(t){throw K(t,{message:"Error occurred during txt encoding",detail:`Error occurred during txt encoding: ${this.params.input.filepath}`})}}async getResult(){if(this.txtResult)return this.txtResult;const t={meta:{pad:this.hashBufferLength,pages:this.totalPage},data:{}};for(const e of this.params.hosts)t.data[e]={cache:this.getCacheInfo(e),parts:await this.getPartList(e),entrance:await this.getEntranceInfo(e)};return await this.setTxtResult(t),t}async clean(){try{if(this.params.debug)return;const t=this.getU8FilePath();await B(t)}catch(t){}}async setEntranceInfo(t,e){const a=`txt_${t}_entrance`;this.dbData[a]=e,await this.db.write()}async getEntranceInfo(t){const e=`txt_${t}_entrance`,a=this.dbData[e];if(a)return a}async txtConvertToUtf8File(){if(this.dbData.txt_utf8_converted)return;const t=this.params.input.filepath,e=this.getU8FilePath();await X(t,e),this.dbData.txt_utf8_converted=!0,await this.db.write()}async txtConvertToGzipFile(t){if(await this.getEntranceInfo(t))return;const e=this.getSizeLimit(t),a=this.getU8FilePath(),i=await this.calculateSlice(),{length:s}=i,r={};let o=0,n=V(this.getPartPath(t,await this.getCurrentFileIndex(t)));for(let h=0;h<s;h++){const d=h==s-1?0:h+1,c=i[d],{index:l,start:p,end:u}=c,g={page:l+1,text:(await j(a,p,u)).toString("utf8")},m=JSON.stringify(g);let w=Buffer.from(m,"utf8");if(0==d){const t={...g,map:r};w=Buffer.from(JSON.stringify(t),"utf8")}const f=await this.getPreviewId({file:"u8zip",start:p,end:u});await new Promise((a,i)=>{q.gzip(w,async(s,h)=>{if(s)return i(s);const c=h.length<this.hashBufferLength?this.hashBuffer:h.subarray(0,this.hashBufferLength),l=Buffer.concat([c,h]),p=l.length;if(o+p>e){n.end();const e=await this.increaseCurrentFileIndex(t);n=V(this.getPartPath(t,e)),o=0}const u=o,g=o+p-1;if(n.write(l),o+=p,0==d){n.end();const e={id:f,start:u,end:g,file:this.getPartName(t,await this.getCurrentFileIndex(t))};await this.setEntranceInfo(t,e)}else r[`p_${d+1}`]={id:f,f:this.getPartName(t,await this.getCurrentFileIndex(t)),s:u,e:g};this.syncSetPreviewIdMap({id:f,file:this.getPartName(t,await this.getCurrentFileIndex(t)),start:u,end:g},t),a(!0)})})}await this.db.write();const h=await this.calculatePartList(t,!1);await this.setPartList(t,h)}async calculateSlice(){if(this.dbData.txt_slice_list)return this.dbData.txt_slice_list;const t=this.getU8FilePath(),e=await new Promise((e,a)=>{G(t,"utf8",(t,i)=>{if(t)return void a(t);const s=this.content_size_1,r=this.content_size_2,o=[];let n=0,h=0,d=0;for(;h<i.length;){let t=Math.min(h+r,i.length);const e=Math.min(h+s,i.length),a=i.slice(e,t-1).indexOf("#");-1!==a&&(t=e+a);const c=i.slice(h,t),l=Buffer.byteLength(c);o.push({index:n++,start:d,end:d+l-1}),this.totalPage=n,h=t,d+=l}e(o)})});return this.dbData.txt_slice_list=e,await this.db.write(),e}};import{resolve as et}from"path";import{getMetadata as at,compress as it}from"@soga/imgutils";import{gzip as st}from"@soga/utils";import{getFileSize as rt}from"@soga/fileutils";import{buildDError as ot}from"@soga/error";import{UploadProgress as nt}from"@soga/node-types";import{remove as ht}from"fs-extra";var dt=class extends Y{getCompressFileName(){return"img_compress.jpg"}getCompressFilePath(){return et(this.params.outputRoot,this.getCompressFileName())}getGzFileName(){return"compressed_img.zip"}getGzFilePath(){return et(this.params.outputRoot,this.getGzFileName())}async sendProgress(t){await this.postProgress({type:nt.transcode_img,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.imgResult)return await this.sendProgress(1),this.imgResult;await this.compress(),await this.sendProgress(.1),await this.gzip(),await this.sendProgress(.4);const{hosts:t}=this.params,{length:e}=t;for(let a=0;a<e;a++){const e=t[a];await this.splitFile(e),await this.calculatePartList(e,!1)}await this.attachCacheData(),await this.sendProgress(.9);const a=await this.getResult();return await this.clean(),await this.sendProgress(1),a}catch(t){throw ot(t,{message:"Error occurred during image encoding",detail:`Error occurred during image encoding: ${this.params.input.filepath}`})}}getCacheInfoFileName(t){return`img_${t}_cache.json`}async getResult(){if(this.imgResult)return this.imgResult;const{input:t}=this.params,e=t.filepath,{width:a,height:i}=await at(e),s=this.getCompressFilePath(),{width:r,height:o}=await at(s),n=await rt(s),h={meta:{width:a,height:i,size:t.filesize,t_width:r,t_height:o,t_size:n},data:{}},{length:d}=this.params.hosts;for(let t=0;t<d;t++){const e=this.params.hosts[t],a=await this.getPartList(e),i=this.getPreviewList(e);h.data[e]={img:{preview:i},cache:this.getCacheInfo(e),parts:a}}return await this.setImgResult(h),h}async clean(){try{if(this.params.debug)return;const t=this.getCompressFilePath();await ht(t)}catch(t){}}async compress(){if(this.dbData.img_compressed)return;const t=this.getCompressFilePath();await it({ffmpeg_path:this.params.ffmpegPath,input_path:this.params.input.filepath,output_path:t}),this.dbData.img_compressed=!0,await this.db.write()}async gzip(){if(this.dbData.img_gziped)return;const t=this.getCompressFilePath(),e=this.getGzFilePath();await st(t,e),this.dbData.img_gziped=!0,await this.db.write()}async setPreviewList(t,e){const a=`img_${t}_preview_list`;this.dbData[a]=e,await this.db.write()}getPreviewList(t){const e=`img_${t}_preview_list`;return this.dbData[e]}async splitFile(t){if(this.getPreviewList(t))return;const e=this.getGzFilePath(),a=await rt(e),i=this.getSizeLimit(t),s=[],r=[];for(let o=0;o<=a-1;o+=i){0!=o&&await this.increaseCurrentFileIndex(t);const n=Math.min(o+i-1,a-1),h=await this.getCurrentFileIndex(t),d=this.getPartName(t,h),c=this.getPartPath(t,h);await w({input_path:e,target_path:c,start:o,end:n});const l=0,p=n-o,u=await this.getPartInfo({host_type:t,filepath:c,filename:d,start:l,end:p,index:h},!1);s.push(u);const g=await this.getPreviewId({file:d,start:l,end:p});r.push({id:g,file:d,start:l,end:p}),await this.setPreviewIdMap({id:g,file:d,start:l,end:p},t)}await this.setPartList(t,s),await this.setPreviewList(t,r)}};import ct from"fluent-ffmpeg";import{spawn as lt}from"child_process";import{parseMediaInfo as pt}from"@soga/mediainfo";var ut=class extends Y{async getMediainfo(){const{mediainfo:t}=this.db.data;if(t)return t;const e=this.params.input.filepath,a=await pt(e);return this.db.data.mediainfo=a,await this.params.db.write(),a}constructor(t){super(t),ct.setFfmpegPath(t.ffmpegPath)}getFluent(){return ct()}async ffmpeg(t,e){const a=this.params.ffmpegPath;return await new Promise((i,s)=>{const r=lt(a,t,Object.assign({stdio:"ignore"},e));r.on("close",t=>{i(t)}),r.on("error",t=>{s(t)})})}};import{resolve as gt}from"path";import{isValidFile as mt,isVideoSupport as wt}from"@soga/fileutils";import{UploadProgress as ft}from"@soga/node-types";import{buildDError as _t}from"@soga/error";var yt=({type:t,track_order:e,quality:a})=>`audio-${e}-${a}-${t}.${"manifest"===t?"m3u8":"mp4"}`,bt=({width:t,height:e})=>`video-formatted-${t}-${e}.mp4`,vt=t=>`grouper_result_${t}`,Pt=t=>{let e=0,a=0,i=0;t.segments.forEach(t=>{a+=t.duration,e+=t.size;const s=8*t.size/t.duration;s>i&&(i=s)});const s=8*e/a;return{bandwidth:Math.ceil(i),average_bandwidth:Math.ceil(s)}},xt=(t,e)=>{if("number"==typeof t.percent)return t.percent/100;return function(t){const e=t.split(":").map(parseFloat),[a=0,i=0,s=0]=e.reverse();return 3600*s+60*i+a}(t.timemark)/e};var Dt=class extends ut{async start(){try{await this.separateVideo(),await this.postProgress({type:ft.separate_video,percent:1})}catch(t){throw _t(t,{message:"Error occurred during video separation",detail:`Error occurred during video separation: ${this.params.input.filepath}`})}}async separateVideo(){const t="video_separated";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],i=bt({width:a.width,height:a.height}),s=gt(this.params.outputRoot,i),r=wt(a.codec),o=["-sn","-an","-map","0:v:0"];let n="copy";r||(n=a.width*a.height>=2073600?"libx265":"libx264","libx265"==n&&o.push("-pix_fmt","yuv420p")),o.push("-c:v",n);const h=a.duration;o.push("-y"),await new Promise((t,e)=>{const a=this.getFluent().input(this.params.input.filepath).outputOptions(o).on("progress",async t=>{if(!r&&t.frames){const e=xt(t,h);await this.postProgress({type:ft.separate_video,percent:e})}}).on("end",async()=>{t("end"),a.kill("SIGKILL")}).on("error",async t=>{e(t)}).output(s);a.run()});if(!await mt(s))throw new Error("Separate Video track failed");this.db.data[t]=!0,await this.params.db.write()}};import{resolve as Tt}from"path";import{isValidFile as zt,isAudioAdapt as Rt,isAudioHigh as It}from"@soga/fileutils";import{UploadProgress as $t}from"@soga/node-types";import{buildDError as Mt}from"@soga/error";var St=class extends ut{async start(){try{await this.separateTracks(),await this.postProgress({type:$t.separate_audio,percent:1})}catch(t){throw Mt(t,{message:"Error occurred during audio separation",detail:`Error occurred during audio separation: ${this.params.input.filepath}`})}}async separateTracks(){if(this.audioSeparatorResult)return;const t=await this.getMediainfo();if(!t?.audio?.length)return;const{audio:e}=t,a=e.length,i=[];for(let t=0;t<a;t++){const s=e[t],{codec:r,channels:o,lossless:n}=s,h={adapt:{need:!0,codec:"",channels:Math.min(o,2)},high:{need:!1,codec:"flac",channels:0}};Rt(r)?o>2?(h.high.need=!0,h.high.codec="copy",h.adapt.codec=r,h.adapt.need=!0):(h.adapt.need=!0,h.adapt.codec="copy",h.adapt.channels=0):It(r)?(h.high.need=!0,h.high.codec="copy",h.adapt.need=!0,h.adapt.codec="aac"):(h.adapt.need=!0,h.adapt.codec="aac",n&&(h.high.need=!0,h.high.codec="flac")),h.adapt.need&&await this.separateAudioTrack(t,{type:"adapt",codec:h.adapt.codec,tracks:a,channels:h.adapt.channels,need_adapt:!0,need_high:h.high.need}),h.high.need&&await this.separateAudioTrack(t,{type:"high",codec:h.high.codec,tracks:a,channels:h.high.channels,need_adapt:h.adapt.need,need_high:!0}),i.push(h)}await this.setAudioSeparatorResult(i)}async separateAudioTrack(t,e){const a=`audio_separated_${t}_${e.type}`;if(this.db.data[a])return;const i=await this.getMediainfo();if(!i?.audio?.length)return;const s=i.audio[t];if(!s)return;const r=s?.duration??i.general?.duration,o=yt({type:"formatted",track_order:t,quality:e.type}),n=Tt(this.params.outputRoot,o),h=["-sn","-vn","-map",`0:a:${t}`];e.codec&&h.push("-c:a",e.codec),e.channels&&h.push("-ac",e.channels.toString()),h.push("-y"),await new Promise((a,i)=>{const s=this.getFluent().input(this.params.input.filepath).outputOptions(h).on("progress",async a=>{if("copy"!=e.codec){const i=xt(a,r);let s=t;"adapt"==e.type?e.need_high?s+=1/3*i:s+=i:e.need_adapt?(s+=1/3,s+=2/3*i):s+=i;const o=s/e.tracks;await this.postProgress({type:$t.separate_audio,percent:o})}}).on("end",async()=>{a("end"),s.kill("SIGKILL")}).on("error",async t=>{i(t)}).output(n);s.run()});if(!await zt(n))throw new Error(`Separate audio track failed: [track_order:${t}, track_quality ${e.type}] `);if("copy"==e.codec){let a=t;"adapt"==e.type&&e.need_high?a+=1/3:a+=1;const i=a/e.tracks;await this.postProgress({type:$t.separate_audio,percent:i})}this.db.data[a]=!0,await this.params.db.write()}};import{resolve as kt}from"path";import{parseMediaInfo as Ft}from"@soga/mediainfo";import{getMp4boxInfo as Et}from"@soga/mp4box";import{parseM3U8 as Nt}from"@soga/m3u8";import{UploadProgress as Ct}from"@soga/node-types";import{isValidFile as Lt,getStandardInfo as At}from"@soga/fileutils";import{remove as Ot}from"fs-extra";import{buildDError as Ut}from"@soga/error";var Vt=class extends ut{getVideoInitName({width:t,height:e}){return`video-init-${t}-${e}.mp4`}getVideoManifestName({width:t,height:e}){return`video-hls-${t}-${e}.m3u8`}async start(){try{await this.transcodeVideo(),await this.saveData(),await this.postProgress({type:Ct.transcode_video,percent:1})}catch(t){throw Ut(t,{message:"Error occurred during video transcoding",detail:`Error occurred during video transcoding: ${this.params.input.filepath}`})}}async saveData(){const t=await this.getMediainfo();if(!t?.video?.length)return;if(this.videoTranscoderResult)return;const{width:e,height:a}=t.video[0],i=bt({width:e,height:a}),s=kt(this.params.outputRoot,i),r=this.getVideoManifestName({width:e,height:a}),o=kt(this.params.outputRoot,r),n=await Nt(o),{videos:h}=await Et(s),{codec:d}=h[0],{bandwidth:c,average_bandwidth:l}=Pt(n),p=(await Ft(s)).video[0],u=At(e,a),g={m3u8:n,m3u8_path:o,codec:d,width:e,height:a,bandwidth:c,average_bandwidth:l,bitdepth:p?.bitdepth,bitrate:p?.bitrate,codec_name:p?.codec??"",framerate:p?.framerate,label:u?.label??"unknown"};await this.setVideoTranscoderResult(g),this.params.debug||await Ot(s)}async transcodeVideo(){const t="video_transcode_state";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],i={width:a.width,height:a.height},s=bt(i),r=this.getVideoInitName(i),o=this.getVideoManifestName({width:a.width,height:a.height}),n=["-i",s,"-an","-sn","-c:v","copy","-hls_list_size","0","-hls_time","6","-hls_segment_type","fmp4","-hls_fmp4_init_filename",r,"-y",o];await this.ffmpeg(n,{cwd:this.params.outputRoot});const h=kt(this.params.outputRoot,o);if(!await Lt(h))throw new Error("Transcode video track failed");this.db.data[t]=!0,await this.db.write()}};import{resolve as Gt}from"path";import{getFileSize as Bt,isValidFile as jt}from"@soga/fileutils";import{getMp4boxInfo as qt}from"@soga/mp4box";import{parseM3U8 as Xt}from"@soga/m3u8";import{parseMediaInfo as Kt}from"@soga/mediainfo";import{remove as Ht}from"fs-extra";import{buildDError as Jt}from"@soga/error";import{UploadProgress as Qt}from"@soga/node-types";var Wt=class extends ut{async start(){try{await this.transcodeAudios(),await this.saveData()}catch(t){throw Jt(t,{message:"Error occurred during audio transcoding",detail:`Error occurred during audio transcoding: ${this.params.input.filepath}`})}}async saveData(){if(this.audioTranscoderResult)return;const t=await this.getMediainfo();if(!t?.audio?.length)return;const e=t.audio.length,a=this.audioSeparatorResult,i=[],s={};for(let t=0;t<e;t++){const e=a[t];e.adapt.need&&(s.adapt=await this.getQualityData({track_order:t,quality:"adapt"})),e.high.need&&(s.high=await this.getQualityData({track_order:t,quality:"high"})),i.push(s)}await this.setAudioTranscoderResult(i);try{if(this.params.debug)return;for(let t=0;t<e;t++){const e=a[t];if(e.adapt.need){const e=yt({type:"formatted",track_order:t,quality:"adapt"}),a=Gt(this.params.outputRoot,e);await Ht(a)}if(e.high.need){const e=yt({type:"formatted",track_order:t,quality:"high"}),a=Gt(this.params.outputRoot,e);await Ht(a)}}}catch(t){}}async getQualityData({track_order:t,quality:e}){const a=yt({type:"formatted",track_order:t,quality:e}),i=Gt(this.params.outputRoot,a),s=await Kt(i);if(!s.audio?.length)throw new Error("parse mediainfo failed!");const r=s.audio[0],o=yt({type:"manifest",track_order:t,quality:e}),n=await Bt(i),h=Gt(this.params.outputRoot,o),d=await qt(i),{audios:c}=d,{language:l,codec:p}=c[0],u=l&&!l.startsWith("un")?{language:l}:void 0,g=await Xt(h),{bandwidth:m,average_bandwidth:w}=Pt(g);return{m3u8:g,m3u8_path:h,codec:p,codec_name:r.codec,...u,order:t,lossless:r.lossless,channels:r.channels,bandwidth:m,size:n,average_bandwidth:w}}async transcodeAudios(){const t="audio_transcoded";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.audio?.length)return;const a=e.audio.length,i=this.audioSeparatorResult;for(let t=0;t<a;t++){const e=i[t];e.adapt.need&&await this.transcodeAudio(t,{...e.adapt,type:"adapt"}),e.high.need&&await this.transcodeAudio(t,{...e.high,type:"high"});const s=(t+1)/a;await this.postProgress({type:Qt.transcode_audio,percent:s})}await this.postProgress({type:Qt.transcode_audio,percent:1}),this.db.data[t]=!0,await this.db.write()}async transcodeAudio(t,e){const a=`audio-transcoded-${t}-${e.type}`;if(this.db.data[a])return;const i=yt({type:"formatted",track_order:t,quality:e.type}),s=yt({type:"init",track_order:t,quality:e.type}),r=yt({type:"manifest",track_order:t,quality:e.type}),o=["-i",i,"-vn","-sn","-c:a","copy","-hls_list_size","0","-hls_time","6","-hls_segment_type","fmp4","-hls_fmp4_init_filename",s,"-y",r];await this.ffmpeg(o,{cwd:this.params.outputRoot});const n=Gt(this.params.outputRoot,r);if(!await jt(n))throw new Error(`Transcode audio track failed: [track_order:${t}, track_quality ${e.type}] `);this.db.data[a]=!0,await this.db.write()}};import{resolve as Zt}from"path";import{getFileSize as Yt}from"@soga/fileutils";import{combine as te}from"@soga/imgutils";import{copy as ee}from"fs-extra";import{UploadProgress as ae}from"@soga/node-types";import{buildDError as ie}from"@soga/error";var se=class extends ut{m3u8_data=null;thumbnail_duration=30;thumbnail_group=[];row=8;col=8;screenshot_width=480;screenshot_height=270;getScreenshotName(t){return`video_screenshot_${t}.jpg`}getTileName(t){return`video_tile_${t}.jpg`}getCoverName(){return"video_cover.jpg"}async updateImagePercent(t,e){const a="screenshot"==e?6*t/7:t/7+6/7;await this.postProgress({type:ae.transcode_thumbnail,percent:a})}store;async initStore(){this.store=await this.getStore("thumbnail_store.json")}async start(){if(!this.videoThumbnailerResult)try{const t=await this.getMediainfo();if(!t?.video?.length)return;if(await this.init(),!this.m3u8_data)return;await this.generateScreenshots(),await this.generateTiles(),await this.saveCoverInfo(),await this.saveThumbnailInfo()}catch(t){throw ie(t,{message:"Error occurred during video thumbnail generation",detail:`Error occurred during video thumbnail generation: ${this.params.input.filepath}`})}}async init(){await this.initStore(),await this.initScreenshotSize(),await this.initM3U8Data(),await this.initThumbnailDuration(),await this.initThumbnailGroup()}async saveThumbnailInfo(){if(this.videoThumbnailerResult)return;const{col:t,row:e,thumbnail_group:a,screenshot_width:i,screenshot_height:s}=this,r=a.length,o=[],n=[];for(let h=0;h<r;h++){const r=a[h],d=r.start_time,c=r.end_time,l=Math.floor(h/(e*t)),p=h%e*i,u=Math.floor(h%(t*e)/e)*s,g=this.getTileName(l);n.push(g),o.push({file:g,st:d,et:c,x:p,y:u,w:i,h:s})}const h=[...new Set(n)],d=h.length,c=[];for(let t=0;t<d;t++){const e=h[t],a=Zt(this.params.outputRoot,e),i=await Yt(a);c.push({file:e,file_path:a,size:i})}const l={width:this.screenshot_width,height:this.screenshot_height,row:this.row,col:this.col,tile_list:c,sprite_list:o};await this.setVideoThumbnailerResult(l)}async saveCoverInfo(){if(this.coverResult)return;const t=this.store.data.thumbnail_screenshot_largest,e=t?.index||0,{screenshot_width:a,screenshot_height:i}=this,s=this.getScreenshotName(e),r=Zt(this.params.outputRoot,s),o=this.getCoverName(),n=Zt(this.params.outputRoot,o);await ee(r,n);const h={file:o,path:n,size:await Yt(n),width:a,height:i};await this.setCoverResult(h)}async generateTiles(){const t=this.store.data.thumbnail_tile_index||0,{length:e}=this.thumbnail_group,a=this.col*this.row,i=Math.ceil(e/a);for(let e=t;e<i;e++)await this.generateOneTile(e),await this.updateImagePercent((e+1)/i,"tile")}async generateOneTile(t){const{col:e,row:a}=this,i=this.thumbnail_group.length,s=a*e,r=t*s,o=Math.min(s,i-r),n=[];for(let t=0;t<o;t++){const e=this.getScreenshotName(r+t),a=Zt(this.params.outputRoot,e);n.push(a)}const h=this.getTileName(t),d=Zt(this.params.outputRoot,h);await this.createSpriteSheet(n,d),this.store.data.thumbnail_tile_index=t+1,await this.store.write()}async createSpriteSheet(t,e){await te({col:this.col,inputs:t,output_path:e,width:this.screenshot_width,height:this.screenshot_height})}getKeyFrameParams(t,e=0){if(t<1)return["-vframes","1"];{const a=Math.max(t-e-.3,.1);if(a<1)return["-vframes","1"];return["-ss",`${a.toFixed(3)}`,"-vframes","1"]}}async generateScreenshots(){if(this.store.data.thumbnail_screenshot_state)return;this.store.data.thumbnail_screenshot_index||=0;const t=this.store.data.thumbnail_screenshot_index,e=this.store.data.thumbnail_screenshot_largest,a={index:0,size:0};if(e){const t=e;a.index=t.index,a.size=t.size}const{segments:i}=this.m3u8_data,{thumbnail_group:s,screenshot_width:r}=this,{length:o}=s,n=async(t,{errorTimes:e,fixedSeconds:o})=>{const h=s[t].item.index,d=i[h];try{const e=this.getScreenshotName(t),i=`concat:${d.init_uri}|${d.uri}`,s=this.getKeyFrameParams(d.duration,o),n=r>this.screenshot_height?`${r}:-2`:`-2:${this.screenshot_height}`,h=["-i",i,...s,"-vf",`scale=${n}:flags=lanczos`,"-y",e];await this.ffmpeg(h,{cwd:this.params.outputRoot});const c=Zt(this.params.outputRoot,e),l=await Yt(c);if(0===l)throw new Error(`Generate video thumbnail error: [index: ${t}, start_time: ${d.start_time}, end_time: ${d.end_time}]`);l>=a.size&&(a.index=t,a.size=l,this.store.data.thumbnail_screenshot_largest=a,await this.store.write()),this.store.data.thumbnail_screenshot_index=t+1,await this.store.write()}catch(a){const i=Math.max(10,d.duration);if(!(e<3))throw a;await n(t,{errorTimes:e+1,fixedSeconds:o+i/5})}};for(let e=t;e<o;e++)await n(e,{errorTimes:0,fixedSeconds:0}),await this.updateImagePercent((e+1)/o,"screenshot");this.store.data.thumbnail_screenshot_state=!0,await this.store.write()}async initScreenshotSize(){const{thumbnail_screenshot_size:t}=this.store.data;if(t)return this.screenshot_width=t.width,void(this.screenshot_height=t.height);const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],{width:i,height:s}=a,r=i>s?480:270;this.screenshot_width=2*Math.floor(Math.min(r,i)/2),this.screenshot_height=2*Math.floor(this.screenshot_width*(s/i)/2),this.store.data.thumbnail_screenshot_size={width:this.screenshot_width,height:this.screenshot_height}}async initThumbnailGroup(){if(this.store.data.thumbnail_group)return void(this.thumbnail_group=this.store.data.thumbnail_group);const t=[],{segments:e}=this.m3u8_data,{length:a}=e,i=this.thumbnail_duration;let s=0,r=[];for(let o=0;o<a;o++){const n=e[o];if(s+=n.duration,r.push(n),s>=i||o===a-1){const e=r.length,a=r[0],i=r[e-1];t.push({duration:s,start_time:a.start_time,end_time:i.end_time,items:r,item:i}),s=0,r=[]}}if(t.length>1){if(t[t.length-1].duration<1){const e=t.pop(),a=t[t.length-2];a.duration=a.duration+e.duration,a.end_time=e.end_time,a.items=a.items.concat(e.items),a.item=e.item,e.items}}t.forEach(t=>{const{items:e}=t;for(let a=e.length-1;a>=0;a--)if(e[a].duration>1){t.item=e[a];break}}),this.thumbnail_group=t,this.store.data.thumbnail_group=t,await this.store.write()}getVideoM3U8Info(){return this.videoTranscoderResult?.m3u8}async initM3U8Data(){this.m3u8_data=this.getVideoM3U8Info()}async initThumbnailDuration(){if(this.store.data.thumbnail_duration)return this.thumbnail_duration=this.store.data.thumbnail_duration,this.thumbnail_duration;let t=30;const e=await this.getMediainfo(),a=e?.video;if(!a?.length)return t;const i=a[0],s=i.duration||e?.general?.duration,{width:r,height:o}=i;r*o>=518400&&(t=10),r*o>=921600&&(t=20),r*o>=2073600&&(t=30),r*o>=3686400&&(t=40),r*o>=8294400&&(t=60);const n=s??0;if(n&&(n<60&&(t=0),n<300&&(t=Math.ceil(t/4)),n<600&&(t=Math.ceil(t/2)),n>3600)){const e=n/3600;t=Math.ceil(t*e)}return t=Math.min(60,t),this.thumbnail_duration=t,this.store.data.thumbnail_duration=t,await this.store.write(),t}};import{resolve as re}from"path";import{pathExists as oe}from"fs-extra";import{getMetadata as ne}from"@soga/imgutils";import{getFileSize as he}from"@soga/fileutils";import{UploadProgress as de}from"@soga/node-types";import{buildDError as ce}from"@soga/error";var le=class extends ut{get cover_name(){return"audio_cover.png"}async start(){try{await this.generateCover(),this.isAudio&&await this.postProgress({type:de.transcode_thumbnail,percent:1})}catch(t){throw ce(t,{message:"Error occurred during audio cover generation",detail:`Error occurred during audio cover generation: ${this.params.input.filepath}`})}}async generateCover(){const t=await this.getMediainfo();if(t.video?.length)return;const e="audio-covered";try{if(this.coverResult)return this.coverResult;if(this.db.data[e])return;const{cover_name:t}=this,a=["-i",this.params.input.filepath,"-map","0:v","-y",t];await this.ffmpeg(a,{cwd:this.params.outputRoot});const i=re(this.params.outputRoot,t),s=await oe(i),r=await ne(i);if(s){const e={file:t,path:i,size:await he(i),width:r.width??0,height:r.height??0};await this.setCoverResult(e)}}catch(t){throw t}finally{this.db.data[e]=!0,await this.db.write()}}};import{parse as pe,resolve as ue}from"path";import{getFileLanguage as ge,isUtf8File as me,saveFileAsUtf8 as we,gzip as fe}from"@soga/utils";import{isValidFile as _e,getFileSize as ye,isValidPath as be}from"@soga/fileutils";import{copy as ve}from"fs-extra";import{buildDError as Pe}from"@soga/error";import{UploadProgress as xe}from"@soga/node-types";var De=class extends ut{builtin_tracks=0;external_tracks=0;get tracks(){return this.builtin_tracks+this.external_tracks}async sendProgress(t){await this.postProgress({type:xe.separate_subtitle,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.subtitleEncoderResult)return;const t=await this.getMediainfo();if(this.builtin_tracks=t?.text?.length||0,this.external_tracks=this.params.subtitles?.length||0,!this.tracks)return await this.setSubtitleEncoderResult([]),void await this.sendProgress(1);const e=await this.parseBuiltinTextTracks();await this.sendProgress(this.builtin_tracks/this.tracks);const a=await this.parseExternalTextTracks(),i=[...e,...a];await this.setSubtitleEncoderResult(i),await this.sendProgress(1)}catch(t){throw Pe(t,{message:"Error occurred while process subtitle track",detail:`Error occurred while process subtitle track: ${this.params.input.filepath}`})}}async parseBuiltinTextTracks(){const t=await this.getMediainfo(),e=t?.text;if(!e?.length)return[];const{subtitle_builtin_tracks:a}=this.dbData;if(a)return a;const i=e.length,s=[];for(let t=0;t<i;t++){const e=await this.parseBuiltinTextTrack(t);e&&s.push(e),await this.sendProgress((t+1)/this.tracks)}return this.dbData.subtitle_builtin_tracks=s,await this.params.db.write(),s}async parseBuiltinTextTrack(t){const e=this.params.outputRoot,a=`subtitle-builtin-${t}.zip`,i=ue(e,a),s=`subtitle-temp-${t}.vtt`,r=ue(e,s),o=ue(e,`subtitle-builtin-u8-${t}.vtt`),n=["-i",this.params.input.filepath,"-vn","-an","-map",`0:s:${t}`,"-c","webvtt","-y",s];await this.ffmpeg(n,{cwd:this.params.outputRoot});if(await _e(r)){if(await me(r))await ve(r,o);else{await we(r,o);await _e(o)||await ve(r,o)}const e=await ge(o),{label:s,lang:n}=e;await fe(o,i);return{file:a,file_path:i,size:await ye(i),lang:n,name:s||`builtin_${t+1}`,title:s||`builtin_${t+1}`,builtin:!0,source:null}}return!1}async parseExternalTextTracks(){const{subtitles:t}=this.params;if(!t?.length)return[];const{subtitle_external_tracks:e}=this.dbData;if(e)return e;const a=[],i=t.length;for(let e=0;e<i;e++){const i=await this.parseExternalTextTrack(e,t[e]);i&&a.push(i),await this.sendProgress((this.builtin_tracks+(e+1))/this.tracks)}return this.dbData.subtitle_external_tracks=a,await this.params.db.write(),a}async parseExternalTextTrack(t,e){const{ext:a}=pe(e),i=this.params.outputRoot,s=`subtitle-external-${t}.vtt`,r=ue(i,s),o=`subtitle-external-${t}.zip`,n=ue(i,o),h=ue(i,`subtitle-external-u8-${t}${a}`),d=`subtitle-external-source-${t}.zip`,c=ue(i,d);if(!await be(e))return!1;if(await me(e))await ve(e,h);else{await we(e,h);if(!await _e(h))return!1}const l=["-i",h,"-c","webvtt","-y",s];await this.ffmpeg(l,{cwd:this.params.outputRoot});if(await _e(r)){const i=await ge(r),{label:s,lang:h}=i;await fe(e,c),await fe(r,n);const l=await ye(c);return{file:o,size:await ye(n),file_path:n,lang:h,name:s||`external_${t+1}`,title:s||`external_${t+1}`,builtin:!1,source:{file:d,file_path:c,size:l,ext:a}}}return!1}};import{buildDError as Te}from"@soga/error";import{resolve as ze}from"path";import{writeFile as Re}from"fs-extra";import{UploadProgress as Ie}from"@soga/node-types";import{getFileSize as $e}from"@soga/fileutils";import{gzip as Me,getFileBufferSlice as Se}from"@soga/utils";import{buildDError as ke}from"@soga/error";import{resolve as Fe}from"path";import{getFileSize as Ee}from"@soga/fileutils";var Ne=class extends ut{hostType;safe_index=0;file_map={};completed_percent=0;total_percent=0;store;async initStore(t){this.store=await this.getStore(`${t}_grouper_store.json`)}getFileName=t=>this.getPreviewSegmentName(t,this.hostType);getGroupedVideoManifestName(t){return`grouper_video_${this.hostType}_${t}.m3u8`}getAudioManifestName(t,e){return`grouper_audio_${this.hostType}_${e}_${t}.m3u8`}getThumbnailInfoFilename(){return`grouper_thumbnail_${this.hostType}.json`}getCacheInfoFilename(){return`grouper_cache_${this.hostType}.json`}constructor(t){super(t),this.hostType=t.host_type,this.completed_percent=t.completed_percent,this.total_percent=1/t.hosts.length}async generateSafeFile(t){return await async function(t){const e=`safe_${t.type}_${t.file_index}.txt`,a=p(t.filesize),i=c(t.outputRoot,e);return await h(i,a),{file_path:i,size:a.length}}({type:t,file_index:this.safe_index++,outputRoot:this.params.outputRoot,filesize:this.params.input.filesize})}readAudioTracks(){return this.audioTranscoderResult??[]}readVideoTracks(){return this.videoTranscoderResult?[this.videoTranscoderResult]:[]}readThumbnailInfo(){return this.videoThumbnailerResult}readCoverInfo(){return this.coverResult}readSubtitleInfo(){return this.subtitleEncoderResult}async getPartData(){const t=this.store.data.grouper_part_names??[],e=[];for(let a=0;a<t.length;a++){const i=t[a],s=Fe(this.params.outputRoot,i),r=await Ee(s),o=await this.getPartInfo({host_type:this.hostType,filepath:s,start:0,end:r-1,filename:i});e.push(o)}return e}async getAudioData(){const t=this.readAudioTracks();if(!t?.length)return;const e=[];for(let a=0;a<t.length;a++){const i=t[a];if(i.adapt){const{average_bandwidth:t,bandwidth:s,channels:r,codec:o,codec_name:n,language:h,order:d}=i.adapt,c=this.getAudioManifestName("adapt",a),l=this.file_map[c],{file_index:p,start:u,end:g,size:m,hash:w}=l,f=this.getFileName(p),_=await this.getPreviewId({file:c});await this.setPreviewIdMap({id:_,file:f,start:u,end:g},this.hostType);const y={id:_,average_band:t,band:s,channels:r,codec:o,codec_name:n,language:h,order:d,file:f,start:u,end:g,size:m,hash:w};if(i.high){const{average_bandwidth:t,bandwidth:e,channels:s,codec:r,codec_name:o,language:n,order:h}=i.high,d=this.getAudioManifestName("high",a),c=this.file_map[d],{file_index:l,start:p,end:u,size:g,hash:m}=c,w=this.getFileName(l),f=await this.getPreviewId({file:d});await this.setPreviewIdMap({id:f,file:w,start:p,end:u},this.hostType),y.high={id:f,average_band:t,band:e,channels:s,codec:r,codec_name:o,language:n,order:h,file:w,start:p,end:u,size:g,hash:m}}e.push(y)}}return e}async getVideoData(){const t=this.readVideoTracks();if(!t?.length)return;const e=[];for(let a=0;a<t.length;a++){const i=t[a],s=this.getGroupedVideoManifestName(a),r=await this.getPreviewId({file:s}),o=this.file_map[s],{file_index:n,start:h,end:d,size:c,hash:l}=o,p=this.getFileName(n);await this.setPreviewIdMap({id:r,file:p,start:h,end:d},this.hostType);const{average_bandwidth:u,bandwidth:g,codec:m,width:w,height:f,label:_,codec_name:y,bitdepth:b,framerate:v}=i,P={id:r,average_band:u,band:g,codec:m,codec_name:y,bitdepth:b,framerate:Math.round(v),width:w,height:f,file:p,start:h,end:d,size:c,label:_,hash:l};e.push(P)}return e}async getSubtitleData(){const t=this.readSubtitleInfo();if(!t?.length)return;const e=[],{length:a}=t;for(let i=0;i<a;i++){const a=t[i],{builtin:s,file:r,lang:o,title:n,name:h,source:d}=a,c=this.file_map[r],{file_index:l,start:p,end:u,size:g}=c,m=this.getFileName(l),w={uuid:await this.getPreviewId({file:r,start:p,end:u}),builtin:s,lang:o,name:h,title:n,file:m,start:p,end:u,size:g};if(d){const{file:t,ext:e}=d,a=this.file_map[t],{file_index:i,start:s,end:r,size:o}=a,n=this.getFileName(i);w.source={size:o,file:n,start:s,end:r,ext:e}}e.push(w)}return e}async getThumbnailData(){const t=this.readThumbnailInfo();if(!t)return;const{row:e,col:a,width:i,height:s}=t,r=this.getThumbnailInfoFilename(),o=this.file_map[r],{file_index:n,start:h,end:d,size:c}=o,l=this.getFileName(n),p=await this.getPreviewId({file:r});await this.setPreviewIdMap({id:p,file:l,start:h,end:d},this.hostType);return{id:p,row:e,col:a,width:i,height:s,file:l,start:h,end:d,size:c}}async getCoverData(){const t=this.readCoverInfo();if(!t)return;const e=t,{file:a,width:i,height:s}=e,r=this.file_map[a],{file_index:o,start:n,end:h,size:d}=r,c=this.getFileName(o),l=await this.getPreviewId({file:e.path});await this.setPreviewIdMap({id:l,file:c,start:n,end:h},this.hostType);return{id:l,width:i,height:s,file:c,start:n,end:h,size:d}}async getCacheData(){const t=this.getCacheInfoFilename(),e=await this.getPreviewId({file:t}),a=this.file_map[t],{file_index:i,start:s,end:r,size:o}=a,n=this.getFileName(i);await this.setPreviewIdMap({id:e,file:n,start:s,end:r},this.hostType);return{id:e,file:n,start:s,end:r}}async saveData(){const t=vt(this.hostType);if(this.db.data[t])return;const e={},a=await this.getAudioData();a&&(e.audios=a);const i=await this.getVideoData();i&&(e.videos=i);const s=await this.getSubtitleData();s&&(e.subtitles=s);const r=await this.getThumbnailData();r&&(e.thumbnail=r);const o=await this.getCoverData();o&&(e.cover=o),e.parts=await this.getPartData(),e.cache=await this.getCacheData(),this.db.data[t]=e,await this.db.write()}},Ce=class extends Ne{current_position=0;current_index=0;group_data=[];async start(){const t=vt(this.hostType);if(this.db.data[t])return this.db.data[t];try{return await this.initStore(this.hostType),await this.calculateData(),await this.postProgress({type:Ie.group_media,percent:this.completed_percent+.5*this.total_percent}),await this.processGroups(),await this.postProgress({type:Ie.group_media,percent:this.completed_percent+.9*this.total_percent}),await this.saveData(),await this.postProgress({type:Ie.group_media,percent:this.completed_percent+this.total_percent}),this.db.data[t]}catch(t){throw ke(t,{message:`Error occurred during media grouping ${this.hostType}`,detail:`Error occurred during media grouping ${this.hostType}: ${this.params.input.filepath}`})}}async processGroups(){const t="grouper_process_state";if(this.store.data[t])return;this.store.data.grouper_process_map||={},this.store.data.grouper_process_index||=0;const{length:e}=this.group_data;for(let t=0;t<e;t++){const a=this.group_data[t];this.store.data.grouper_process_map[a.filename]||(await u({outputRoot:this.params.outputRoot,files:a.files,filename:a.filename}),this.store.data.grouper_process_map[a.filename]=!0,await this.store.write(),await this.postProgress({type:Ie.group_media,percent:this.completed_percent+.5*this.total_percent+this.total_percent*(.4*(t+1)/e)}))}this.store.data[t]=!0,await this.store.write()}async insertSafeFile(){const t=await this.generateSafeFile(this.hostType);this.addOne(t,!0)}async calculateData(){this.store.data.grouper_group_list||=[],this.store.data.grouper_file_map||={},await this.insertSafeFile(),await this.calculateMediaTracks(),await this.calculateThumbnails(),await this.calculateCovers(),await this.calculateCaches(),this.current_index+=1,this.current_position=0,await this.calculateSubtitles(),this.store.data.grouper_group_list=this.group_data,this.store.data.grouper_file_map=this.file_map;const t=this.group_data.map(t=>t.filename);this.store.data.grouper_part_names=t,this.store.data.grouper_calculate_state=!0,await this.store.write()}async calculateSubtitles(){const t=this.readSubtitleInfo();if(!t?.length)return;await this.insertSafeFile();const{length:e}=t;for(let a=0;a<e;a++){const e=t[a],{file:i,file_path:s,size:r}=e,o=this.addOne({file_path:s,size:r});if(this.file_map[i]=o,e.source){const{file:t,file_path:a,size:i}=e.source,s=this.addOne({file_path:a,size:i});this.file_map[t]=s}}}async calculateCaches(){await this.getAudioData(),await this.getVideoData(),await this.getThumbnailData(),await this.getCoverData();const t=this.getPreviewIdMap(this.hostType),e=this.getCacheInfoFilename(),a=await this.writeText(e,JSON.stringify(t));this.file_map[e]=a}async calculateCovers(){const t=this.readCoverInfo();if(!t)return;const{file:e,path:a,size:i}=t,s=this.addOne({file_path:a,size:i});this.file_map[e]=s}async calculateMediaTracks(){const t=this.readAudioTracks(),e=this.readVideoTracks(),a=t?.length;for(let e=0;e<a;e++){const i=t[e];if(i.adapt){const t=await this.calculateOneTrack(i.adapt.m3u8),a=this.getAudioManifestName("adapt",e),s=await this.writeTrackText(a,t);this.file_map[a]=s}if(i.high){const t=await this.calculateOneTrack(i.high.m3u8),a=this.getAudioManifestName("high",e),s=await this.writeTrackText(a,t);this.file_map[a]=s}await this.postProgress({type:Ie.group_media,percent:this.completed_percent+.4*this.total_percent*((e+1)/a)})}const i=e.length;for(let t=0;t<i;t++){const a=e[t],s=await this.calculateOneTrack(a.m3u8),r=this.getGroupedVideoManifestName(t),o=await this.writeTrackText(r,s);this.file_map[r]=o,await this.postProgress({type:Ie.group_media,percent:this.completed_percent+.2*this.total_percent+.2*this.total_percent*((t+1)/i)})}}async calculateThumbnails(){const t=this.readThumbnailInfo();if(!t)return;if(!t)return;const{tile_list:e}=t,{length:a}=e;let i=[...t.sprite_list];for(let t=0;t<a;t++){const a=e[t],s=a.file,r=await this.safelyAddOne({file_path:a.file_path,size:a.size}),o=await this.getPreviewId({file:s}),n=this.getFileName(r.file_index);await this.setPreviewIdMap({id:o,file:n,start:r.start,end:r.end},this.hostType),this.file_map[s]=r,i=i.map(t=>t.file===s?{...t,file:n,id:o,s:r.start,e:r.end}:t)}const s=this.getThumbnailInfoFilename(),r=await this.writeText(s,JSON.stringify(i));this.file_map[s]=r}async calculateOneTrack(t){const{segments:e,init:a,version:i,targetDuration:s,mediaSequence:r,endList:o}=t,n={},h=this.addOne({size:a.size,file_path:a.file_path}),d=await this.getPreviewId({file:a.uri}),c=this.getFileName(h.file_index),l=`${c}?id=${d}`;await this.setPreviewIdMap({id:d,file:c,start:h.start,end:h.end},this.hostType);const p=["#EXTM3U",`#EXT-X-VERSION:${i}`,`#EXT-X-TARGETDURATION:${s}`,`#EXT-X-MEDIA-SEQUENCE:${r}`,`#EXT-X-MAP:URI=${l},BYTERANGE="${h.size}@${h.start}"`];[...e].forEach(t=>{const{uri:e,size:a,duration:i,file_path:s}=t;n[e]=this.addOne({size:a,duration:i,file_path:s})});for(const[t,e]of Object.entries(n)){const a=await this.getPreviewId({file:t}),i=this.getFileName(e.file_index);await this.setPreviewIdMap({id:a,file:i,start:e.start,end:e.end},this.hostType),p.push(`#EXTINF:${e.duration},`),p.push(`#EXT-X-BYTERANGE:${e.size}@${e.start}`),p.push(`${i}?id=${a}`)}o&&p.push("#EXT-X-ENDLIST");return p.join("\n")}async writeTrackText(t,e){const a=ze(this.params.outputRoot,t),r=ze(this.params.outputRoot,`${t}.gz`),o=ze(this.params.outputRoot,`${t}.bin`);await Re(a,e,"utf-8"),await Me(a,r);if(await $e(r)>16){const t=(await Se(r,0,15)).toString("base64");await async function(t,e){await new Promise((a,r)=>{const o=i(t,{start:16}),n=s(e);o.pipe(n),n.on("finish",()=>{a(!0)}),o.on("error",t=>{r(t)}),n.on("error",t=>{r(t)})})}(r,o);return{...this.addOne({file_path:o,size:await $e(o)}),hash:t}}return{...this.addOne({file_path:a,size:await $e(a)}),hash:""}}async writeText(t,e){const a=ze(this.params.outputRoot,t);await Re(a,e,"utf-8");return this.addOne({file_path:a,size:await $e(a)})}addOne({file_path:t,size:e,duration:a=0},i=!1){const s=this.getSizeLimit(this.hostType),{current_position:r,group_data:o}=this;if(i&&o[this.current_index]||!(r+e<=s)){this.current_index+=1;const{current_index:i}=this;o[i]?o[i].files.push(t):o[i]={filename:this.getFileName(i),files:[t]};const s=0,r=e-1;return this.current_position=e,{file_index:i,start:s,end:r,duration:a,size:r-s+1}}{const{current_index:i}=this,s=r,n=r+e-1;return this.current_position=n+1,o[i]?o[i].files.push(t):o[i]={filename:this.getFileName(i),files:[t]},{file_index:i,start:s,end:n,duration:a,size:n-s+1}}}async safelyAddOne(t){const e=this.getSizeLimit(this.hostType),{current_position:a}=this;return a+t.size<=e?0===a?(await this.insertSafeFile(),this.addOne(t)):this.addOne(t):(await this.insertSafeFile(),this.addOne(t))}},Le=class extends ut{async start(){try{if(this.grouperResult)return this.grouperResult;const t={meta:await this.getMetaData(),data:{}},{length:e}=this.params.hosts;for(let a=0;a<e;a++){const i=this.params.hosts[a],s=this.getSizeLimit(i),r=new Ce({...this.params,host_type:i,file_size_limit:s,completed_percent:a/e}),o=await r.start();t.data[i]=o}return await this.setGrouperResult(t),t}catch(t){throw Te(t,{message:t.message||"Error occurred during media grouping",detail:t.detail||`Error occurred during media grouping: ${this.params.input.filepath}`})}}async getMetaData(){const t={},e=this.audioTranscoderResult??[],a=this.videoTranscoderResult?[this.videoTranscoderResult]:[];if(a?.length){const e=await this.getMediainfo(),{duration:i}=e?.general;if(a?.length){const{width:e,height:s,framerate:r,bitdepth:o,label:n,codec:h,codec_name:d}=a[0];t.videos=[{duration:i,bitdepth:o,width:e,height:s,framerate:r,label:n,codec:h,codec_name:d}]}}if(e?.length)for(const a of e){const{high:e,adapt:i}=a,{channels:s,lossless:r}=i,o=await this.getMediainfo(),{duration:n}=o?.general,{codec:h,codec_name:d}=i,c={duration:n,channels:s,lossless:r,codec:h,codec_name:d};e&&(c.high={channels:e.channels,codec:e.codec,codec_name:e.codec_name,lossless:e.lossless}),t.audios=t.audios||[],t.audios.push(c)}return t}},Ae=class extends ut{async start(){if(this.db.data.grouper_result)return this.db.data.grouper_result;const t=await this.getMediainfo();if(!t)return;const e=t.video,a=e?.length,i=t.audio,s=i?.length;if(!s&&!a)return;const r=new De(this.params);if(await r.start(),s){const t=new St(this.params);await t.start();const e=new Wt(this.params);await e.start();const a=new le(this.params);await a.start()}if(a){const t=new Dt(this.params);await t.start();const e=new Vt(this.params);await e.start();const a=new se(this.params);await a.start()}const o=new Le(this.params);await o.start()}async getResult(){return this.db.data.grouper_result}};import{HostType as Oe}from"@soga/types";import{UploadProgress as Ue}from"@soga/node-types";import{parseMediaInfo as Ve}from"@soga/mediainfo";import{getFileSize as Ge,isAudioAdapt as Be,isAudioHigh as je,isVideoSupport as qe}from"@soga/fileutils";import{ensureDir as Xe}from"fs-extra";import Ke from"check-disk-space";import{buildDError as He}from"@soga/error";var Je=class extends L{async start(){this.prepareResult||(await this.checkStorage(),await this.calculateMeta(),await this.calculateProgress())}async checkStorage(){const{length:t}=this.params.hosts,e=await Ke(this.params.outputRoot),a=e.free,i=e.diskPath;if((3+t)*this.params.input.filesize>a)throw He(new Error(`${i} have no enough computer disk space, please adjust the temporary path in user settings.`),{message:`${i} have no enough computer disk space, please adjust the temporary path in user settings.`,detail:`${i} have no enough computer disk space to process ${this.params.input.filepath}`})}async calculateMeta(){if(this.meta)return this.meta;const{filename:t,local_btime:e,local_ctime:a,local_mtime:i,filesize:s}=this.params.input,r={file:t,size:s,btime:e,ctime:a,mtime:i,md5:""};return await this.setMeta(r),r}async calculateProgress(){if(this.prepareResult)return;const t={[Ue.prepare]:{weight:0,percent:1},[Ue.calculate_md5]:{weight:0,percent:0},[Ue.separate_video]:{weight:0,percent:0},[Ue.separate_audio]:{weight:0,percent:0},[Ue.separate_subtitle]:{weight:0,percent:0},[Ue.transcode_video]:{weight:0,percent:0},[Ue.transcode_audio]:{weight:0,percent:0},[Ue.transcode_thumbnail]:{weight:0,percent:0},[Ue.transcode_source]:{weight:0,percent:0},[Ue.transcode_txt]:{weight:0,percent:0},[Ue.transcode_img]:{weight:0,percent:0},[Ue.group_media]:{weight:0,percent:0},[Ue.upload_baidu]:{weight:0,percent:0},[Ue.upload_ali]:{weight:0,percent:0},[Ue.end]:{weight:0,percent:0}},e={keep_preview:this.params.keepPreview,keep_source:this.params.keepSource},a=await Ge(this.params.input.filepath);t[Ue.prepare].weight=t[Ue.end].weight=Math.ceil(a/1024/1024/500),t[Ue.calculate_md5].weight=Math.ceil(a/1024/1024/200);let i=0;if(this.isMedia)if(this.params.keepPreview){const s=await Ve(this.params.input.filepath),r=s?.general?.duration??0;if(s.video?.length){const e=s.video[0],{width:a,height:i,codec:r}=e,o=qe(r),{duration:n}=s.general,h=o?n/400:n*(a*i)/1920/1080;t[Ue.separate_video].weight=Math.ceil(h),t[Ue.transcode_video].weight=Math.ceil(.01*n)}if(s.audio?.length){const{duration:e}=s.general;let a=0;s.audio.forEach(t=>{const{codec:i,lossless:s,channels:r}=t,o={high_need:!1,high_transcode:!1,adapt_need:!1,adapt_transcode:!1};Be(i)?r>2?(o.high_need=!0,o.high_transcode=!1,o.adapt_need=!0,o.adapt_transcode=!0):(o.high_need=!1,o.adapt_need=!0,o.adapt_transcode=!1):je(i)?(o.high_need=!0,o.high_transcode=!1,o.adapt_need=!0,o.adapt_transcode=!0):(o.high_need=!1,o.adapt_need=!0,o.adapt_transcode=!1,s&&(o.high_need=!0,o.high_transcode=!0)),o.adapt_need&&(a+=o.adapt_transcode?e/40:5),o.high_need&&(a+=o.high_transcode?e/20:10)}),t[Ue.separate_audio].weight=Math.ceil(a),t[Ue.transcode_audio].weight=Math.ceil(.01*e)}const o=s.video?.length??0,n=s.audio?.length??0;if(o||n){e.keep_preview=!0;const o=(s.text?.length||0)+(this.params.subtitles?.length||0);t[Ue.separate_subtitle].weight=Math.ceil(o),t[Ue.transcode_thumbnail].weight=Math.ceil(.08*r),i+=a,t[Ue.group_media].weight=Math.ceil(a/1024/1024/10)}else e.keep_preview=!1,e.keep_source=!0,i+=a}else e.keep_source=!0,i+=a;else this.isTxt?e.keep_preview?(t[Ue.transcode_txt].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a):this.isImg?e.keep_preview&&(t[Ue.transcode_img].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a);e.keep_source&&(t[Ue.transcode_source].weight=Math.ceil(a/1024/1024/30)),this.params.hosts.includes(Oe.BAIDU)&&(t[Ue.upload_baidu].weight=Math.ceil(i/1024/1024/1)),this.params.hosts.includes(Oe.ALI)&&(t[Ue.upload_ali].weight=Math.ceil(i/1024/1024/2));const s={preview:e.keep_preview,source:e.keep_source};await this.setKeeps(s),await this.setPrepareResult(t)}},Qe=async t=>{await Xe(t.outputRoot);const e=await m(t);try{const a=new Je({...t,db:e});return await a.start(),a}catch(t){}};import{UploadProgress as We}from"@soga/node-types";import{createHash as Ze}from"crypto";import{createReadStream as Ye}from"fs-extra";import{HostType as ta}from"@soga/types";var ea=class extends L{async start(){await this.processFile();return await this.getResult()}async calculateMd5(){if(this.md5)return this.md5;const t=this.params.input.filepath,e=this.params.input.filesize;let a=0;const i=await new Promise((i,s)=>{let r=0;const o=Ze("md5"),n=Ye(t,{highWaterMark:4194304});n.on("data",async t=>{o.update(t),r+=t.length;const i=r/e;r-a>104857600&&(a=r,await this.postProgress({type:We.calculate_md5,percent:Math.min(i,1)}))}),n.on("end",()=>{const t=o.digest("hex");i(t)}),n.on("error",t=>{s(t)})});return i&&await this.setMd5(i),await this.postProgress({type:We.calculate_md5,percent:1}),i}getCloudName({host_type:t,md5:e,is_attachment:a}){const i=a?"a":"f";return t==ta.BAIDU?`dpan_${i}-${e}.bin`:`dpan_${i}_${e}.txt`}async getResult(){if(this.result)return this.result;const{sourceResult:t,grouperResult:e,imgResult:a,txtResult:i,meta:s,keeps:r}=this,{length:o}=this.params.hosts,n={meta:{preview:r.preview,source:r.source,file:s}};for(let s=0;s<o;s++){const r=this.params.hosts[s];n[r]={max_size:0,parts:[]};const o=t=>{const e=t.map(t=>{const e=this.getCloudName({host_type:r,md5:t.md5,is_attachment:this.params.is_attachment});return{...t,name:e}});n[r].parts=[...n[r].parts,...e]},h=a?.data[r];if(h){h.cache&&(n[r].cache=h?.cache);const t=h.parts?.map(t=>({...t,preview:!0,source:!1}));t&&o(t),n.meta.img=a.meta,h.img&&(n[r].img=h.img)}const d=i?.data[r];if(d){o((d.parts||[]).map(t=>({...t,preview:!0,source:!1}))),n[r].cache=d.cache,n[r].txt={entrance:d.entrance,pad:i?.meta.pad,pages:i?.meta.pages}}const c=e?.data[r];if(c?.parts){o(c.parts.map(t=>({...t,preview:!0,source:!1}))),n.meta.audios=e.meta.audios,n.meta.videos=e.meta.videos,n[r].cache=c.cache,n[r].media={audios:c.audios,videos:c.videos,subtitles:c.subtitles,thumbnail:c.thumbnail,cover:c.cover}}const l=t?.data[r];if(l?.parts){o(l.parts.map(t=>{let e=!0;return(this.isMedia||this.isTxt)&&(e=!1),{...t,preview:e,source:!0}})),n[r].source={head:t.meta.head,download:l.download}}[...n[r]?.parts].forEach(t=>{t.size>n[r].max_size&&(n[r].max_size=t.size)})}return await this.setResult(n),n}async processFile(){const t="encoder_processed";if(this.db.data[t])return;const e=await Qe(this.params),{keeps:a}=e,i={...this.params,keepPreview:a.preview,keepSource:a.source},s=await this.calculateMd5();if(await this.setMd5(s),i.keepSource){const t=new O(this.params);await t.start()}if(e.isMedia&&i.keepPreview){const t=new Ae(this.params);await t.start()}if(e.isTxt&&i.keepPreview){const t=new tt(this.params);await t.start()}if(e.isImg){const t=new dt(this.params);await t.start()}this.db.data[t]=!0,await this.db.write()}},aa=async e=>{try{const t=await m(e),a=new ea({...e,db:t});return a.start()}catch(a){throw t(a,{message:"Error occurred during file encoding",detail:`Error occurred during file encoding: ${e.input.filepath}`})}};export{aa as encode,Qe as getPrepare};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soga/file-encoder",
3
- "version": "1.3.14",
3
+ "version": "1.3.16",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -20,7 +20,7 @@
20
20
  "tsup": "^8.5.0",
21
21
  "tsx": "^4.20.6",
22
22
  "typescript": "^5.8.3",
23
- "@soga/typescript-config": "1.3.14"
23
+ "@soga/typescript-config": "1.3.16"
24
24
  },
25
25
  "keywords": [],
26
26
  "author": "",
@@ -32,16 +32,16 @@
32
32
  "piscina": "^5.0.0",
33
33
  "uuid": "^11.1.0",
34
34
  "check-disk-space": "^3.4.0",
35
- "@soga/fileutils": "1.3.14",
36
- "@soga/utils": "1.3.14",
37
- "@soga/node-types": "1.3.14",
38
- "@soga/error": "1.3.14",
39
- "@soga/types": "1.3.14",
40
- "@soga/lowdb": "1.3.14",
41
- "@soga/mp4box": "1.3.14",
42
- "@soga/m3u8": "1.3.14",
43
- "@soga/mediainfo": "1.3.14",
44
- "@soga/imgutils": "1.3.14"
35
+ "@soga/fileutils": "1.3.16",
36
+ "@soga/node-types": "1.3.16",
37
+ "@soga/error": "1.3.16",
38
+ "@soga/types": "1.3.16",
39
+ "@soga/lowdb": "1.3.16",
40
+ "@soga/m3u8": "1.3.16",
41
+ "@soga/imgutils": "1.3.16",
42
+ "@soga/mediainfo": "1.3.16",
43
+ "@soga/mp4box": "1.3.16",
44
+ "@soga/utils": "1.3.16"
45
45
  },
46
46
  "scripts": {
47
47
  "demo": "tsx ./demo/demo",