@soga/file-encoder 1.3.26 → 1.3.28

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.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:()=>Oe,getPrepare:()=>Ee}),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"),D=require("@soga/node-types"),R=require("fs-extra"),S=require("@soga/types"),$=2097152,M=4294967296,I=M,F=M,k=M,q=M,E=M,N=M,U=M,C=require("@soga/types"),L=require("@soga/utils"),A=require("worker_threads"),O=class{segmentNames={};params;id;port=null;db;get lowData(){return this.db.data}get isVideo(){return this.params.type==C.RecordType.VIDEO}get isAudio(){return this.params.type==C.RecordType.AUDIO}get isMedia(){return this.isAudio||this.isVideo}get isTxt(){return this.params.type==C.RecordType.DOC&&this.params.ftype==C.RecordFtype.DOC_TXT}get isImg(){return this.params.type==C.RecordType.IMAGE}getSizeLimit({host_type:t,is_source:e}){return(({is_shop:t,is_source:e,host_type:a})=>t?e?a==S.HostType.BAIDU?q:N:a==S.HostType.BAIDU?E:U:e?a==S.HostType.BAIDU?I:F:a==S.HostType.BAIDU?52428800:k)({is_shop:this.params.is_shop_space,is_source:e,host_type:t})}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,L.calculateMd5)({file:e,start:a,end:i}):""};if(o){if(t===C.HostType.BAIDU){const t=await(0,L.calculateMd4)({file:e,start:a,end:i});n.md4=t}if(t===C.HostType.ALI){const t=await(0,L.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):A.parentPort&&A.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}}},V=class extends O{syncGetSourceId(t){return this._syncGetId(t,"source")}async getSourceId(t,e=!0){const a=this.syncGetSourceId(t);return e&&await this.db.write(),a}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}},G=class extends V{head_size=32;as_preview=!1;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:D.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({as_preview:t}){try{if(this.as_preview=t,this.sourceResult)return await this.sendProgress(1),this.sourceResult;await this.gzip();const{length:e}=this.params.hosts;for(let t=0;t<e;t++){const e=this.params.hosts[t];await this.calculatePartList(e),await this.processDownloadMap(e)}await this.sendProgress(.9);const a=await this.getResult();return await this.sendProgress(1),a}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,R.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({host_type:t,is_source:!this.as_preview}),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,R.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,R.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({host_type:t,is_source:!this.as_preview}),{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+=$){const e=Math.min(t+$-1,o),a=e-t+1,i=l+a-1,s=await this.getSourceId({file:"source_zip",start:t,end:e},!1);n.push({id:s,file:d,start:l,end:i}),l+=a}await this.db.write(),s.push(c),e++}}await this.setPartList(t,s),await this.setDownloadList(t,n),this.dbData[e]=!0,await this.db.write()}},B=require("path"),j=require("fs-extra"),H=require("@soga/utils"),X=h(require("zlib")),W=require("@soga/utils"),K=require("@soga/error"),J=require("@soga/node-types"),Q=require("path"),Z=require("@soga/fileutils"),Y=require("fs-extra"),tt=class extends O{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,Q.resolve)(this.params.outputRoot,this.getPartName(t,e))}syncGetPreviewId(t){return this._syncGetId(t,"preview")}async getPreviewId(t,e=!0){const a=this.syncGetPreviewId(t);return e&&await this.db.write(),a}getPreviewIdMap(t){return this.db.data[`preview_${t}_id_map`]||{}}syncSetPreviewIdMap(t,e){this._syncSetIdMap(t,"preview",e)}async setPreviewIdMap(t,e,a=!0){this.syncSetPreviewIdMap(t,e),a&&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,Z.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,Q.resolve)(this.params.outputRoot,a);await(0,Y.writeFile)(i,e,"utf-8");return{file_path:i,size:await(0,Z.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({host_type:t,is_source:!1});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,Z.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,Y.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)}}},et=class extends tt{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,B.resolve)(this.params.outputRoot,this.getU8FileName())}async sendProgress(t){await this.postProgress({type:J.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,K.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,j.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,W.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({host_type:t,is_source:!1}),a=this.getU8FilePath(),i=await this.calculateSlice(),{length:s}=i,r={};let o=0,n=(0,j.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,H.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)=>{X.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,j.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,j.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}},at=require("path"),it=require("@soga/imgutils"),st=require("@soga/utils"),rt=require("@soga/fileutils"),ot=require("@soga/error"),nt=require("@soga/node-types"),ht=require("fs-extra"),dt=class extends tt{compress_file_name="";output_format="jpg";output_width=0;output_height=0;getCompressFilePath(){if(!this.compress_file_name)throw new Error("Compress file name is empty");return(0,at.resolve)(this.params.outputRoot,this.compress_file_name)}getGzFileName(){return"compressed_img.zip"}getGzFilePath(){return(0,at.resolve)(this.params.outputRoot,this.getGzFileName())}async sendProgress(t){await this.postProgress({type:nt.UploadProgress.transcode_img,percent:t})}get dbData(){return this.db.data}get image_type(){return this.params.input.filepath.includes(".")?this.params.input.filepath.split(".").pop():"unknown"}preview_type="jpg";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,ot.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,it.getMetadata)(e),s=this.getCompressFilePath(),{width:r,height:o}=await(0,it.getMetadata)(s),n=await(0,rt.getFileSize)(s),h={meta:{type:this.image_type,width:a,height:i,size:t.filesize,t_type:this.output_format,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,ht.remove)(t)}catch(t){}}async compress(){if(this.dbData.img_compressed)return;const{width:t,height:e,output_filename:a,output_format:i}=await(0,it.compress)({ffmpeg_path:this.params.ffmpegPath,input_path:this.params.input.filepath,output_basename:"img_compress",output_root:this.params.outputRoot});this.compress_file_name=a,this.output_format=i,this.output_width=t,this.output_height=e,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,st.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,rt.getFileSize)(e),i=this.getSizeLimit({host_type:t,is_source:!1}),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)}},ct=h(require("fluent-ffmpeg")),lt=require("child_process"),ut=require("@soga/mediainfo"),pt=class extends tt{async getMediainfo(){const{mediainfo:t}=this.db.data;if(t)return t;const e=this.params.input.filepath,a=await(0,ut.parseMediaInfo)(e);return this.db.data.mediainfo=a,await this.params.db.write(),a}constructor(t){super(t),ct.default.setFfmpegPath(t.ffmpegPath)}getFluent(){return(0,ct.default)()}async ffmpeg(t,e){const a=this.params.ffmpegPath;return await new Promise((i,s)=>{const r=(0,lt.spawn)(a,t,Object.assign({stdio:"ignore"},e));r.on("close",t=>{i(t)}),r.on("error",t=>{s(t)})})}},gt=require("path"),wt=require("@soga/fileutils"),mt=require("@soga/node-types"),ft=require("@soga/error"),_t=({type:t,track_order:e,quality:a})=>`audio-${e}-${a}-${t}.${"manifest"===t?"m3u8":"mp4"}`,yt=({width:t,height:e})=>`video-formatted-${t}-${e}.mp4`,bt=t=>`grouper_result_${t}`,vt=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)}},Pt=(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 xt=class extends pt{async start(){try{await this.separateVideo(),await this.postProgress({type:mt.UploadProgress.separate_video,percent:1})}catch(t){throw(0,ft.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=yt({width:a.width,height:a.height}),s=(0,gt.resolve)(this.params.outputRoot,i),r=(0,wt.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=Pt(t,h);await this.postProgress({type:mt.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,wt.isValidFile)(s))throw new Error("Separate Video track failed");this.db.data[t]=!0,await this.params.db.write()}},zt=require("path"),Tt=require("@soga/fileutils"),Dt=require("@soga/node-types"),Rt=require("@soga/error"),St=class extends pt{async start(){try{await this.separateTracks(),await this.postProgress({type:Dt.UploadProgress.separate_audio,percent:1})}catch(t){throw(0,Rt.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,Tt.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,Tt.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=_t({type:"formatted",track_order:t,quality:e.type}),n=(0,zt.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=Pt(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:Dt.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,Tt.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:Dt.UploadProgress.separate_audio,percent:i})}this.db.data[a]=!0,await this.params.db.write()}},$t=require("path"),Mt=require("@soga/mediainfo"),It=require("@soga/mp4box"),Ft=require("@soga/m3u8"),kt=require("@soga/node-types"),qt=require("@soga/fileutils"),Et=require("fs-extra"),Nt=require("@soga/error"),Ut=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:kt.UploadProgress.transcode_video,percent:1})}catch(t){throw(0,Nt.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=yt({width:e,height:a}),s=(0,$t.resolve)(this.params.outputRoot,i),r=this.getVideoManifestName({width:e,height:a}),o=(0,$t.resolve)(this.params.outputRoot,r),n=await(0,Ft.parseM3U8)(o),{videos:h}=await(0,It.getMp4boxInfo)(s),{codec:d}=h[0],{bandwidth:c,average_bandwidth:l}=vt(n),u=(await(0,Mt.parseMediaInfo)(s)).video[0],p=(0,qt.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,Et.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=yt(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,$t.resolve)(this.params.outputRoot,o);if(!await(0,qt.isValidFile)(h))throw new Error("Transcode video track failed");this.db.data[t]=!0,await this.db.write()}},Ct=require("path"),Lt=require("@soga/fileutils"),At=require("@soga/mp4box"),Ot=require("@soga/m3u8"),Vt=require("@soga/mediainfo"),Gt=require("fs-extra"),Bt=require("@soga/error"),jt=require("@soga/node-types"),Ht=class extends pt{async start(){try{await this.transcodeAudios(),await this.saveData()}catch(t){throw(0,Bt.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=_t({type:"formatted",track_order:t,quality:"adapt"}),a=(0,Ct.resolve)(this.params.outputRoot,e);await(0,Gt.remove)(a)}if(e.high.need){const e=_t({type:"formatted",track_order:t,quality:"high"}),a=(0,Ct.resolve)(this.params.outputRoot,e);await(0,Gt.remove)(a)}}}catch(t){}}async getQualityData({track_order:t,quality:e}){const a=_t({type:"formatted",track_order:t,quality:e}),i=(0,Ct.resolve)(this.params.outputRoot,a),s=await(0,Vt.parseMediaInfo)(i);if(!s.audio?.length)throw new Error("parse mediainfo failed!");const r=s.audio[0],o=_t({type:"manifest",track_order:t,quality:e}),n=await(0,Lt.getFileSize)(i),h=(0,Ct.resolve)(this.params.outputRoot,o),d=await(0,At.getMp4boxInfo)(i),{audios:c}=d,{language:l,codec:u}=c[0],p=l&&!l.startsWith("un")?{language:l}:void 0,g=await(0,Ot.parseM3U8)(h),{bandwidth:w,average_bandwidth:m}=vt(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:jt.UploadProgress.transcode_audio,percent:s})}await this.postProgress({type:jt.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=_t({type:"formatted",track_order:t,quality:e.type}),s=_t({type:"init",track_order:t,quality:e.type}),r=_t({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,Ct.resolve)(this.params.outputRoot,r);if(!await(0,Lt.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()}},Xt=require("path"),Wt=require("@soga/fileutils"),Kt=require("@soga/imgutils"),Jt=require("fs-extra"),Qt=require("@soga/node-types"),Zt=require("@soga/error"),Yt=class extends pt{m3u8_data=null;thumbnail_duration=30;thumbnail_group=[];row=4;col=4;screenshot_width=960;screenshot_height=540;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:Qt.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,Zt.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,Xt.resolve)(this.params.outputRoot,e),i=await(0,Wt.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,Xt.resolve)(this.params.outputRoot,s),o=this.getCoverName(),n=(0,Xt.resolve)(this.params.outputRoot,o);await(0,Jt.copy)(r,n);const h={file:o,path:n,size:await(0,Wt.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,Xt.resolve)(this.params.outputRoot,e);n.push(a)}const h=this.getTileName(t),d=(0,Xt.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,Kt.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,Xt.resolve)(this.params.outputRoot,e),l=await(0,Wt.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?this.screenshot_width:this.screenshot_height;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}},te=require("path"),ee=require("fs-extra"),ae=require("@soga/imgutils"),ie=require("@soga/fileutils"),se=require("@soga/node-types"),re=require("@soga/error"),oe=class extends pt{get cover_name(){return"audio_cover.png"}async start(){try{await this.generateCover(),this.isAudio&&await this.postProgress({type:se.UploadProgress.transcode_thumbnail,percent:1})}catch(t){throw(0,re.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,te.resolve)(this.params.outputRoot,t);if(await(0,ee.pathExists)(i)){const e=await(0,ae.getMetadata)(i),a={file:t,path:i,size:await(0,ie.getFileSize)(i),width:e.width??0,height:e.height??0};await this.setCoverResult(a)}}catch(t){throw t}finally{this.db.data[e]=!0,await this.db.write()}}},ne=require("path"),he=require("@soga/utils"),de=require("@soga/fileutils"),ce=require("fs-extra"),le=require("@soga/error"),ue=require("@soga/node-types"),pe=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:ue.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,le.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,ne.resolve)(e,a),s=`subtitle-temp-${t}.vtt`,r=(0,ne.resolve)(e,s),o=`subtitle-builtin-u8-${t}.vtt`,n=(0,ne.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,de.isValidFile)(r)){if(await(0,he.isUtf8File)(r))await(0,ce.copy)(r,n);else{await(0,he.saveFileAsUtf8)(r,n);await(0,de.isValidFile)(n)||await(0,ce.copy)(r,n)}const e=await(0,he.getFileLanguage)(n),{label:s,lang:o}=e;await(0,he.gzip)(n,i);return{file:a,file_path:i,size:await(0,de.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,ne.parse)(e),i=this.params.outputRoot,s=`subtitle-external-${t}.vtt`,r=(0,ne.resolve)(i,s),o=`subtitle-external-${t}.zip`,n=(0,ne.resolve)(i,o),h=`subtitle-external-u8-${t}${a}`,d=(0,ne.resolve)(i,h),c=`subtitle-external-source-${t}.zip`,l=(0,ne.resolve)(i,c);if(!await(0,de.isValidPath)(e))return!1;if(await(0,he.isUtf8File)(e))await(0,ce.copy)(e,d);else{await(0,he.saveFileAsUtf8)(e,d);if(!await(0,de.isValidFile)(d))return!1}const u=["-i",d,"-c","webvtt","-y",s];await this.ffmpeg(u,{cwd:this.params.outputRoot});if(await(0,de.isValidFile)(r)){const i=await(0,he.getFileLanguage)(r),{label:s,lang:h}=i;await(0,he.gzip)(e,l),await(0,he.gzip)(r,n);const d=await(0,de.getFileSize)(l);return{file:o,size:await(0,de.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}},ge=require("@soga/error"),we=require("path"),me=require("fs-extra"),fe=require("@soga/node-types"),_e=require("@soga/fileutils"),ye=require("@soga/utils"),be=require("@soga/error"),ve=require("path"),Pe=require("@soga/fileutils"),xe=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=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,ve.resolve)(this.params.outputRoot,i),r=await(0,Pe.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=bt(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()}},ze=class extends xe{current_position=0;current_index=0;group_data=[];async start(){const t=bt(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:fe.UploadProgress.group_media,percent:this.completed_percent+.5*this.total_percent}),await this.processGroups(),await this.postProgress({type:fe.UploadProgress.group_media,percent:this.completed_percent+.9*this.total_percent}),await this.saveData(),await this.postProgress({type:fe.UploadProgress.group_media,percent:this.completed_percent+this.total_percent}),this.db.data[t]}catch(t){throw(0,be.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||={};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:fe.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:fe.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:fe.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,!1),this.file_map[s]=r,i=i.map(t=>t.file===s?{...t,file:n,id:o,s:r.start,e:r.end}:t)}await this.db.write();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},!1),i=this.getFileName(e.file_index);await this.setPreviewIdMap({id:a,file:i,start:e.start,end:e.end},this.hostType,!1),u.push(`#EXTINF:${e.duration},`),u.push(`#EXT-X-BYTERANGE:${e.size}@${e.start}`),u.push(`${i}?id=${a}`)}await this.db.write(),o&&u.push("#EXT-X-ENDLIST");return u.join("\n")}async writeTrackText(t,e){const a=(0,we.resolve)(this.params.outputRoot,t),i=(0,we.resolve)(this.params.outputRoot,`${t}.gz`),s=(0,we.resolve)(this.params.outputRoot,`${t}.bin`);await(0,me.writeFile)(a,e,"utf-8"),await(0,ye.gzip)(a,i);if(await(0,_e.getFileSize)(i)>16){const t=(await(0,ye.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,_e.getFileSize)(s)}),hash:t}}return{...this.addOne({file_path:a,size:await(0,_e.getFileSize)(a)}),hash:""}}async writeText(t,e){const a=(0,we.resolve)(this.params.outputRoot,t);await(0,me.writeFile)(a,e,"utf-8");return this.addOne({file_path:a,size:await(0,_e.getFileSize)(a)})}addOne({file_path:t,size:e,duration:a=0},i=!1){const s=this.getSizeLimit({host_type:this.hostType,is_source:!1}),{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({host_type:this.hostType,is_source:!1}),{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))}},Te=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({host_type:i,is_source:!1}),r=new ze({...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,ge.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}},De=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 pe(this.params);if(await r.start(),s){const t=new St(this.params);await t.start();const e=new Ht(this.params);await e.start();const a=new oe(this.params);await a.start()}if(a){const t=new xt(this.params);await t.start();const e=new Ut(this.params);await e.start();const a=new Yt(this.params);await a.start()}const o=new Te(this.params);await o.start()}async getResult(){return this.db.data.grouper_result}},Re=require("@soga/types"),Se=require("@soga/node-types"),$e=require("@soga/mediainfo"),Me=require("@soga/fileutils"),Ie=require("fs-extra"),Fe=h(require("check-disk-space")),ke=require("@soga/error"),qe=class extends O{async start(){await this.calculateProgress(),await this.checkStorage(),await this.calculateMeta()}async checkStorage(){const{length:t}=this.params.hosts,{keeps:e}=this,a=await(0,Fe.default)(this.params.outputRoot),i=a.free,s=a.diskPath,r=this.params.input.filesize;if(((e.preview?1.3:0)+(e.source?1.2:0))*r*t>i)throw(0,ke.buildDError)(new Error(`${s} have no enough computer disk space, please adjust the temporary path in user settings.`),{message:`${s} have no enough computer disk space, please adjust the temporary path in user settings.`,detail:`${s} 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={[Se.UploadProgress.prepare]:{weight:0,percent:1},[Se.UploadProgress.calculate_md5]:{weight:0,percent:0},[Se.UploadProgress.separate_video]:{weight:0,percent:0},[Se.UploadProgress.separate_audio]:{weight:0,percent:0},[Se.UploadProgress.separate_subtitle]:{weight:0,percent:0},[Se.UploadProgress.transcode_video]:{weight:0,percent:0},[Se.UploadProgress.transcode_audio]:{weight:0,percent:0},[Se.UploadProgress.transcode_thumbnail]:{weight:0,percent:0},[Se.UploadProgress.transcode_source]:{weight:0,percent:0},[Se.UploadProgress.transcode_txt]:{weight:0,percent:0},[Se.UploadProgress.transcode_img]:{weight:0,percent:0},[Se.UploadProgress.group_media]:{weight:0,percent:0},[Se.UploadProgress.upload_baidu]:{weight:0,percent:0},[Se.UploadProgress.upload_ali]:{weight:0,percent:0},[Se.UploadProgress.end]:{weight:0,percent:0}},e={keep_preview:this.params.keepPreview,keep_source:this.params.keepSource},a=await(0,Me.getFileSize)(this.params.input.filepath);t[Se.UploadProgress.prepare].weight=t[Se.UploadProgress.end].weight=Math.ceil(a/1024/1024/500),t[Se.UploadProgress.calculate_md5].weight=Math.ceil(a/1024/1024/200);let i=0;if(this.isMedia)if(this.params.keepPreview){const s=await(0,$e.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,Me.isVideoSupport)(r),{duration:n}=s.general,h=o?n/400:n*(a*i)/1920/1080;t[Se.UploadProgress.separate_video].weight=Math.ceil(h),t[Se.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,Me.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,Me.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[Se.UploadProgress.separate_audio].weight=Math.ceil(a),t[Se.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[Se.UploadProgress.separate_subtitle].weight=Math.ceil(o),t[Se.UploadProgress.transcode_thumbnail].weight=Math.ceil(.08*r),i+=a,t[Se.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[Se.UploadProgress.transcode_txt].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a):this.isImg?e.keep_preview&&(t[Se.UploadProgress.transcode_img].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a);e.keep_source&&(t[Se.UploadProgress.transcode_source].weight=Math.ceil(a/1024/1024/30)),this.params.hosts.includes(Re.HostType.BAIDU)&&(t[Se.UploadProgress.upload_baidu].weight=Math.ceil(i/1024/1024/1)),this.params.hosts.includes(Re.HostType.ALI)&&(t[Se.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)}},Ee=async t=>{await(0,Ie.ensureDir)(t.outputRoot);const e=await b(t),a=new qe({...t,db:e});return await a.start(),a},Ne=require("@soga/node-types"),Ue=require("crypto"),Ce=require("fs-extra"),Le=require("@soga/types"),Ae=class extends O{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,Ue.createHash)("md5"),n=(0,Ce.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:Ne.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:Ne.UploadProgress.calculate_md5,percent:1}),i}getCloudName({host_type:t,md5:e,is_attachment:a}){const i=a?"a":"f";return t==Le.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 Ee(this.params),{keeps:a}=this,i={...this.params,keepPreview:a.preview,keepSource:a.source},s=await this.calculateMd5();if(await this.setMd5(s),i.keepSource){const t=new G(this.params);await t.start({as_preview:!a.preview})}if(e.isMedia&&i.keepPreview){const t=new De(this.params);await t.start()}if(e.isTxt&&i.keepPreview){const t=new et(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()}},Oe=async t=>{try{const e=await b(t),a=new Ae({...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:()=>Oe,getPrepare:()=>Ee}),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"),D=require("@soga/node-types"),R=require("fs-extra"),S=require("@soga/types"),$=2097152,M=4294967296,I=M,F=M,k=M,q=M,E=M,N=M,U=M,C=require("@soga/types"),L=require("@soga/utils"),A=require("worker_threads"),O=class{segmentNames={};params;id;port=null;db;get lowData(){return this.db.data}get isVideo(){return this.params.type==C.RecordType.VIDEO}get isAudio(){return this.params.type==C.RecordType.AUDIO}get isMedia(){return this.isAudio||this.isVideo}get isTxt(){return this.params.type==C.RecordType.DOC&&this.params.ftype==C.RecordFtype.DOC_TXT}get isImg(){return this.params.type==C.RecordType.IMAGE}getSizeLimit({host_type:t,is_source:e}){return(({is_shop:t,is_source:e,host_type:a})=>t?e?a==S.HostType.BAIDU?q:N:a==S.HostType.BAIDU?E:U:e?a==S.HostType.BAIDU?I:F:a==S.HostType.BAIDU?52428800:k)({is_shop:this.params.is_shop_space,is_source:e,host_type:t})}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,L.calculateMd5)({file:e,start:a,end:i}):""};if(o){if(t===C.HostType.BAIDU){const t=await(0,L.calculateMd4)({file:e,start:a,end:i});n.md4=t}if(t===C.HostType.ALI){const t=await(0,L.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):A.parentPort&&A.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}}},V=class extends O{syncGetSourceId(t){return this._syncGetId(t,"source")}async getSourceId(t,e=!0){const a=this.syncGetSourceId(t);return e&&await this.db.write(),a}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}},G=class extends V{head_size=32;as_preview=!1;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:D.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({as_preview:t}){try{if(this.as_preview=t,this.sourceResult)return await this.sendProgress(1),this.sourceResult;await this.gzip();const{length:e}=this.params.hosts;for(let t=0;t<e;t++){const e=this.params.hosts[t];await this.calculatePartList(e),await this.processDownloadMap(e)}await this.sendProgress(.9);const a=await this.getResult();return await this.sendProgress(1),a}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,R.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({host_type:t,is_source:!this.as_preview}),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,R.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,R.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({host_type:t,is_source:!this.as_preview}),{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+=$){const e=Math.min(t+$-1,o),a=e-t+1,i=l+a-1,s=await this.getSourceId({file:"source_zip",start:t,end:e},!1);n.push({id:s,file:d,start:l,end:i}),l+=a}await this.db.write(),s.push(c),e++}}await this.setPartList(t,s),await this.setDownloadList(t,n),this.dbData[e]=!0,await this.db.write()}},B=require("path"),j=require("fs-extra"),H=require("@soga/utils"),X=h(require("zlib")),W=require("@soga/utils"),K=require("@soga/error"),J=require("@soga/node-types"),Q=require("path"),Z=require("@soga/fileutils"),Y=require("fs-extra"),tt=class extends O{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,Q.resolve)(this.params.outputRoot,this.getPartName(t,e))}syncGetPreviewId(t){return this._syncGetId(t,"preview")}async getPreviewId(t,e=!0){const a=this.syncGetPreviewId(t);return e&&await this.db.write(),a}getPreviewIdMap(t){return this.db.data[`preview_${t}_id_map`]||{}}syncSetPreviewIdMap(t,e){this._syncSetIdMap(t,"preview",e)}async setPreviewIdMap(t,e,a=!0){this.syncSetPreviewIdMap(t,e),a&&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,Z.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,Q.resolve)(this.params.outputRoot,a);await(0,Y.writeFile)(i,e,"utf-8");return{file_path:i,size:await(0,Z.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({host_type:t,is_source:!1});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,Z.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,Y.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)}}},et=class extends tt{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,B.resolve)(this.params.outputRoot,this.getU8FileName())}async sendProgress(t){await this.postProgress({type:J.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,K.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,j.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,W.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({host_type:t,is_source:!1}),a=this.getU8FilePath(),i=await this.calculateSlice(),{length:s}=i,r={};let o=0,n=(0,j.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,H.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)=>{X.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,j.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,j.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}},at=require("path"),it=require("@soga/imgutils"),st=require("@soga/utils"),rt=require("@soga/fileutils"),ot=require("@soga/error"),nt=require("@soga/node-types"),ht=require("fs-extra"),dt=class extends tt{compress_file_name="";output_format="jpg";output_width=0;output_height=0;getCompressFilePath(){if(!this.compress_file_name)throw new Error("Compress file name is empty");return(0,at.resolve)(this.params.outputRoot,this.compress_file_name)}getGzFileName(){return"compressed_img.zip"}getGzFilePath(){return(0,at.resolve)(this.params.outputRoot,this.getGzFileName())}async sendProgress(t){await this.postProgress({type:nt.UploadProgress.transcode_img,percent:t})}get dbData(){return this.db.data}get image_type(){return this.params.input.filepath.includes(".")?this.params.input.filepath.split(".").pop():"unknown"}preview_type="jpg";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,ot.buildDError)(t,{message:t.message,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,it.getMetadata)(e),s=this.getCompressFilePath(),{width:r,height:o}=await(0,it.getMetadata)(s),n=await(0,rt.getFileSize)(s),h={meta:{type:this.image_type,width:a,height:i,size:t.filesize,t_type:this.output_format,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,ht.remove)(t)}catch(t){}}async compress(){if(this.dbData.img_compressed)return;const{width:t,height:e,state:a,output_filename:i,output_format:s}=await(0,it.compress)({ffmpeg_path:this.params.ffmpegPath,input_path:this.params.input.filepath,output_basename:"img_compress",output_root:this.params.outputRoot,need_default:!!this.keeps.source});if(!a)throw new Error("Unable to generate preview image");this.compress_file_name=i,this.output_format=s,this.output_width=t,this.output_height=e,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,st.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,rt.getFileSize)(e),i=this.getSizeLimit({host_type:t,is_source:!1}),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)}},ct=h(require("fluent-ffmpeg")),lt=require("child_process"),ut=require("@soga/mediainfo"),pt=class extends tt{async getMediainfo(){const{mediainfo:t}=this.db.data;if(t)return t;const e=this.params.input.filepath,a=await(0,ut.parseMediaInfo)(e);return this.db.data.mediainfo=a,await this.params.db.write(),a}constructor(t){super(t),ct.default.setFfmpegPath(t.ffmpegPath)}getFluent(){return(0,ct.default)()}async ffmpeg(t,e){const a=this.params.ffmpegPath;return await new Promise((i,s)=>{const r=(0,lt.spawn)(a,t,Object.assign({stdio:"ignore"},e));r.on("close",t=>{i(t)}),r.on("error",t=>{s(t)})})}},gt=require("path"),wt=require("@soga/fileutils"),mt=require("@soga/node-types"),ft=require("@soga/error"),_t=({type:t,track_order:e,quality:a})=>`audio-${e}-${a}-${t}.${"manifest"===t?"m3u8":"mp4"}`,yt=({width:t,height:e})=>`video-formatted-${t}-${e}.mp4`,bt=t=>`grouper_result_${t}`,vt=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)}},Pt=(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 xt=class extends pt{async start(){try{await this.separateVideo(),await this.postProgress({type:mt.UploadProgress.separate_video,percent:1})}catch(t){throw(0,ft.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=yt({width:a.width,height:a.height}),s=(0,gt.resolve)(this.params.outputRoot,i),r=(0,wt.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=Pt(t,h);await this.postProgress({type:mt.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,wt.isValidFile)(s))throw new Error("Separate Video track failed");this.db.data[t]=!0,await this.params.db.write()}},zt=require("path"),Tt=require("@soga/fileutils"),Dt=require("@soga/node-types"),Rt=require("@soga/error"),St=class extends pt{async start(){try{await this.separateTracks(),await this.postProgress({type:Dt.UploadProgress.separate_audio,percent:1})}catch(t){throw(0,Rt.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,Tt.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,Tt.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=_t({type:"formatted",track_order:t,quality:e.type}),n=(0,zt.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=Pt(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:Dt.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,Tt.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:Dt.UploadProgress.separate_audio,percent:i})}this.db.data[a]=!0,await this.params.db.write()}},$t=require("path"),Mt=require("@soga/mediainfo"),It=require("@soga/mp4box"),Ft=require("@soga/m3u8"),kt=require("@soga/node-types"),qt=require("@soga/fileutils"),Et=require("fs-extra"),Nt=require("@soga/error"),Ut=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:kt.UploadProgress.transcode_video,percent:1})}catch(t){throw(0,Nt.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=yt({width:e,height:a}),s=(0,$t.resolve)(this.params.outputRoot,i),r=this.getVideoManifestName({width:e,height:a}),o=(0,$t.resolve)(this.params.outputRoot,r),n=await(0,Ft.parseM3U8)(o),{videos:h}=await(0,It.getMp4boxInfo)(s),{codec:d}=h[0],{bandwidth:c,average_bandwidth:l}=vt(n),u=(await(0,Mt.parseMediaInfo)(s)).video[0],p=(0,qt.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,Et.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=yt(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,$t.resolve)(this.params.outputRoot,o);if(!await(0,qt.isValidFile)(h))throw new Error("Transcode video track failed");this.db.data[t]=!0,await this.db.write()}},Ct=require("path"),Lt=require("@soga/fileutils"),At=require("@soga/mp4box"),Ot=require("@soga/m3u8"),Vt=require("@soga/mediainfo"),Gt=require("fs-extra"),Bt=require("@soga/error"),jt=require("@soga/node-types"),Ht=class extends pt{async start(){try{await this.transcodeAudios(),await this.saveData()}catch(t){throw(0,Bt.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=_t({type:"formatted",track_order:t,quality:"adapt"}),a=(0,Ct.resolve)(this.params.outputRoot,e);await(0,Gt.remove)(a)}if(e.high.need){const e=_t({type:"formatted",track_order:t,quality:"high"}),a=(0,Ct.resolve)(this.params.outputRoot,e);await(0,Gt.remove)(a)}}}catch(t){}}async getQualityData({track_order:t,quality:e}){const a=_t({type:"formatted",track_order:t,quality:e}),i=(0,Ct.resolve)(this.params.outputRoot,a),s=await(0,Vt.parseMediaInfo)(i);if(!s.audio?.length)throw new Error("parse mediainfo failed!");const r=s.audio[0],o=_t({type:"manifest",track_order:t,quality:e}),n=await(0,Lt.getFileSize)(i),h=(0,Ct.resolve)(this.params.outputRoot,o),d=await(0,At.getMp4boxInfo)(i),{audios:c}=d,{language:l,codec:u}=c[0],p=l&&!l.startsWith("un")?{language:l}:void 0,g=await(0,Ot.parseM3U8)(h),{bandwidth:w,average_bandwidth:m}=vt(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:jt.UploadProgress.transcode_audio,percent:s})}await this.postProgress({type:jt.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=_t({type:"formatted",track_order:t,quality:e.type}),s=_t({type:"init",track_order:t,quality:e.type}),r=_t({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,Ct.resolve)(this.params.outputRoot,r);if(!await(0,Lt.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()}},Xt=require("path"),Wt=require("@soga/fileutils"),Kt=require("@soga/imgutils"),Jt=require("fs-extra"),Qt=require("@soga/node-types"),Zt=require("@soga/error"),Yt=class extends pt{m3u8_data=null;thumbnail_duration=30;thumbnail_group=[];row=4;col=4;screenshot_width=960;screenshot_height=540;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:Qt.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,Zt.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,Xt.resolve)(this.params.outputRoot,e),i=await(0,Wt.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,Xt.resolve)(this.params.outputRoot,s),o=this.getCoverName(),n=(0,Xt.resolve)(this.params.outputRoot,o);await(0,Jt.copy)(r,n);const h={file:o,path:n,size:await(0,Wt.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,Xt.resolve)(this.params.outputRoot,e);n.push(a)}const h=this.getTileName(t),d=(0,Xt.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,Kt.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,Xt.resolve)(this.params.outputRoot,e),l=await(0,Wt.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?this.screenshot_width:this.screenshot_height;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}},te=require("path"),ee=require("fs-extra"),ae=require("@soga/imgutils"),ie=require("@soga/fileutils"),se=require("@soga/node-types"),re=require("@soga/error"),oe=class extends pt{get cover_name(){return"audio_cover.png"}async start(){try{await this.generateCover(),this.isAudio&&await this.postProgress({type:se.UploadProgress.transcode_thumbnail,percent:1})}catch(t){throw(0,re.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,te.resolve)(this.params.outputRoot,t);if(await(0,ee.pathExists)(i)){const e=await(0,ae.getMetadata)(i),a={file:t,path:i,size:await(0,ie.getFileSize)(i),width:e.width??0,height:e.height??0};await this.setCoverResult(a)}}catch(t){throw t}finally{this.db.data[e]=!0,await this.db.write()}}},ne=require("path"),he=require("@soga/utils"),de=require("@soga/fileutils"),ce=require("fs-extra"),le=require("@soga/error"),ue=require("@soga/node-types"),pe=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:ue.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,le.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,ne.resolve)(e,a),s=`subtitle-temp-${t}.vtt`,r=(0,ne.resolve)(e,s),o=`subtitle-builtin-u8-${t}.vtt`,n=(0,ne.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,de.isValidFile)(r)){if(await(0,he.isUtf8File)(r))await(0,ce.copy)(r,n);else{await(0,he.saveFileAsUtf8)(r,n);await(0,de.isValidFile)(n)||await(0,ce.copy)(r,n)}const e=await(0,he.getFileLanguage)(n),{label:s,lang:o}=e;await(0,he.gzip)(n,i);return{file:a,file_path:i,size:await(0,de.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,ne.parse)(e),i=this.params.outputRoot,s=`subtitle-external-${t}.vtt`,r=(0,ne.resolve)(i,s),o=`subtitle-external-${t}.zip`,n=(0,ne.resolve)(i,o),h=`subtitle-external-u8-${t}${a}`,d=(0,ne.resolve)(i,h),c=`subtitle-external-source-${t}.zip`,l=(0,ne.resolve)(i,c);if(!await(0,de.isValidPath)(e))return!1;if(await(0,he.isUtf8File)(e))await(0,ce.copy)(e,d);else{await(0,he.saveFileAsUtf8)(e,d);if(!await(0,de.isValidFile)(d))return!1}const u=["-i",d,"-c","webvtt","-y",s];await this.ffmpeg(u,{cwd:this.params.outputRoot});if(await(0,de.isValidFile)(r)){const i=await(0,he.getFileLanguage)(r),{label:s,lang:h}=i;await(0,he.gzip)(e,l),await(0,he.gzip)(r,n);const d=await(0,de.getFileSize)(l);return{file:o,size:await(0,de.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}},ge=require("@soga/error"),we=require("path"),me=require("fs-extra"),fe=require("@soga/node-types"),_e=require("@soga/fileutils"),ye=require("@soga/utils"),be=require("@soga/error"),ve=require("path"),Pe=require("@soga/fileutils"),xe=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=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,ve.resolve)(this.params.outputRoot,i),r=await(0,Pe.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=bt(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()}},ze=class extends xe{current_position=0;current_index=0;group_data=[];async start(){const t=bt(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:fe.UploadProgress.group_media,percent:this.completed_percent+.5*this.total_percent}),await this.processGroups(),await this.postProgress({type:fe.UploadProgress.group_media,percent:this.completed_percent+.9*this.total_percent}),await this.saveData(),await this.postProgress({type:fe.UploadProgress.group_media,percent:this.completed_percent+this.total_percent}),this.db.data[t]}catch(t){throw(0,be.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||={};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:fe.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:fe.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:fe.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,!1),this.file_map[s]=r,i=i.map(t=>t.file===s?{...t,file:n,id:o,s:r.start,e:r.end}:t)}await this.db.write();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},!1),i=this.getFileName(e.file_index);await this.setPreviewIdMap({id:a,file:i,start:e.start,end:e.end},this.hostType,!1),u.push(`#EXTINF:${e.duration},`),u.push(`#EXT-X-BYTERANGE:${e.size}@${e.start}`),u.push(`${i}?id=${a}`)}await this.db.write(),o&&u.push("#EXT-X-ENDLIST");return u.join("\n")}async writeTrackText(t,e){const a=(0,we.resolve)(this.params.outputRoot,t),i=(0,we.resolve)(this.params.outputRoot,`${t}.gz`),s=(0,we.resolve)(this.params.outputRoot,`${t}.bin`);await(0,me.writeFile)(a,e,"utf-8"),await(0,ye.gzip)(a,i);if(await(0,_e.getFileSize)(i)>16){const t=(await(0,ye.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,_e.getFileSize)(s)}),hash:t}}return{...this.addOne({file_path:a,size:await(0,_e.getFileSize)(a)}),hash:""}}async writeText(t,e){const a=(0,we.resolve)(this.params.outputRoot,t);await(0,me.writeFile)(a,e,"utf-8");return this.addOne({file_path:a,size:await(0,_e.getFileSize)(a)})}addOne({file_path:t,size:e,duration:a=0},i=!1){const s=this.getSizeLimit({host_type:this.hostType,is_source:!1}),{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({host_type:this.hostType,is_source:!1}),{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))}},Te=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({host_type:i,is_source:!1}),r=new ze({...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,ge.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}},De=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 pe(this.params);if(await r.start(),s){const t=new St(this.params);await t.start();const e=new Ht(this.params);await e.start();const a=new oe(this.params);await a.start()}if(a){const t=new xt(this.params);await t.start();const e=new Ut(this.params);await e.start();const a=new Yt(this.params);await a.start()}const o=new Te(this.params);await o.start()}async getResult(){return this.db.data.grouper_result}},Re=require("@soga/types"),Se=require("@soga/node-types"),$e=require("@soga/mediainfo"),Me=require("@soga/fileutils"),Ie=require("fs-extra"),Fe=h(require("check-disk-space")),ke=require("@soga/error"),qe=class extends O{async start(){await this.calculateProgress(),await this.checkStorage(),await this.calculateMeta()}async checkStorage(){const{length:t}=this.params.hosts,{keeps:e}=this,a=await(0,Fe.default)(this.params.outputRoot),i=a.free,s=a.diskPath,r=this.params.input.filesize;if(((e.preview?1.3:0)+(e.source?1.2:0))*r*t>i)throw(0,ke.buildDError)(new Error(`${s} have no enough computer disk space, please adjust the temporary path in user settings.`),{message:`${s} have no enough computer disk space, please adjust the temporary path in user settings.`,detail:`${s} 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={[Se.UploadProgress.prepare]:{weight:0,percent:1},[Se.UploadProgress.calculate_md5]:{weight:0,percent:0},[Se.UploadProgress.separate_video]:{weight:0,percent:0},[Se.UploadProgress.separate_audio]:{weight:0,percent:0},[Se.UploadProgress.separate_subtitle]:{weight:0,percent:0},[Se.UploadProgress.transcode_video]:{weight:0,percent:0},[Se.UploadProgress.transcode_audio]:{weight:0,percent:0},[Se.UploadProgress.transcode_thumbnail]:{weight:0,percent:0},[Se.UploadProgress.transcode_source]:{weight:0,percent:0},[Se.UploadProgress.transcode_txt]:{weight:0,percent:0},[Se.UploadProgress.transcode_img]:{weight:0,percent:0},[Se.UploadProgress.group_media]:{weight:0,percent:0},[Se.UploadProgress.upload_baidu]:{weight:0,percent:0},[Se.UploadProgress.upload_ali]:{weight:0,percent:0},[Se.UploadProgress.end]:{weight:0,percent:0}},e={keep_preview:this.params.keepPreview,keep_source:this.params.keepSource},a=await(0,Me.getFileSize)(this.params.input.filepath);t[Se.UploadProgress.prepare].weight=t[Se.UploadProgress.end].weight=Math.ceil(a/1024/1024/500),t[Se.UploadProgress.calculate_md5].weight=Math.ceil(a/1024/1024/200);let i=0;if(this.isMedia)if(this.params.keepPreview){const s=await(0,$e.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,Me.isVideoSupport)(r),{duration:n}=s.general,h=o?n/400:n*(a*i)/1920/1080;t[Se.UploadProgress.separate_video].weight=Math.ceil(h),t[Se.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,Me.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,Me.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[Se.UploadProgress.separate_audio].weight=Math.ceil(a),t[Se.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[Se.UploadProgress.separate_subtitle].weight=Math.ceil(o),t[Se.UploadProgress.transcode_thumbnail].weight=Math.ceil(.08*r),i+=a,t[Se.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[Se.UploadProgress.transcode_txt].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a):this.isImg?e.keep_preview&&(t[Se.UploadProgress.transcode_img].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a);e.keep_source&&(t[Se.UploadProgress.transcode_source].weight=Math.ceil(a/1024/1024/30)),this.params.hosts.includes(Re.HostType.BAIDU)&&(t[Se.UploadProgress.upload_baidu].weight=Math.ceil(i/1024/1024/1)),this.params.hosts.includes(Re.HostType.ALI)&&(t[Se.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)}},Ee=async t=>{await(0,Ie.ensureDir)(t.outputRoot);const e=await b(t),a=new qe({...t,db:e});return await a.start(),a},Ne=require("@soga/node-types"),Ue=require("crypto"),Ce=require("fs-extra"),Le=require("@soga/types"),Ae=class extends O{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,Ue.createHash)("md5"),n=(0,Ce.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:Ne.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:Ne.UploadProgress.calculate_md5,percent:1}),i}getCloudName({host_type:t,md5:e,is_attachment:a}){const i=a?"a":"f";return t==Le.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 Ee(this.params),{keeps:a}=this,i={...this.params,keepPreview:a.preview,keepSource:a.source},s=await this.calculateMd5();if(await this.setMd5(s),i.keepSource){const t=new G(this.params);await t.start({as_preview:!a.preview})}if(e.isMedia&&i.keepPreview){const t=new De(this.params);await t.start()}if(e.isTxt&&i.keepPreview){const t=new et(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()}},Oe=async t=>{try{const e=await b(t),a=new Ae({...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 p}from"stream/promises";function u(t){const e=a("md5");return e.update(`${t}`),e.digest("hex")}async function l(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,p=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 p(e+1)}};await p(0),n&&h.end(),e(!0)})()})}async function m(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 g(t){return await m({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 p(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,$=4294967296,I=$,M=$,k=$,S=$,F=$,E=$,N=$;import{HostType as C,RecordFtype as L,RecordType as A}from"@soga/types";import{calculateMd4 as O,calculateMd5 as U,calculateSha1 as V}from"@soga/utils";import{parentPort as G}from"worker_threads";var B=class{segmentNames={};params;id;port=null;db;get lowData(){return this.db.data}get isVideo(){return this.params.type==A.VIDEO}get isAudio(){return this.params.type==A.AUDIO}get isMedia(){return this.isAudio||this.isVideo}get isTxt(){return this.params.type==A.DOC&&this.params.ftype==L.DOC_TXT}get isImg(){return this.params.type==A.IMAGE}getSizeLimit({host_type:t,is_source:e}){return(({is_shop:t,is_source:e,host_type:a})=>t?e?a==z.BAIDU?S:E:a==z.BAIDU?F:N:e?a==z.BAIDU?I:M:a==z.BAIDU?52428800:k)({is_shop:this.params.is_shop_space,is_source:e,host_type:t})}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 U({file:e,start:a,end:i}):""};if(o){if(t===C.BAIDU){const t=await O({file:e,start:a,end:i});n.md4=t}if(t===C.ALI){const t=await V({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 m({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):G&&G.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}}},j=class extends B{syncGetSourceId(t){return this._syncGetId(t,"source")}async getSourceId(t,e=!0){const a=this.syncGetSourceId(t);return e&&await this.db.write(),a}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-${u(`source-${e}-${a}-${this.md5}-${t}`)}`;return this.segmentNames[i]=s,s}},q=class extends j{head_size=32;as_preview=!1;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({as_preview:t}){try{if(this.as_preview=t,this.sourceResult)return await this.sendProgress(1),this.sourceResult;await this.gzip();const{length:e}=this.params.hosts;for(let t=0;t<e;t++){const e=this.params.hosts[t];await this.calculatePartList(e),await this.processDownloadMap(e)}await this.sendProgress(.9);const a=await this.getResult();return await this.sendProgress(1),a}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({host_type:t,is_source:!this.as_preview}),d=this.getPartList(t);if(d.length){const e=d[d.length-1],{path:a,size:c,file:u,index:l,end:m,start:g}=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 p(r,o);const n=i(e),h=s(a,{flags:"a"});await p(n,h)}({source1:{filepath:a,start:g,end:m},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:l});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=l+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({host_type:t,is_source:!this.as_preview}),{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 p=0;for(let t=h;t<o;t+=R){const e=Math.min(t+R-1,o),a=e-t+1,i=p+a-1,s=await this.getSourceId({file:"source_zip",start:t,end:e},!1);n.push({id:s,file:d,start:p,end:i}),p+=a}await this.db.write(),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 X}from"path";import{createWriteStream as K,readFile as H,remove as J}from"fs-extra";import{getFileBufferSlice as Q}from"@soga/utils";import W from"zlib";import{saveFileAsUtf8 as Z}from"@soga/utils";import{buildDError as Y}from"@soga/error";import{UploadProgress as tt}from"@soga/node-types";import{resolve as et}from"path";import{getFileSize as at}from"@soga/fileutils";import{copy as it,writeFile as st}from"fs-extra";var rt=class extends B{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 et(this.params.outputRoot,this.getPartName(t,e))}syncGetPreviewId(t){return this._syncGetId(t,"preview")}async getPreviewId(t,e=!0){const a=this.syncGetPreviewId(t);return e&&await this.db.write(),a}getPreviewIdMap(t){return this.db.data[`preview_${t}_id_map`]||{}}syncSetPreviewIdMap(t,e){this._syncSetIdMap(t,"preview",e)}async setPreviewIdMap(t,e,a=!0){this.syncSetPreviewIdMap(t,e),a&&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-${u(`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 at(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=et(this.params.outputRoot,a);await st(i,e,"utf-8");return{file_path:i,size:await at(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({host_type:t,is_source:!1});if(e.length){const a=e[e.length-1],{path:c,size:u,file:l,index:m,end:g}=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 p(r,o)}({filepath:c,size:u},r);const a=await at(c),h=await this.getPartInfo({host_type:t,filename:l,filepath:c,index:m,start:0,end:a-1});e[e.length-1]=h;const f=g+1,_=g+o;w={id:await this.getPreviewId({file:l,start:f,end:_}),file:l,start:f,end:_}}else{const a=m+1,i=this.getPartName(t,a),s=this.getPartPath(t,a);await it(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)}}},ot=class extends rt{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 X(this.params.outputRoot,this.getU8FileName())}async sendProgress(t){await this.postProgress({type:tt.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 Y(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 J(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 Z(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({host_type:t,is_source:!1}),a=this.getU8FilePath(),i=await this.calculateSlice(),{length:s}=i,r={};let o=0,n=K(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:p,start:u,end:l}=c,m={page:p+1,text:(await Q(a,u,l)).toString("utf8")},g=JSON.stringify(m);let w=Buffer.from(g,"utf8");if(0==d){const t={...m,map:r};w=Buffer.from(JSON.stringify(t),"utf8")}const f=await this.getPreviewId({file:"u8zip",start:u,end:l});await new Promise((a,i)=>{W.gzip(w,async(s,h)=>{if(s)return i(s);const c=h.length<this.hashBufferLength?this.hashBuffer:h.subarray(0,this.hashBufferLength),p=Buffer.concat([c,h]),u=p.length;if(o+u>e){n.end();const e=await this.increaseCurrentFileIndex(t);n=K(this.getPartPath(t,e)),o=0}const l=o,m=o+u-1;if(n.write(p),o+=u,0==d){n.end();const e={id:f,start:l,end:m,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:l,e:m};this.syncSetPreviewIdMap({id:f,file:this.getPartName(t,await this.getCurrentFileIndex(t)),start:l,end:m},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)=>{H(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),p=Buffer.byteLength(c);o.push({index:n++,start:d,end:d+p-1}),this.totalPage=n,h=t,d+=p}e(o)})});return this.dbData.txt_slice_list=e,await this.db.write(),e}};import{resolve as nt}from"path";import{getMetadata as ht,compress as dt}from"@soga/imgutils";import{gzip as ct}from"@soga/utils";import{getFileSize as pt}from"@soga/fileutils";import{buildDError as ut}from"@soga/error";import{UploadProgress as lt}from"@soga/node-types";import{remove as mt}from"fs-extra";var gt=class extends rt{compress_file_name="";output_format="jpg";output_width=0;output_height=0;getCompressFilePath(){if(!this.compress_file_name)throw new Error("Compress file name is empty");return nt(this.params.outputRoot,this.compress_file_name)}getGzFileName(){return"compressed_img.zip"}getGzFilePath(){return nt(this.params.outputRoot,this.getGzFileName())}async sendProgress(t){await this.postProgress({type:lt.transcode_img,percent:t})}get dbData(){return this.db.data}get image_type(){return this.params.input.filepath.includes(".")?this.params.input.filepath.split(".").pop():"unknown"}preview_type="jpg";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 ut(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 ht(e),s=this.getCompressFilePath(),{width:r,height:o}=await ht(s),n=await pt(s),h={meta:{type:this.image_type,width:a,height:i,size:t.filesize,t_type:this.output_format,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 mt(t)}catch(t){}}async compress(){if(this.dbData.img_compressed)return;const{width:t,height:e,output_filename:a,output_format:i}=await dt({ffmpeg_path:this.params.ffmpegPath,input_path:this.params.input.filepath,output_basename:"img_compress",output_root:this.params.outputRoot});this.compress_file_name=a,this.output_format=i,this.output_width=t,this.output_height=e,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 ct(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 pt(e),i=this.getSizeLimit({host_type:t,is_source:!1}),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 p=0,u=n-o,l=await this.getPartInfo({host_type:t,filepath:c,filename:d,start:p,end:u,index:h},!1);s.push(l);const m=await this.getPreviewId({file:d,start:p,end:u});r.push({id:m,file:d,start:p,end:u}),await this.setPreviewIdMap({id:m,file:d,start:p,end:u},t)}await this.setPartList(t,s),await this.setPreviewList(t,r)}};import wt from"fluent-ffmpeg";import{spawn as ft}from"child_process";import{parseMediaInfo as _t}from"@soga/mediainfo";var yt=class extends rt{async getMediainfo(){const{mediainfo:t}=this.db.data;if(t)return t;const e=this.params.input.filepath,a=await _t(e);return this.db.data.mediainfo=a,await this.params.db.write(),a}constructor(t){super(t),wt.setFfmpegPath(t.ffmpegPath)}getFluent(){return wt()}async ffmpeg(t,e){const a=this.params.ffmpegPath;return await new Promise((i,s)=>{const r=ft(a,t,Object.assign({stdio:"ignore"},e));r.on("close",t=>{i(t)}),r.on("error",t=>{s(t)})})}};import{resolve as bt}from"path";import{isValidFile as vt,isVideoSupport as Pt}from"@soga/fileutils";import{UploadProgress as xt}from"@soga/node-types";import{buildDError as Dt}from"@soga/error";var Tt=({type:t,track_order:e,quality:a})=>`audio-${e}-${a}-${t}.${"manifest"===t?"m3u8":"mp4"}`,zt=({width:t,height:e})=>`video-formatted-${t}-${e}.mp4`,Rt=t=>`grouper_result_${t}`,$t=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)}},It=(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 Mt=class extends yt{async start(){try{await this.separateVideo(),await this.postProgress({type:xt.separate_video,percent:1})}catch(t){throw Dt(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=zt({width:a.width,height:a.height}),s=bt(this.params.outputRoot,i),r=Pt(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=It(t,h);await this.postProgress({type:xt.separate_video,percent:e})}}).on("end",async()=>{t("end"),a.kill("SIGKILL")}).on("error",async t=>{e(t)}).output(s);a.run()});if(!await vt(s))throw new Error("Separate Video track failed");this.db.data[t]=!0,await this.params.db.write()}};import{resolve as kt}from"path";import{isValidFile as St,isAudioAdapt as Ft,isAudioHigh as Et}from"@soga/fileutils";import{UploadProgress as Nt}from"@soga/node-types";import{buildDError as Ct}from"@soga/error";var Lt=class extends yt{async start(){try{await this.separateTracks(),await this.postProgress({type:Nt.separate_audio,percent:1})}catch(t){throw Ct(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}};Ft(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):Et(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=Tt({type:"formatted",track_order:t,quality:e.type}),n=kt(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=It(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:Nt.separate_audio,percent:o})}}).on("end",async()=>{a("end"),s.kill("SIGKILL")}).on("error",async t=>{i(t)}).output(n);s.run()});if(!await St(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:Nt.separate_audio,percent:i})}this.db.data[a]=!0,await this.params.db.write()}};import{resolve as At}from"path";import{parseMediaInfo as Ot}from"@soga/mediainfo";import{getMp4boxInfo as Ut}from"@soga/mp4box";import{parseM3U8 as Vt}from"@soga/m3u8";import{UploadProgress as Gt}from"@soga/node-types";import{isValidFile as Bt,getStandardInfo as jt}from"@soga/fileutils";import{remove as qt}from"fs-extra";import{buildDError as Xt}from"@soga/error";var Kt=class extends yt{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:Gt.transcode_video,percent:1})}catch(t){throw Xt(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=zt({width:e,height:a}),s=At(this.params.outputRoot,i),r=this.getVideoManifestName({width:e,height:a}),o=At(this.params.outputRoot,r),n=await Vt(o),{videos:h}=await Ut(s),{codec:d}=h[0],{bandwidth:c,average_bandwidth:p}=$t(n),u=(await Ot(s)).video[0],l=jt(e,a),m={m3u8:n,m3u8_path:o,codec:d,width:e,height:a,bandwidth:c,average_bandwidth:p,bitdepth:u?.bitdepth,bitrate:u?.bitrate,codec_name:u?.codec??"",framerate:u?.framerate,label:l?.label??"unknown"};await this.setVideoTranscoderResult(m),this.params.debug||await qt(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=zt(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=At(this.params.outputRoot,o);if(!await Bt(h))throw new Error("Transcode video track failed");this.db.data[t]=!0,await this.db.write()}};import{resolve as Ht}from"path";import{getFileSize as Jt,isValidFile as Qt}from"@soga/fileutils";import{getMp4boxInfo as Wt}from"@soga/mp4box";import{parseM3U8 as Zt}from"@soga/m3u8";import{parseMediaInfo as Yt}from"@soga/mediainfo";import{remove as te}from"fs-extra";import{buildDError as ee}from"@soga/error";import{UploadProgress as ae}from"@soga/node-types";var ie=class extends yt{async start(){try{await this.transcodeAudios(),await this.saveData()}catch(t){throw ee(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=Tt({type:"formatted",track_order:t,quality:"adapt"}),a=Ht(this.params.outputRoot,e);await te(a)}if(e.high.need){const e=Tt({type:"formatted",track_order:t,quality:"high"}),a=Ht(this.params.outputRoot,e);await te(a)}}}catch(t){}}async getQualityData({track_order:t,quality:e}){const a=Tt({type:"formatted",track_order:t,quality:e}),i=Ht(this.params.outputRoot,a),s=await Yt(i);if(!s.audio?.length)throw new Error("parse mediainfo failed!");const r=s.audio[0],o=Tt({type:"manifest",track_order:t,quality:e}),n=await Jt(i),h=Ht(this.params.outputRoot,o),d=await Wt(i),{audios:c}=d,{language:p,codec:u}=c[0],l=p&&!p.startsWith("un")?{language:p}:void 0,m=await Zt(h),{bandwidth:g,average_bandwidth:w}=$t(m);return{m3u8:m,m3u8_path:h,codec:u,codec_name:r.codec,...l,order:t,lossless:r.lossless,channels:r.channels,bandwidth:g,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:ae.transcode_audio,percent:s})}await this.postProgress({type:ae.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=Tt({type:"formatted",track_order:t,quality:e.type}),s=Tt({type:"init",track_order:t,quality:e.type}),r=Tt({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=Ht(this.params.outputRoot,r);if(!await Qt(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 se}from"path";import{getFileSize as re}from"@soga/fileutils";import{combine as oe}from"@soga/imgutils";import{copy as ne}from"fs-extra";import{UploadProgress as he}from"@soga/node-types";import{buildDError as de}from"@soga/error";var ce=class extends yt{m3u8_data=null;thumbnail_duration=30;thumbnail_group=[];row=4;col=4;screenshot_width=960;screenshot_height=540;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:he.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 de(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,p=Math.floor(h/(e*t)),u=h%e*i,l=Math.floor(h%(t*e)/e)*s,m=this.getTileName(p);n.push(m),o.push({file:m,st:d,et:c,x:u,y:l,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=se(this.params.outputRoot,e),i=await re(a);c.push({file:e,file_path:a,size:i})}const p={width:this.screenshot_width,height:this.screenshot_height,row:this.row,col:this.col,tile_list:c,sprite_list:o};await this.setVideoThumbnailerResult(p)}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=se(this.params.outputRoot,s),o=this.getCoverName(),n=se(this.params.outputRoot,o);await ne(r,n);const h={file:o,path:n,size:await re(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=se(this.params.outputRoot,e);n.push(a)}const h=this.getTileName(t),d=se(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 oe({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=se(this.params.outputRoot,e),p=await re(c);if(0===p)throw new Error(`Generate video thumbnail error: [index: ${t}, start_time: ${d.start_time}, end_time: ${d.end_time}]`);p>=a.size&&(a.index=t,a.size=p,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?this.screenshot_width:this.screenshot_height;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 pe}from"path";import{pathExists as ue}from"fs-extra";import{getMetadata as le}from"@soga/imgutils";import{getFileSize as me}from"@soga/fileutils";import{UploadProgress as ge}from"@soga/node-types";import{buildDError as we}from"@soga/error";var fe=class extends yt{get cover_name(){return"audio_cover.png"}async start(){try{await this.generateCover(),this.isAudio&&await this.postProgress({type:ge.transcode_thumbnail,percent:1})}catch(t){throw we(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=pe(this.params.outputRoot,t);if(await ue(i)){const e=await le(i),a={file:t,path:i,size:await me(i),width:e.width??0,height:e.height??0};await this.setCoverResult(a)}}catch(t){throw t}finally{this.db.data[e]=!0,await this.db.write()}}};import{parse as _e,resolve as ye}from"path";import{getFileLanguage as be,isUtf8File as ve,saveFileAsUtf8 as Pe,gzip as xe}from"@soga/utils";import{isValidFile as De,getFileSize as Te,isValidPath as ze}from"@soga/fileutils";import{copy as Re}from"fs-extra";import{buildDError as $e}from"@soga/error";import{UploadProgress as Ie}from"@soga/node-types";var Me=class extends yt{builtin_tracks=0;external_tracks=0;get tracks(){return this.builtin_tracks+this.external_tracks}async sendProgress(t){await this.postProgress({type:Ie.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 $e(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=ye(e,a),s=`subtitle-temp-${t}.vtt`,r=ye(e,s),o=ye(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 De(r)){if(await ve(r))await Re(r,o);else{await Pe(r,o);await De(o)||await Re(r,o)}const e=await be(o),{label:s,lang:n}=e;await xe(o,i);return{file:a,file_path:i,size:await Te(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}=_e(e),i=this.params.outputRoot,s=`subtitle-external-${t}.vtt`,r=ye(i,s),o=`subtitle-external-${t}.zip`,n=ye(i,o),h=ye(i,`subtitle-external-u8-${t}${a}`),d=`subtitle-external-source-${t}.zip`,c=ye(i,d);if(!await ze(e))return!1;if(await ve(e))await Re(e,h);else{await Pe(e,h);if(!await De(h))return!1}const p=["-i",h,"-c","webvtt","-y",s];await this.ffmpeg(p,{cwd:this.params.outputRoot});if(await De(r)){const i=await be(r),{label:s,lang:h}=i;await xe(e,c),await xe(r,n);const p=await Te(c);return{file:o,size:await Te(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:p,ext:a}}}return!1}};import{buildDError as ke}from"@soga/error";import{resolve as Se}from"path";import{writeFile as Fe}from"fs-extra";import{UploadProgress as Ee}from"@soga/node-types";import{getFileSize as Ne}from"@soga/fileutils";import{gzip as Ce,getFileBufferSlice as Le}from"@soga/utils";import{buildDError as Ae}from"@soga/error";import{resolve as Oe}from"path";import{getFileSize as Ue}from"@soga/fileutils";var Ve=class extends yt{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=Oe(this.params.outputRoot,i),r=await Ue(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),p=this.file_map[c],{file_index:u,start:l,end:m,size:g,hash:w}=p,f=this.getFileName(u),_=await this.getPreviewId({file:c});await this.setPreviewIdMap({id:_,file:f,start:l,end:m},this.hostType);const y={id:_,average_band:t,band:s,channels:r,codec:o,codec_name:n,language:h,order:d,file:f,start:l,end:m,size:g,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:p,start:u,end:l,size:m,hash:g}=c,w=this.getFileName(p),f=await this.getPreviewId({file:d});await this.setPreviewIdMap({id:f,file:w,start:u,end:l},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:l,size:m,hash:g}}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:p}=o,u=this.getFileName(n);await this.setPreviewIdMap({id:r,file:u,start:h,end:d},this.hostType);const{average_bandwidth:l,bandwidth:m,codec:g,width:w,height:f,label:_,codec_name:y,bitdepth:b,framerate:v}=i,P={id:r,average_band:l,band:m,codec:g,codec_name:y,bitdepth:b,framerate:Math.round(v),width:w,height:f,file:u,start:h,end:d,size:c,label:_,hash:p};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:p,start:u,end:l,size:m}=c,g=this.getFileName(p),w={uuid:await this.getPreviewId({file:r,start:u,end:l}),builtin:s,lang:o,name:h,title:n,file:g,start:u,end:l,size:m};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,p=this.getFileName(n),u=await this.getPreviewId({file:r});await this.setPreviewIdMap({id:u,file:p,start:h,end:d},this.hostType);return{id:u,row:e,col:a,width:i,height:s,file:p,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),p=await this.getPreviewId({file:e.path});await this.setPreviewIdMap({id:p,file:c,start:n,end:h},this.hostType);return{id:p,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=Rt(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()}},Ge=class extends Ve{current_position=0;current_index=0;group_data=[];async start(){const t=Rt(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:Ee.group_media,percent:this.completed_percent+.5*this.total_percent}),await this.processGroups(),await this.postProgress({type:Ee.group_media,percent:this.completed_percent+.9*this.total_percent}),await this.saveData(),await this.postProgress({type:Ee.group_media,percent:this.completed_percent+this.total_percent}),this.db.data[t]}catch(t){throw Ae(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||={};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 l({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:Ee.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:Ee.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:Ee.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,!1),this.file_map[s]=r,i=i.map(t=>t.file===s?{...t,file:n,id:o,s:r.start,e:r.end}:t)}await this.db.write();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),p=`${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=${p},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},!1),i=this.getFileName(e.file_index);await this.setPreviewIdMap({id:a,file:i,start:e.start,end:e.end},this.hostType,!1),u.push(`#EXTINF:${e.duration},`),u.push(`#EXT-X-BYTERANGE:${e.size}@${e.start}`),u.push(`${i}?id=${a}`)}await this.db.write(),o&&u.push("#EXT-X-ENDLIST");return u.join("\n")}async writeTrackText(t,e){const a=Se(this.params.outputRoot,t),r=Se(this.params.outputRoot,`${t}.gz`),o=Se(this.params.outputRoot,`${t}.bin`);await Fe(a,e,"utf-8"),await Ce(a,r);if(await Ne(r)>16){const t=(await Le(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 Ne(o)}),hash:t}}return{...this.addOne({file_path:a,size:await Ne(a)}),hash:""}}async writeText(t,e){const a=Se(this.params.outputRoot,t);await Fe(a,e,"utf-8");return this.addOne({file_path:a,size:await Ne(a)})}addOne({file_path:t,size:e,duration:a=0},i=!1){const s=this.getSizeLimit({host_type:this.hostType,is_source:!1}),{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({host_type:this.hostType,is_source:!1}),{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))}},Be=class extends yt{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({host_type:i,is_source:!1}),r=new Ge({...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 ke(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}},je=class extends yt{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 Me(this.params);if(await r.start(),s){const t=new Lt(this.params);await t.start();const e=new ie(this.params);await e.start();const a=new fe(this.params);await a.start()}if(a){const t=new Mt(this.params);await t.start();const e=new Kt(this.params);await e.start();const a=new ce(this.params);await a.start()}const o=new Be(this.params);await o.start()}async getResult(){return this.db.data.grouper_result}};import{HostType as qe}from"@soga/types";import{UploadProgress as Xe}from"@soga/node-types";import{parseMediaInfo as Ke}from"@soga/mediainfo";import{getFileSize as He,isAudioAdapt as Je,isAudioHigh as Qe,isVideoSupport as We}from"@soga/fileutils";import{ensureDir as Ze}from"fs-extra";import Ye from"check-disk-space";import{buildDError as ta}from"@soga/error";var ea=class extends B{async start(){await this.calculateProgress(),await this.checkStorage(),await this.calculateMeta()}async checkStorage(){const{length:t}=this.params.hosts,{keeps:e}=this,a=await Ye(this.params.outputRoot),i=a.free,s=a.diskPath,r=this.params.input.filesize;if(((e.preview?1.3:0)+(e.source?1.2:0))*r*t>i)throw ta(new Error(`${s} have no enough computer disk space, please adjust the temporary path in user settings.`),{message:`${s} have no enough computer disk space, please adjust the temporary path in user settings.`,detail:`${s} 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={[Xe.prepare]:{weight:0,percent:1},[Xe.calculate_md5]:{weight:0,percent:0},[Xe.separate_video]:{weight:0,percent:0},[Xe.separate_audio]:{weight:0,percent:0},[Xe.separate_subtitle]:{weight:0,percent:0},[Xe.transcode_video]:{weight:0,percent:0},[Xe.transcode_audio]:{weight:0,percent:0},[Xe.transcode_thumbnail]:{weight:0,percent:0},[Xe.transcode_source]:{weight:0,percent:0},[Xe.transcode_txt]:{weight:0,percent:0},[Xe.transcode_img]:{weight:0,percent:0},[Xe.group_media]:{weight:0,percent:0},[Xe.upload_baidu]:{weight:0,percent:0},[Xe.upload_ali]:{weight:0,percent:0},[Xe.end]:{weight:0,percent:0}},e={keep_preview:this.params.keepPreview,keep_source:this.params.keepSource},a=await He(this.params.input.filepath);t[Xe.prepare].weight=t[Xe.end].weight=Math.ceil(a/1024/1024/500),t[Xe.calculate_md5].weight=Math.ceil(a/1024/1024/200);let i=0;if(this.isMedia)if(this.params.keepPreview){const s=await Ke(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=We(r),{duration:n}=s.general,h=o?n/400:n*(a*i)/1920/1080;t[Xe.separate_video].weight=Math.ceil(h),t[Xe.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};Je(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):Qe(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[Xe.separate_audio].weight=Math.ceil(a),t[Xe.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[Xe.separate_subtitle].weight=Math.ceil(o),t[Xe.transcode_thumbnail].weight=Math.ceil(.08*r),i+=a,t[Xe.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[Xe.transcode_txt].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a):this.isImg?e.keep_preview&&(t[Xe.transcode_img].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a);e.keep_source&&(t[Xe.transcode_source].weight=Math.ceil(a/1024/1024/30)),this.params.hosts.includes(qe.BAIDU)&&(t[Xe.upload_baidu].weight=Math.ceil(i/1024/1024/1)),this.params.hosts.includes(qe.ALI)&&(t[Xe.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)}},aa=async t=>{await Ze(t.outputRoot);const e=await g(t),a=new ea({...t,db:e});return await a.start(),a};import{UploadProgress as ia}from"@soga/node-types";import{createHash as sa}from"crypto";import{createReadStream as ra}from"fs-extra";import{HostType as oa}from"@soga/types";var na=class extends B{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=sa("md5"),n=ra(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:ia.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:ia.calculate_md5,percent:1}),i}getCloudName({host_type:t,md5:e,is_attachment:a}){const i=a?"a":"f";return t==oa.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 p=t?.data[r];if(p?.parts){o(p.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:p.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 aa(this.params),{keeps:a}=this,i={...this.params,keepPreview:a.preview,keepSource:a.source},s=await this.calculateMd5();if(await this.setMd5(s),i.keepSource){const t=new q(this.params);await t.start({as_preview:!a.preview})}if(e.isMedia&&i.keepPreview){const t=new je(this.params);await t.start()}if(e.isTxt&&i.keepPreview){const t=new ot(this.params);await t.start()}if(e.isImg){const t=new gt(this.params);await t.start()}this.db.data[t]=!0,await this.db.write()}},ha=async e=>{try{const t=await g(e),a=new na({...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{ha as encode,aa 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 p}from"stream/promises";function l(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,p=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 p(e+1)}};await p(0),n&&h.end(),e(!0)})()})}async function m(t,a){const i=l(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 g(t){return await m({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 p(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,$=4294967296,I=$,M=$,k=$,S=$,F=$,E=$,N=$;import{HostType as C,RecordFtype as L,RecordType as A}from"@soga/types";import{calculateMd4 as U,calculateMd5 as O,calculateSha1 as V}from"@soga/utils";import{parentPort as G}from"worker_threads";var B=class{segmentNames={};params;id;port=null;db;get lowData(){return this.db.data}get isVideo(){return this.params.type==A.VIDEO}get isAudio(){return this.params.type==A.AUDIO}get isMedia(){return this.isAudio||this.isVideo}get isTxt(){return this.params.type==A.DOC&&this.params.ftype==L.DOC_TXT}get isImg(){return this.params.type==A.IMAGE}getSizeLimit({host_type:t,is_source:e}){return(({is_shop:t,is_source:e,host_type:a})=>t?e?a==z.BAIDU?S:E:a==z.BAIDU?F:N:e?a==z.BAIDU?I:M:a==z.BAIDU?52428800:k)({is_shop:this.params.is_shop_space,is_source:e,host_type:t})}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 O({file:e,start:a,end:i}):""};if(o){if(t===C.BAIDU){const t=await U({file:e,start:a,end:i});n.md4=t}if(t===C.ALI){const t=await V({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 m({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):G&&G.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}}},j=class extends B{syncGetSourceId(t){return this._syncGetId(t,"source")}async getSourceId(t,e=!0){const a=this.syncGetSourceId(t);return e&&await this.db.write(),a}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-${l(`source-${e}-${a}-${this.md5}-${t}`)}`;return this.segmentNames[i]=s,s}},q=class extends j{head_size=32;as_preview=!1;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({as_preview:t}){try{if(this.as_preview=t,this.sourceResult)return await this.sendProgress(1),this.sourceResult;await this.gzip();const{length:e}=this.params.hosts;for(let t=0;t<e;t++){const e=this.params.hosts[t];await this.calculatePartList(e),await this.processDownloadMap(e)}await this.sendProgress(.9);const a=await this.getResult();return await this.sendProgress(1),a}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({host_type:t,is_source:!this.as_preview}),d=this.getPartList(t);if(d.length){const e=d[d.length-1],{path:a,size:c,file:l,index:u,end:m,start:g}=e,w=f(this.params.outputRoot,l);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 p(r,o);const n=i(e),h=s(a,{flags:"a"});await p(n,h)}({source1:{filepath:a,start:g,end:m},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:l,index:u});d[d.length-1]=f;r={id:await this.getSourceId({file:l,start:c,end:h}),file:l,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({host_type:t,is_source:!this.as_preview}),{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 p=0;for(let t=h;t<o;t+=R){const e=Math.min(t+R-1,o),a=e-t+1,i=p+a-1,s=await this.getSourceId({file:"source_zip",start:t,end:e},!1);n.push({id:s,file:d,start:p,end:i}),p+=a}await this.db.write(),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 X}from"path";import{createWriteStream as K,readFile as H,remove as J}from"fs-extra";import{getFileBufferSlice as Q}from"@soga/utils";import W from"zlib";import{saveFileAsUtf8 as Z}from"@soga/utils";import{buildDError as Y}from"@soga/error";import{UploadProgress as tt}from"@soga/node-types";import{resolve as et}from"path";import{getFileSize as at}from"@soga/fileutils";import{copy as it,writeFile as st}from"fs-extra";var rt=class extends B{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 et(this.params.outputRoot,this.getPartName(t,e))}syncGetPreviewId(t){return this._syncGetId(t,"preview")}async getPreviewId(t,e=!0){const a=this.syncGetPreviewId(t);return e&&await this.db.write(),a}getPreviewIdMap(t){return this.db.data[`preview_${t}_id_map`]||{}}syncSetPreviewIdMap(t,e){this._syncSetIdMap(t,"preview",e)}async setPreviewIdMap(t,e,a=!0){this.syncSetPreviewIdMap(t,e),a&&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-${l(`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 at(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=et(this.params.outputRoot,a);await st(i,e,"utf-8");return{file_path:i,size:await at(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({host_type:t,is_source:!1});if(e.length){const a=e[e.length-1],{path:c,size:l,file:u,index:m,end:g}=a;let w;if(l+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 p(r,o)}({filepath:c,size:l},r);const a=await at(c),h=await this.getPartInfo({host_type:t,filename:u,filepath:c,index:m,start:0,end:a-1});e[e.length-1]=h;const f=g+1,_=g+o;w={id:await this.getPreviewId({file:u,start:f,end:_}),file:u,start:f,end:_}}else{const a=m+1,i=this.getPartName(t,a),s=this.getPartPath(t,a);await it(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)}}},ot=class extends rt{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 X(this.params.outputRoot,this.getU8FileName())}async sendProgress(t){await this.postProgress({type:tt.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 Y(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 J(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 Z(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({host_type:t,is_source:!1}),a=this.getU8FilePath(),i=await this.calculateSlice(),{length:s}=i,r={};let o=0,n=K(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:p,start:l,end:u}=c,m={page:p+1,text:(await Q(a,l,u)).toString("utf8")},g=JSON.stringify(m);let w=Buffer.from(g,"utf8");if(0==d){const t={...m,map:r};w=Buffer.from(JSON.stringify(t),"utf8")}const f=await this.getPreviewId({file:"u8zip",start:l,end:u});await new Promise((a,i)=>{W.gzip(w,async(s,h)=>{if(s)return i(s);const c=h.length<this.hashBufferLength?this.hashBuffer:h.subarray(0,this.hashBufferLength),p=Buffer.concat([c,h]),l=p.length;if(o+l>e){n.end();const e=await this.increaseCurrentFileIndex(t);n=K(this.getPartPath(t,e)),o=0}const u=o,m=o+l-1;if(n.write(p),o+=l,0==d){n.end();const e={id:f,start:u,end:m,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:m};this.syncSetPreviewIdMap({id:f,file:this.getPartName(t,await this.getCurrentFileIndex(t)),start:u,end:m},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)=>{H(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),p=Buffer.byteLength(c);o.push({index:n++,start:d,end:d+p-1}),this.totalPage=n,h=t,d+=p}e(o)})});return this.dbData.txt_slice_list=e,await this.db.write(),e}};import{resolve as nt}from"path";import{getMetadata as ht,compress as dt}from"@soga/imgutils";import{gzip as ct}from"@soga/utils";import{getFileSize as pt}from"@soga/fileutils";import{buildDError as lt}from"@soga/error";import{UploadProgress as ut}from"@soga/node-types";import{remove as mt}from"fs-extra";var gt=class extends rt{compress_file_name="";output_format="jpg";output_width=0;output_height=0;getCompressFilePath(){if(!this.compress_file_name)throw new Error("Compress file name is empty");return nt(this.params.outputRoot,this.compress_file_name)}getGzFileName(){return"compressed_img.zip"}getGzFilePath(){return nt(this.params.outputRoot,this.getGzFileName())}async sendProgress(t){await this.postProgress({type:ut.transcode_img,percent:t})}get dbData(){return this.db.data}get image_type(){return this.params.input.filepath.includes(".")?this.params.input.filepath.split(".").pop():"unknown"}preview_type="jpg";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 lt(t,{message:t.message,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 ht(e),s=this.getCompressFilePath(),{width:r,height:o}=await ht(s),n=await pt(s),h={meta:{type:this.image_type,width:a,height:i,size:t.filesize,t_type:this.output_format,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 mt(t)}catch(t){}}async compress(){if(this.dbData.img_compressed)return;const{width:t,height:e,state:a,output_filename:i,output_format:s}=await dt({ffmpeg_path:this.params.ffmpegPath,input_path:this.params.input.filepath,output_basename:"img_compress",output_root:this.params.outputRoot,need_default:!!this.keeps.source});if(!a)throw new Error("Unable to generate preview image");this.compress_file_name=i,this.output_format=s,this.output_width=t,this.output_height=e,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 ct(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 pt(e),i=this.getSizeLimit({host_type:t,is_source:!1}),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 p=0,l=n-o,u=await this.getPartInfo({host_type:t,filepath:c,filename:d,start:p,end:l,index:h},!1);s.push(u);const m=await this.getPreviewId({file:d,start:p,end:l});r.push({id:m,file:d,start:p,end:l}),await this.setPreviewIdMap({id:m,file:d,start:p,end:l},t)}await this.setPartList(t,s),await this.setPreviewList(t,r)}};import wt from"fluent-ffmpeg";import{spawn as ft}from"child_process";import{parseMediaInfo as _t}from"@soga/mediainfo";var yt=class extends rt{async getMediainfo(){const{mediainfo:t}=this.db.data;if(t)return t;const e=this.params.input.filepath,a=await _t(e);return this.db.data.mediainfo=a,await this.params.db.write(),a}constructor(t){super(t),wt.setFfmpegPath(t.ffmpegPath)}getFluent(){return wt()}async ffmpeg(t,e){const a=this.params.ffmpegPath;return await new Promise((i,s)=>{const r=ft(a,t,Object.assign({stdio:"ignore"},e));r.on("close",t=>{i(t)}),r.on("error",t=>{s(t)})})}};import{resolve as bt}from"path";import{isValidFile as vt,isVideoSupport as Pt}from"@soga/fileutils";import{UploadProgress as xt}from"@soga/node-types";import{buildDError as Dt}from"@soga/error";var Tt=({type:t,track_order:e,quality:a})=>`audio-${e}-${a}-${t}.${"manifest"===t?"m3u8":"mp4"}`,zt=({width:t,height:e})=>`video-formatted-${t}-${e}.mp4`,Rt=t=>`grouper_result_${t}`,$t=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)}},It=(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 Mt=class extends yt{async start(){try{await this.separateVideo(),await this.postProgress({type:xt.separate_video,percent:1})}catch(t){throw Dt(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=zt({width:a.width,height:a.height}),s=bt(this.params.outputRoot,i),r=Pt(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=It(t,h);await this.postProgress({type:xt.separate_video,percent:e})}}).on("end",async()=>{t("end"),a.kill("SIGKILL")}).on("error",async t=>{e(t)}).output(s);a.run()});if(!await vt(s))throw new Error("Separate Video track failed");this.db.data[t]=!0,await this.params.db.write()}};import{resolve as kt}from"path";import{isValidFile as St,isAudioAdapt as Ft,isAudioHigh as Et}from"@soga/fileutils";import{UploadProgress as Nt}from"@soga/node-types";import{buildDError as Ct}from"@soga/error";var Lt=class extends yt{async start(){try{await this.separateTracks(),await this.postProgress({type:Nt.separate_audio,percent:1})}catch(t){throw Ct(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}};Ft(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):Et(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=Tt({type:"formatted",track_order:t,quality:e.type}),n=kt(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=It(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:Nt.separate_audio,percent:o})}}).on("end",async()=>{a("end"),s.kill("SIGKILL")}).on("error",async t=>{i(t)}).output(n);s.run()});if(!await St(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:Nt.separate_audio,percent:i})}this.db.data[a]=!0,await this.params.db.write()}};import{resolve as At}from"path";import{parseMediaInfo as Ut}from"@soga/mediainfo";import{getMp4boxInfo as Ot}from"@soga/mp4box";import{parseM3U8 as Vt}from"@soga/m3u8";import{UploadProgress as Gt}from"@soga/node-types";import{isValidFile as Bt,getStandardInfo as jt}from"@soga/fileutils";import{remove as qt}from"fs-extra";import{buildDError as Xt}from"@soga/error";var Kt=class extends yt{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:Gt.transcode_video,percent:1})}catch(t){throw Xt(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=zt({width:e,height:a}),s=At(this.params.outputRoot,i),r=this.getVideoManifestName({width:e,height:a}),o=At(this.params.outputRoot,r),n=await Vt(o),{videos:h}=await Ot(s),{codec:d}=h[0],{bandwidth:c,average_bandwidth:p}=$t(n),l=(await Ut(s)).video[0],u=jt(e,a),m={m3u8:n,m3u8_path:o,codec:d,width:e,height:a,bandwidth:c,average_bandwidth:p,bitdepth:l?.bitdepth,bitrate:l?.bitrate,codec_name:l?.codec??"",framerate:l?.framerate,label:u?.label??"unknown"};await this.setVideoTranscoderResult(m),this.params.debug||await qt(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=zt(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=At(this.params.outputRoot,o);if(!await Bt(h))throw new Error("Transcode video track failed");this.db.data[t]=!0,await this.db.write()}};import{resolve as Ht}from"path";import{getFileSize as Jt,isValidFile as Qt}from"@soga/fileutils";import{getMp4boxInfo as Wt}from"@soga/mp4box";import{parseM3U8 as Zt}from"@soga/m3u8";import{parseMediaInfo as Yt}from"@soga/mediainfo";import{remove as te}from"fs-extra";import{buildDError as ee}from"@soga/error";import{UploadProgress as ae}from"@soga/node-types";var ie=class extends yt{async start(){try{await this.transcodeAudios(),await this.saveData()}catch(t){throw ee(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=Tt({type:"formatted",track_order:t,quality:"adapt"}),a=Ht(this.params.outputRoot,e);await te(a)}if(e.high.need){const e=Tt({type:"formatted",track_order:t,quality:"high"}),a=Ht(this.params.outputRoot,e);await te(a)}}}catch(t){}}async getQualityData({track_order:t,quality:e}){const a=Tt({type:"formatted",track_order:t,quality:e}),i=Ht(this.params.outputRoot,a),s=await Yt(i);if(!s.audio?.length)throw new Error("parse mediainfo failed!");const r=s.audio[0],o=Tt({type:"manifest",track_order:t,quality:e}),n=await Jt(i),h=Ht(this.params.outputRoot,o),d=await Wt(i),{audios:c}=d,{language:p,codec:l}=c[0],u=p&&!p.startsWith("un")?{language:p}:void 0,m=await Zt(h),{bandwidth:g,average_bandwidth:w}=$t(m);return{m3u8:m,m3u8_path:h,codec:l,codec_name:r.codec,...u,order:t,lossless:r.lossless,channels:r.channels,bandwidth:g,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:ae.transcode_audio,percent:s})}await this.postProgress({type:ae.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=Tt({type:"formatted",track_order:t,quality:e.type}),s=Tt({type:"init",track_order:t,quality:e.type}),r=Tt({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=Ht(this.params.outputRoot,r);if(!await Qt(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 se}from"path";import{getFileSize as re}from"@soga/fileutils";import{combine as oe}from"@soga/imgutils";import{copy as ne}from"fs-extra";import{UploadProgress as he}from"@soga/node-types";import{buildDError as de}from"@soga/error";var ce=class extends yt{m3u8_data=null;thumbnail_duration=30;thumbnail_group=[];row=4;col=4;screenshot_width=960;screenshot_height=540;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:he.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 de(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,p=Math.floor(h/(e*t)),l=h%e*i,u=Math.floor(h%(t*e)/e)*s,m=this.getTileName(p);n.push(m),o.push({file:m,st:d,et:c,x:l,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=se(this.params.outputRoot,e),i=await re(a);c.push({file:e,file_path:a,size:i})}const p={width:this.screenshot_width,height:this.screenshot_height,row:this.row,col:this.col,tile_list:c,sprite_list:o};await this.setVideoThumbnailerResult(p)}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=se(this.params.outputRoot,s),o=this.getCoverName(),n=se(this.params.outputRoot,o);await ne(r,n);const h={file:o,path:n,size:await re(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=se(this.params.outputRoot,e);n.push(a)}const h=this.getTileName(t),d=se(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 oe({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=se(this.params.outputRoot,e),p=await re(c);if(0===p)throw new Error(`Generate video thumbnail error: [index: ${t}, start_time: ${d.start_time}, end_time: ${d.end_time}]`);p>=a.size&&(a.index=t,a.size=p,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?this.screenshot_width:this.screenshot_height;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 pe}from"path";import{pathExists as le}from"fs-extra";import{getMetadata as ue}from"@soga/imgutils";import{getFileSize as me}from"@soga/fileutils";import{UploadProgress as ge}from"@soga/node-types";import{buildDError as we}from"@soga/error";var fe=class extends yt{get cover_name(){return"audio_cover.png"}async start(){try{await this.generateCover(),this.isAudio&&await this.postProgress({type:ge.transcode_thumbnail,percent:1})}catch(t){throw we(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=pe(this.params.outputRoot,t);if(await le(i)){const e=await ue(i),a={file:t,path:i,size:await me(i),width:e.width??0,height:e.height??0};await this.setCoverResult(a)}}catch(t){throw t}finally{this.db.data[e]=!0,await this.db.write()}}};import{parse as _e,resolve as ye}from"path";import{getFileLanguage as be,isUtf8File as ve,saveFileAsUtf8 as Pe,gzip as xe}from"@soga/utils";import{isValidFile as De,getFileSize as Te,isValidPath as ze}from"@soga/fileutils";import{copy as Re}from"fs-extra";import{buildDError as $e}from"@soga/error";import{UploadProgress as Ie}from"@soga/node-types";var Me=class extends yt{builtin_tracks=0;external_tracks=0;get tracks(){return this.builtin_tracks+this.external_tracks}async sendProgress(t){await this.postProgress({type:Ie.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 $e(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=ye(e,a),s=`subtitle-temp-${t}.vtt`,r=ye(e,s),o=ye(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 De(r)){if(await ve(r))await Re(r,o);else{await Pe(r,o);await De(o)||await Re(r,o)}const e=await be(o),{label:s,lang:n}=e;await xe(o,i);return{file:a,file_path:i,size:await Te(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}=_e(e),i=this.params.outputRoot,s=`subtitle-external-${t}.vtt`,r=ye(i,s),o=`subtitle-external-${t}.zip`,n=ye(i,o),h=ye(i,`subtitle-external-u8-${t}${a}`),d=`subtitle-external-source-${t}.zip`,c=ye(i,d);if(!await ze(e))return!1;if(await ve(e))await Re(e,h);else{await Pe(e,h);if(!await De(h))return!1}const p=["-i",h,"-c","webvtt","-y",s];await this.ffmpeg(p,{cwd:this.params.outputRoot});if(await De(r)){const i=await be(r),{label:s,lang:h}=i;await xe(e,c),await xe(r,n);const p=await Te(c);return{file:o,size:await Te(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:p,ext:a}}}return!1}};import{buildDError as ke}from"@soga/error";import{resolve as Se}from"path";import{writeFile as Fe}from"fs-extra";import{UploadProgress as Ee}from"@soga/node-types";import{getFileSize as Ne}from"@soga/fileutils";import{gzip as Ce,getFileBufferSlice as Le}from"@soga/utils";import{buildDError as Ae}from"@soga/error";import{resolve as Ue}from"path";import{getFileSize as Oe}from"@soga/fileutils";var Ve=class extends yt{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=l(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=Ue(this.params.outputRoot,i),r=await Oe(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),p=this.file_map[c],{file_index:l,start:u,end:m,size:g,hash:w}=p,f=this.getFileName(l),_=await this.getPreviewId({file:c});await this.setPreviewIdMap({id:_,file:f,start:u,end:m},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:m,size:g,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:p,start:l,end:u,size:m,hash:g}=c,w=this.getFileName(p),f=await this.getPreviewId({file:d});await this.setPreviewIdMap({id:f,file:w,start:l,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:l,end:u,size:m,hash:g}}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:p}=o,l=this.getFileName(n);await this.setPreviewIdMap({id:r,file:l,start:h,end:d},this.hostType);const{average_bandwidth:u,bandwidth:m,codec:g,width:w,height:f,label:_,codec_name:y,bitdepth:b,framerate:v}=i,P={id:r,average_band:u,band:m,codec:g,codec_name:y,bitdepth:b,framerate:Math.round(v),width:w,height:f,file:l,start:h,end:d,size:c,label:_,hash:p};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:p,start:l,end:u,size:m}=c,g=this.getFileName(p),w={uuid:await this.getPreviewId({file:r,start:l,end:u}),builtin:s,lang:o,name:h,title:n,file:g,start:l,end:u,size:m};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,p=this.getFileName(n),l=await this.getPreviewId({file:r});await this.setPreviewIdMap({id:l,file:p,start:h,end:d},this.hostType);return{id:l,row:e,col:a,width:i,height:s,file:p,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),p=await this.getPreviewId({file:e.path});await this.setPreviewIdMap({id:p,file:c,start:n,end:h},this.hostType);return{id:p,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=Rt(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()}},Ge=class extends Ve{current_position=0;current_index=0;group_data=[];async start(){const t=Rt(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:Ee.group_media,percent:this.completed_percent+.5*this.total_percent}),await this.processGroups(),await this.postProgress({type:Ee.group_media,percent:this.completed_percent+.9*this.total_percent}),await this.saveData(),await this.postProgress({type:Ee.group_media,percent:this.completed_percent+this.total_percent}),this.db.data[t]}catch(t){throw Ae(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||={};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:Ee.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:Ee.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:Ee.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,!1),this.file_map[s]=r,i=i.map(t=>t.file===s?{...t,file:n,id:o,s:r.start,e:r.end}:t)}await this.db.write();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),p=`${c}?id=${d}`;await this.setPreviewIdMap({id:d,file:c,start:h.start,end:h.end},this.hostType);const l=["#EXTM3U",`#EXT-X-VERSION:${i}`,`#EXT-X-TARGETDURATION:${s}`,`#EXT-X-MEDIA-SEQUENCE:${r}`,`#EXT-X-MAP:URI=${p},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},!1),i=this.getFileName(e.file_index);await this.setPreviewIdMap({id:a,file:i,start:e.start,end:e.end},this.hostType,!1),l.push(`#EXTINF:${e.duration},`),l.push(`#EXT-X-BYTERANGE:${e.size}@${e.start}`),l.push(`${i}?id=${a}`)}await this.db.write(),o&&l.push("#EXT-X-ENDLIST");return l.join("\n")}async writeTrackText(t,e){const a=Se(this.params.outputRoot,t),r=Se(this.params.outputRoot,`${t}.gz`),o=Se(this.params.outputRoot,`${t}.bin`);await Fe(a,e,"utf-8"),await Ce(a,r);if(await Ne(r)>16){const t=(await Le(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 Ne(o)}),hash:t}}return{...this.addOne({file_path:a,size:await Ne(a)}),hash:""}}async writeText(t,e){const a=Se(this.params.outputRoot,t);await Fe(a,e,"utf-8");return this.addOne({file_path:a,size:await Ne(a)})}addOne({file_path:t,size:e,duration:a=0},i=!1){const s=this.getSizeLimit({host_type:this.hostType,is_source:!1}),{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({host_type:this.hostType,is_source:!1}),{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))}},Be=class extends yt{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({host_type:i,is_source:!1}),r=new Ge({...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 ke(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}},je=class extends yt{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 Me(this.params);if(await r.start(),s){const t=new Lt(this.params);await t.start();const e=new ie(this.params);await e.start();const a=new fe(this.params);await a.start()}if(a){const t=new Mt(this.params);await t.start();const e=new Kt(this.params);await e.start();const a=new ce(this.params);await a.start()}const o=new Be(this.params);await o.start()}async getResult(){return this.db.data.grouper_result}};import{HostType as qe}from"@soga/types";import{UploadProgress as Xe}from"@soga/node-types";import{parseMediaInfo as Ke}from"@soga/mediainfo";import{getFileSize as He,isAudioAdapt as Je,isAudioHigh as Qe,isVideoSupport as We}from"@soga/fileutils";import{ensureDir as Ze}from"fs-extra";import Ye from"check-disk-space";import{buildDError as ta}from"@soga/error";var ea=class extends B{async start(){await this.calculateProgress(),await this.checkStorage(),await this.calculateMeta()}async checkStorage(){const{length:t}=this.params.hosts,{keeps:e}=this,a=await Ye(this.params.outputRoot),i=a.free,s=a.diskPath,r=this.params.input.filesize;if(((e.preview?1.3:0)+(e.source?1.2:0))*r*t>i)throw ta(new Error(`${s} have no enough computer disk space, please adjust the temporary path in user settings.`),{message:`${s} have no enough computer disk space, please adjust the temporary path in user settings.`,detail:`${s} 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={[Xe.prepare]:{weight:0,percent:1},[Xe.calculate_md5]:{weight:0,percent:0},[Xe.separate_video]:{weight:0,percent:0},[Xe.separate_audio]:{weight:0,percent:0},[Xe.separate_subtitle]:{weight:0,percent:0},[Xe.transcode_video]:{weight:0,percent:0},[Xe.transcode_audio]:{weight:0,percent:0},[Xe.transcode_thumbnail]:{weight:0,percent:0},[Xe.transcode_source]:{weight:0,percent:0},[Xe.transcode_txt]:{weight:0,percent:0},[Xe.transcode_img]:{weight:0,percent:0},[Xe.group_media]:{weight:0,percent:0},[Xe.upload_baidu]:{weight:0,percent:0},[Xe.upload_ali]:{weight:0,percent:0},[Xe.end]:{weight:0,percent:0}},e={keep_preview:this.params.keepPreview,keep_source:this.params.keepSource},a=await He(this.params.input.filepath);t[Xe.prepare].weight=t[Xe.end].weight=Math.ceil(a/1024/1024/500),t[Xe.calculate_md5].weight=Math.ceil(a/1024/1024/200);let i=0;if(this.isMedia)if(this.params.keepPreview){const s=await Ke(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=We(r),{duration:n}=s.general,h=o?n/400:n*(a*i)/1920/1080;t[Xe.separate_video].weight=Math.ceil(h),t[Xe.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};Je(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):Qe(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[Xe.separate_audio].weight=Math.ceil(a),t[Xe.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[Xe.separate_subtitle].weight=Math.ceil(o),t[Xe.transcode_thumbnail].weight=Math.ceil(.08*r),i+=a,t[Xe.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[Xe.transcode_txt].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a):this.isImg?e.keep_preview&&(t[Xe.transcode_img].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a);e.keep_source&&(t[Xe.transcode_source].weight=Math.ceil(a/1024/1024/30)),this.params.hosts.includes(qe.BAIDU)&&(t[Xe.upload_baidu].weight=Math.ceil(i/1024/1024/1)),this.params.hosts.includes(qe.ALI)&&(t[Xe.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)}},aa=async t=>{await Ze(t.outputRoot);const e=await g(t),a=new ea({...t,db:e});return await a.start(),a};import{UploadProgress as ia}from"@soga/node-types";import{createHash as sa}from"crypto";import{createReadStream as ra}from"fs-extra";import{HostType as oa}from"@soga/types";var na=class extends B{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=sa("md5"),n=ra(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:ia.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:ia.calculate_md5,percent:1}),i}getCloudName({host_type:t,md5:e,is_attachment:a}){const i=a?"a":"f";return t==oa.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 p=t?.data[r];if(p?.parts){o(p.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:p.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 aa(this.params),{keeps:a}=this,i={...this.params,keepPreview:a.preview,keepSource:a.source},s=await this.calculateMd5();if(await this.setMd5(s),i.keepSource){const t=new q(this.params);await t.start({as_preview:!a.preview})}if(e.isMedia&&i.keepPreview){const t=new je(this.params);await t.start()}if(e.isTxt&&i.keepPreview){const t=new ot(this.params);await t.start()}if(e.isImg){const t=new gt(this.params);await t.start()}this.db.data[t]=!0,await this.db.write()}},ha=async e=>{try{const t=await g(e),a=new na({...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{ha as encode,aa as getPrepare};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soga/file-encoder",
3
- "version": "1.3.26",
3
+ "version": "1.3.28",
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.26"
23
+ "@soga/typescript-config": "1.3.28"
24
24
  },
25
25
  "keywords": [],
26
26
  "author": "",
@@ -33,15 +33,15 @@
33
33
  "piscina": "^5.0.0",
34
34
  "uuid": "^11.1.0",
35
35
  "check-disk-space": "^3.4.0",
36
- "@soga/fileutils": "1.3.26",
37
- "@soga/utils": "1.3.26",
38
- "@soga/node-types": "1.3.26",
39
- "@soga/error": "1.3.26",
40
- "@soga/lowdb": "1.3.26",
41
- "@soga/m3u8": "1.3.26",
42
- "@soga/mp4box": "1.3.26",
43
- "@soga/mediainfo": "1.3.26",
44
- "@soga/imgutils": "1.3.26"
36
+ "@soga/fileutils": "1.3.28",
37
+ "@soga/utils": "1.3.28",
38
+ "@soga/node-types": "1.3.28",
39
+ "@soga/error": "1.3.28",
40
+ "@soga/lowdb": "1.3.28",
41
+ "@soga/m3u8": "1.3.28",
42
+ "@soga/mp4box": "1.3.28",
43
+ "@soga/mediainfo": "1.3.28",
44
+ "@soga/imgutils": "1.3.28"
45
45
  },
46
46
  "scripts": {
47
47
  "demo": "tsx ./demo/demo",