@soga/file-encoder 1.3.8 → 1.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +12 -12
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
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:()=>ke,getPrepare:()=>De}),module.exports=(t=d,n(a({},"__esModule",{value:!0}),t));var c=require("@soga/error"),l=require("@soga/lowdb"),u=require("crypto"),p=require("fs-extra"),g=require("fs/promises"),w=require("path"),m=require("stream/promises");function f(t){const e=(0,u.createHash)("md5");return e.update(`${t}`),e.digest("hex")}async function _(t){await new Promise((e,a)=>{(async()=>{const i=(0,w.resolve)(t.outputRoot,t.filename);await(0,p.remove)(i);let s=!1;const r=(0,p.createWriteStream)(i);r.on("open",()=>{s=!0}).on("error",async t=>{s&&r.close(),await(0,p.remove)(i),a(t)});const{length:o}=t.files,n=async(e=0)=>{if(e<o){const a=t.files[e],o=t.files.length;await new Promise((t,e)=>{const n=(0,p.createReadStream)(a);n.pipe(r,{end:!o}),n.on("end",()=>{n.close(),t(!0)}),n.on("error",async t=>{n.destroy(),s&&r.close(),await(0,p.remove)(i),e(t)})}),await n(e+1)}};await n(0),s&&r.end(),e(!0)})()})}async function y(t,e){const a=f(JSON.stringify({...t,dbName:e})),i="db_unique_key",s=(0,w.resolve)(t.outputRoot,e),r=await(0,l.getDb)(s,{});return r.data[i]?r.data[i]!=a&&(r.data={[i]:a},await r.write()):(r.data[i]=a,await r.write()),r}async function b(t){return await y({file_id:t.id,input:{filepath:t.input.filepath,filesize:t.input.filesize},outputRoot:t.outputRoot},"encoder_store.json")}async function v({input_path:t,target_path:e,start:a,end:i}){const s=(0,p.createReadStream)(t,{start:a,end:i,highWaterMark:65536}),r=(0,p.createWriteStream)(e);try{await(0,m.pipeline)(s,r)}catch(t){try{(0,p.existsSync)(e)&&await(0,p.remove)(e)}catch(t){console.warn("Failed to clean up incomplete file:",t.message)}throw t}}var P=require("path"),x=require("@soga/utils"),z=require("@soga/fileutils"),T=require("@soga/error"),R=require("@soga/node-types"),S=require("fs-extra"),D=require("@soga/types"),M=2097152,I={[D.HostType.BAIDU]:52428800,[D.HostType.ALI]:2147483648},F=(D.HostType.BAIDU,D.HostType.ALI,require("@soga/types")),$=require("@soga/utils"),k=require("worker_threads"),q=class{segmentNames={};params;id;port=null;db;get lowData(){return this.db.data}get isVideo(){return this.params.type==F.RecordType.VIDEO}get isAudio(){return this.params.type==F.RecordType.AUDIO}get isMedia(){return this.isAudio||this.isVideo}get isTxt(){return this.params.type==F.RecordType.DOC&&this.params.ftype==F.RecordFtype.DOC_TXT}get isImg(){return this.params.type==F.RecordType.IMAGE}getSizeLimit(t){return I[t]||52428800}getFilesize(){return this.params.input.filesize}constructor(t){this.params=t,this.id=t.id,this.port=t.port??null,this.db=t.db}async getPartInfo({host_type:t,filepath:e,start:a,end:i,filename:s,index:r},o=!0){const n={start:a,end:i,size:i-a+1,path:e,index:r,file:s,md5:o?await(0,$.calculateMd5)({file:e,start:a,end:i}):""};if(o){if(t===F.HostType.BAIDU){const t=await(0,$.calculateMd4)({file:e,start:a,end:i});n.md4=t}if(t===F.HostType.ALI){const t=await(0,$.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):k.parentPort&&k.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}}},E=class extends q{syncGetSourceId(t){return this._syncGetId(t,"source")}async getSourceId(t){const e=this.syncGetSourceId(t);return await this.db.write(),e}getSourceIdMap(t){return this.db.data[`source_${t}_id_map`]||{}}syncSetSourceIdMap(t,e){this._syncSetIdMap(t,"source",e)}async setSourceIdMap(t,e){this.syncSetSourceIdMap(t,e),await this.db.write()}getSourceSegmentName=(t,e)=>{const a=`source_${e}_${t}`;if(this.segmentNames[a])return this.segmentNames[a];const i=`s-${f(`source-${e}-${this.md5}-${t}`)}`;return this.segmentNames[a]=i,i}},N=class extends E{head_size=32;getZipFilePath(){return(0,P.resolve)(this.params.outputRoot,"souce_zip.bin")}getDownloadListFileName(t){return`source_${t}_download_list.json`}getPartName(t,e){return this.getSourceSegmentName(e,t)}getPartPath(t,e){return(0,P.resolve)(this.params.outputRoot,this.getPartName(t,e))}get dbData(){return this.db.data}async setPartList(t,e){const a=`source_${t}_part_list`;this.dbData[a]=e,await this.params.db.write()}getPartList(t){const e=`source_${t}_part_list`;return this.dbData[e]}async setDownloadMap(t,e){const a=`source_${t}_download_map`;this.dbData[a]=e,await this.params.db.write()}getDownloadMap(t){const e=`source_${t}_download_map`;return this.dbData[e]}async sendProgress(t){await this.postProgress({type:R.UploadProgress.transcode_source,percent:t})}async setDownloadList(t,e){const a=`source_${t}_download_list`;this.dbData[a]=e,await this.params.db.write()}getDownloadList(t){const e=`source_${t}_download_list`;return this.dbData[e]}async start(){try{if(this.sourceResult)return await this.sendProgress(1),this.sourceResult;await this.gzip();const{length:t}=this.params.hosts;for(let e=0;e<t;e++){const t=this.params.hosts[e];await this.calculatePartList(t),await this.processDownloadMap(t)}await this.sendProgress(.9);const e=await this.getResult();return await this.sendProgress(1),e}catch(t){throw(0,T.buildDError)(t,{message:"Error occurred during source encoding",detail:`Error occurred during source encoding: ${this.params.input.filepath}`})}}async gzip(){if(this.dbData.source_gziped)return;const t=this.params.input.filepath,e=this.getZipFilePath();await(0,x.gzip)(t,e,async({percent:t})=>{await this.sendProgress(.6*t)}),this.dbData.source_gziped=!0,await this.params.db.write()}async getResult(){if(this.sourceResult)return this.sourceResult;const t={meta:await this.getMetaData(),data:{}},{length:e}=this.params.hosts;for(let a=0;a<e;a++){const e=this.params.hosts[a],i=this.getPartList(e),s=this.getDownloadMap(e);t.data[e]={download:s,parts:i}}return await this.setSourceResult(t),t}async getMetaData(){const t="source_meta",e=this.dbData[t];if(e)return e;const a=this.getZipFilePath(),i=await(0,z.getFileSize)(a),s={path:a,start:0,end:0},{head_size:r}=this;s.end=i<=r?i-1:r-1;const o={head:(await(0,x.getFileBufferSlice)(s.path,s.start,s.end)).toString("base64")};return this.dbData[t]=o,await this.params.db.write(),o}async writeDownloadListFile(t,e){const a=this.getDownloadListFileName(t),i=(0,P.resolve)(this.params.outputRoot,a);await(0,S.writeFile)(i,e,"utf-8");return{file_path:i,size:await(0,z.getFileSize)(i)}}async processDownloadMap(t){const e=this.getDownloadMap(t);if(e)return e;const a=this.getDownloadList(t);let i;const{file_path:s,size:r}=await this.writeDownloadListFile(t,JSON.stringify(a)),o=this.getSizeLimit(t),n=this.getPartList(t);if(n.length){const e=n[n.length-1],{path:a,size:h,file:d,index:c,end:l,start:u}=e,g=(0,P.resolve)(this.params.outputRoot,d);if(h+r<=o){await async function({source1:t,source2:e,target:a}){const i=(0,p.createReadStream)(t.filepath,{start:t.start,end:t.end}),s=(0,p.createWriteStream)(a);await(0,m.pipeline)(i,s);const r=(0,p.createReadStream)(e),o=(0,p.createWriteStream)(a,{flags:"a"});await(0,m.pipeline)(r,o)}({source1:{filepath:a,start:u,end:l},source2:s,target:g});const e=(await(0,S.stat)(g)).size,o=e-1,h=e-r,w=await this.getPartInfo({host_type:t,filepath:g,start:0,end:e-1,filename:d,index:c});n[n.length-1]=w;i={id:await this.getSourceId({file:d,start:h,end:o}),file:d,start:h,end:o}}else{const e=c+1,a=this.getPartName(t,e),o=this.getPartPath(t,e);await(0,S.rename)(s,o);const h=await this.getSourceId({file:a,start:0,end:r-1}),d=await this.getPartInfo({host_type:t,filepath:o,start:0,end:r-1,filename:a,index:e});n.push(d),i={id:h,file:a,start:0,end:r-1}}return await this.setPartList(t,n),await this.setDownloadMap(t,i),i}}async calculatePartList(t){const e=`source_${t}_list_calculated`;if(this.dbData[e])return;const a=this.getZipFilePath(),i=await(0,z.getFileSize)(a),s=[],r=this.getSizeLimit(t),{head_size:o}=this,n=[];if(i>o){let e=0;for(let h=o;h<=i-1;h+=r){const o=Math.min(h+r-1,i-1),d=this.getPartName(t,e),c=await this.getPartInfo({host_type:t,filepath:a,start:h,end:o,filename:d,index:e});let l=0;for(let t=h;t<o;t+=M){const e=Math.min(t+M-1,o),a=e-t+1,i=l+a-1,s=await this.getSourceId({file:"source_zip",start:t,end:e});n.push({id:s,file:d,start:l,end:i}),l+=a}s.push(c),e++}}await this.setPartList(t,s),await this.setDownloadList(t,n),this.dbData[e]=!0,await this.db.write()}},U=require("path"),L=require("fs-extra"),C=require("@soga/utils"),A=h(require("zlib")),O=require("@soga/utils"),V=require("@soga/error"),G=require("@soga/node-types"),B=require("path"),j=require("@soga/fileutils"),X=require("fs-extra"),H=class extends q{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,B.resolve)(this.params.outputRoot,this.getPartName(t,e))}syncGetPreviewId(t){return this._syncGetId(t,"preview")}async getPreviewId(t){const e=this.syncGetPreviewId(t);return await this.db.write(),e}getPreviewIdMap(t){return this.db.data[`preview_${t}_id_map`]||{}}syncSetPreviewIdMap(t,e){this._syncSetIdMap(t,"preview",e)}async setPreviewIdMap(t,e){this.syncSetPreviewIdMap(t,e),await this.db.write()}getPreviewSegmentName=(t,e)=>{const a=`preview_${e}_${t}`;if(this.segmentNames[a])return this.segmentNames[a];const i=`p-${f(`preview-${e}-${this.md5}-${t}`)}`;return this.segmentNames[a]=i,i};async calculatePartList(t,e){const a=[],i=await this.getCurrentFileIndex(t);for(let s=0;s<i+1;s++){const i=this.getPartName(t,s),r=this.getPartPath(t,s),o=await(0,j.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,B.resolve)(this.params.outputRoot,a);await(0,X.writeFile)(i,e,"utf-8");return{file_path:i,size:await(0,j.getFileSize)(i)}}async setCacheInfo(t,e){const a=`preview_${t}_cache_info`;this.preview_common_db_data[a]=e,await this.db.write()}async attachHostCacheData(t){if(this.getCacheInfo(t))return;const e=await this.getPartList(t),a=this.getPreviewIdMap(t),{file_path:i,size:s}=await this.writeCacheFile(t,JSON.stringify(a)),r=this.getSizeLimit(t);if(e.length){const a=e[e.length-1],{path:o,size:n,file:h,index:d,end:c}=a;let l;if(n+s<=r){await async function({filepath:t,size:e},a){(await(0,p.stat)(t)).size>e&&await(0,g.truncate)(t,e);const i=(0,p.createReadStream)(a),s=(0,p.createWriteStream)(t,{flags:"a"});await(0,m.pipeline)(i,s)}({filepath:o,size:n},i);const a=await(0,j.getFileSize)(o),r=await this.getPartInfo({host_type:t,filename:h,filepath:o,index:d,start:0,end:a-1});e[e.length-1]=r;const u=c+1,w=c+s;l={id:await this.getPreviewId({file:h,start:u,end:w}),file:h,start:u,end:w}}else{const a=d+1,r=this.getPartName(t,a),o=this.getPartPath(t,a);await(0,X.copy)(i,o);const n=await this.getPreviewId({file:r,start:0,end:s-1}),h=await this.getPartInfo({host_type:t,filename:r,filepath:o,index:a,start:0,end:s-1},!1);e.push(h),await this.setPartList(t,e),l={id:n,file:r,start:0,end:s-1}}l&&await this.setCacheInfo(t,l)}}},W=class extends H{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,U.resolve)(this.params.outputRoot,this.getU8FileName())}async sendProgress(t){await this.postProgress({type:G.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,V.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,L.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,O.saveFileAsUtf8)(t,e),this.dbData.txt_utf8_converted=!0,await this.db.write()}async txtConvertToGzipFile(t){if(await this.getEntranceInfo(t))return;const e=this.getSizeLimit(t),a=this.getU8FilePath(),i=await this.calculateSlice(),{length:s}=i,r={};let o=0,n=(0,L.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,C.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)=>{A.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,L.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,L.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}},K=require("path"),J=require("@soga/imgutils"),Q=require("@soga/utils"),Z=require("@soga/fileutils"),Y=require("@soga/error"),tt=require("@soga/node-types"),et=require("fs-extra"),at=class extends H{getCompressFileName(){return"img_compress.jpg"}getCompressFilePath(){return(0,K.resolve)(this.params.outputRoot,this.getCompressFileName())}getGzFileName(){return"compressed_img.zip"}getGzFilePath(){return(0,K.resolve)(this.params.outputRoot,this.getGzFileName())}async sendProgress(t){await this.postProgress({type:tt.UploadProgress.transcode_img,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.imgResult)return await this.sendProgress(1),this.imgResult;await this.compress(),await this.sendProgress(.1),await this.gzip(),await this.sendProgress(.4);const{hosts:t}=this.params,{length:e}=t;for(let a=0;a<e;a++){const e=t[a];await this.splitFile(e),await this.calculatePartList(e,!1)}await this.attachCacheData(),await this.sendProgress(.9);const a=await this.getResult();return await this.clean(),await this.sendProgress(1),a}catch(t){throw(0,Y.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,J.getMetadata)(e),s=this.getCompressFilePath(),{width:r,height:o}=await(0,J.getMetadata)(s),n=await(0,Z.getFileSize)(s),h={meta:{width:a,height:i,size:t.filesize,t_width:r,t_height:o,t_size:n},data:{}},{length:d}=this.params.hosts;for(let t=0;t<d;t++){const e=this.params.hosts[t],a=await this.getPartList(e),i=this.getPreviewList(e);h.data[e]={img:{preview:i},cache:this.getCacheInfo(e),parts:a}}return await this.setImgResult(h),h}async clean(){try{if(this.params.debug)return;const t=this.getCompressFilePath();await(0,et.remove)(t)}catch(t){}}async compress(){if(this.dbData.img_compressed)return;const t=this.getCompressFilePath();await(0,J.compress)({ffmpeg_path:this.params.ffmpegPath,input_path:this.params.input.filepath,output_path:t}),this.dbData.img_compressed=!0,await this.db.write()}async gzip(){if(this.dbData.img_gziped)return;const t=this.getCompressFilePath(),e=this.getGzFilePath();await(0,Q.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,Z.getFileSize)(e),i=this.getSizeLimit(t),s=[],r=[];for(let o=0;o<=a-1;o+=i){0!=o&&await this.increaseCurrentFileIndex(t);const n=Math.min(o+i-1,a-1),h=await this.getCurrentFileIndex(t),d=this.getPartName(t,h),c=this.getPartPath(t,h);await v({input_path:e,target_path:c,start:o,end:n});const l=0,u=n-o,p=await this.getPartInfo({host_type:t,filepath:c,filename:d,start:l,end:u,index:h},!1);s.push(p);const g=await this.getPreviewId({file:d,start:l,end:u});r.push({id:g,file:d,start:l,end:u}),await this.setPreviewIdMap({id:g,file:d,start:l,end:u},t)}await this.setPartList(t,s),await this.setPreviewList(t,r)}},it=h(require("fluent-ffmpeg")),st=require("child_process"),rt=require("@soga/mediainfo"),ot=class extends H{async getMediainfo(){const{mediainfo:t}=this.db.data;if(t)return t;const e=this.params.input.filepath,a=await(0,rt.parseMediaInfo)(e);return this.db.data.mediainfo=a,await this.params.db.write(),a}constructor(t){super(t),it.default.setFfmpegPath(t.ffmpegPath)}getFluent(){return(0,it.default)()}async ffmpeg(t,e){const a=this.params.ffmpegPath;return await new Promise((i,s)=>{const r=(0,st.spawn)(a,t,Object.assign({stdio:"ignore"},e));r.on("close",t=>{i(t)}),r.on("error",t=>{s(t)})})}},nt=require("path"),ht=require("@soga/fileutils"),dt=require("@soga/node-types"),ct=require("@soga/error"),lt=({type:t,track_order:e,quality:a})=>`audio-${e}-${a}-${t}.${"manifest"===t?"m3u8":"mp4"}`,ut=({width:t,height:e})=>`video-formatted-${t}-${e}.mp4`,pt=t=>`grouper_result_${t}`,gt=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)}},wt=(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 ot{async start(){try{await this.separateVideo(),await this.postProgress({type:dt.UploadProgress.separate_video,percent:1})}catch(t){throw(0,ct.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=ut({width:a.width,height:a.height}),s=(0,nt.resolve)(this.params.outputRoot,i),r=(0,ht.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=wt(t,h);await this.postProgress({type:dt.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,ht.isValidFile)(s))throw new Error("Separate Video track failed");this.db.data[t]=!0,await this.params.db.write()}},ft=require("path"),_t=require("@soga/fileutils"),yt=require("@soga/node-types"),bt=require("@soga/error"),vt=class extends ot{async start(){try{await this.separateTracks(),await this.postProgress({type:yt.UploadProgress.separate_audio,percent:1})}catch(t){throw(0,bt.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,_t.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,_t.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=lt({type:"formatted",track_order:t,quality:e.type}),n=(0,ft.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=wt(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:yt.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,_t.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:yt.UploadProgress.separate_audio,percent:i})}this.db.data[a]=!0,await this.params.db.write()}},Pt=require("path"),xt=require("@soga/mediainfo"),zt=require("@soga/mp4box"),Tt=require("@soga/m3u8"),Rt=require("@soga/node-types"),St=require("@soga/fileutils"),Dt=require("fs-extra"),Mt=require("@soga/error"),It=class extends ot{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:Rt.UploadProgress.transcode_video,percent:1})}catch(t){throw(0,Mt.buildDError)(t,{message:"Error occurred during video transcoding",detail:`Error occurred during video transcoding: ${this.params.input.filepath}`})}}async saveData(){const t=await this.getMediainfo();if(!t?.video?.length)return;if(this.videoTranscoderResult)return;const{width:e,height:a}=t.video[0],i=ut({width:e,height:a}),s=(0,Pt.resolve)(this.params.outputRoot,i),r=this.getVideoManifestName({width:e,height:a}),o=(0,Pt.resolve)(this.params.outputRoot,r),n=await(0,Tt.parseM3U8)(o),{videos:h}=await(0,zt.getMp4boxInfo)(s),{codec:d}=h[0],{bandwidth:c,average_bandwidth:l}=gt(n),u=(await(0,xt.parseMediaInfo)(s)).video[0],p=(0,St.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,Dt.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=ut(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,Pt.resolve)(this.params.outputRoot,o);if(!await(0,St.isValidFile)(h))throw new Error("Transcode video track failed");this.db.data[t]=!0,await this.db.write()}},Ft=require("path"),$t=require("@soga/fileutils"),kt=require("@soga/mp4box"),qt=require("@soga/m3u8"),Et=require("@soga/mediainfo"),Nt=require("fs-extra"),Ut=require("@soga/error"),Lt=require("@soga/node-types"),Ct=class extends ot{async start(){try{await this.transcodeAudios(),await this.saveData()}catch(t){throw(0,Ut.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=lt({type:"formatted",track_order:t,quality:"adapt"}),a=(0,Ft.resolve)(this.params.outputRoot,e);await(0,Nt.remove)(a)}if(e.high.need){const e=lt({type:"formatted",track_order:t,quality:"high"}),a=(0,Ft.resolve)(this.params.outputRoot,e);await(0,Nt.remove)(a)}}}catch(t){}}async getQualityData({track_order:t,quality:e}){const a=lt({type:"formatted",track_order:t,quality:e}),i=(0,Ft.resolve)(this.params.outputRoot,a),s=await(0,Et.parseMediaInfo)(i);if(!s.audio?.length)throw new Error("parse mediainfo failed!");const r=s.audio[0],o=lt({type:"manifest",track_order:t,quality:e}),n=await(0,$t.getFileSize)(i),h=(0,Ft.resolve)(this.params.outputRoot,o),d=await(0,kt.getMp4boxInfo)(i),{audios:c}=d,{language:l,codec:u}=c[0],p=l&&!l.startsWith("un")?{language:l}:void 0,g=await(0,qt.parseM3U8)(h),{bandwidth:w,average_bandwidth:m}=gt(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:Lt.UploadProgress.transcode_audio,percent:s})}await this.postProgress({type:Lt.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=lt({type:"formatted",track_order:t,quality:e.type}),s=lt({type:"init",track_order:t,quality:e.type}),r=lt({type:"manifest",track_order:t,quality:e.type}),o=["-i",i,"-vn","-sn","-c:a","copy","-hls_list_size","0","-hls_time","6","-hls_segment_type","fmp4","-hls_fmp4_init_filename",s,"-y",r];await this.ffmpeg(o,{cwd:this.params.outputRoot});const n=(0,Ft.resolve)(this.params.outputRoot,r);if(!await(0,$t.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()}},At=require("path"),Ot=require("@soga/fileutils"),Vt=require("@soga/imgutils"),Gt=require("fs-extra"),Bt=require("@soga/node-types"),jt=require("@soga/error"),Xt=class extends ot{m3u8_data=null;thumbnail_duration=30;thumbnail_group=[];row=8;col=8;screenshot_width=480;screenshot_height=270;getScreenshotName(t){return`video_screenshot_${t}.jpg`}getTileName(t){return`video_tile_${t}.jpg`}getCoverName(){return"video_cover.jpg"}async updateImagePercent(t,e){const a="screenshot"==e?6*t/7:t/7+6/7;await this.postProgress({type:Bt.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,jt.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,At.resolve)(this.params.outputRoot,e),i=await(0,Ot.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,At.resolve)(this.params.outputRoot,s),o=this.getCoverName(),n=(0,At.resolve)(this.params.outputRoot,o);await(0,Gt.copy)(r,n);const h={file:o,path:n,size:await(0,Ot.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,At.resolve)(this.params.outputRoot,e);n.push(a)}const h=this.getTileName(t),d=(0,At.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,Vt.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,At.resolve)(this.params.outputRoot,e),l=await(0,Ot.getFileSize)(c);if(0===l)throw new Error(`Generate video thumbnail error: [index: ${t}, start_time: ${d.start_time}, end_time: ${d.end_time}]`);l>=a.size&&(a.index=t,a.size=l,this.store.data.thumbnail_screenshot_largest=a,await this.store.write()),this.store.data.thumbnail_screenshot_index=t+1,await this.store.write()}catch(a){const i=Math.max(10,d.duration);if(!(e<3))throw a;await n(t,{errorTimes:e+1,fixedSeconds:o+i/5})}};for(let e=t;e<o;e++)await n(e,{errorTimes:0,fixedSeconds:0}),await this.updateImagePercent((e+1)/o,"screenshot");this.store.data.thumbnail_screenshot_state=!0,await this.store.write()}async initScreenshotSize(){const{thumbnail_screenshot_size:t}=this.store.data;if(t)return this.screenshot_width=t.width,void(this.screenshot_height=t.height);const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],{width:i,height:s}=a,r=i>s?480:270;this.screenshot_width=2*Math.floor(Math.min(r,i)/2),this.screenshot_height=2*Math.floor(this.screenshot_width*(s/i)/2),this.store.data.thumbnail_screenshot_size={width:this.screenshot_width,height:this.screenshot_height}}async initThumbnailGroup(){if(this.store.data.thumbnail_group)return void(this.thumbnail_group=this.store.data.thumbnail_group);const t=[],{segments:e}=this.m3u8_data,{length:a}=e,i=this.thumbnail_duration;let s=0,r=[];for(let o=0;o<a;o++){const n=e[o];if(s+=n.duration,r.push(n),s>=i||o===a-1){const e=r.length,a=r[0],i=r[e-1];t.push({duration:s,start_time:a.start_time,end_time:i.end_time,items:r,item:i}),s=0,r=[]}}if(t.length>1){if(t[t.length-1].duration<1){const e=t.pop(),a=t[t.length-2];a.duration=a.duration+e.duration,a.end_time=e.end_time,a.items=a.items.concat(e.items),a.item=e.item,e.items}}t.forEach(t=>{const{items:e}=t;for(let a=e.length-1;a>=0;a--)if(e[a].duration>1){t.item=e[a];break}}),this.thumbnail_group=t,this.store.data.thumbnail_group=t,await this.store.write()}getVideoM3U8Info(){return this.videoTranscoderResult?.m3u8}async initM3U8Data(){this.m3u8_data=this.getVideoM3U8Info()}async initThumbnailDuration(){if(this.store.data.thumbnail_duration)return this.thumbnail_duration=this.store.data.thumbnail_duration,this.thumbnail_duration;let t=30;const e=await this.getMediainfo(),a=e?.video;if(!a?.length)return t;const i=a[0],s=i.duration||e?.general?.duration,{width:r,height:o}=i;r*o>=518400&&(t=10),r*o>=921600&&(t=20),r*o>=2073600&&(t=30),r*o>=3686400&&(t=40),r*o>=8294400&&(t=60);const n=s??0;if(n&&(n<60&&(t=0),n<300&&(t=Math.ceil(t/4)),n<600&&(t=Math.ceil(t/2)),n>3600)){const e=n/3600;t=Math.ceil(t*e)}return t=Math.min(60,t),this.thumbnail_duration=t,this.store.data.thumbnail_duration=t,await this.store.write(),t}},Ht=require("path"),Wt=require("fs-extra"),Kt=require("@soga/imgutils"),Jt=require("@soga/fileutils"),Qt=require("@soga/node-types"),Zt=require("@soga/error"),Yt=class extends ot{get cover_name(){return"audio_cover.png"}async start(){try{await this.generateCover(),this.isAudio&&await this.postProgress({type:Qt.UploadProgress.transcode_thumbnail,percent:1})}catch(t){throw(0,Zt.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,Ht.resolve)(this.params.outputRoot,t),s=await(0,Wt.pathExists)(i),r=await(0,Kt.getMetadata)(i);if(s){const e={file:t,path:i,size:await(0,Jt.getFileSize)(i),width:r.width??0,height:r.height??0};await this.setCoverResult(e)}}catch(t){throw t}finally{this.db.data[e]=!0,await this.db.write()}}},te=require("path"),ee=require("@soga/utils"),ae=require("@soga/fileutils"),ie=require("fs-extra"),se=require("@soga/error"),re=require("@soga/node-types"),oe=class extends ot{builtin_tracks=0;external_tracks=0;get tracks(){return this.builtin_tracks+this.external_tracks}async sendProgress(t){await this.postProgress({type:re.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,se.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,te.resolve)(e,a),s=`subtitle-temp-${t}.vtt`,r=(0,te.resolve)(e,s),o=`subtitle-builtin-u8-${t}.vtt`,n=(0,te.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,ae.isValidFile)(r)){if(await(0,ee.isUtf8File)(r))await(0,ie.copy)(r,n);else{await(0,ee.saveFileAsUtf8)(r,n);await(0,ae.isValidFile)(n)||await(0,ie.copy)(r,n)}const e=await(0,ee.getFileLanguage)(n),{label:s,lang:o}=e;await(0,ee.gzip)(n,i);return{file:a,file_path:i,size:await(0,ae.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,te.parse)(e),i=this.params.outputRoot,s=`subtitle-external-${t}.vtt`,r=(0,te.resolve)(i,s),o=`subtitle-external-${t}.zip`,n=(0,te.resolve)(i,o),h=`subtitle-external-u8-${t}${a}`,d=(0,te.resolve)(i,h),c=`subtitle-external-source-${t}.zip`,l=(0,te.resolve)(i,c);if(!await(0,ae.isValidPath)(e))return!1;if(await(0,ee.isUtf8File)(e))await(0,ie.copy)(e,d);else{await(0,ee.saveFileAsUtf8)(e,d);if(!await(0,ae.isValidFile)(d))return!1}const u=["-i",d,"-c","webvtt","-y",s];await this.ffmpeg(u,{cwd:this.params.outputRoot});if(await(0,ae.isValidFile)(r)){const i=await(0,ee.getFileLanguage)(r),{label:s,lang:h}=i;await(0,ee.gzip)(e,l),await(0,ee.gzip)(r,n);const d=await(0,ae.getFileSize)(l);return{file:o,size:await(0,ae.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}},ne=require("@soga/error"),he=require("path"),de=require("fs-extra"),ce=require("@soga/node-types"),le=require("@soga/fileutils"),ue=require("@soga/utils"),pe=require("@soga/error"),ge=require("path"),we=require("@soga/fileutils"),me=class extends ot{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,ge.resolve)(this.params.outputRoot,i),r=await(0,we.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=pt(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()}},fe=class extends me{current_position=0;current_index=0;group_data=[];async start(){const t=pt(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:ce.UploadProgress.group_media,percent:this.completed_percent+.5*this.total_percent}),await this.processGroups(),await this.postProgress({type:ce.UploadProgress.group_media,percent:this.completed_percent+.9*this.total_percent}),await this.saveData(),await this.postProgress({type:ce.UploadProgress.group_media,percent:this.completed_percent+this.total_percent}),this.db.data[t]}catch(t){throw(0,pe.buildDError)(t,{message:`Error occurred during media grouping ${this.hostType}`,detail:`Error occurred during media grouping ${this.hostType}: ${this.params.input.filepath}`})}}async processGroups(){const t="grouper_process_state";if(this.store.data[t])return;this.store.data.grouper_process_map||={},this.store.data.grouper_process_index||=0;const{length:e}=this.group_data;for(let t=0;t<e;t++){const a=this.group_data[t];this.store.data.grouper_process_map[a.filename]||(await _({outputRoot:this.params.outputRoot,files:a.files,filename:a.filename}),this.store.data.grouper_process_map[a.filename]=!0,await this.store.write(),await this.postProgress({type:ce.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:ce.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:ce.UploadProgress.group_media,percent:this.completed_percent+.2*this.total_percent+.2*this.total_percent*((t+1)/i)})}}async calculateThumbnails(){const t=this.readThumbnailInfo();if(!t)return;if(!t)return;const{tile_list:e}=t,{length:a}=e;let i=[...t.sprite_list];for(let t=0;t<a;t++){const a=e[t],s=a.file,r=await this.safelyAddOne({file_path:a.file_path,size:a.size}),o=await this.getPreviewId({file:s}),n=this.getFileName(r.file_index);await this.setPreviewIdMap({id:o,file:n,start:r.start,end:r.end},this.hostType),this.file_map[s]=r,i=i.map(t=>t.file===s?{...t,file:n,id:o,s:r.start,e:r.end}:t)}const s=this.getThumbnailInfoFilename(),r=await this.writeText(s,JSON.stringify(i));this.file_map[s]=r}async calculateOneTrack(t){const{segments:e,init:a,version:i,targetDuration:s,mediaSequence:r,endList:o}=t,n={},h=this.addOne({size:a.size,file_path:a.file_path}),d=await this.getPreviewId({file:a.uri}),c=this.getFileName(h.file_index),l=`${c}?id=${d}`;await this.setPreviewIdMap({id:d,file:c,start:h.start,end:h.end},this.hostType);const u=["#EXTM3U",`#EXT-X-VERSION:${i}`,`#EXT-X-TARGETDURATION:${s}`,`#EXT-X-MEDIA-SEQUENCE:${r}`,`#EXT-X-MAP:URI=${l},BYTERANGE="${h.size}@${h.start}"`];[...e].forEach(t=>{const{uri:e,size:a,duration:i,file_path:s}=t;n[e]=this.addOne({size:a,duration:i,file_path:s})});for(const[t,e]of Object.entries(n)){const a=await this.getPreviewId({file:t}),i=this.getFileName(e.file_index);await this.setPreviewIdMap({id:a,file:i,start:e.start,end:e.end},this.hostType),u.push(`#EXTINF:${e.duration},`),u.push(`#EXT-X-BYTERANGE:${e.size}@${e.start}`),u.push(`${i}?id=${a}`)}o&&u.push("#EXT-X-ENDLIST");return u.join("\n")}async writeTrackText(t,e){const a=(0,he.resolve)(this.params.outputRoot,t),i=(0,he.resolve)(this.params.outputRoot,`${t}.gz`),s=(0,he.resolve)(this.params.outputRoot,`${t}.bin`);await(0,de.writeFile)(a,e,"utf-8"),await(0,ue.gzip)(a,i);if(await(0,le.getFileSize)(i)>16){const t=(await(0,ue.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,le.getFileSize)(s)}),hash:t}}return{...this.addOne({file_path:a,size:await(0,le.getFileSize)(a)}),hash:""}}async writeText(t,e){const a=(0,he.resolve)(this.params.outputRoot,t);await(0,de.writeFile)(a,e,"utf-8");return this.addOne({file_path:a,size:await(0,le.getFileSize)(a)})}addOne({file_path:t,size:e,duration:a=0},i=!1){const s=this.getSizeLimit(this.hostType),{current_position:r,group_data:o}=this;if(i&&o[this.current_index]||!(r+e<=s)){this.current_index+=1;const{current_index:i}=this;o[i]?o[i].files.push(t):o[i]={filename:this.getFileName(i),files:[t]};const s=0,r=e-1;return this.current_position=e,{file_index:i,start:s,end:r,duration:a,size:r-s+1}}{const{current_index:i}=this,s=r,n=r+e-1;return this.current_position=n+1,o[i]?o[i].files.push(t):o[i]={filename:this.getFileName(i),files:[t]},{file_index:i,start:s,end:n,duration:a,size:n-s+1}}}async safelyAddOne(t){const e=this.getSizeLimit(this.hostType),{current_position:a}=this;return a+t.size<=e?0===a?(await this.insertSafeFile(),this.addOne(t)):this.addOne(t):(await this.insertSafeFile(),this.addOne(t))}},_e=class extends ot{async start(){try{if(this.grouperResult)return this.grouperResult;const t={meta:await this.getMetaData(),data:{}},{length:e}=this.params.hosts;for(let a=0;a<e;a++){const i=this.params.hosts[a],s=this.getSizeLimit(i),r=new fe({...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,ne.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}},ye=class extends ot{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 oe(this.params);if(await r.start(),s){const t=new vt(this.params);await t.start();const e=new Ct(this.params);await e.start();const a=new Yt(this.params);await a.start()}if(a){const t=new mt(this.params);await t.start();const e=new It(this.params);await e.start();const a=new Xt(this.params);await a.start()}const o=new _e(this.params);await o.start()}async getResult(){return this.db.data.grouper_result}},be=require("@soga/types"),ve=require("@soga/node-types"),Pe=require("@soga/mediainfo"),xe=require("@soga/fileutils"),ze=require("fs-extra"),Te=h(require("check-disk-space")),Re=require("@soga/error"),Se=class extends q{async start(){this.prepareResult||(await this.checkStorage(),await this.calculateMeta(),await this.calculateProgress())}async checkStorage(){const{length:t}=this.params.hosts,e=await(0,Te.default)(this.params.outputRoot),a=e.free,i=e.diskPath;if((3+t)*this.params.input.filesize>a)throw(0,Re.buildDError)(new Error(`${i} have no enough computer disk space, please adjust the temporary path in user settings.`),{message:`${i} have no enough computer disk space, please adjust the temporary path in user settings.`,detail:`${i} have no enough computer disk space to process ${this.params.input.filepath}`})}async calculateMeta(){if(this.meta)return this.meta;const{filename:t,local_btime:e,local_ctime:a,local_mtime:i,filesize:s}=this.params.input,r={file:t,size:s,btime:e,ctime:a,mtime:i,md5:""};return await this.setMeta(r),r}async calculateProgress(){if(this.prepareResult)return;const t={[ve.UploadProgress.prepare]:{weight:0,percent:1},[ve.UploadProgress.calculate_md5]:{weight:0,percent:0},[ve.UploadProgress.separate_video]:{weight:0,percent:0},[ve.UploadProgress.separate_audio]:{weight:0,percent:0},[ve.UploadProgress.separate_subtitle]:{weight:0,percent:0},[ve.UploadProgress.transcode_video]:{weight:0,percent:0},[ve.UploadProgress.transcode_audio]:{weight:0,percent:0},[ve.UploadProgress.transcode_thumbnail]:{weight:0,percent:0},[ve.UploadProgress.transcode_source]:{weight:0,percent:0},[ve.UploadProgress.transcode_txt]:{weight:0,percent:0},[ve.UploadProgress.transcode_img]:{weight:0,percent:0},[ve.UploadProgress.group_media]:{weight:0,percent:0},[ve.UploadProgress.upload_baidu]:{weight:0,percent:0},[ve.UploadProgress.upload_ali]:{weight:0,percent:0},[ve.UploadProgress.end]:{weight:0,percent:0}},e={keep_preview:this.params.keepPreview,keep_source:this.params.keepSource},a=await(0,xe.getFileSize)(this.params.input.filepath);t[ve.UploadProgress.prepare].weight=t[ve.UploadProgress.end].weight=Math.ceil(a/1024/1024/500),t[ve.UploadProgress.calculate_md5].weight=Math.ceil(a/1024/1024/200);let i=0;if(this.isMedia)if(this.params.keepPreview){const s=await(0,Pe.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,xe.isVideoSupport)(r),{duration:n}=s.general,h=o?n/400:n*(a*i)/1920/1080;t[ve.UploadProgress.separate_video].weight=Math.ceil(h),t[ve.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,xe.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,xe.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[ve.UploadProgress.separate_audio].weight=Math.ceil(a),t[ve.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[ve.UploadProgress.separate_subtitle].weight=Math.ceil(o),t[ve.UploadProgress.transcode_thumbnail].weight=Math.ceil(.08*r),i+=a,t[ve.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[ve.UploadProgress.transcode_txt].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a):this.isImg?e.keep_preview&&(t[ve.UploadProgress.transcode_img].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a);e.keep_source&&(t[ve.UploadProgress.transcode_source].weight=Math.ceil(a/1024/1024/30)),this.params.hosts.includes(be.HostType.BAIDU)&&(t[ve.UploadProgress.upload_baidu].weight=Math.ceil(i/1024/1024/1)),this.params.hosts.includes(be.HostType.ALI)&&(t[ve.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)}},De=async t=>{await(0,ze.ensureDir)(t.outputRoot);const e=await b(t);try{const a=new Se({...t,db:e});return await a.start(),a}catch(t){}},Me=require("@soga/node-types"),Ie=require("crypto"),Fe=require("fs-extra"),$e=class extends q{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,Ie.createHash)("md5"),n=(0,Fe.createReadStream)(t,{highWaterMark:4194304});n.on("data",async t=>{o.update(t),r+=t.length;const i=r/e;r-a>104857600&&(a=r,await this.postProgress({type:Me.UploadProgress.calculate_md5,percent:Math.min(i,1)}))}),n.on("end",()=>{const t=o.digest("hex");i(t)}),n.on("error",t=>{s(t)})});return i&&await this.setMd5(i),await this.postProgress({type:Me.UploadProgress.calculate_md5,percent:1}),i}async getResult(){if(this.result)return this.result;const{sourceResult:t,grouperResult:e,imgResult:a,txtResult:i,meta:s,keeps:r}=this,{length:o}=this.params.hosts,n={meta:{preview:r.preview,source:r.source,file:s}};for(let s=0;s<o;s++){const r=this.params.hosts[s];n[r]={max_size:0,parts:[]};const o=t=>{n[r].parts=[...n[r].parts,...t]},h=a?.data[r];if(h){h.cache&&(n[r].cache=h?.cache);const t=h.parts?.map(t=>({...t,preview:!0,source:!1}));t&&o(t),n.meta.img=a.meta,h.img&&(n[r].img=h.img)}const d=i?.data[r];if(d){o((d.parts||[]).map(t=>({...t,preview:!0,source:!1}))),n[r].cache=d.cache,n[r].txt={entrance:d.entrance,pad:i?.meta.pad,pages:i?.meta.pages}}const c=e?.data[r];if(c?.parts){o(c.parts.map(t=>({...t,preview:!0,source:!1}))),n.meta.audios=e.meta.audios,n.meta.videos=e.meta.videos,n[r].cache=c.cache,n[r].media={audios:c.audios,videos:c.videos,subtitles:c.subtitles,thumbnail:c.thumbnail,cover:c.cover}}const l=t?.data[r];if(l?.parts){o(l.parts.map(t=>{let e=!0;return(this.isMedia||this.isTxt)&&(e=!1),{...t,preview:e,source:!0}})),n[r].source={head:t.meta.head,download:l.download}}[...n[r]?.parts].forEach(t=>{t.size>n[r].max_size&&(n[r].max_size=t.size)})}return await this.setResult(n),n}async processFile(){const t="encoder_processed";if(this.db.data[t])return;const e=await De(this.params),{keeps:a}=e,i={...this.params,keepPreview:a.preview,keepSource:a.source},s=await this.calculateMd5();if(await this.setMd5(s),i.keepSource){const t=new N(this.params);await t.start()}if(e.isMedia&&i.keepPreview){const t=new ye(this.params);await t.start()}if(e.isTxt&&i.keepPreview){const t=new W(this.params);await t.start()}if(e.isImg){const t=new at(this.params);await t.start()}this.db.data[t]=!0,await this.db.write()}},ke=async t=>{try{const e=await b(t),a=new $e({...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:()=>qe,getPrepare:()=>Ie}),module.exports=(t=d,n(a({},"__esModule",{value:!0}),t));var c=require("@soga/error"),l=require("@soga/lowdb"),u=require("crypto"),p=require("fs-extra"),g=require("fs/promises"),w=require("path"),m=require("stream/promises");function f(t){const e=(0,u.createHash)("md5");return e.update(`${t}`),e.digest("hex")}async function _(t){await new Promise((e,a)=>{(async()=>{const i=(0,w.resolve)(t.outputRoot,t.filename);await(0,p.remove)(i);let s=!1;const r=(0,p.createWriteStream)(i);r.on("open",()=>{s=!0}).on("error",async t=>{s&&r.close(),await(0,p.remove)(i),a(t)});const{length:o}=t.files,n=async(e=0)=>{if(e<o){const a=t.files[e],o=t.files.length;await new Promise((t,e)=>{const n=(0,p.createReadStream)(a);n.pipe(r,{end:!o}),n.on("end",()=>{n.close(),t(!0)}),n.on("error",async t=>{n.destroy(),s&&r.close(),await(0,p.remove)(i),e(t)})}),await n(e+1)}};await n(0),s&&r.end(),e(!0)})()})}async function y(t,e){const a=f(JSON.stringify({...t,dbName:e})),i="db_unique_key",s=(0,w.resolve)(t.outputRoot,e),r=await(0,l.getDb)(s,{});return r.data[i]?r.data[i]!=a&&(r.data={[i]:a},await r.write()):(r.data[i]=a,await r.write()),r}async function b(t){return await y({file_id:t.id,input:{filepath:t.input.filepath,filesize:t.input.filesize},outputRoot:t.outputRoot},"encoder_store.json")}async function v({input_path:t,target_path:e,start:a,end:i}){const s=(0,p.createReadStream)(t,{start:a,end:i,highWaterMark:65536}),r=(0,p.createWriteStream)(e);try{await(0,m.pipeline)(s,r)}catch(t){try{(0,p.existsSync)(e)&&await(0,p.remove)(e)}catch(t){console.warn("Failed to clean up incomplete file:",t.message)}throw t}}var P=require("path"),x=require("@soga/utils"),z=require("@soga/fileutils"),T=require("@soga/error"),R=require("@soga/node-types"),S=require("fs-extra"),D=require("@soga/types"),I=2097152,M={[D.HostType.BAIDU]:52428800,[D.HostType.ALI]:4294967296},F={[D.HostType.BAIDU]:2147483648,[D.HostType.ALI]:4294967296},$=(D.HostType.BAIDU,D.HostType.ALI,require("@soga/types")),k=require("@soga/utils"),q=require("worker_threads"),E=class{segmentNames={};params;id;port=null;db;get lowData(){return this.db.data}get isVideo(){return this.params.type==$.RecordType.VIDEO}get isAudio(){return this.params.type==$.RecordType.AUDIO}get isMedia(){return this.isAudio||this.isVideo}get isTxt(){return this.params.type==$.RecordType.DOC&&this.params.ftype==$.RecordFtype.DOC_TXT}get isImg(){return this.params.type==$.RecordType.IMAGE}getSizeLimit(t){return this.params.is_shop_space?F[t]||2147483648:M[t]||52428800}getFilesize(){return this.params.input.filesize}constructor(t){this.params=t,this.id=t.id,this.port=t.port??null,this.db=t.db}async getPartInfo({host_type:t,filepath:e,start:a,end:i,filename:s,index:r},o=!0){const n={start:a,end:i,size:i-a+1,path:e,index:r,file:s,md5:o?await(0,k.calculateMd5)({file:e,start:a,end:i}):""};if(o){if(t===$.HostType.BAIDU){const t=await(0,k.calculateMd4)({file:e,start:a,end:i});n.md4=t}if(t===$.HostType.ALI){const t=await(0,k.calculateSha1)({file:e,start:a,end:i});n.sha1=t}}return n}async getStore(t){const{id:e,input:a,outputRoot:i}=this.params;return await y({file_id:e,input:{filepath:a.filepath,filesize:a.filesize},outputRoot:i},t)}async postProgress(t){const e={step:t.type,percent:t.percent};await this.postMessage({id:this.id,type:"percent",data:e})}async postMessage(t){this.port?this.port.postMessage(t):q.parentPort&&q.parentPort.postMessage(t)}async setKeeps(t){this.lowData.keeps=t,await this.db.write()}get keeps(){return this.lowData.keeps}async setMeta(t){this.lowData.meta=t,await this.db.write()}get meta(){return this.lowData.meta}async setSourceResult(t){this.lowData.source_result=t,await this.db.write()}get sourceResult(){return this.lowData.source_result}async setPrepareResult(t){this.lowData.prepare_result=t,await this.db.write()}get prepareResult(){return this.lowData.prepare_result}async setMd5(t){this.lowData.meta.md5=t,await this.db.write()}get md5(){return this.lowData.meta.md5}async setSubtitleEncoderResult(t){this.lowData.subtitle_encoder_result=t,await this.db.write()}get subtitleEncoderResult(){return this.lowData.subtitle_encoder_result}async setAudioSeparatorResult(t){this.lowData.audio_separator_result=t,await this.db.write()}get audioSeparatorResult(){return this.lowData.audio_separator_result}async setAudioTranscoderResult(t){this.lowData.audio_transcoder_result=t,await this.db.write()}get audioTranscoderResult(){return this.lowData.audio_transcoder_result}async setCoverResult(t){this.lowData.cover_result=t,await this.db.write()}get coverResult(){return this.lowData.cover_result}async setVideoTranscoderResult(t){this.lowData.video_transcoder_result=t,await this.db.write()}get videoTranscoderResult(){return this.lowData.video_transcoder_result}async setVideoThumbnailerResult(t){this.lowData.video_thumbnailer_result=t,await this.db.write()}get videoThumbnailerResult(){return this.lowData.video_thumbnailer_result}async setGrouperResult(t){this.lowData.grouper_result=t,await this.db.write()}get grouperResult(){return this.lowData.grouper_result}async setImgResult(t){this.lowData.img_result=t,await this.db.write()}get imgResult(){return this.lowData.img_result}async setTxtResult(t){this.lowData.txt_result=t,await this.db.write()}get txtResult(){return this.lowData.txt_result}async setResult(t){this.lowData.result=t,await this.db.write()}get result(){return this.lowData.result}_syncGetId({file:t,start:e,end:a},i){const s=`${i}_key_index`,r=`${i}_key_map`,o=`${t}_${e||0}_${a||0}`,n=this.db.data[r]||{};if(n[o])return n[o];this.db.data[s]=this.db.data[s]||0,this.db.data[r]=this.db.data[r]||{};const h=this.db.data[s]+1,d=`id_${h}`;return this.db.data[r][o]=d,this.db.data[s]=h,d}_syncSetIdMap({id:t,file:e,start:a,end:i},s,r){const o=`${s}_${r}_id_map`;this.db.data[o]=this.db.data[o]||{},this.db.data[o][t]={f:e,s:a,e:i}}},N=class extends E{syncGetSourceId(t){return this._syncGetId(t,"source")}async getSourceId(t){const e=this.syncGetSourceId(t);return await this.db.write(),e}getSourceIdMap(t){return this.db.data[`source_${t}_id_map`]||{}}syncSetSourceIdMap(t,e){this._syncSetIdMap(t,"source",e)}async setSourceIdMap(t,e){this.syncSetSourceIdMap(t,e),await this.db.write()}getSourceSegmentName=(t,e)=>{const a=`source_${e}_${t}`;if(this.segmentNames[a])return this.segmentNames[a];const i=`s-${f(`source-${e}-${this.md5}-${t}`)}`;return this.segmentNames[a]=i,i}},U=class extends N{head_size=32;getZipFilePath(){return(0,P.resolve)(this.params.outputRoot,"souce_zip.bin")}getDownloadListFileName(t){return`source_${t}_download_list.json`}getPartName(t,e){return this.getSourceSegmentName(e,t)}getPartPath(t,e){return(0,P.resolve)(this.params.outputRoot,this.getPartName(t,e))}get dbData(){return this.db.data}async setPartList(t,e){const a=`source_${t}_part_list`;this.dbData[a]=e,await this.params.db.write()}getPartList(t){const e=`source_${t}_part_list`;return this.dbData[e]}async setDownloadMap(t,e){const a=`source_${t}_download_map`;this.dbData[a]=e,await this.params.db.write()}getDownloadMap(t){const e=`source_${t}_download_map`;return this.dbData[e]}async sendProgress(t){await this.postProgress({type:R.UploadProgress.transcode_source,percent:t})}async setDownloadList(t,e){const a=`source_${t}_download_list`;this.dbData[a]=e,await this.params.db.write()}getDownloadList(t){const e=`source_${t}_download_list`;return this.dbData[e]}async start(){try{if(this.sourceResult)return await this.sendProgress(1),this.sourceResult;await this.gzip();const{length:t}=this.params.hosts;for(let e=0;e<t;e++){const t=this.params.hosts[e];await this.calculatePartList(t),await this.processDownloadMap(t)}await this.sendProgress(.9);const e=await this.getResult();return await this.sendProgress(1),e}catch(t){throw(0,T.buildDError)(t,{message:"Error occurred during source encoding",detail:`Error occurred during source encoding: ${this.params.input.filepath}`})}}async gzip(){if(this.dbData.source_gziped)return;const t=this.params.input.filepath,e=this.getZipFilePath();await(0,x.gzip)(t,e,async({percent:t})=>{await this.sendProgress(.6*t)}),this.dbData.source_gziped=!0,await this.params.db.write()}async getResult(){if(this.sourceResult)return this.sourceResult;const t={meta:await this.getMetaData(),data:{}},{length:e}=this.params.hosts;for(let a=0;a<e;a++){const e=this.params.hosts[a],i=this.getPartList(e),s=this.getDownloadMap(e);t.data[e]={download:s,parts:i}}return await this.setSourceResult(t),t}async getMetaData(){const t="source_meta",e=this.dbData[t];if(e)return e;const a=this.getZipFilePath(),i=await(0,z.getFileSize)(a),s={path:a,start:0,end:0},{head_size:r}=this;s.end=i<=r?i-1:r-1;const o={head:(await(0,x.getFileBufferSlice)(s.path,s.start,s.end)).toString("base64")};return this.dbData[t]=o,await this.params.db.write(),o}async writeDownloadListFile(t,e){const a=this.getDownloadListFileName(t),i=(0,P.resolve)(this.params.outputRoot,a);await(0,S.writeFile)(i,e,"utf-8");return{file_path:i,size:await(0,z.getFileSize)(i)}}async processDownloadMap(t){const e=this.getDownloadMap(t);if(e)return e;const a=this.getDownloadList(t);let i;const{file_path:s,size:r}=await this.writeDownloadListFile(t,JSON.stringify(a)),o=this.getSizeLimit(t),n=this.getPartList(t);if(n.length){const e=n[n.length-1],{path:a,size:h,file:d,index:c,end:l,start:u}=e,g=(0,P.resolve)(this.params.outputRoot,d);if(h+r<=o){await async function({source1:t,source2:e,target:a}){const i=(0,p.createReadStream)(t.filepath,{start:t.start,end:t.end}),s=(0,p.createWriteStream)(a);await(0,m.pipeline)(i,s);const r=(0,p.createReadStream)(e),o=(0,p.createWriteStream)(a,{flags:"a"});await(0,m.pipeline)(r,o)}({source1:{filepath:a,start:u,end:l},source2:s,target:g});const e=(await(0,S.stat)(g)).size,o=e-1,h=e-r,w=await this.getPartInfo({host_type:t,filepath:g,start:0,end:e-1,filename:d,index:c});n[n.length-1]=w;i={id:await this.getSourceId({file:d,start:h,end:o}),file:d,start:h,end:o}}else{const e=c+1,a=this.getPartName(t,e),o=this.getPartPath(t,e);await(0,S.rename)(s,o);const h=await this.getSourceId({file:a,start:0,end:r-1}),d=await this.getPartInfo({host_type:t,filepath:o,start:0,end:r-1,filename:a,index:e});n.push(d),i={id:h,file:a,start:0,end:r-1}}return await this.setPartList(t,n),await this.setDownloadMap(t,i),i}}async calculatePartList(t){const e=`source_${t}_list_calculated`;if(this.dbData[e])return;const a=this.getZipFilePath(),i=await(0,z.getFileSize)(a),s=[],r=this.getSizeLimit(t),{head_size:o}=this,n=[];if(i>o){let e=0;for(let h=o;h<=i-1;h+=r){const o=Math.min(h+r-1,i-1),d=this.getPartName(t,e),c=await this.getPartInfo({host_type:t,filepath:a,start:h,end:o,filename:d,index:e});let l=0;for(let t=h;t<o;t+=I){const e=Math.min(t+I-1,o),a=e-t+1,i=l+a-1,s=await this.getSourceId({file:"source_zip",start:t,end:e});n.push({id:s,file:d,start:l,end:i}),l+=a}s.push(c),e++}}await this.setPartList(t,s),await this.setDownloadList(t,n),this.dbData[e]=!0,await this.db.write()}},L=require("path"),C=require("fs-extra"),A=require("@soga/utils"),O=h(require("zlib")),V=require("@soga/utils"),G=require("@soga/error"),B=require("@soga/node-types"),j=require("path"),H=require("@soga/fileutils"),X=require("fs-extra"),W=class extends E{get preview_common_db_data(){return this.db.data}async getCurrentFileIndex(t){const e=this.db.data[`preview_${t}_current_index`];return"number"!=typeof e?(this.db.data[`preview_${t}_current_index`]=0,await this.db.write(),0):e}async increaseCurrentFileIndex(t){const e=await this.getCurrentFileIndex(t)+1;return this.db.data[`preview_${t}_current_index`]=e,await this.db.write(),e}getPartName(t,e){return this.getPreviewSegmentName(e,t)}getPartPath(t,e){return(0,j.resolve)(this.params.outputRoot,this.getPartName(t,e))}syncGetPreviewId(t){return this._syncGetId(t,"preview")}async getPreviewId(t){const e=this.syncGetPreviewId(t);return await this.db.write(),e}getPreviewIdMap(t){return this.db.data[`preview_${t}_id_map`]||{}}syncSetPreviewIdMap(t,e){this._syncSetIdMap(t,"preview",e)}async setPreviewIdMap(t,e){this.syncSetPreviewIdMap(t,e),await this.db.write()}getPreviewSegmentName=(t,e)=>{const a=`preview_${e}_${t}`;if(this.segmentNames[a])return this.segmentNames[a];const i=`p-${f(`preview-${e}-${this.md5}-${t}`)}`;return this.segmentNames[a]=i,i};async calculatePartList(t,e){const a=[],i=await this.getCurrentFileIndex(t);for(let s=0;s<i+1;s++){const i=this.getPartName(t,s),r=this.getPartPath(t,s),o=await(0,H.getFileSize)(r),n=await this.getPartInfo({host_type:t,filename:i,filepath:r,index:s,start:0,end:o-1},e);a.push(n)}return a}getPartListKey(t){return`preview_${t}_part_list`}async completePartList(t){const e=await this.getPartList(t);if(e){const a=[];for(const i of e)if(i.md5)a.push(i);else{const e=await this.getPartInfo({filename:i.file,filepath:i.path,start:i.start,end:i.end,host_type:t,index:i.index},!0);a.push(e)}await this.setPartList(t,a)}}async getPartList(t){const e=this.getPartListKey(t),a=this.preview_common_db_data[e];if(a)return a}async setPartList(t,e){const a=this.getPartListKey(t);this.preview_common_db_data[a]=e,await this.db.write()}async attachCacheData(){const{hosts:t}=this.params;for(const e of t)await this.attachHostCacheData(e),await this.completePartList(e)}getCacheInfo(t){const e=`preview_${t}_cache_info`;return this.preview_common_db_data[e]}async writeCacheFile(t,e){const a=`preview_${t}_cache_info.txt`,i=(0,j.resolve)(this.params.outputRoot,a);await(0,X.writeFile)(i,e,"utf-8");return{file_path:i,size:await(0,H.getFileSize)(i)}}async setCacheInfo(t,e){const a=`preview_${t}_cache_info`;this.preview_common_db_data[a]=e,await this.db.write()}async attachHostCacheData(t){if(this.getCacheInfo(t))return;const e=await this.getPartList(t),a=this.getPreviewIdMap(t),{file_path:i,size:s}=await this.writeCacheFile(t,JSON.stringify(a)),r=this.getSizeLimit(t);if(e.length){const a=e[e.length-1],{path:o,size:n,file:h,index:d,end:c}=a;let l;if(n+s<=r){await async function({filepath:t,size:e},a){(await(0,p.stat)(t)).size>e&&await(0,g.truncate)(t,e);const i=(0,p.createReadStream)(a),s=(0,p.createWriteStream)(t,{flags:"a"});await(0,m.pipeline)(i,s)}({filepath:o,size:n},i);const a=await(0,H.getFileSize)(o),r=await this.getPartInfo({host_type:t,filename:h,filepath:o,index:d,start:0,end:a-1});e[e.length-1]=r;const u=c+1,w=c+s;l={id:await this.getPreviewId({file:h,start:u,end:w}),file:h,start:u,end:w}}else{const a=d+1,r=this.getPartName(t,a),o=this.getPartPath(t,a);await(0,X.copy)(i,o);const n=await this.getPreviewId({file:r,start:0,end:s-1}),h=await this.getPartInfo({host_type:t,filename:r,filepath:o,index:a,start:0,end:s-1},!1);e.push(h),await this.setPartList(t,e),l={id:n,file:r,start:0,end:s-1}}l&&await this.setCacheInfo(t,l)}}},K=class extends W{content_size_1=81920;content_size_2=102400;totalPage=1;hashBuffer=Buffer.from("dpan");get hashBufferLength(){return this.hashBuffer.length}getU8FileName(){return`text_utf8_${this.params.id}.txt`}getU8FilePath(){return(0,L.resolve)(this.params.outputRoot,this.getU8FileName())}async sendProgress(t){await this.postProgress({type:B.UploadProgress.transcode_txt,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.dbData.txt_result)return await this.sendProgress(1),this.dbData.txt_result;await this.txtConvertToUtf8File(),await this.sendProgress(.2);const{length:t}=this.params.hosts;for(let e=0;e<t;e++){const a=this.params.hosts[e];await this.txtConvertToGzipFile(a),await this.sendProgress(.2+(e+1)/t*.6)}await this.attachCacheData();const e=await this.getResult();return await this.clean(),await this.sendProgress(1),e}catch(t){throw(0,G.buildDError)(t,{message:"Error occurred during txt encoding",detail:`Error occurred during txt encoding: ${this.params.input.filepath}`})}}async getResult(){if(this.txtResult)return this.txtResult;const t={meta:{pad:this.hashBufferLength,pages:this.totalPage},data:{}};for(const e of this.params.hosts)t.data[e]={cache:this.getCacheInfo(e),parts:await this.getPartList(e),entrance:await this.getEntranceInfo(e)};return await this.setTxtResult(t),t}async clean(){try{if(this.params.debug)return;const t=this.getU8FilePath();await(0,C.remove)(t)}catch(t){}}async setEntranceInfo(t,e){const a=`txt_${t}_entrance`;this.dbData[a]=e,await this.db.write()}async getEntranceInfo(t){const e=`txt_${t}_entrance`,a=this.dbData[e];if(a)return a}async txtConvertToUtf8File(){if(this.dbData.txt_utf8_converted)return;const t=this.params.input.filepath,e=this.getU8FilePath();await(0,V.saveFileAsUtf8)(t,e),this.dbData.txt_utf8_converted=!0,await this.db.write()}async txtConvertToGzipFile(t){if(await this.getEntranceInfo(t))return;const e=this.getSizeLimit(t),a=this.getU8FilePath(),i=await this.calculateSlice(),{length:s}=i,r={};let o=0,n=(0,C.createWriteStream)(this.getPartPath(t,await this.getCurrentFileIndex(t)));for(let h=0;h<s;h++){const d=h==s-1?0:h+1,c=i[d],{index:l,start:u,end:p}=c,g={page:l+1,text:(await(0,A.getFileBufferSlice)(a,u,p)).toString("utf8")},w=JSON.stringify(g);let m=Buffer.from(w,"utf8");if(0==d){const t={...g,map:r};m=Buffer.from(JSON.stringify(t),"utf8")}const f=await this.getPreviewId({file:"u8zip",start:u,end:p});await new Promise((a,i)=>{O.default.gzip(m,async(s,h)=>{if(s)return i(s);const c=h.length<this.hashBufferLength?this.hashBuffer:h.subarray(0,this.hashBufferLength),l=Buffer.concat([c,h]),u=l.length;if(o+u>e){n.end();const e=await this.increaseCurrentFileIndex(t);n=(0,C.createWriteStream)(this.getPartPath(t,e)),o=0}const p=o,g=o+u-1;if(n.write(l),o+=u,0==d){n.end();const e={id:f,start:p,end:g,file:this.getPartName(t,await this.getCurrentFileIndex(t))};await this.setEntranceInfo(t,e)}else r[`p_${d+1}`]={id:f,f:this.getPartName(t,await this.getCurrentFileIndex(t)),s:p,e:g};this.syncSetPreviewIdMap({id:f,file:this.getPartName(t,await this.getCurrentFileIndex(t)),start:p,end:g},t),a(!0)})})}await this.db.write();const h=await this.calculatePartList(t,!1);await this.setPartList(t,h)}async calculateSlice(){if(this.dbData.txt_slice_list)return this.dbData.txt_slice_list;const t=this.getU8FilePath(),e=await new Promise((e,a)=>{(0,C.readFile)(t,"utf8",(t,i)=>{if(t)return void a(t);const s=this.content_size_1,r=this.content_size_2,o=[];let n=0,h=0,d=0;for(;h<i.length;){let t=Math.min(h+r,i.length);const e=Math.min(h+s,i.length),a=i.slice(e,t-1).indexOf("#");-1!==a&&(t=e+a);const c=i.slice(h,t),l=Buffer.byteLength(c);o.push({index:n++,start:d,end:d+l-1}),this.totalPage=n,h=t,d+=l}e(o)})});return this.dbData.txt_slice_list=e,await this.db.write(),e}},J=require("path"),Q=require("@soga/imgutils"),Z=require("@soga/utils"),Y=require("@soga/fileutils"),tt=require("@soga/error"),et=require("@soga/node-types"),at=require("fs-extra"),it=class extends W{getCompressFileName(){return"img_compress.jpg"}getCompressFilePath(){return(0,J.resolve)(this.params.outputRoot,this.getCompressFileName())}getGzFileName(){return"compressed_img.zip"}getGzFilePath(){return(0,J.resolve)(this.params.outputRoot,this.getGzFileName())}async sendProgress(t){await this.postProgress({type:et.UploadProgress.transcode_img,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.imgResult)return await this.sendProgress(1),this.imgResult;await this.compress(),await this.sendProgress(.1),await this.gzip(),await this.sendProgress(.4);const{hosts:t}=this.params,{length:e}=t;for(let a=0;a<e;a++){const e=t[a];await this.splitFile(e),await this.calculatePartList(e,!1)}await this.attachCacheData(),await this.sendProgress(.9);const a=await this.getResult();return await this.clean(),await this.sendProgress(1),a}catch(t){throw(0,tt.buildDError)(t,{message:"Error occurred during image encoding",detail:`Error occurred during image encoding: ${this.params.input.filepath}`})}}getCacheInfoFileName(t){return`img_${t}_cache.json`}async getResult(){if(this.imgResult)return this.imgResult;const{input:t}=this.params,e=t.filepath,{width:a,height:i}=await(0,Q.getMetadata)(e),s=this.getCompressFilePath(),{width:r,height:o}=await(0,Q.getMetadata)(s),n=await(0,Y.getFileSize)(s),h={meta:{width:a,height:i,size:t.filesize,t_width:r,t_height:o,t_size:n},data:{}},{length:d}=this.params.hosts;for(let t=0;t<d;t++){const e=this.params.hosts[t],a=await this.getPartList(e),i=this.getPreviewList(e);h.data[e]={img:{preview:i},cache:this.getCacheInfo(e),parts:a}}return await this.setImgResult(h),h}async clean(){try{if(this.params.debug)return;const t=this.getCompressFilePath();await(0,at.remove)(t)}catch(t){}}async compress(){if(this.dbData.img_compressed)return;const t=this.getCompressFilePath();await(0,Q.compress)({ffmpeg_path:this.params.ffmpegPath,input_path:this.params.input.filepath,output_path:t}),this.dbData.img_compressed=!0,await this.db.write()}async gzip(){if(this.dbData.img_gziped)return;const t=this.getCompressFilePath(),e=this.getGzFilePath();await(0,Z.gzip)(t,e),this.dbData.img_gziped=!0,await this.db.write()}async setPreviewList(t,e){const a=`img_${t}_preview_list`;this.dbData[a]=e,await this.db.write()}getPreviewList(t){const e=`img_${t}_preview_list`;return this.dbData[e]}async splitFile(t){if(this.getPreviewList(t))return;const e=this.getGzFilePath(),a=await(0,Y.getFileSize)(e),i=this.getSizeLimit(t),s=[],r=[];for(let o=0;o<=a-1;o+=i){0!=o&&await this.increaseCurrentFileIndex(t);const n=Math.min(o+i-1,a-1),h=await this.getCurrentFileIndex(t),d=this.getPartName(t,h),c=this.getPartPath(t,h);await v({input_path:e,target_path:c,start:o,end:n});const l=0,u=n-o,p=await this.getPartInfo({host_type:t,filepath:c,filename:d,start:l,end:u,index:h},!1);s.push(p);const g=await this.getPreviewId({file:d,start:l,end:u});r.push({id:g,file:d,start:l,end:u}),await this.setPreviewIdMap({id:g,file:d,start:l,end:u},t)}await this.setPartList(t,s),await this.setPreviewList(t,r)}},st=h(require("fluent-ffmpeg")),rt=require("child_process"),ot=require("@soga/mediainfo"),nt=class extends W{async getMediainfo(){const{mediainfo:t}=this.db.data;if(t)return t;const e=this.params.input.filepath,a=await(0,ot.parseMediaInfo)(e);return this.db.data.mediainfo=a,await this.params.db.write(),a}constructor(t){super(t),st.default.setFfmpegPath(t.ffmpegPath)}getFluent(){return(0,st.default)()}async ffmpeg(t,e){const a=this.params.ffmpegPath;return await new Promise((i,s)=>{const r=(0,rt.spawn)(a,t,Object.assign({stdio:"ignore"},e));r.on("close",t=>{i(t)}),r.on("error",t=>{s(t)})})}},ht=require("path"),dt=require("@soga/fileutils"),ct=require("@soga/node-types"),lt=require("@soga/error"),ut=({type:t,track_order:e,quality:a})=>`audio-${e}-${a}-${t}.${"manifest"===t?"m3u8":"mp4"}`,pt=({width:t,height:e})=>`video-formatted-${t}-${e}.mp4`,gt=t=>`grouper_result_${t}`,wt=t=>{let e=0,a=0,i=0;t.segments.forEach(t=>{a+=t.duration,e+=t.size;const s=8*t.size/t.duration;s>i&&(i=s)});const s=8*e/a;return{bandwidth:Math.ceil(i),average_bandwidth:Math.ceil(s)}},mt=(t,e)=>{if("number"==typeof t.percent)return t.percent/100;return function(t){const e=t.split(":").map(parseFloat),[a=0,i=0,s=0]=e.reverse();return 3600*s+60*i+a}(t.timemark)/e};var ft=class extends nt{async start(){try{await this.separateVideo(),await this.postProgress({type:ct.UploadProgress.separate_video,percent:1})}catch(t){throw(0,lt.buildDError)(t,{message:"Error occurred during video separation",detail:`Error occurred during video separation: ${this.params.input.filepath}`})}}async separateVideo(){const t="video_separated";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],i=pt({width:a.width,height:a.height}),s=(0,ht.resolve)(this.params.outputRoot,i),r=(0,dt.isVideoSupport)(a.codec),o=["-sn","-an","-map","0:v:0"];let n="copy";r||(n=a.width*a.height>=2073600?"libx265":"libx264","libx265"==n&&o.push("-pix_fmt","yuv420p")),o.push("-c:v",n);const h=a.duration;o.push("-y"),await new Promise((t,e)=>{const a=this.getFluent().input(this.params.input.filepath).outputOptions(o).on("progress",async t=>{if(!r&&t.frames){const e=mt(t,h);await this.postProgress({type:ct.UploadProgress.separate_video,percent:e})}}).on("end",async()=>{t("end"),a.kill("SIGKILL")}).on("error",async t=>{e(t)}).output(s);a.run()});if(!await(0,dt.isValidFile)(s))throw new Error("Separate Video track failed");this.db.data[t]=!0,await this.params.db.write()}},_t=require("path"),yt=require("@soga/fileutils"),bt=require("@soga/node-types"),vt=require("@soga/error"),Pt=class extends nt{async start(){try{await this.separateTracks(),await this.postProgress({type:bt.UploadProgress.separate_audio,percent:1})}catch(t){throw(0,vt.buildDError)(t,{message:"Error occurred during audio separation",detail:`Error occurred during audio separation: ${this.params.input.filepath}`})}}async separateTracks(){if(this.audioSeparatorResult)return;const t=await this.getMediainfo();if(!t?.audio?.length)return;const{audio:e}=t,a=e.length,i=[];for(let t=0;t<a;t++){const s=e[t],{codec:r,channels:o,lossless:n}=s,h={adapt:{need:!0,codec:"",channels:Math.min(o,2)},high:{need:!1,codec:"flac",channels:0}};(0,yt.isAudioAdapt)(r)?o>2?(h.high.need=!0,h.high.codec="copy",h.adapt.codec=r,h.adapt.need=!0):(h.adapt.need=!0,h.adapt.codec="copy",h.adapt.channels=0):(0,yt.isAudioHigh)(r)?(h.high.need=!0,h.high.codec="copy",h.adapt.need=!0,h.adapt.codec="aac"):(h.adapt.need=!0,h.adapt.codec="aac",n&&(h.high.need=!0,h.high.codec="flac")),h.adapt.need&&await this.separateAudioTrack(t,{type:"adapt",codec:h.adapt.codec,tracks:a,channels:h.adapt.channels,need_adapt:!0,need_high:h.high.need}),h.high.need&&await this.separateAudioTrack(t,{type:"high",codec:h.high.codec,tracks:a,channels:h.high.channels,need_adapt:h.adapt.need,need_high:!0}),i.push(h)}await this.setAudioSeparatorResult(i)}async separateAudioTrack(t,e){const a=`audio_separated_${t}_${e.type}`;if(this.db.data[a])return;const i=await this.getMediainfo();if(!i?.audio?.length)return;const s=i.audio[t];if(!s)return;const r=s?.duration??i.general?.duration,o=ut({type:"formatted",track_order:t,quality:e.type}),n=(0,_t.resolve)(this.params.outputRoot,o),h=["-sn","-vn","-map",`0:a:${t}`];e.codec&&h.push("-c:a",e.codec),e.channels&&h.push("-ac",e.channels.toString()),h.push("-y"),await new Promise((a,i)=>{const s=this.getFluent().input(this.params.input.filepath).outputOptions(h).on("progress",async a=>{if("copy"!=e.codec){const i=mt(a,r);let s=t;"adapt"==e.type?e.need_high?s+=1/3*i:s+=i:e.need_adapt?(s+=1/3,s+=2/3*i):s+=i;const o=s/e.tracks;await this.postProgress({type:bt.UploadProgress.separate_audio,percent:o})}}).on("end",async()=>{a("end"),s.kill("SIGKILL")}).on("error",async t=>{i(t)}).output(n);s.run()});if(!await(0,yt.isValidFile)(n))throw new Error(`Separate audio track failed: [track_order:${t}, track_quality ${e.type}] `);if("copy"==e.codec){let a=t;"adapt"==e.type&&e.need_high?a+=1/3:a+=1;const i=a/e.tracks;await this.postProgress({type:bt.UploadProgress.separate_audio,percent:i})}this.db.data[a]=!0,await this.params.db.write()}},xt=require("path"),zt=require("@soga/mediainfo"),Tt=require("@soga/mp4box"),Rt=require("@soga/m3u8"),St=require("@soga/node-types"),Dt=require("@soga/fileutils"),It=require("fs-extra"),Mt=require("@soga/error"),Ft=class extends nt{getVideoInitName({width:t,height:e}){return`video-init-${t}-${e}.mp4`}getVideoManifestName({width:t,height:e}){return`video-hls-${t}-${e}.m3u8`}async start(){try{await this.transcodeVideo(),await this.saveData(),await this.postProgress({type:St.UploadProgress.transcode_video,percent:1})}catch(t){throw(0,Mt.buildDError)(t,{message:"Error occurred during video transcoding",detail:`Error occurred during video transcoding: ${this.params.input.filepath}`})}}async saveData(){const t=await this.getMediainfo();if(!t?.video?.length)return;if(this.videoTranscoderResult)return;const{width:e,height:a}=t.video[0],i=pt({width:e,height:a}),s=(0,xt.resolve)(this.params.outputRoot,i),r=this.getVideoManifestName({width:e,height:a}),o=(0,xt.resolve)(this.params.outputRoot,r),n=await(0,Rt.parseM3U8)(o),{videos:h}=await(0,Tt.getMp4boxInfo)(s),{codec:d}=h[0],{bandwidth:c,average_bandwidth:l}=wt(n),u=(await(0,zt.parseMediaInfo)(s)).video[0],p=(0,Dt.getStandardInfo)(e,a),g={m3u8:n,m3u8_path:o,codec:d,width:e,height:a,bandwidth:c,average_bandwidth:l,bitdepth:u?.bitdepth,bitrate:u?.bitrate,codec_name:u?.codec??"",framerate:u?.framerate,label:p?.label??"unknown"};await this.setVideoTranscoderResult(g),this.params.debug||await(0,It.remove)(s)}async transcodeVideo(){const t="video_transcode_state";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],i={width:a.width,height:a.height},s=pt(i),r=this.getVideoInitName(i),o=this.getVideoManifestName({width:a.width,height:a.height}),n=["-i",s,"-an","-sn","-c:v","copy","-hls_list_size","0","-hls_time","6","-hls_segment_type","fmp4","-hls_fmp4_init_filename",r,"-y",o];await this.ffmpeg(n,{cwd:this.params.outputRoot});const h=(0,xt.resolve)(this.params.outputRoot,o);if(!await(0,Dt.isValidFile)(h))throw new Error("Transcode video track failed");this.db.data[t]=!0,await this.db.write()}},$t=require("path"),kt=require("@soga/fileutils"),qt=require("@soga/mp4box"),Et=require("@soga/m3u8"),Nt=require("@soga/mediainfo"),Ut=require("fs-extra"),Lt=require("@soga/error"),Ct=require("@soga/node-types"),At=class extends nt{async start(){try{await this.transcodeAudios(),await this.saveData()}catch(t){throw(0,Lt.buildDError)(t,{message:"Error occurred during audio transcoding",detail:`Error occurred during audio transcoding: ${this.params.input.filepath}`})}}async saveData(){if(this.audioTranscoderResult)return;const t=await this.getMediainfo();if(!t?.audio?.length)return;const e=t.audio.length,a=this.audioSeparatorResult,i=[],s={};for(let t=0;t<e;t++){const e=a[t];e.adapt.need&&(s.adapt=await this.getQualityData({track_order:t,quality:"adapt"})),e.high.need&&(s.high=await this.getQualityData({track_order:t,quality:"high"})),i.push(s)}await this.setAudioTranscoderResult(i);try{if(this.params.debug)return;for(let t=0;t<e;t++){const e=a[t];if(e.adapt.need){const e=ut({type:"formatted",track_order:t,quality:"adapt"}),a=(0,$t.resolve)(this.params.outputRoot,e);await(0,Ut.remove)(a)}if(e.high.need){const e=ut({type:"formatted",track_order:t,quality:"high"}),a=(0,$t.resolve)(this.params.outputRoot,e);await(0,Ut.remove)(a)}}}catch(t){}}async getQualityData({track_order:t,quality:e}){const a=ut({type:"formatted",track_order:t,quality:e}),i=(0,$t.resolve)(this.params.outputRoot,a),s=await(0,Nt.parseMediaInfo)(i);if(!s.audio?.length)throw new Error("parse mediainfo failed!");const r=s.audio[0],o=ut({type:"manifest",track_order:t,quality:e}),n=await(0,kt.getFileSize)(i),h=(0,$t.resolve)(this.params.outputRoot,o),d=await(0,qt.getMp4boxInfo)(i),{audios:c}=d,{language:l,codec:u}=c[0],p=l&&!l.startsWith("un")?{language:l}:void 0,g=await(0,Et.parseM3U8)(h),{bandwidth:w,average_bandwidth:m}=wt(g);return{m3u8:g,m3u8_path:h,codec:u,codec_name:r.codec,...p,order:t,lossless:r.lossless,channels:r.channels,bandwidth:w,size:n,average_bandwidth:m}}async transcodeAudios(){const t="audio_transcoded";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.audio?.length)return;const a=e.audio.length,i=this.audioSeparatorResult;for(let t=0;t<a;t++){const e=i[t];e.adapt.need&&await this.transcodeAudio(t,{...e.adapt,type:"adapt"}),e.high.need&&await this.transcodeAudio(t,{...e.high,type:"high"});const s=(t+1)/a;await this.postProgress({type:Ct.UploadProgress.transcode_audio,percent:s})}await this.postProgress({type:Ct.UploadProgress.transcode_audio,percent:1}),this.db.data[t]=!0,await this.db.write()}async transcodeAudio(t,e){const a=`audio-transcoded-${t}-${e.type}`;if(this.db.data[a])return;const i=ut({type:"formatted",track_order:t,quality:e.type}),s=ut({type:"init",track_order:t,quality:e.type}),r=ut({type:"manifest",track_order:t,quality:e.type}),o=["-i",i,"-vn","-sn","-c:a","copy","-hls_list_size","0","-hls_time","6","-hls_segment_type","fmp4","-hls_fmp4_init_filename",s,"-y",r];await this.ffmpeg(o,{cwd:this.params.outputRoot});const n=(0,$t.resolve)(this.params.outputRoot,r);if(!await(0,kt.isValidFile)(n))throw new Error(`Transcode audio track failed: [track_order:${t}, track_quality ${e.type}] `);this.db.data[a]=!0,await this.db.write()}},Ot=require("path"),Vt=require("@soga/fileutils"),Gt=require("@soga/imgutils"),Bt=require("fs-extra"),jt=require("@soga/node-types"),Ht=require("@soga/error"),Xt=class extends nt{m3u8_data=null;thumbnail_duration=30;thumbnail_group=[];row=8;col=8;screenshot_width=480;screenshot_height=270;getScreenshotName(t){return`video_screenshot_${t}.jpg`}getTileName(t){return`video_tile_${t}.jpg`}getCoverName(){return"video_cover.jpg"}async updateImagePercent(t,e){const a="screenshot"==e?6*t/7:t/7+6/7;await this.postProgress({type:jt.UploadProgress.transcode_thumbnail,percent:a})}store;async initStore(){this.store=await this.getStore("thumbnail_store.json")}async start(){if(!this.videoThumbnailerResult)try{const t=await this.getMediainfo();if(!t?.video?.length)return;if(await this.init(),!this.m3u8_data)return;await this.generateScreenshots(),await this.generateTiles(),await this.saveCoverInfo(),await this.saveThumbnailInfo()}catch(t){throw(0,Ht.buildDError)(t,{message:"Error occurred during video thumbnail generation",detail:`Error occurred during video thumbnail generation: ${this.params.input.filepath}`})}}async init(){await this.initStore(),await this.initScreenshotSize(),await this.initM3U8Data(),await this.initThumbnailDuration(),await this.initThumbnailGroup()}async saveThumbnailInfo(){if(this.videoThumbnailerResult)return;const{col:t,row:e,thumbnail_group:a,screenshot_width:i,screenshot_height:s}=this,r=a.length,o=[],n=[];for(let h=0;h<r;h++){const r=a[h],d=r.start_time,c=r.end_time,l=Math.floor(h/(e*t)),u=h%e*i,p=Math.floor(h%(t*e)/e)*s,g=this.getTileName(l);n.push(g),o.push({file:g,st:d,et:c,x:u,y:p,w:i,h:s})}const h=[...new Set(n)],d=h.length,c=[];for(let t=0;t<d;t++){const e=h[t],a=(0,Ot.resolve)(this.params.outputRoot,e),i=await(0,Vt.getFileSize)(a);c.push({file:e,file_path:a,size:i})}const l={width:this.screenshot_width,height:this.screenshot_height,row:this.row,col:this.col,tile_list:c,sprite_list:o};await this.setVideoThumbnailerResult(l)}async saveCoverInfo(){if(this.coverResult)return;const t=this.store.data.thumbnail_screenshot_largest,e=t?.index||0,{screenshot_width:a,screenshot_height:i}=this,s=this.getScreenshotName(e),r=(0,Ot.resolve)(this.params.outputRoot,s),o=this.getCoverName(),n=(0,Ot.resolve)(this.params.outputRoot,o);await(0,Bt.copy)(r,n);const h={file:o,path:n,size:await(0,Vt.getFileSize)(n),width:a,height:i};await this.setCoverResult(h)}async generateTiles(){const t=this.store.data.thumbnail_tile_index||0,{length:e}=this.thumbnail_group,a=this.col*this.row,i=Math.ceil(e/a);for(let e=t;e<i;e++)await this.generateOneTile(e),await this.updateImagePercent((e+1)/i,"tile")}async generateOneTile(t){const{col:e,row:a}=this,i=this.thumbnail_group.length,s=a*e,r=t*s,o=Math.min(s,i-r),n=[];for(let t=0;t<o;t++){const e=this.getScreenshotName(r+t),a=(0,Ot.resolve)(this.params.outputRoot,e);n.push(a)}const h=this.getTileName(t),d=(0,Ot.resolve)(this.params.outputRoot,h);await this.createSpriteSheet(n,d),this.store.data.thumbnail_tile_index=t+1,await this.store.write()}async createSpriteSheet(t,e){await(0,Gt.combine)({col:this.col,inputs:t,output_path:e,width:this.screenshot_width,height:this.screenshot_height})}getKeyFrameParams(t,e=0){if(t<1)return["-vframes","1"];{const a=Math.max(t-e-.3,.1);if(a<1)return["-vframes","1"];return["-ss",`${a.toFixed(3)}`,"-vframes","1"]}}async generateScreenshots(){if(this.store.data.thumbnail_screenshot_state)return;this.store.data.thumbnail_screenshot_index||=0;const t=this.store.data.thumbnail_screenshot_index,e=this.store.data.thumbnail_screenshot_largest,a={index:0,size:0};if(e){const t=e;a.index=t.index,a.size=t.size}const{segments:i}=this.m3u8_data,{thumbnail_group:s,screenshot_width:r}=this,{length:o}=s,n=async(t,{errorTimes:e,fixedSeconds:o})=>{const h=s[t].item.index,d=i[h];try{const e=this.getScreenshotName(t),i=`concat:${d.init_uri}|${d.uri}`,s=this.getKeyFrameParams(d.duration,o),n=r>this.screenshot_height?`${r}:-2`:`-2:${this.screenshot_height}`,h=["-i",i,...s,"-vf",`scale=${n}:flags=lanczos`,"-y",e];await this.ffmpeg(h,{cwd:this.params.outputRoot});const c=(0,Ot.resolve)(this.params.outputRoot,e),l=await(0,Vt.getFileSize)(c);if(0===l)throw new Error(`Generate video thumbnail error: [index: ${t}, start_time: ${d.start_time}, end_time: ${d.end_time}]`);l>=a.size&&(a.index=t,a.size=l,this.store.data.thumbnail_screenshot_largest=a,await this.store.write()),this.store.data.thumbnail_screenshot_index=t+1,await this.store.write()}catch(a){const i=Math.max(10,d.duration);if(!(e<3))throw a;await n(t,{errorTimes:e+1,fixedSeconds:o+i/5})}};for(let e=t;e<o;e++)await n(e,{errorTimes:0,fixedSeconds:0}),await this.updateImagePercent((e+1)/o,"screenshot");this.store.data.thumbnail_screenshot_state=!0,await this.store.write()}async initScreenshotSize(){const{thumbnail_screenshot_size:t}=this.store.data;if(t)return this.screenshot_width=t.width,void(this.screenshot_height=t.height);const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],{width:i,height:s}=a,r=i>s?480:270;this.screenshot_width=2*Math.floor(Math.min(r,i)/2),this.screenshot_height=2*Math.floor(this.screenshot_width*(s/i)/2),this.store.data.thumbnail_screenshot_size={width:this.screenshot_width,height:this.screenshot_height}}async initThumbnailGroup(){if(this.store.data.thumbnail_group)return void(this.thumbnail_group=this.store.data.thumbnail_group);const t=[],{segments:e}=this.m3u8_data,{length:a}=e,i=this.thumbnail_duration;let s=0,r=[];for(let o=0;o<a;o++){const n=e[o];if(s+=n.duration,r.push(n),s>=i||o===a-1){const e=r.length,a=r[0],i=r[e-1];t.push({duration:s,start_time:a.start_time,end_time:i.end_time,items:r,item:i}),s=0,r=[]}}if(t.length>1){if(t[t.length-1].duration<1){const e=t.pop(),a=t[t.length-2];a.duration=a.duration+e.duration,a.end_time=e.end_time,a.items=a.items.concat(e.items),a.item=e.item,e.items}}t.forEach(t=>{const{items:e}=t;for(let a=e.length-1;a>=0;a--)if(e[a].duration>1){t.item=e[a];break}}),this.thumbnail_group=t,this.store.data.thumbnail_group=t,await this.store.write()}getVideoM3U8Info(){return this.videoTranscoderResult?.m3u8}async initM3U8Data(){this.m3u8_data=this.getVideoM3U8Info()}async initThumbnailDuration(){if(this.store.data.thumbnail_duration)return this.thumbnail_duration=this.store.data.thumbnail_duration,this.thumbnail_duration;let t=30;const e=await this.getMediainfo(),a=e?.video;if(!a?.length)return t;const i=a[0],s=i.duration||e?.general?.duration,{width:r,height:o}=i;r*o>=518400&&(t=10),r*o>=921600&&(t=20),r*o>=2073600&&(t=30),r*o>=3686400&&(t=40),r*o>=8294400&&(t=60);const n=s??0;if(n&&(n<60&&(t=0),n<300&&(t=Math.ceil(t/4)),n<600&&(t=Math.ceil(t/2)),n>3600)){const e=n/3600;t=Math.ceil(t*e)}return t=Math.min(60,t),this.thumbnail_duration=t,this.store.data.thumbnail_duration=t,await this.store.write(),t}},Wt=require("path"),Kt=require("fs-extra"),Jt=require("@soga/imgutils"),Qt=require("@soga/fileutils"),Zt=require("@soga/node-types"),Yt=require("@soga/error"),te=class extends nt{get cover_name(){return"audio_cover.png"}async start(){try{await this.generateCover(),this.isAudio&&await this.postProgress({type:Zt.UploadProgress.transcode_thumbnail,percent:1})}catch(t){throw(0,Yt.buildDError)(t,{message:"Error occurred during audio cover generation",detail:`Error occurred during audio cover generation: ${this.params.input.filepath}`})}}async generateCover(){const t=await this.getMediainfo();if(t.video?.length)return;const e="audio-covered";try{if(this.coverResult)return this.coverResult;if(this.db.data[e])return;const{cover_name:t}=this,a=["-i",this.params.input.filepath,"-map","0:v","-y",t];await this.ffmpeg(a,{cwd:this.params.outputRoot});const i=(0,Wt.resolve)(this.params.outputRoot,t),s=await(0,Kt.pathExists)(i),r=await(0,Jt.getMetadata)(i);if(s){const e={file:t,path:i,size:await(0,Qt.getFileSize)(i),width:r.width??0,height:r.height??0};await this.setCoverResult(e)}}catch(t){throw t}finally{this.db.data[e]=!0,await this.db.write()}}},ee=require("path"),ae=require("@soga/utils"),ie=require("@soga/fileutils"),se=require("fs-extra"),re=require("@soga/error"),oe=require("@soga/node-types"),ne=class extends nt{builtin_tracks=0;external_tracks=0;get tracks(){return this.builtin_tracks+this.external_tracks}async sendProgress(t){await this.postProgress({type:oe.UploadProgress.separate_subtitle,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.subtitleEncoderResult)return;const t=await this.getMediainfo();if(this.builtin_tracks=t?.text?.length||0,this.external_tracks=this.params.subtitles?.length||0,!this.tracks)return await this.setSubtitleEncoderResult([]),void await this.sendProgress(1);const e=await this.parseBuiltinTextTracks();await this.sendProgress(this.builtin_tracks/this.tracks);const a=await this.parseExternalTextTracks(),i=[...e,...a];await this.setSubtitleEncoderResult(i),await this.sendProgress(1)}catch(t){throw(0,re.buildDError)(t,{message:"Error occurred while process subtitle track",detail:`Error occurred while process subtitle track: ${this.params.input.filepath}`})}}async parseBuiltinTextTracks(){const t=await this.getMediainfo(),e=t?.text;if(!e?.length)return[];const{subtitle_builtin_tracks:a}=this.dbData;if(a)return a;const i=e.length,s=[];for(let t=0;t<i;t++){const e=await this.parseBuiltinTextTrack(t);e&&s.push(e),await this.sendProgress((t+1)/this.tracks)}return this.dbData.subtitle_builtin_tracks=s,await this.params.db.write(),s}async parseBuiltinTextTrack(t){const e=this.params.outputRoot,a=`subtitle-builtin-${t}.zip`,i=(0,ee.resolve)(e,a),s=`subtitle-temp-${t}.vtt`,r=(0,ee.resolve)(e,s),o=`subtitle-builtin-u8-${t}.vtt`,n=(0,ee.resolve)(e,o),h=["-i",this.params.input.filepath,"-vn","-an","-map",`0:s:${t}`,"-c","webvtt","-y",s];await this.ffmpeg(h,{cwd:this.params.outputRoot});if(await(0,ie.isValidFile)(r)){if(await(0,ae.isUtf8File)(r))await(0,se.copy)(r,n);else{await(0,ae.saveFileAsUtf8)(r,n);await(0,ie.isValidFile)(n)||await(0,se.copy)(r,n)}const e=await(0,ae.getFileLanguage)(n),{label:s,lang:o}=e;await(0,ae.gzip)(n,i);return{file:a,file_path:i,size:await(0,ie.getFileSize)(i),lang:o,name:s||`builtin_${t+1}`,title:s||`builtin_${t+1}`,builtin:!0,source:null}}return!1}async parseExternalTextTracks(){const{subtitles:t}=this.params;if(!t?.length)return[];const{subtitle_external_tracks:e}=this.dbData;if(e)return e;const a=[],i=t.length;for(let e=0;e<i;e++){const i=await this.parseExternalTextTrack(e,t[e]);i&&a.push(i),await this.sendProgress((this.builtin_tracks+(e+1))/this.tracks)}return this.dbData.subtitle_external_tracks=a,await this.params.db.write(),a}async parseExternalTextTrack(t,e){const{ext:a}=(0,ee.parse)(e),i=this.params.outputRoot,s=`subtitle-external-${t}.vtt`,r=(0,ee.resolve)(i,s),o=`subtitle-external-${t}.zip`,n=(0,ee.resolve)(i,o),h=`subtitle-external-u8-${t}${a}`,d=(0,ee.resolve)(i,h),c=`subtitle-external-source-${t}.zip`,l=(0,ee.resolve)(i,c);if(!await(0,ie.isValidPath)(e))return!1;if(await(0,ae.isUtf8File)(e))await(0,se.copy)(e,d);else{await(0,ae.saveFileAsUtf8)(e,d);if(!await(0,ie.isValidFile)(d))return!1}const u=["-i",d,"-c","webvtt","-y",s];await this.ffmpeg(u,{cwd:this.params.outputRoot});if(await(0,ie.isValidFile)(r)){const i=await(0,ae.getFileLanguage)(r),{label:s,lang:h}=i;await(0,ae.gzip)(e,l),await(0,ae.gzip)(r,n);const d=await(0,ie.getFileSize)(l);return{file:o,size:await(0,ie.getFileSize)(n),file_path:n,lang:h,name:s||`external_${t+1}`,title:s||`external_${t+1}`,builtin:!1,source:{file:c,file_path:l,size:d,ext:a}}}return!1}},he=require("@soga/error"),de=require("path"),ce=require("fs-extra"),le=require("@soga/node-types"),ue=require("@soga/fileutils"),pe=require("@soga/utils"),ge=require("@soga/error"),we=require("path"),me=require("@soga/fileutils"),fe=class extends nt{hostType;safe_index=0;file_map={};completed_percent=0;total_percent=0;store;async initStore(t){this.store=await this.getStore(`${t}_grouper_store.json`)}getFileName=t=>this.getPreviewSegmentName(t,this.hostType);getGroupedVideoManifestName(t){return`grouper_video_${this.hostType}_${t}.m3u8`}getAudioManifestName(t,e){return`grouper_audio_${this.hostType}_${e}_${t}.m3u8`}getThumbnailInfoFilename(){return`grouper_thumbnail_${this.hostType}.json`}getCacheInfoFilename(){return`grouper_cache_${this.hostType}.json`}constructor(t){super(t),this.hostType=t.host_type,this.completed_percent=t.completed_percent,this.total_percent=1/t.hosts.length}async generateSafeFile(t){return await async function(t){const e=`safe_${t.type}_${t.file_index}.txt`,a=f(t.filesize),i=(0,w.resolve)(t.outputRoot,e);return await(0,p.writeFile)(i,a),{file_path:i,size:a.length}}({type:t,file_index:this.safe_index++,outputRoot:this.params.outputRoot,filesize:this.params.input.filesize})}readAudioTracks(){return this.audioTranscoderResult??[]}readVideoTracks(){return this.videoTranscoderResult?[this.videoTranscoderResult]:[]}readThumbnailInfo(){return this.videoThumbnailerResult}readCoverInfo(){return this.coverResult}readSubtitleInfo(){return this.subtitleEncoderResult}async getPartData(){const t=this.store.data.grouper_part_names??[],e=[];for(let a=0;a<t.length;a++){const i=t[a],s=(0,we.resolve)(this.params.outputRoot,i),r=await(0,me.getFileSize)(s),o=await this.getPartInfo({host_type:this.hostType,filepath:s,start:0,end:r-1,filename:i});e.push(o)}return e}async getAudioData(){const t=this.readAudioTracks();if(!t?.length)return;const e=[];for(let a=0;a<t.length;a++){const i=t[a];if(i.adapt){const{average_bandwidth:t,bandwidth:s,channels:r,codec:o,codec_name:n,language:h,order:d}=i.adapt,c=this.getAudioManifestName("adapt",a),l=this.file_map[c],{file_index:u,start:p,end:g,size:w,hash:m}=l,f=this.getFileName(u),_=await this.getPreviewId({file:c});await this.setPreviewIdMap({id:_,file:f,start:p,end:g},this.hostType);const y={id:_,average_band:t,band:s,channels:r,codec:o,codec_name:n,language:h,order:d,file:f,start:p,end:g,size:w,hash:m};if(i.high){const{average_bandwidth:t,bandwidth:e,channels:s,codec:r,codec_name:o,language:n,order:h}=i.high,d=this.getAudioManifestName("high",a),c=this.file_map[d],{file_index:l,start:u,end:p,size:g,hash:w}=c,m=this.getFileName(l),f=await this.getPreviewId({file:d});await this.setPreviewIdMap({id:f,file:m,start:u,end:p},this.hostType),y.high={id:f,average_band:t,band:e,channels:s,codec:r,codec_name:o,language:n,order:h,file:m,start:u,end:p,size:g,hash:w}}e.push(y)}}return e}async getVideoData(){const t=this.readVideoTracks();if(!t?.length)return;const e=[];for(let a=0;a<t.length;a++){const i=t[a],s=this.getGroupedVideoManifestName(a),r=await this.getPreviewId({file:s}),o=this.file_map[s],{file_index:n,start:h,end:d,size:c,hash:l}=o,u=this.getFileName(n);await this.setPreviewIdMap({id:r,file:u,start:h,end:d},this.hostType);const{average_bandwidth:p,bandwidth:g,codec:w,width:m,height:f,label:_,codec_name:y,bitdepth:b,framerate:v}=i,P={id:r,average_band:p,band:g,codec:w,codec_name:y,bitdepth:b,framerate:Math.round(v),width:m,height:f,file:u,start:h,end:d,size:c,label:_,hash:l};e.push(P)}return e}async getSubtitleData(){const t=this.readSubtitleInfo();if(!t?.length)return;const e=[],{length:a}=t;for(let i=0;i<a;i++){const a=t[i],{builtin:s,file:r,lang:o,title:n,name:h,source:d}=a,c=this.file_map[r],{file_index:l,start:u,end:p,size:g}=c,w=this.getFileName(l),m={uuid:await this.getPreviewId({file:r,start:u,end:p}),builtin:s,lang:o,name:h,title:n,file:w,start:u,end:p,size:g};if(d){const{file:t,ext:e}=d,a=this.file_map[t],{file_index:i,start:s,end:r,size:o}=a,n=this.getFileName(i);m.source={size:o,file:n,start:s,end:r,ext:e}}e.push(m)}return e}async getThumbnailData(){const t=this.readThumbnailInfo();if(!t)return;const{row:e,col:a,width:i,height:s}=t,r=this.getThumbnailInfoFilename(),o=this.file_map[r],{file_index:n,start:h,end:d,size:c}=o,l=this.getFileName(n),u=await this.getPreviewId({file:r});await this.setPreviewIdMap({id:u,file:l,start:h,end:d},this.hostType);return{id:u,row:e,col:a,width:i,height:s,file:l,start:h,end:d,size:c}}async getCoverData(){const t=this.readCoverInfo();if(!t)return;const e=t,{file:a,width:i,height:s}=e,r=this.file_map[a],{file_index:o,start:n,end:h,size:d}=r,c=this.getFileName(o),l=await this.getPreviewId({file:e.path});await this.setPreviewIdMap({id:l,file:c,start:n,end:h},this.hostType);return{id:l,width:i,height:s,file:c,start:n,end:h,size:d}}async getCacheData(){const t=this.getCacheInfoFilename(),e=await this.getPreviewId({file:t}),a=this.file_map[t],{file_index:i,start:s,end:r,size:o}=a,n=this.getFileName(i);await this.setPreviewIdMap({id:e,file:n,start:s,end:r},this.hostType);return{id:e,file:n,start:s,end:r}}async saveData(){const t=gt(this.hostType);if(this.db.data[t])return;const e={},a=await this.getAudioData();a&&(e.audios=a);const i=await this.getVideoData();i&&(e.videos=i);const s=await this.getSubtitleData();s&&(e.subtitles=s);const r=await this.getThumbnailData();r&&(e.thumbnail=r);const o=await this.getCoverData();o&&(e.cover=o),e.parts=await this.getPartData(),e.cache=await this.getCacheData(),this.db.data[t]=e,await this.db.write()}},_e=class extends fe{current_position=0;current_index=0;group_data=[];async start(){const t=gt(this.hostType);if(this.db.data[t])return this.db.data[t];try{return await this.initStore(this.hostType),await this.calculateData(),await this.postProgress({type:le.UploadProgress.group_media,percent:this.completed_percent+.5*this.total_percent}),await this.processGroups(),await this.postProgress({type:le.UploadProgress.group_media,percent:this.completed_percent+.9*this.total_percent}),await this.saveData(),await this.postProgress({type:le.UploadProgress.group_media,percent:this.completed_percent+this.total_percent}),this.db.data[t]}catch(t){throw(0,ge.buildDError)(t,{message:`Error occurred during media grouping ${this.hostType}`,detail:`Error occurred during media grouping ${this.hostType}: ${this.params.input.filepath}`})}}async processGroups(){const t="grouper_process_state";if(this.store.data[t])return;this.store.data.grouper_process_map||={},this.store.data.grouper_process_index||=0;const{length:e}=this.group_data;for(let t=0;t<e;t++){const a=this.group_data[t];this.store.data.grouper_process_map[a.filename]||(await _({outputRoot:this.params.outputRoot,files:a.files,filename:a.filename}),this.store.data.grouper_process_map[a.filename]=!0,await this.store.write(),await this.postProgress({type:le.UploadProgress.group_media,percent:this.completed_percent+.5*this.total_percent+this.total_percent*(.4*(t+1)/e)}))}this.store.data[t]=!0,await this.store.write()}async insertSafeFile(){const t=await this.generateSafeFile(this.hostType);this.addOne(t,!0)}async calculateData(){this.store.data.grouper_group_list||=[],this.store.data.grouper_file_map||={},await this.insertSafeFile(),await this.calculateMediaTracks(),await this.calculateThumbnails(),await this.calculateCovers(),await this.calculateCaches(),this.current_index+=1,this.current_position=0,await this.calculateSubtitles(),this.store.data.grouper_group_list=this.group_data,this.store.data.grouper_file_map=this.file_map;const t=this.group_data.map(t=>t.filename);this.store.data.grouper_part_names=t,this.store.data.grouper_calculate_state=!0,await this.store.write()}async calculateSubtitles(){const t=this.readSubtitleInfo();if(!t?.length)return;await this.insertSafeFile();const{length:e}=t;for(let a=0;a<e;a++){const e=t[a],{file:i,file_path:s,size:r}=e,o=this.addOne({file_path:s,size:r});if(this.file_map[i]=o,e.source){const{file:t,file_path:a,size:i}=e.source,s=this.addOne({file_path:a,size:i});this.file_map[t]=s}}}async calculateCaches(){await this.getAudioData(),await this.getVideoData(),await this.getThumbnailData(),await this.getCoverData();const t=this.getPreviewIdMap(this.hostType),e=this.getCacheInfoFilename(),a=await this.writeText(e,JSON.stringify(t));this.file_map[e]=a}async calculateCovers(){const t=this.readCoverInfo();if(!t)return;const{file:e,path:a,size:i}=t,s=this.addOne({file_path:a,size:i});this.file_map[e]=s}async calculateMediaTracks(){const t=this.readAudioTracks(),e=this.readVideoTracks(),a=t?.length;for(let e=0;e<a;e++){const i=t[e];if(i.adapt){const t=await this.calculateOneTrack(i.adapt.m3u8),a=this.getAudioManifestName("adapt",e),s=await this.writeTrackText(a,t);this.file_map[a]=s}if(i.high){const t=await this.calculateOneTrack(i.high.m3u8),a=this.getAudioManifestName("high",e),s=await this.writeTrackText(a,t);this.file_map[a]=s}await this.postProgress({type:le.UploadProgress.group_media,percent:this.completed_percent+.4*this.total_percent*((e+1)/a)})}const i=e.length;for(let t=0;t<i;t++){const a=e[t],s=await this.calculateOneTrack(a.m3u8),r=this.getGroupedVideoManifestName(t),o=await this.writeTrackText(r,s);this.file_map[r]=o,await this.postProgress({type:le.UploadProgress.group_media,percent:this.completed_percent+.2*this.total_percent+.2*this.total_percent*((t+1)/i)})}}async calculateThumbnails(){const t=this.readThumbnailInfo();if(!t)return;if(!t)return;const{tile_list:e}=t,{length:a}=e;let i=[...t.sprite_list];for(let t=0;t<a;t++){const a=e[t],s=a.file,r=await this.safelyAddOne({file_path:a.file_path,size:a.size}),o=await this.getPreviewId({file:s}),n=this.getFileName(r.file_index);await this.setPreviewIdMap({id:o,file:n,start:r.start,end:r.end},this.hostType),this.file_map[s]=r,i=i.map(t=>t.file===s?{...t,file:n,id:o,s:r.start,e:r.end}:t)}const s=this.getThumbnailInfoFilename(),r=await this.writeText(s,JSON.stringify(i));this.file_map[s]=r}async calculateOneTrack(t){const{segments:e,init:a,version:i,targetDuration:s,mediaSequence:r,endList:o}=t,n={},h=this.addOne({size:a.size,file_path:a.file_path}),d=await this.getPreviewId({file:a.uri}),c=this.getFileName(h.file_index),l=`${c}?id=${d}`;await this.setPreviewIdMap({id:d,file:c,start:h.start,end:h.end},this.hostType);const u=["#EXTM3U",`#EXT-X-VERSION:${i}`,`#EXT-X-TARGETDURATION:${s}`,`#EXT-X-MEDIA-SEQUENCE:${r}`,`#EXT-X-MAP:URI=${l},BYTERANGE="${h.size}@${h.start}"`];[...e].forEach(t=>{const{uri:e,size:a,duration:i,file_path:s}=t;n[e]=this.addOne({size:a,duration:i,file_path:s})});for(const[t,e]of Object.entries(n)){const a=await this.getPreviewId({file:t}),i=this.getFileName(e.file_index);await this.setPreviewIdMap({id:a,file:i,start:e.start,end:e.end},this.hostType),u.push(`#EXTINF:${e.duration},`),u.push(`#EXT-X-BYTERANGE:${e.size}@${e.start}`),u.push(`${i}?id=${a}`)}o&&u.push("#EXT-X-ENDLIST");return u.join("\n")}async writeTrackText(t,e){const a=(0,de.resolve)(this.params.outputRoot,t),i=(0,de.resolve)(this.params.outputRoot,`${t}.gz`),s=(0,de.resolve)(this.params.outputRoot,`${t}.bin`);await(0,ce.writeFile)(a,e,"utf-8"),await(0,pe.gzip)(a,i);if(await(0,ue.getFileSize)(i)>16){const t=(await(0,pe.getFileBufferSlice)(i,0,15)).toString("base64");await async function(t,e){await new Promise((a,i)=>{const s=(0,p.createReadStream)(t,{start:16}),r=(0,p.createWriteStream)(e);s.pipe(r),r.on("finish",()=>{a(!0)}),s.on("error",t=>{i(t)}),r.on("error",t=>{i(t)})})}(i,s);return{...this.addOne({file_path:s,size:await(0,ue.getFileSize)(s)}),hash:t}}return{...this.addOne({file_path:a,size:await(0,ue.getFileSize)(a)}),hash:""}}async writeText(t,e){const a=(0,de.resolve)(this.params.outputRoot,t);await(0,ce.writeFile)(a,e,"utf-8");return this.addOne({file_path:a,size:await(0,ue.getFileSize)(a)})}addOne({file_path:t,size:e,duration:a=0},i=!1){const s=this.getSizeLimit(this.hostType),{current_position:r,group_data:o}=this;if(i&&o[this.current_index]||!(r+e<=s)){this.current_index+=1;const{current_index:i}=this;o[i]?o[i].files.push(t):o[i]={filename:this.getFileName(i),files:[t]};const s=0,r=e-1;return this.current_position=e,{file_index:i,start:s,end:r,duration:a,size:r-s+1}}{const{current_index:i}=this,s=r,n=r+e-1;return this.current_position=n+1,o[i]?o[i].files.push(t):o[i]={filename:this.getFileName(i),files:[t]},{file_index:i,start:s,end:n,duration:a,size:n-s+1}}}async safelyAddOne(t){const e=this.getSizeLimit(this.hostType),{current_position:a}=this;return a+t.size<=e?0===a?(await this.insertSafeFile(),this.addOne(t)):this.addOne(t):(await this.insertSafeFile(),this.addOne(t))}},ye=class extends nt{async start(){try{if(this.grouperResult)return this.grouperResult;const t={meta:await this.getMetaData(),data:{}},{length:e}=this.params.hosts;for(let a=0;a<e;a++){const i=this.params.hosts[a],s=this.getSizeLimit(i),r=new _e({...this.params,host_type:i,file_size_limit:s,completed_percent:a/e}),o=await r.start();t.data[i]=o}return await this.setGrouperResult(t),t}catch(t){throw(0,he.buildDError)(t,{message:t.message||"Error occurred during media grouping",detail:t.detail||`Error occurred during media grouping: ${this.params.input.filepath}`})}}async getMetaData(){const t={},e=this.audioTranscoderResult??[],a=this.videoTranscoderResult?[this.videoTranscoderResult]:[];if(a?.length){const e=await this.getMediainfo(),{duration:i}=e?.general;if(a?.length){const{width:e,height:s,framerate:r,bitdepth:o,label:n,codec:h,codec_name:d}=a[0];t.videos=[{duration:i,bitdepth:o,width:e,height:s,framerate:r,label:n,codec:h,codec_name:d}]}}if(e?.length)for(const a of e){const{high:e,adapt:i}=a,{channels:s,lossless:r}=i,o=await this.getMediainfo(),{duration:n}=o?.general,{codec:h,codec_name:d}=i,c={duration:n,channels:s,lossless:r,codec:h,codec_name:d};e&&(c.high={channels:e.channels,codec:e.codec,codec_name:e.codec_name,lossless:e.lossless}),t.audios=t.audios||[],t.audios.push(c)}return t}},be=class extends nt{async start(){if(this.db.data.grouper_result)return this.db.data.grouper_result;const t=await this.getMediainfo();if(!t)return;const e=t.video,a=e?.length,i=t.audio,s=i?.length;if(!s&&!a)return;const r=new ne(this.params);if(await r.start(),s){const t=new Pt(this.params);await t.start();const e=new At(this.params);await e.start();const a=new te(this.params);await a.start()}if(a){const t=new ft(this.params);await t.start();const e=new Ft(this.params);await e.start();const a=new Xt(this.params);await a.start()}const o=new ye(this.params);await o.start()}async getResult(){return this.db.data.grouper_result}},ve=require("@soga/types"),Pe=require("@soga/node-types"),xe=require("@soga/mediainfo"),ze=require("@soga/fileutils"),Te=require("fs-extra"),Re=h(require("check-disk-space")),Se=require("@soga/error"),De=class extends E{async start(){this.prepareResult||(await this.checkStorage(),await this.calculateMeta(),await this.calculateProgress())}async checkStorage(){const{length:t}=this.params.hosts,e=await(0,Re.default)(this.params.outputRoot),a=e.free,i=e.diskPath;if((3+t)*this.params.input.filesize>a)throw(0,Se.buildDError)(new Error(`${i} have no enough computer disk space, please adjust the temporary path in user settings.`),{message:`${i} have no enough computer disk space, please adjust the temporary path in user settings.`,detail:`${i} have no enough computer disk space to process ${this.params.input.filepath}`})}async calculateMeta(){if(this.meta)return this.meta;const{filename:t,local_btime:e,local_ctime:a,local_mtime:i,filesize:s}=this.params.input,r={file:t,size:s,btime:e,ctime:a,mtime:i,md5:""};return await this.setMeta(r),r}async calculateProgress(){if(this.prepareResult)return;const t={[Pe.UploadProgress.prepare]:{weight:0,percent:1},[Pe.UploadProgress.calculate_md5]:{weight:0,percent:0},[Pe.UploadProgress.separate_video]:{weight:0,percent:0},[Pe.UploadProgress.separate_audio]:{weight:0,percent:0},[Pe.UploadProgress.separate_subtitle]:{weight:0,percent:0},[Pe.UploadProgress.transcode_video]:{weight:0,percent:0},[Pe.UploadProgress.transcode_audio]:{weight:0,percent:0},[Pe.UploadProgress.transcode_thumbnail]:{weight:0,percent:0},[Pe.UploadProgress.transcode_source]:{weight:0,percent:0},[Pe.UploadProgress.transcode_txt]:{weight:0,percent:0},[Pe.UploadProgress.transcode_img]:{weight:0,percent:0},[Pe.UploadProgress.group_media]:{weight:0,percent:0},[Pe.UploadProgress.upload_baidu]:{weight:0,percent:0},[Pe.UploadProgress.upload_ali]:{weight:0,percent:0},[Pe.UploadProgress.end]:{weight:0,percent:0}},e={keep_preview:this.params.keepPreview,keep_source:this.params.keepSource},a=await(0,ze.getFileSize)(this.params.input.filepath);t[Pe.UploadProgress.prepare].weight=t[Pe.UploadProgress.end].weight=Math.ceil(a/1024/1024/500),t[Pe.UploadProgress.calculate_md5].weight=Math.ceil(a/1024/1024/200);let i=0;if(this.isMedia)if(this.params.keepPreview){const s=await(0,xe.parseMediaInfo)(this.params.input.filepath),r=s?.general?.duration??0;if(s.video?.length){const e=s.video[0],{width:a,height:i,codec:r}=e,o=(0,ze.isVideoSupport)(r),{duration:n}=s.general,h=o?n/400:n*(a*i)/1920/1080;t[Pe.UploadProgress.separate_video].weight=Math.ceil(h),t[Pe.UploadProgress.transcode_video].weight=Math.ceil(.01*n)}if(s.audio?.length){const{duration:e}=s.general;let a=0;s.audio.forEach(t=>{const{codec:i,lossless:s,channels:r}=t,o={high_need:!1,high_transcode:!1,adapt_need:!1,adapt_transcode:!1};(0,ze.isAudioAdapt)(i)?r>2?(o.high_need=!0,o.high_transcode=!1,o.adapt_need=!0,o.adapt_transcode=!0):(o.high_need=!1,o.adapt_need=!0,o.adapt_transcode=!1):(0,ze.isAudioHigh)(i)?(o.high_need=!0,o.high_transcode=!1,o.adapt_need=!0,o.adapt_transcode=!0):(o.high_need=!1,o.adapt_need=!0,o.adapt_transcode=!1,s&&(o.high_need=!0,o.high_transcode=!0)),o.adapt_need&&(a+=o.adapt_transcode?e/40:5),o.high_need&&(a+=o.high_transcode?e/20:10)}),t[Pe.UploadProgress.separate_audio].weight=Math.ceil(a),t[Pe.UploadProgress.transcode_audio].weight=Math.ceil(.01*e)}const o=s.video?.length??0,n=s.audio?.length??0;if(o||n){e.keep_preview=!0;const o=(s.text?.length||0)+(this.params.subtitles?.length||0);t[Pe.UploadProgress.separate_subtitle].weight=Math.ceil(o),t[Pe.UploadProgress.transcode_thumbnail].weight=Math.ceil(.08*r),i+=a,t[Pe.UploadProgress.group_media].weight=Math.ceil(a/1024/1024/10)}else e.keep_preview=!1,e.keep_source=!0,i+=a}else e.keep_source=!0,i+=a;else this.isTxt?e.keep_preview?(t[Pe.UploadProgress.transcode_txt].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a):this.isImg?e.keep_preview&&(t[Pe.UploadProgress.transcode_img].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a);e.keep_source&&(t[Pe.UploadProgress.transcode_source].weight=Math.ceil(a/1024/1024/30)),this.params.hosts.includes(ve.HostType.BAIDU)&&(t[Pe.UploadProgress.upload_baidu].weight=Math.ceil(i/1024/1024/1)),this.params.hosts.includes(ve.HostType.ALI)&&(t[Pe.UploadProgress.upload_ali].weight=Math.ceil(i/1024/1024/2));const s={preview:e.keep_preview,source:e.keep_source};await this.setKeeps(s),await this.setPrepareResult(t)}},Ie=async t=>{await(0,Te.ensureDir)(t.outputRoot);const e=await b(t);try{const a=new De({...t,db:e});return await a.start(),a}catch(t){}},Me=require("@soga/node-types"),Fe=require("crypto"),$e=require("fs-extra"),ke=class extends E{async start(){await this.processFile();return await this.getResult()}async calculateMd5(){if(this.md5)return this.md5;const t=this.params.input.filepath,e=this.params.input.filesize;let a=0;const i=await new Promise((i,s)=>{let r=0;const o=(0,Fe.createHash)("md5"),n=(0,$e.createReadStream)(t,{highWaterMark:4194304});n.on("data",async t=>{o.update(t),r+=t.length;const i=r/e;r-a>104857600&&(a=r,await this.postProgress({type:Me.UploadProgress.calculate_md5,percent:Math.min(i,1)}))}),n.on("end",()=>{const t=o.digest("hex");i(t)}),n.on("error",t=>{s(t)})});return i&&await this.setMd5(i),await this.postProgress({type:Me.UploadProgress.calculate_md5,percent:1}),i}async getResult(){if(this.result)return this.result;const{sourceResult:t,grouperResult:e,imgResult:a,txtResult:i,meta:s,keeps:r}=this,{length:o}=this.params.hosts,n={meta:{preview:r.preview,source:r.source,file:s}};for(let s=0;s<o;s++){const r=this.params.hosts[s];n[r]={max_size:0,parts:[]};const o=t=>{n[r].parts=[...n[r].parts,...t]},h=a?.data[r];if(h){h.cache&&(n[r].cache=h?.cache);const t=h.parts?.map(t=>({...t,preview:!0,source:!1}));t&&o(t),n.meta.img=a.meta,h.img&&(n[r].img=h.img)}const d=i?.data[r];if(d){o((d.parts||[]).map(t=>({...t,preview:!0,source:!1}))),n[r].cache=d.cache,n[r].txt={entrance:d.entrance,pad:i?.meta.pad,pages:i?.meta.pages}}const c=e?.data[r];if(c?.parts){o(c.parts.map(t=>({...t,preview:!0,source:!1}))),n.meta.audios=e.meta.audios,n.meta.videos=e.meta.videos,n[r].cache=c.cache,n[r].media={audios:c.audios,videos:c.videos,subtitles:c.subtitles,thumbnail:c.thumbnail,cover:c.cover}}const l=t?.data[r];if(l?.parts){o(l.parts.map(t=>{let e=!0;return(this.isMedia||this.isTxt)&&(e=!1),{...t,preview:e,source:!0}})),n[r].source={head:t.meta.head,download:l.download}}[...n[r]?.parts].forEach(t=>{t.size>n[r].max_size&&(n[r].max_size=t.size)})}return await this.setResult(n),n}async processFile(){const t="encoder_processed";if(this.db.data[t])return;const e=await Ie(this.params),{keeps:a}=e,i={...this.params,keepPreview:a.preview,keepSource:a.source},s=await this.calculateMd5();if(await this.setMd5(s),i.keepSource){const t=new U(this.params);await t.start()}if(e.isMedia&&i.keepPreview){const t=new be(this.params);await t.start()}if(e.isTxt&&i.keepPreview){const t=new K(this.params);await t.start()}if(e.isImg){const t=new it(this.params);await t.start()}this.db.data[t]=!0,await this.db.write()}},qe=async t=>{try{const e=await b(t),a=new ke({...t,db:e});return a.start()}catch(e){throw(0,c.buildDError)(e,{message:"Error occurred during file encoding",detail:`Error occurred during file encoding: ${t.input.filepath}`})}};
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{buildDError as t}from"@soga/error";import{getDb as e}from"@soga/lowdb";import{createHash as a}from"crypto";import{createReadStream as i,createWriteStream as s,existsSync as r,remove as o,stat as n,writeFile as h}from"fs-extra";import{truncate as d}from"fs/promises";import{resolve as c}from"path";import{pipeline as l}from"stream/promises";function u(t){const e=a("md5");return e.update(`${t}`),e.digest("hex")}async function p(t){await new Promise((e,a)=>{(async()=>{const r=c(t.outputRoot,t.filename);await o(r);let n=!1;const h=s(r);h.on("open",()=>{n=!0}).on("error",async t=>{n&&h.close(),await o(r),a(t)});const{length:d}=t.files,l=async(e=0)=>{if(e<d){const a=t.files[e],s=t.files.length;await new Promise((t,e)=>{const d=i(a);d.pipe(h,{end:!s}),d.on("end",()=>{d.close(),t(!0)}),d.on("error",async t=>{d.destroy(),n&&h.close(),await o(r),e(t)})}),await l(e+1)}};await l(0),n&&h.end(),e(!0)})()})}async function g(t,a){const i=u(JSON.stringify({...t,dbName:a})),s="db_unique_key",r=c(t.outputRoot,a),o=await e(r,{});return o.data[s]?o.data[s]!=i&&(o.data={[s]:i},await o.write()):(o.data[s]=i,await o.write()),o}async function m(t){return await g({file_id:t.id,input:{filepath:t.input.filepath,filesize:t.input.filesize},outputRoot:t.outputRoot},"encoder_store.json")}async function w({input_path:t,target_path:e,start:a,end:n}){const h=i(t,{start:a,end:n,highWaterMark:65536}),d=s(e);try{await l(h,d)}catch(t){try{r(e)&&await o(e)}catch(t){console.warn("Failed to clean up incomplete file:",t.message)}throw t}}import{resolve as f}from"path";import{gzip as _,getFileBufferSlice as y}from"@soga/utils";import{getFileSize as b}from"@soga/fileutils";import{buildDError as v}from"@soga/error";import{UploadProgress as P}from"@soga/node-types";import{rename as x,stat as D,writeFile as T}from"fs-extra";import{HostType as z}from"@soga/types";var R=2097152,I={[z.BAIDU]:52428800,[z.ALI]:2147483648};z.BAIDU,z.ALI;import{HostType as M,RecordFtype as $,RecordType as S}from"@soga/types";import{calculateMd4 as k,calculateMd5 as F,calculateSha1 as E}from"@soga/utils";import{parentPort as N}from"worker_threads";var C=class{segmentNames={};params;id;port=null;db;get lowData(){return this.db.data}get isVideo(){return this.params.type==S.VIDEO}get isAudio(){return this.params.type==S.AUDIO}get isMedia(){return this.isAudio||this.isVideo}get isTxt(){return this.params.type==S.DOC&&this.params.ftype==$.DOC_TXT}get isImg(){return this.params.type==S.IMAGE}getSizeLimit(t){return I[t]||52428800}getFilesize(){return this.params.input.filesize}constructor(t){this.params=t,this.id=t.id,this.port=t.port??null,this.db=t.db}async getPartInfo({host_type:t,filepath:e,start:a,end:i,filename:s,index:r},o=!0){const n={start:a,end:i,size:i-a+1,path:e,index:r,file:s,md5:o?await F({file:e,start:a,end:i}):""};if(o){if(t===M.BAIDU){const t=await k({file:e,start:a,end:i});n.md4=t}if(t===M.ALI){const t=await E({file:e,start:a,end:i});n.sha1=t}}return n}async getStore(t){const{id:e,input:a,outputRoot:i}=this.params;return await g({file_id:e,input:{filepath:a.filepath,filesize:a.filesize},outputRoot:i},t)}async postProgress(t){const e={step:t.type,percent:t.percent};await this.postMessage({id:this.id,type:"percent",data:e})}async postMessage(t){this.port?this.port.postMessage(t):N&&N.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}}},L=class extends C{syncGetSourceId(t){return this._syncGetId(t,"source")}async getSourceId(t){const e=this.syncGetSourceId(t);return await this.db.write(),e}getSourceIdMap(t){return this.db.data[`source_${t}_id_map`]||{}}syncSetSourceIdMap(t,e){this._syncSetIdMap(t,"source",e)}async setSourceIdMap(t,e){this.syncSetSourceIdMap(t,e),await this.db.write()}getSourceSegmentName=(t,e)=>{const a=`source_${e}_${t}`;if(this.segmentNames[a])return this.segmentNames[a];const i=`s-${u(`source-${e}-${this.md5}-${t}`)}`;return this.segmentNames[a]=i,i}},A=class extends L{head_size=32;getZipFilePath(){return f(this.params.outputRoot,"souce_zip.bin")}getDownloadListFileName(t){return`source_${t}_download_list.json`}getPartName(t,e){return this.getSourceSegmentName(e,t)}getPartPath(t,e){return f(this.params.outputRoot,this.getPartName(t,e))}get dbData(){return this.db.data}async setPartList(t,e){const a=`source_${t}_part_list`;this.dbData[a]=e,await this.params.db.write()}getPartList(t){const e=`source_${t}_part_list`;return this.dbData[e]}async setDownloadMap(t,e){const a=`source_${t}_download_map`;this.dbData[a]=e,await this.params.db.write()}getDownloadMap(t){const e=`source_${t}_download_map`;return this.dbData[e]}async sendProgress(t){await this.postProgress({type:P.transcode_source,percent:t})}async setDownloadList(t,e){const a=`source_${t}_download_list`;this.dbData[a]=e,await this.params.db.write()}getDownloadList(t){const e=`source_${t}_download_list`;return this.dbData[e]}async start(){try{if(this.sourceResult)return await this.sendProgress(1),this.sourceResult;await this.gzip();const{length:t}=this.params.hosts;for(let e=0;e<t;e++){const t=this.params.hosts[e];await this.calculatePartList(t),await this.processDownloadMap(t)}await this.sendProgress(.9);const e=await this.getResult();return await this.sendProgress(1),e}catch(t){throw v(t,{message:"Error occurred during source encoding",detail:`Error occurred during source encoding: ${this.params.input.filepath}`})}}async gzip(){if(this.dbData.source_gziped)return;const t=this.params.input.filepath,e=this.getZipFilePath();await _(t,e,async({percent:t})=>{await this.sendProgress(.6*t)}),this.dbData.source_gziped=!0,await this.params.db.write()}async getResult(){if(this.sourceResult)return this.sourceResult;const t={meta:await this.getMetaData(),data:{}},{length:e}=this.params.hosts;for(let a=0;a<e;a++){const e=this.params.hosts[a],i=this.getPartList(e),s=this.getDownloadMap(e);t.data[e]={download:s,parts:i}}return await this.setSourceResult(t),t}async getMetaData(){const t="source_meta",e=this.dbData[t];if(e)return e;const a=this.getZipFilePath(),i=await b(a),s={path:a,start:0,end:0},{head_size:r}=this;s.end=i<=r?i-1:r-1;const o={head:(await y(s.path,s.start,s.end)).toString("base64")};return this.dbData[t]=o,await this.params.db.write(),o}async writeDownloadListFile(t,e){const a=this.getDownloadListFileName(t),i=f(this.params.outputRoot,a);await T(i,e,"utf-8");return{file_path:i,size:await b(i)}}async processDownloadMap(t){const e=this.getDownloadMap(t);if(e)return e;const a=this.getDownloadList(t);let r;const{file_path:o,size:n}=await this.writeDownloadListFile(t,JSON.stringify(a)),h=this.getSizeLimit(t),d=this.getPartList(t);if(d.length){const e=d[d.length-1],{path:a,size:c,file:u,index:p,end:g,start:m}=e,w=f(this.params.outputRoot,u);if(c+n<=h){await async function({source1:t,source2:e,target:a}){const r=i(t.filepath,{start:t.start,end:t.end}),o=s(a);await l(r,o);const n=i(e),h=s(a,{flags:"a"});await l(n,h)}({source1:{filepath:a,start:m,end:g},source2:o,target:w});const e=(await D(w)).size,h=e-1,c=e-n,f=await this.getPartInfo({host_type:t,filepath:w,start:0,end:e-1,filename:u,index:p});d[d.length-1]=f;r={id:await this.getSourceId({file:u,start:c,end:h}),file:u,start:c,end:h}}else{const e=p+1,a=this.getPartName(t,e),i=this.getPartPath(t,e);await x(o,i);const s=await this.getSourceId({file:a,start:0,end:n-1}),h=await this.getPartInfo({host_type:t,filepath:i,start:0,end:n-1,filename:a,index:e});d.push(h),r={id:s,file:a,start:0,end:n-1}}return await this.setPartList(t,d),await this.setDownloadMap(t,r),r}}async calculatePartList(t){const e=`source_${t}_list_calculated`;if(this.dbData[e])return;const a=this.getZipFilePath(),i=await b(a),s=[],r=this.getSizeLimit(t),{head_size:o}=this,n=[];if(i>o){let e=0;for(let h=o;h<=i-1;h+=r){const o=Math.min(h+r-1,i-1),d=this.getPartName(t,e),c=await this.getPartInfo({host_type:t,filepath:a,start:h,end:o,filename:d,index:e});let l=0;for(let t=h;t<o;t+=R){const e=Math.min(t+R-1,o),a=e-t+1,i=l+a-1,s=await this.getSourceId({file:"source_zip",start:t,end:e});n.push({id:s,file:d,start:l,end:i}),l+=a}s.push(c),e++}}await this.setPartList(t,s),await this.setDownloadList(t,n),this.dbData[e]=!0,await this.db.write()}};import{resolve as O}from"path";import{createWriteStream as U,readFile as V,remove as G}from"fs-extra";import{getFileBufferSlice as B}from"@soga/utils";import j from"zlib";import{saveFileAsUtf8 as q}from"@soga/utils";import{buildDError as X}from"@soga/error";import{UploadProgress as K}from"@soga/node-types";import{resolve as J}from"path";import{getFileSize as H}from"@soga/fileutils";import{copy as Q,writeFile as W}from"fs-extra";var Z=class extends C{get preview_common_db_data(){return this.db.data}async getCurrentFileIndex(t){const e=this.db.data[`preview_${t}_current_index`];return"number"!=typeof e?(this.db.data[`preview_${t}_current_index`]=0,await this.db.write(),0):e}async increaseCurrentFileIndex(t){const e=await this.getCurrentFileIndex(t)+1;return this.db.data[`preview_${t}_current_index`]=e,await this.db.write(),e}getPartName(t,e){return this.getPreviewSegmentName(e,t)}getPartPath(t,e){return J(this.params.outputRoot,this.getPartName(t,e))}syncGetPreviewId(t){return this._syncGetId(t,"preview")}async getPreviewId(t){const e=this.syncGetPreviewId(t);return await this.db.write(),e}getPreviewIdMap(t){return this.db.data[`preview_${t}_id_map`]||{}}syncSetPreviewIdMap(t,e){this._syncSetIdMap(t,"preview",e)}async setPreviewIdMap(t,e){this.syncSetPreviewIdMap(t,e),await this.db.write()}getPreviewSegmentName=(t,e)=>{const a=`preview_${e}_${t}`;if(this.segmentNames[a])return this.segmentNames[a];const i=`p-${u(`preview-${e}-${this.md5}-${t}`)}`;return this.segmentNames[a]=i,i};async calculatePartList(t,e){const a=[],i=await this.getCurrentFileIndex(t);for(let s=0;s<i+1;s++){const i=this.getPartName(t,s),r=this.getPartPath(t,s),o=await H(r),n=await this.getPartInfo({host_type:t,filename:i,filepath:r,index:s,start:0,end:o-1},e);a.push(n)}return a}getPartListKey(t){return`preview_${t}_part_list`}async completePartList(t){const e=await this.getPartList(t);if(e){const a=[];for(const i of e)if(i.md5)a.push(i);else{const e=await this.getPartInfo({filename:i.file,filepath:i.path,start:i.start,end:i.end,host_type:t,index:i.index},!0);a.push(e)}await this.setPartList(t,a)}}async getPartList(t){const e=this.getPartListKey(t),a=this.preview_common_db_data[e];if(a)return a}async setPartList(t,e){const a=this.getPartListKey(t);this.preview_common_db_data[a]=e,await this.db.write()}async attachCacheData(){const{hosts:t}=this.params;for(const e of t)await this.attachHostCacheData(e),await this.completePartList(e)}getCacheInfo(t){const e=`preview_${t}_cache_info`;return this.preview_common_db_data[e]}async writeCacheFile(t,e){const a=`preview_${t}_cache_info.txt`,i=J(this.params.outputRoot,a);await W(i,e,"utf-8");return{file_path:i,size:await H(i)}}async setCacheInfo(t,e){const a=`preview_${t}_cache_info`;this.preview_common_db_data[a]=e,await this.db.write()}async attachHostCacheData(t){if(this.getCacheInfo(t))return;const e=await this.getPartList(t),a=this.getPreviewIdMap(t),{file_path:r,size:o}=await this.writeCacheFile(t,JSON.stringify(a)),h=this.getSizeLimit(t);if(e.length){const a=e[e.length-1],{path:c,size:u,file:p,index:g,end:m}=a;let w;if(u+o<=h){await async function({filepath:t,size:e},a){(await n(t)).size>e&&await d(t,e);const r=i(a),o=s(t,{flags:"a"});await l(r,o)}({filepath:c,size:u},r);const a=await H(c),h=await this.getPartInfo({host_type:t,filename:p,filepath:c,index:g,start:0,end:a-1});e[e.length-1]=h;const f=m+1,_=m+o;w={id:await this.getPreviewId({file:p,start:f,end:_}),file:p,start:f,end:_}}else{const a=g+1,i=this.getPartName(t,a),s=this.getPartPath(t,a);await Q(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)}}},Y=class extends Z{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 O(this.params.outputRoot,this.getU8FileName())}async sendProgress(t){await this.postProgress({type:K.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 X(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 G(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 q(t,e),this.dbData.txt_utf8_converted=!0,await this.db.write()}async txtConvertToGzipFile(t){if(await this.getEntranceInfo(t))return;const e=this.getSizeLimit(t),a=this.getU8FilePath(),i=await this.calculateSlice(),{length:s}=i,r={};let o=0,n=U(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 B(a,u,p)).toString("utf8")},m=JSON.stringify(g);let w=Buffer.from(m,"utf8");if(0==d){const t={...g,map:r};w=Buffer.from(JSON.stringify(t),"utf8")}const f=await this.getPreviewId({file:"u8zip",start:u,end:p});await new Promise((a,i)=>{j.gzip(w,async(s,h)=>{if(s)return i(s);const c=h.length<this.hashBufferLength?this.hashBuffer:h.subarray(0,this.hashBufferLength),l=Buffer.concat([c,h]),u=l.length;if(o+u>e){n.end();const e=await this.increaseCurrentFileIndex(t);n=U(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)=>{V(t,"utf8",(t,i)=>{if(t)return void a(t);const s=this.content_size_1,r=this.content_size_2,o=[];let n=0,h=0,d=0;for(;h<i.length;){let t=Math.min(h+r,i.length);const e=Math.min(h+s,i.length),a=i.slice(e,t-1).indexOf("#");-1!==a&&(t=e+a);const c=i.slice(h,t),l=Buffer.byteLength(c);o.push({index:n++,start:d,end:d+l-1}),this.totalPage=n,h=t,d+=l}e(o)})});return this.dbData.txt_slice_list=e,await this.db.write(),e}};import{resolve as tt}from"path";import{getMetadata as et,compress as at}from"@soga/imgutils";import{gzip as it}from"@soga/utils";import{getFileSize as st}from"@soga/fileutils";import{buildDError as rt}from"@soga/error";import{UploadProgress as ot}from"@soga/node-types";import{remove as nt}from"fs-extra";var ht=class extends Z{getCompressFileName(){return"img_compress.jpg"}getCompressFilePath(){return tt(this.params.outputRoot,this.getCompressFileName())}getGzFileName(){return"compressed_img.zip"}getGzFilePath(){return tt(this.params.outputRoot,this.getGzFileName())}async sendProgress(t){await this.postProgress({type:ot.transcode_img,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.imgResult)return await this.sendProgress(1),this.imgResult;await this.compress(),await this.sendProgress(.1),await this.gzip(),await this.sendProgress(.4);const{hosts:t}=this.params,{length:e}=t;for(let a=0;a<e;a++){const e=t[a];await this.splitFile(e),await this.calculatePartList(e,!1)}await this.attachCacheData(),await this.sendProgress(.9);const a=await this.getResult();return await this.clean(),await this.sendProgress(1),a}catch(t){throw rt(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 et(e),s=this.getCompressFilePath(),{width:r,height:o}=await et(s),n=await st(s),h={meta:{width:a,height:i,size:t.filesize,t_width:r,t_height:o,t_size:n},data:{}},{length:d}=this.params.hosts;for(let t=0;t<d;t++){const e=this.params.hosts[t],a=await this.getPartList(e),i=this.getPreviewList(e);h.data[e]={img:{preview:i},cache:this.getCacheInfo(e),parts:a}}return await this.setImgResult(h),h}async clean(){try{if(this.params.debug)return;const t=this.getCompressFilePath();await nt(t)}catch(t){}}async compress(){if(this.dbData.img_compressed)return;const t=this.getCompressFilePath();await at({ffmpeg_path:this.params.ffmpegPath,input_path:this.params.input.filepath,output_path:t}),this.dbData.img_compressed=!0,await this.db.write()}async gzip(){if(this.dbData.img_gziped)return;const t=this.getCompressFilePath(),e=this.getGzFilePath();await it(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 st(e),i=this.getSizeLimit(t),s=[],r=[];for(let o=0;o<=a-1;o+=i){0!=o&&await this.increaseCurrentFileIndex(t);const n=Math.min(o+i-1,a-1),h=await this.getCurrentFileIndex(t),d=this.getPartName(t,h),c=this.getPartPath(t,h);await w({input_path:e,target_path:c,start:o,end:n});const l=0,u=n-o,p=await this.getPartInfo({host_type:t,filepath:c,filename:d,start:l,end:u,index:h},!1);s.push(p);const g=await this.getPreviewId({file:d,start:l,end:u});r.push({id:g,file:d,start:l,end:u}),await this.setPreviewIdMap({id:g,file:d,start:l,end:u},t)}await this.setPartList(t,s),await this.setPreviewList(t,r)}};import dt from"fluent-ffmpeg";import{spawn as ct}from"child_process";import{parseMediaInfo as lt}from"@soga/mediainfo";var ut=class extends Z{async getMediainfo(){const{mediainfo:t}=this.db.data;if(t)return t;const e=this.params.input.filepath,a=await lt(e);return this.db.data.mediainfo=a,await this.params.db.write(),a}constructor(t){super(t),dt.setFfmpegPath(t.ffmpegPath)}getFluent(){return dt()}async ffmpeg(t,e){const a=this.params.ffmpegPath;return await new Promise((i,s)=>{const r=ct(a,t,Object.assign({stdio:"ignore"},e));r.on("close",t=>{i(t)}),r.on("error",t=>{s(t)})})}};import{resolve as pt}from"path";import{isValidFile as gt,isVideoSupport as mt}from"@soga/fileutils";import{UploadProgress as wt}from"@soga/node-types";import{buildDError as ft}from"@soga/error";var _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 ut{async start(){try{await this.separateVideo(),await this.postProgress({type:wt.separate_video,percent:1})}catch(t){throw ft(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=pt(this.params.outputRoot,i),r=mt(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:wt.separate_video,percent:e})}}).on("end",async()=>{t("end"),a.kill("SIGKILL")}).on("error",async t=>{e(t)}).output(s);a.run()});if(!await gt(s))throw new Error("Separate Video track failed");this.db.data[t]=!0,await this.params.db.write()}};import{resolve as Dt}from"path";import{isValidFile as Tt,isAudioAdapt as zt,isAudioHigh as Rt}from"@soga/fileutils";import{UploadProgress as It}from"@soga/node-types";import{buildDError as Mt}from"@soga/error";var $t=class extends ut{async start(){try{await this.separateTracks(),await this.postProgress({type:It.separate_audio,percent:1})}catch(t){throw Mt(t,{message:"Error occurred during audio separation",detail:`Error occurred during audio separation: ${this.params.input.filepath}`})}}async separateTracks(){if(this.audioSeparatorResult)return;const t=await this.getMediainfo();if(!t?.audio?.length)return;const{audio:e}=t,a=e.length,i=[];for(let t=0;t<a;t++){const s=e[t],{codec:r,channels:o,lossless:n}=s,h={adapt:{need:!0,codec:"",channels:Math.min(o,2)},high:{need:!1,codec:"flac",channels:0}};zt(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):Rt(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=Dt(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:It.separate_audio,percent:o})}}).on("end",async()=>{a("end"),s.kill("SIGKILL")}).on("error",async t=>{i(t)}).output(n);s.run()});if(!await Tt(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:It.separate_audio,percent:i})}this.db.data[a]=!0,await this.params.db.write()}};import{resolve as St}from"path";import{parseMediaInfo as kt}from"@soga/mediainfo";import{getMp4boxInfo as Ft}from"@soga/mp4box";import{parseM3U8 as Et}from"@soga/m3u8";import{UploadProgress as Nt}from"@soga/node-types";import{isValidFile as Ct,getStandardInfo as Lt}from"@soga/fileutils";import{remove as At}from"fs-extra";import{buildDError as Ot}from"@soga/error";var Ut=class extends ut{getVideoInitName({width:t,height:e}){return`video-init-${t}-${e}.mp4`}getVideoManifestName({width:t,height:e}){return`video-hls-${t}-${e}.m3u8`}async start(){try{await this.transcodeVideo(),await this.saveData(),await this.postProgress({type:Nt.transcode_video,percent:1})}catch(t){throw Ot(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=St(this.params.outputRoot,i),r=this.getVideoManifestName({width:e,height:a}),o=St(this.params.outputRoot,r),n=await Et(o),{videos:h}=await Ft(s),{codec:d}=h[0],{bandwidth:c,average_bandwidth:l}=vt(n),u=(await kt(s)).video[0],p=Lt(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 At(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=St(this.params.outputRoot,o);if(!await Ct(h))throw new Error("Transcode video track failed");this.db.data[t]=!0,await this.db.write()}};import{resolve as Vt}from"path";import{getFileSize as Gt,isValidFile as Bt}from"@soga/fileutils";import{getMp4boxInfo as jt}from"@soga/mp4box";import{parseM3U8 as qt}from"@soga/m3u8";import{parseMediaInfo as Xt}from"@soga/mediainfo";import{remove as Kt}from"fs-extra";import{buildDError as Jt}from"@soga/error";import{UploadProgress as Ht}from"@soga/node-types";var Qt=class extends ut{async start(){try{await this.transcodeAudios(),await this.saveData()}catch(t){throw Jt(t,{message:"Error occurred during audio transcoding",detail:`Error occurred during audio transcoding: ${this.params.input.filepath}`})}}async saveData(){if(this.audioTranscoderResult)return;const t=await this.getMediainfo();if(!t?.audio?.length)return;const e=t.audio.length,a=this.audioSeparatorResult,i=[],s={};for(let t=0;t<e;t++){const e=a[t];e.adapt.need&&(s.adapt=await this.getQualityData({track_order:t,quality:"adapt"})),e.high.need&&(s.high=await this.getQualityData({track_order:t,quality:"high"})),i.push(s)}await this.setAudioTranscoderResult(i);try{if(this.params.debug)return;for(let t=0;t<e;t++){const e=a[t];if(e.adapt.need){const e=_t({type:"formatted",track_order:t,quality:"adapt"}),a=Vt(this.params.outputRoot,e);await Kt(a)}if(e.high.need){const e=_t({type:"formatted",track_order:t,quality:"high"}),a=Vt(this.params.outputRoot,e);await Kt(a)}}}catch(t){}}async getQualityData({track_order:t,quality:e}){const a=_t({type:"formatted",track_order:t,quality:e}),i=Vt(this.params.outputRoot,a),s=await Xt(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 Gt(i),h=Vt(this.params.outputRoot,o),d=await jt(i),{audios:c}=d,{language:l,codec:u}=c[0],p=l&&!l.startsWith("un")?{language:l}:void 0,g=await qt(h),{bandwidth:m,average_bandwidth:w}=vt(g);return{m3u8:g,m3u8_path:h,codec:u,codec_name:r.codec,...p,order:t,lossless:r.lossless,channels:r.channels,bandwidth:m,size:n,average_bandwidth:w}}async transcodeAudios(){const t="audio_transcoded";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.audio?.length)return;const a=e.audio.length,i=this.audioSeparatorResult;for(let t=0;t<a;t++){const e=i[t];e.adapt.need&&await this.transcodeAudio(t,{...e.adapt,type:"adapt"}),e.high.need&&await this.transcodeAudio(t,{...e.high,type:"high"});const s=(t+1)/a;await this.postProgress({type:Ht.transcode_audio,percent:s})}await this.postProgress({type:Ht.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=Vt(this.params.outputRoot,r);if(!await Bt(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 Wt}from"path";import{getFileSize as Zt}from"@soga/fileutils";import{combine as Yt}from"@soga/imgutils";import{copy as te}from"fs-extra";import{UploadProgress as ee}from"@soga/node-types";import{buildDError as ae}from"@soga/error";var ie=class extends ut{m3u8_data=null;thumbnail_duration=30;thumbnail_group=[];row=8;col=8;screenshot_width=480;screenshot_height=270;getScreenshotName(t){return`video_screenshot_${t}.jpg`}getTileName(t){return`video_tile_${t}.jpg`}getCoverName(){return"video_cover.jpg"}async updateImagePercent(t,e){const a="screenshot"==e?6*t/7:t/7+6/7;await this.postProgress({type:ee.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 ae(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=Wt(this.params.outputRoot,e),i=await Zt(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=Wt(this.params.outputRoot,s),o=this.getCoverName(),n=Wt(this.params.outputRoot,o);await te(r,n);const h={file:o,path:n,size:await Zt(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=Wt(this.params.outputRoot,e);n.push(a)}const h=this.getTileName(t),d=Wt(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 Yt({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=Wt(this.params.outputRoot,e),l=await Zt(c);if(0===l)throw new Error(`Generate video thumbnail error: [index: ${t}, start_time: ${d.start_time}, end_time: ${d.end_time}]`);l>=a.size&&(a.index=t,a.size=l,this.store.data.thumbnail_screenshot_largest=a,await this.store.write()),this.store.data.thumbnail_screenshot_index=t+1,await this.store.write()}catch(a){const i=Math.max(10,d.duration);if(!(e<3))throw a;await n(t,{errorTimes:e+1,fixedSeconds:o+i/5})}};for(let e=t;e<o;e++)await n(e,{errorTimes:0,fixedSeconds:0}),await this.updateImagePercent((e+1)/o,"screenshot");this.store.data.thumbnail_screenshot_state=!0,await this.store.write()}async initScreenshotSize(){const{thumbnail_screenshot_size:t}=this.store.data;if(t)return this.screenshot_width=t.width,void(this.screenshot_height=t.height);const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],{width:i,height:s}=a,r=i>s?480:270;this.screenshot_width=2*Math.floor(Math.min(r,i)/2),this.screenshot_height=2*Math.floor(this.screenshot_width*(s/i)/2),this.store.data.thumbnail_screenshot_size={width:this.screenshot_width,height:this.screenshot_height}}async initThumbnailGroup(){if(this.store.data.thumbnail_group)return void(this.thumbnail_group=this.store.data.thumbnail_group);const t=[],{segments:e}=this.m3u8_data,{length:a}=e,i=this.thumbnail_duration;let s=0,r=[];for(let o=0;o<a;o++){const n=e[o];if(s+=n.duration,r.push(n),s>=i||o===a-1){const e=r.length,a=r[0],i=r[e-1];t.push({duration:s,start_time:a.start_time,end_time:i.end_time,items:r,item:i}),s=0,r=[]}}if(t.length>1){if(t[t.length-1].duration<1){const e=t.pop(),a=t[t.length-2];a.duration=a.duration+e.duration,a.end_time=e.end_time,a.items=a.items.concat(e.items),a.item=e.item,e.items}}t.forEach(t=>{const{items:e}=t;for(let a=e.length-1;a>=0;a--)if(e[a].duration>1){t.item=e[a];break}}),this.thumbnail_group=t,this.store.data.thumbnail_group=t,await this.store.write()}getVideoM3U8Info(){return this.videoTranscoderResult?.m3u8}async initM3U8Data(){this.m3u8_data=this.getVideoM3U8Info()}async initThumbnailDuration(){if(this.store.data.thumbnail_duration)return this.thumbnail_duration=this.store.data.thumbnail_duration,this.thumbnail_duration;let t=30;const e=await this.getMediainfo(),a=e?.video;if(!a?.length)return t;const i=a[0],s=i.duration||e?.general?.duration,{width:r,height:o}=i;r*o>=518400&&(t=10),r*o>=921600&&(t=20),r*o>=2073600&&(t=30),r*o>=3686400&&(t=40),r*o>=8294400&&(t=60);const n=s??0;if(n&&(n<60&&(t=0),n<300&&(t=Math.ceil(t/4)),n<600&&(t=Math.ceil(t/2)),n>3600)){const e=n/3600;t=Math.ceil(t*e)}return t=Math.min(60,t),this.thumbnail_duration=t,this.store.data.thumbnail_duration=t,await this.store.write(),t}};import{resolve as se}from"path";import{pathExists as re}from"fs-extra";import{getMetadata as oe}from"@soga/imgutils";import{getFileSize as ne}from"@soga/fileutils";import{UploadProgress as he}from"@soga/node-types";import{buildDError as de}from"@soga/error";var ce=class extends ut{get cover_name(){return"audio_cover.png"}async start(){try{await this.generateCover(),this.isAudio&&await this.postProgress({type:he.transcode_thumbnail,percent:1})}catch(t){throw de(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=se(this.params.outputRoot,t),s=await re(i),r=await oe(i);if(s){const e={file:t,path:i,size:await ne(i),width:r.width??0,height:r.height??0};await this.setCoverResult(e)}}catch(t){throw t}finally{this.db.data[e]=!0,await this.db.write()}}};import{parse as le,resolve as ue}from"path";import{getFileLanguage as pe,isUtf8File as ge,saveFileAsUtf8 as me,gzip as we}from"@soga/utils";import{isValidFile as fe,getFileSize as _e,isValidPath as ye}from"@soga/fileutils";import{copy as be}from"fs-extra";import{buildDError as ve}from"@soga/error";import{UploadProgress as Pe}from"@soga/node-types";var xe=class extends ut{builtin_tracks=0;external_tracks=0;get tracks(){return this.builtin_tracks+this.external_tracks}async sendProgress(t){await this.postProgress({type:Pe.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 ve(t,{message:"Error occurred while process subtitle track",detail:`Error occurred while process subtitle track: ${this.params.input.filepath}`})}}async parseBuiltinTextTracks(){const t=await this.getMediainfo(),e=t?.text;if(!e?.length)return[];const{subtitle_builtin_tracks:a}=this.dbData;if(a)return a;const i=e.length,s=[];for(let t=0;t<i;t++){const e=await this.parseBuiltinTextTrack(t);e&&s.push(e),await this.sendProgress((t+1)/this.tracks)}return this.dbData.subtitle_builtin_tracks=s,await this.params.db.write(),s}async parseBuiltinTextTrack(t){const e=this.params.outputRoot,a=`subtitle-builtin-${t}.zip`,i=ue(e,a),s=`subtitle-temp-${t}.vtt`,r=ue(e,s),o=ue(e,`subtitle-builtin-u8-${t}.vtt`),n=["-i",this.params.input.filepath,"-vn","-an","-map",`0:s:${t}`,"-c","webvtt","-y",s];await this.ffmpeg(n,{cwd:this.params.outputRoot});if(await fe(r)){if(await ge(r))await be(r,o);else{await me(r,o);await fe(o)||await be(r,o)}const e=await pe(o),{label:s,lang:n}=e;await we(o,i);return{file:a,file_path:i,size:await _e(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}=le(e),i=this.params.outputRoot,s=`subtitle-external-${t}.vtt`,r=ue(i,s),o=`subtitle-external-${t}.zip`,n=ue(i,o),h=ue(i,`subtitle-external-u8-${t}${a}`),d=`subtitle-external-source-${t}.zip`,c=ue(i,d);if(!await ye(e))return!1;if(await ge(e))await be(e,h);else{await me(e,h);if(!await fe(h))return!1}const l=["-i",h,"-c","webvtt","-y",s];await this.ffmpeg(l,{cwd:this.params.outputRoot});if(await fe(r)){const i=await pe(r),{label:s,lang:h}=i;await we(e,c),await we(r,n);const l=await _e(c);return{file:o,size:await _e(n),file_path:n,lang:h,name:s||`external_${t+1}`,title:s||`external_${t+1}`,builtin:!1,source:{file:d,file_path:c,size:l,ext:a}}}return!1}};import{buildDError as De}from"@soga/error";import{resolve as Te}from"path";import{writeFile as ze}from"fs-extra";import{UploadProgress as Re}from"@soga/node-types";import{getFileSize as Ie}from"@soga/fileutils";import{gzip as Me,getFileBufferSlice as $e}from"@soga/utils";import{buildDError as Se}from"@soga/error";import{resolve as ke}from"path";import{getFileSize as Fe}from"@soga/fileutils";var Ee=class extends ut{hostType;safe_index=0;file_map={};completed_percent=0;total_percent=0;store;async initStore(t){this.store=await this.getStore(`${t}_grouper_store.json`)}getFileName=t=>this.getPreviewSegmentName(t,this.hostType);getGroupedVideoManifestName(t){return`grouper_video_${this.hostType}_${t}.m3u8`}getAudioManifestName(t,e){return`grouper_audio_${this.hostType}_${e}_${t}.m3u8`}getThumbnailInfoFilename(){return`grouper_thumbnail_${this.hostType}.json`}getCacheInfoFilename(){return`grouper_cache_${this.hostType}.json`}constructor(t){super(t),this.hostType=t.host_type,this.completed_percent=t.completed_percent,this.total_percent=1/t.hosts.length}async generateSafeFile(t){return await async function(t){const e=`safe_${t.type}_${t.file_index}.txt`,a=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=ke(this.params.outputRoot,i),r=await Fe(s),o=await this.getPartInfo({host_type:this.hostType,filepath:s,start:0,end:r-1,filename:i});e.push(o)}return e}async getAudioData(){const t=this.readAudioTracks();if(!t?.length)return;const e=[];for(let a=0;a<t.length;a++){const i=t[a];if(i.adapt){const{average_bandwidth:t,bandwidth:s,channels:r,codec:o,codec_name:n,language:h,order:d}=i.adapt,c=this.getAudioManifestName("adapt",a),l=this.file_map[c],{file_index:u,start:p,end:g,size:m,hash:w}=l,f=this.getFileName(u),_=await this.getPreviewId({file:c});await this.setPreviewIdMap({id:_,file:f,start:p,end:g},this.hostType);const y={id:_,average_band:t,band:s,channels:r,codec:o,codec_name:n,language:h,order:d,file:f,start:p,end:g,size:m,hash:w};if(i.high){const{average_bandwidth:t,bandwidth:e,channels:s,codec:r,codec_name:o,language:n,order:h}=i.high,d=this.getAudioManifestName("high",a),c=this.file_map[d],{file_index:l,start:u,end:p,size:g,hash:m}=c,w=this.getFileName(l),f=await this.getPreviewId({file:d});await this.setPreviewIdMap({id:f,file:w,start:u,end:p},this.hostType),y.high={id:f,average_band:t,band:e,channels:s,codec:r,codec_name:o,language:n,order:h,file:w,start:u,end:p,size:g,hash:m}}e.push(y)}}return e}async getVideoData(){const t=this.readVideoTracks();if(!t?.length)return;const e=[];for(let a=0;a<t.length;a++){const i=t[a],s=this.getGroupedVideoManifestName(a),r=await this.getPreviewId({file:s}),o=this.file_map[s],{file_index:n,start:h,end:d,size:c,hash:l}=o,u=this.getFileName(n);await this.setPreviewIdMap({id:r,file:u,start:h,end:d},this.hostType);const{average_bandwidth:p,bandwidth:g,codec:m,width:w,height:f,label:_,codec_name:y,bitdepth:b,framerate:v}=i,P={id:r,average_band:p,band:g,codec:m,codec_name:y,bitdepth:b,framerate:Math.round(v),width:w,height:f,file:u,start:h,end:d,size:c,label:_,hash:l};e.push(P)}return e}async getSubtitleData(){const t=this.readSubtitleInfo();if(!t?.length)return;const e=[],{length:a}=t;for(let i=0;i<a;i++){const a=t[i],{builtin:s,file:r,lang:o,title:n,name:h,source:d}=a,c=this.file_map[r],{file_index:l,start:u,end:p,size:g}=c,m=this.getFileName(l),w={uuid:await this.getPreviewId({file:r,start:u,end:p}),builtin:s,lang:o,name:h,title:n,file:m,start:u,end:p,size:g};if(d){const{file:t,ext:e}=d,a=this.file_map[t],{file_index:i,start:s,end:r,size:o}=a,n=this.getFileName(i);w.source={size:o,file:n,start:s,end:r,ext:e}}e.push(w)}return e}async getThumbnailData(){const t=this.readThumbnailInfo();if(!t)return;const{row:e,col:a,width:i,height:s}=t,r=this.getThumbnailInfoFilename(),o=this.file_map[r],{file_index:n,start:h,end:d,size:c}=o,l=this.getFileName(n),u=await this.getPreviewId({file:r});await this.setPreviewIdMap({id:u,file:l,start:h,end:d},this.hostType);return{id:u,row:e,col:a,width:i,height:s,file:l,start:h,end:d,size:c}}async getCoverData(){const t=this.readCoverInfo();if(!t)return;const e=t,{file:a,width:i,height:s}=e,r=this.file_map[a],{file_index:o,start:n,end:h,size:d}=r,c=this.getFileName(o),l=await this.getPreviewId({file:e.path});await this.setPreviewIdMap({id:l,file:c,start:n,end:h},this.hostType);return{id:l,width:i,height:s,file:c,start:n,end:h,size:d}}async getCacheData(){const t=this.getCacheInfoFilename(),e=await this.getPreviewId({file:t}),a=this.file_map[t],{file_index:i,start:s,end:r,size:o}=a,n=this.getFileName(i);await this.setPreviewIdMap({id:e,file:n,start:s,end:r},this.hostType);return{id:e,file:n,start:s,end:r}}async saveData(){const t=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()}},Ne=class extends Ee{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:Re.group_media,percent:this.completed_percent+.5*this.total_percent}),await this.processGroups(),await this.postProgress({type:Re.group_media,percent:this.completed_percent+.9*this.total_percent}),await this.saveData(),await this.postProgress({type:Re.group_media,percent:this.completed_percent+this.total_percent}),this.db.data[t]}catch(t){throw Se(t,{message:`Error occurred during media grouping ${this.hostType}`,detail:`Error occurred during media grouping ${this.hostType}: ${this.params.input.filepath}`})}}async processGroups(){const t="grouper_process_state";if(this.store.data[t])return;this.store.data.grouper_process_map||={},this.store.data.grouper_process_index||=0;const{length:e}=this.group_data;for(let t=0;t<e;t++){const a=this.group_data[t];this.store.data.grouper_process_map[a.filename]||(await p({outputRoot:this.params.outputRoot,files:a.files,filename:a.filename}),this.store.data.grouper_process_map[a.filename]=!0,await this.store.write(),await this.postProgress({type:Re.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:Re.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:Re.group_media,percent:this.completed_percent+.2*this.total_percent+.2*this.total_percent*((t+1)/i)})}}async calculateThumbnails(){const t=this.readThumbnailInfo();if(!t)return;if(!t)return;const{tile_list:e}=t,{length:a}=e;let i=[...t.sprite_list];for(let t=0;t<a;t++){const a=e[t],s=a.file,r=await this.safelyAddOne({file_path:a.file_path,size:a.size}),o=await this.getPreviewId({file:s}),n=this.getFileName(r.file_index);await this.setPreviewIdMap({id:o,file:n,start:r.start,end:r.end},this.hostType),this.file_map[s]=r,i=i.map(t=>t.file===s?{...t,file:n,id:o,s:r.start,e:r.end}:t)}const s=this.getThumbnailInfoFilename(),r=await this.writeText(s,JSON.stringify(i));this.file_map[s]=r}async calculateOneTrack(t){const{segments:e,init:a,version:i,targetDuration:s,mediaSequence:r,endList:o}=t,n={},h=this.addOne({size:a.size,file_path:a.file_path}),d=await this.getPreviewId({file:a.uri}),c=this.getFileName(h.file_index),l=`${c}?id=${d}`;await this.setPreviewIdMap({id:d,file:c,start:h.start,end:h.end},this.hostType);const u=["#EXTM3U",`#EXT-X-VERSION:${i}`,`#EXT-X-TARGETDURATION:${s}`,`#EXT-X-MEDIA-SEQUENCE:${r}`,`#EXT-X-MAP:URI=${l},BYTERANGE="${h.size}@${h.start}"`];[...e].forEach(t=>{const{uri:e,size:a,duration:i,file_path:s}=t;n[e]=this.addOne({size:a,duration:i,file_path:s})});for(const[t,e]of Object.entries(n)){const a=await this.getPreviewId({file:t}),i=this.getFileName(e.file_index);await this.setPreviewIdMap({id:a,file:i,start:e.start,end:e.end},this.hostType),u.push(`#EXTINF:${e.duration},`),u.push(`#EXT-X-BYTERANGE:${e.size}@${e.start}`),u.push(`${i}?id=${a}`)}o&&u.push("#EXT-X-ENDLIST");return u.join("\n")}async writeTrackText(t,e){const a=Te(this.params.outputRoot,t),r=Te(this.params.outputRoot,`${t}.gz`),o=Te(this.params.outputRoot,`${t}.bin`);await ze(a,e,"utf-8"),await Me(a,r);if(await Ie(r)>16){const t=(await $e(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 Ie(o)}),hash:t}}return{...this.addOne({file_path:a,size:await Ie(a)}),hash:""}}async writeText(t,e){const a=Te(this.params.outputRoot,t);await ze(a,e,"utf-8");return this.addOne({file_path:a,size:await Ie(a)})}addOne({file_path:t,size:e,duration:a=0},i=!1){const s=this.getSizeLimit(this.hostType),{current_position:r,group_data:o}=this;if(i&&o[this.current_index]||!(r+e<=s)){this.current_index+=1;const{current_index:i}=this;o[i]?o[i].files.push(t):o[i]={filename:this.getFileName(i),files:[t]};const s=0,r=e-1;return this.current_position=e,{file_index:i,start:s,end:r,duration:a,size:r-s+1}}{const{current_index:i}=this,s=r,n=r+e-1;return this.current_position=n+1,o[i]?o[i].files.push(t):o[i]={filename:this.getFileName(i),files:[t]},{file_index:i,start:s,end:n,duration:a,size:n-s+1}}}async safelyAddOne(t){const e=this.getSizeLimit(this.hostType),{current_position:a}=this;return a+t.size<=e?0===a?(await this.insertSafeFile(),this.addOne(t)):this.addOne(t):(await this.insertSafeFile(),this.addOne(t))}},Ce=class extends ut{async start(){try{if(this.grouperResult)return this.grouperResult;const t={meta:await this.getMetaData(),data:{}},{length:e}=this.params.hosts;for(let a=0;a<e;a++){const i=this.params.hosts[a],s=this.getSizeLimit(i),r=new Ne({...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 De(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}},Le=class extends ut{async start(){if(this.db.data.grouper_result)return this.db.data.grouper_result;const t=await this.getMediainfo();if(!t)return;const e=t.video,a=e?.length,i=t.audio,s=i?.length;if(!s&&!a)return;const r=new xe(this.params);if(await r.start(),s){const t=new $t(this.params);await t.start();const e=new Qt(this.params);await e.start();const a=new ce(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 ie(this.params);await a.start()}const o=new Ce(this.params);await o.start()}async getResult(){return this.db.data.grouper_result}};import{HostType as Ae}from"@soga/types";import{UploadProgress as Oe}from"@soga/node-types";import{parseMediaInfo as Ue}from"@soga/mediainfo";import{getFileSize as Ve,isAudioAdapt as Ge,isAudioHigh as Be,isVideoSupport as je}from"@soga/fileutils";import{ensureDir as qe}from"fs-extra";import Xe from"check-disk-space";import{buildDError as Ke}from"@soga/error";var Je=class extends C{async start(){this.prepareResult||(await this.checkStorage(),await this.calculateMeta(),await this.calculateProgress())}async checkStorage(){const{length:t}=this.params.hosts,e=await Xe(this.params.outputRoot),a=e.free,i=e.diskPath;if((3+t)*this.params.input.filesize>a)throw Ke(new Error(`${i} have no enough computer disk space, please adjust the temporary path in user settings.`),{message:`${i} have no enough computer disk space, please adjust the temporary path in user settings.`,detail:`${i} have no enough computer disk space to process ${this.params.input.filepath}`})}async calculateMeta(){if(this.meta)return this.meta;const{filename:t,local_btime:e,local_ctime:a,local_mtime:i,filesize:s}=this.params.input,r={file:t,size:s,btime:e,ctime:a,mtime:i,md5:""};return await this.setMeta(r),r}async calculateProgress(){if(this.prepareResult)return;const t={[Oe.prepare]:{weight:0,percent:1},[Oe.calculate_md5]:{weight:0,percent:0},[Oe.separate_video]:{weight:0,percent:0},[Oe.separate_audio]:{weight:0,percent:0},[Oe.separate_subtitle]:{weight:0,percent:0},[Oe.transcode_video]:{weight:0,percent:0},[Oe.transcode_audio]:{weight:0,percent:0},[Oe.transcode_thumbnail]:{weight:0,percent:0},[Oe.transcode_source]:{weight:0,percent:0},[Oe.transcode_txt]:{weight:0,percent:0},[Oe.transcode_img]:{weight:0,percent:0},[Oe.group_media]:{weight:0,percent:0},[Oe.upload_baidu]:{weight:0,percent:0},[Oe.upload_ali]:{weight:0,percent:0},[Oe.end]:{weight:0,percent:0}},e={keep_preview:this.params.keepPreview,keep_source:this.params.keepSource},a=await Ve(this.params.input.filepath);t[Oe.prepare].weight=t[Oe.end].weight=Math.ceil(a/1024/1024/500),t[Oe.calculate_md5].weight=Math.ceil(a/1024/1024/200);let i=0;if(this.isMedia)if(this.params.keepPreview){const s=await Ue(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=je(r),{duration:n}=s.general,h=o?n/400:n*(a*i)/1920/1080;t[Oe.separate_video].weight=Math.ceil(h),t[Oe.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};Ge(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):Be(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[Oe.separate_audio].weight=Math.ceil(a),t[Oe.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[Oe.separate_subtitle].weight=Math.ceil(o),t[Oe.transcode_thumbnail].weight=Math.ceil(.08*r),i+=a,t[Oe.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[Oe.transcode_txt].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a):this.isImg?e.keep_preview&&(t[Oe.transcode_img].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a);e.keep_source&&(t[Oe.transcode_source].weight=Math.ceil(a/1024/1024/30)),this.params.hosts.includes(Ae.BAIDU)&&(t[Oe.upload_baidu].weight=Math.ceil(i/1024/1024/1)),this.params.hosts.includes(Ae.ALI)&&(t[Oe.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)}},He=async t=>{await qe(t.outputRoot);const e=await m(t);try{const a=new Je({...t,db:e});return await a.start(),a}catch(t){}};import{UploadProgress as Qe}from"@soga/node-types";import{createHash as We}from"crypto";import{createReadStream as Ze}from"fs-extra";var Ye=class extends C{async start(){await this.processFile();return await this.getResult()}async calculateMd5(){if(this.md5)return this.md5;const t=this.params.input.filepath,e=this.params.input.filesize;let a=0;const i=await new Promise((i,s)=>{let r=0;const o=We("md5"),n=Ze(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:Qe.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:Qe.calculate_md5,percent:1}),i}async getResult(){if(this.result)return this.result;const{sourceResult:t,grouperResult:e,imgResult:a,txtResult:i,meta:s,keeps:r}=this,{length:o}=this.params.hosts,n={meta:{preview:r.preview,source:r.source,file:s}};for(let s=0;s<o;s++){const r=this.params.hosts[s];n[r]={max_size:0,parts:[]};const o=t=>{n[r].parts=[...n[r].parts,...t]},h=a?.data[r];if(h){h.cache&&(n[r].cache=h?.cache);const t=h.parts?.map(t=>({...t,preview:!0,source:!1}));t&&o(t),n.meta.img=a.meta,h.img&&(n[r].img=h.img)}const d=i?.data[r];if(d){o((d.parts||[]).map(t=>({...t,preview:!0,source:!1}))),n[r].cache=d.cache,n[r].txt={entrance:d.entrance,pad:i?.meta.pad,pages:i?.meta.pages}}const c=e?.data[r];if(c?.parts){o(c.parts.map(t=>({...t,preview:!0,source:!1}))),n.meta.audios=e.meta.audios,n.meta.videos=e.meta.videos,n[r].cache=c.cache,n[r].media={audios:c.audios,videos:c.videos,subtitles:c.subtitles,thumbnail:c.thumbnail,cover:c.cover}}const l=t?.data[r];if(l?.parts){o(l.parts.map(t=>{let e=!0;return(this.isMedia||this.isTxt)&&(e=!1),{...t,preview:e,source:!0}})),n[r].source={head:t.meta.head,download:l.download}}[...n[r]?.parts].forEach(t=>{t.size>n[r].max_size&&(n[r].max_size=t.size)})}return await this.setResult(n),n}async processFile(){const t="encoder_processed";if(this.db.data[t])return;const e=await He(this.params),{keeps:a}=e,i={...this.params,keepPreview:a.preview,keepSource:a.source},s=await this.calculateMd5();if(await this.setMd5(s),i.keepSource){const t=new A(this.params);await t.start()}if(e.isMedia&&i.keepPreview){const t=new Le(this.params);await t.start()}if(e.isTxt&&i.keepPreview){const t=new Y(this.params);await t.start()}if(e.isImg){const t=new ht(this.params);await t.start()}this.db.data[t]=!0,await this.db.write()}},ta=async e=>{try{const t=await m(e),a=new Ye({...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{ta as encode,He as getPrepare};
|
|
1
|
+
import{buildDError as t}from"@soga/error";import{getDb as e}from"@soga/lowdb";import{createHash as a}from"crypto";import{createReadStream as i,createWriteStream as s,existsSync as r,remove as o,stat as n,writeFile as h}from"fs-extra";import{truncate as d}from"fs/promises";import{resolve as c}from"path";import{pipeline as l}from"stream/promises";function u(t){const e=a("md5");return e.update(`${t}`),e.digest("hex")}async function p(t){await new Promise((e,a)=>{(async()=>{const r=c(t.outputRoot,t.filename);await o(r);let n=!1;const h=s(r);h.on("open",()=>{n=!0}).on("error",async t=>{n&&h.close(),await o(r),a(t)});const{length:d}=t.files,l=async(e=0)=>{if(e<d){const a=t.files[e],s=t.files.length;await new Promise((t,e)=>{const d=i(a);d.pipe(h,{end:!s}),d.on("end",()=>{d.close(),t(!0)}),d.on("error",async t=>{d.destroy(),n&&h.close(),await o(r),e(t)})}),await l(e+1)}};await l(0),n&&h.end(),e(!0)})()})}async function g(t,a){const i=u(JSON.stringify({...t,dbName:a})),s="db_unique_key",r=c(t.outputRoot,a),o=await e(r,{});return o.data[s]?o.data[s]!=i&&(o.data={[s]:i},await o.write()):(o.data[s]=i,await o.write()),o}async function m(t){return await g({file_id:t.id,input:{filepath:t.input.filepath,filesize:t.input.filesize},outputRoot:t.outputRoot},"encoder_store.json")}async function w({input_path:t,target_path:e,start:a,end:n}){const h=i(t,{start:a,end:n,highWaterMark:65536}),d=s(e);try{await l(h,d)}catch(t){try{r(e)&&await o(e)}catch(t){console.warn("Failed to clean up incomplete file:",t.message)}throw t}}import{resolve as f}from"path";import{gzip as _,getFileBufferSlice as y}from"@soga/utils";import{getFileSize as b}from"@soga/fileutils";import{buildDError as v}from"@soga/error";import{UploadProgress as P}from"@soga/node-types";import{rename as x,stat as D,writeFile as T}from"fs-extra";import{HostType as z}from"@soga/types";var R=2097152,I={[z.BAIDU]:52428800,[z.ALI]:4294967296},M={[z.BAIDU]:2147483648,[z.ALI]:4294967296};z.BAIDU,z.ALI;import{HostType as $,RecordFtype as S,RecordType as k}from"@soga/types";import{calculateMd4 as F,calculateMd5 as E,calculateSha1 as N}from"@soga/utils";import{parentPort as L}from"worker_threads";var C=class{segmentNames={};params;id;port=null;db;get lowData(){return this.db.data}get isVideo(){return this.params.type==k.VIDEO}get isAudio(){return this.params.type==k.AUDIO}get isMedia(){return this.isAudio||this.isVideo}get isTxt(){return this.params.type==k.DOC&&this.params.ftype==S.DOC_TXT}get isImg(){return this.params.type==k.IMAGE}getSizeLimit(t){return this.params.is_shop_space?M[t]||2147483648:I[t]||52428800}getFilesize(){return this.params.input.filesize}constructor(t){this.params=t,this.id=t.id,this.port=t.port??null,this.db=t.db}async getPartInfo({host_type:t,filepath:e,start:a,end:i,filename:s,index:r},o=!0){const n={start:a,end:i,size:i-a+1,path:e,index:r,file:s,md5:o?await E({file:e,start:a,end:i}):""};if(o){if(t===$.BAIDU){const t=await F({file:e,start:a,end:i});n.md4=t}if(t===$.ALI){const t=await N({file:e,start:a,end:i});n.sha1=t}}return n}async getStore(t){const{id:e,input:a,outputRoot:i}=this.params;return await g({file_id:e,input:{filepath:a.filepath,filesize:a.filesize},outputRoot:i},t)}async postProgress(t){const e={step:t.type,percent:t.percent};await this.postMessage({id:this.id,type:"percent",data:e})}async postMessage(t){this.port?this.port.postMessage(t):L&&L.postMessage(t)}async setKeeps(t){this.lowData.keeps=t,await this.db.write()}get keeps(){return this.lowData.keeps}async setMeta(t){this.lowData.meta=t,await this.db.write()}get meta(){return this.lowData.meta}async setSourceResult(t){this.lowData.source_result=t,await this.db.write()}get sourceResult(){return this.lowData.source_result}async setPrepareResult(t){this.lowData.prepare_result=t,await this.db.write()}get prepareResult(){return this.lowData.prepare_result}async setMd5(t){this.lowData.meta.md5=t,await this.db.write()}get md5(){return this.lowData.meta.md5}async setSubtitleEncoderResult(t){this.lowData.subtitle_encoder_result=t,await this.db.write()}get subtitleEncoderResult(){return this.lowData.subtitle_encoder_result}async setAudioSeparatorResult(t){this.lowData.audio_separator_result=t,await this.db.write()}get audioSeparatorResult(){return this.lowData.audio_separator_result}async setAudioTranscoderResult(t){this.lowData.audio_transcoder_result=t,await this.db.write()}get audioTranscoderResult(){return this.lowData.audio_transcoder_result}async setCoverResult(t){this.lowData.cover_result=t,await this.db.write()}get coverResult(){return this.lowData.cover_result}async setVideoTranscoderResult(t){this.lowData.video_transcoder_result=t,await this.db.write()}get videoTranscoderResult(){return this.lowData.video_transcoder_result}async setVideoThumbnailerResult(t){this.lowData.video_thumbnailer_result=t,await this.db.write()}get videoThumbnailerResult(){return this.lowData.video_thumbnailer_result}async setGrouperResult(t){this.lowData.grouper_result=t,await this.db.write()}get grouperResult(){return this.lowData.grouper_result}async setImgResult(t){this.lowData.img_result=t,await this.db.write()}get imgResult(){return this.lowData.img_result}async setTxtResult(t){this.lowData.txt_result=t,await this.db.write()}get txtResult(){return this.lowData.txt_result}async setResult(t){this.lowData.result=t,await this.db.write()}get result(){return this.lowData.result}_syncGetId({file:t,start:e,end:a},i){const s=`${i}_key_index`,r=`${i}_key_map`,o=`${t}_${e||0}_${a||0}`,n=this.db.data[r]||{};if(n[o])return n[o];this.db.data[s]=this.db.data[s]||0,this.db.data[r]=this.db.data[r]||{};const h=this.db.data[s]+1,d=`id_${h}`;return this.db.data[r][o]=d,this.db.data[s]=h,d}_syncSetIdMap({id:t,file:e,start:a,end:i},s,r){const o=`${s}_${r}_id_map`;this.db.data[o]=this.db.data[o]||{},this.db.data[o][t]={f:e,s:a,e:i}}},A=class extends C{syncGetSourceId(t){return this._syncGetId(t,"source")}async getSourceId(t){const e=this.syncGetSourceId(t);return await this.db.write(),e}getSourceIdMap(t){return this.db.data[`source_${t}_id_map`]||{}}syncSetSourceIdMap(t,e){this._syncSetIdMap(t,"source",e)}async setSourceIdMap(t,e){this.syncSetSourceIdMap(t,e),await this.db.write()}getSourceSegmentName=(t,e)=>{const a=`source_${e}_${t}`;if(this.segmentNames[a])return this.segmentNames[a];const i=`s-${u(`source-${e}-${this.md5}-${t}`)}`;return this.segmentNames[a]=i,i}},O=class extends A{head_size=32;getZipFilePath(){return f(this.params.outputRoot,"souce_zip.bin")}getDownloadListFileName(t){return`source_${t}_download_list.json`}getPartName(t,e){return this.getSourceSegmentName(e,t)}getPartPath(t,e){return f(this.params.outputRoot,this.getPartName(t,e))}get dbData(){return this.db.data}async setPartList(t,e){const a=`source_${t}_part_list`;this.dbData[a]=e,await this.params.db.write()}getPartList(t){const e=`source_${t}_part_list`;return this.dbData[e]}async setDownloadMap(t,e){const a=`source_${t}_download_map`;this.dbData[a]=e,await this.params.db.write()}getDownloadMap(t){const e=`source_${t}_download_map`;return this.dbData[e]}async sendProgress(t){await this.postProgress({type:P.transcode_source,percent:t})}async setDownloadList(t,e){const a=`source_${t}_download_list`;this.dbData[a]=e,await this.params.db.write()}getDownloadList(t){const e=`source_${t}_download_list`;return this.dbData[e]}async start(){try{if(this.sourceResult)return await this.sendProgress(1),this.sourceResult;await this.gzip();const{length:t}=this.params.hosts;for(let e=0;e<t;e++){const t=this.params.hosts[e];await this.calculatePartList(t),await this.processDownloadMap(t)}await this.sendProgress(.9);const e=await this.getResult();return await this.sendProgress(1),e}catch(t){throw v(t,{message:"Error occurred during source encoding",detail:`Error occurred during source encoding: ${this.params.input.filepath}`})}}async gzip(){if(this.dbData.source_gziped)return;const t=this.params.input.filepath,e=this.getZipFilePath();await _(t,e,async({percent:t})=>{await this.sendProgress(.6*t)}),this.dbData.source_gziped=!0,await this.params.db.write()}async getResult(){if(this.sourceResult)return this.sourceResult;const t={meta:await this.getMetaData(),data:{}},{length:e}=this.params.hosts;for(let a=0;a<e;a++){const e=this.params.hosts[a],i=this.getPartList(e),s=this.getDownloadMap(e);t.data[e]={download:s,parts:i}}return await this.setSourceResult(t),t}async getMetaData(){const t="source_meta",e=this.dbData[t];if(e)return e;const a=this.getZipFilePath(),i=await b(a),s={path:a,start:0,end:0},{head_size:r}=this;s.end=i<=r?i-1:r-1;const o={head:(await y(s.path,s.start,s.end)).toString("base64")};return this.dbData[t]=o,await this.params.db.write(),o}async writeDownloadListFile(t,e){const a=this.getDownloadListFileName(t),i=f(this.params.outputRoot,a);await T(i,e,"utf-8");return{file_path:i,size:await b(i)}}async processDownloadMap(t){const e=this.getDownloadMap(t);if(e)return e;const a=this.getDownloadList(t);let r;const{file_path:o,size:n}=await this.writeDownloadListFile(t,JSON.stringify(a)),h=this.getSizeLimit(t),d=this.getPartList(t);if(d.length){const e=d[d.length-1],{path:a,size:c,file:u,index:p,end:g,start:m}=e,w=f(this.params.outputRoot,u);if(c+n<=h){await async function({source1:t,source2:e,target:a}){const r=i(t.filepath,{start:t.start,end:t.end}),o=s(a);await l(r,o);const n=i(e),h=s(a,{flags:"a"});await l(n,h)}({source1:{filepath:a,start:m,end:g},source2:o,target:w});const e=(await D(w)).size,h=e-1,c=e-n,f=await this.getPartInfo({host_type:t,filepath:w,start:0,end:e-1,filename:u,index:p});d[d.length-1]=f;r={id:await this.getSourceId({file:u,start:c,end:h}),file:u,start:c,end:h}}else{const e=p+1,a=this.getPartName(t,e),i=this.getPartPath(t,e);await x(o,i);const s=await this.getSourceId({file:a,start:0,end:n-1}),h=await this.getPartInfo({host_type:t,filepath:i,start:0,end:n-1,filename:a,index:e});d.push(h),r={id:s,file:a,start:0,end:n-1}}return await this.setPartList(t,d),await this.setDownloadMap(t,r),r}}async calculatePartList(t){const e=`source_${t}_list_calculated`;if(this.dbData[e])return;const a=this.getZipFilePath(),i=await b(a),s=[],r=this.getSizeLimit(t),{head_size:o}=this,n=[];if(i>o){let e=0;for(let h=o;h<=i-1;h+=r){const o=Math.min(h+r-1,i-1),d=this.getPartName(t,e),c=await this.getPartInfo({host_type:t,filepath:a,start:h,end:o,filename:d,index:e});let l=0;for(let t=h;t<o;t+=R){const e=Math.min(t+R-1,o),a=e-t+1,i=l+a-1,s=await this.getSourceId({file:"source_zip",start:t,end:e});n.push({id:s,file:d,start:l,end:i}),l+=a}s.push(c),e++}}await this.setPartList(t,s),await this.setDownloadList(t,n),this.dbData[e]=!0,await this.db.write()}};import{resolve as U}from"path";import{createWriteStream as V,readFile as G,remove as B}from"fs-extra";import{getFileBufferSlice as j}from"@soga/utils";import q from"zlib";import{saveFileAsUtf8 as X}from"@soga/utils";import{buildDError as K}from"@soga/error";import{UploadProgress as J}from"@soga/node-types";import{resolve as H}from"path";import{getFileSize as Q}from"@soga/fileutils";import{copy as W,writeFile as Z}from"fs-extra";var Y=class extends C{get preview_common_db_data(){return this.db.data}async getCurrentFileIndex(t){const e=this.db.data[`preview_${t}_current_index`];return"number"!=typeof e?(this.db.data[`preview_${t}_current_index`]=0,await this.db.write(),0):e}async increaseCurrentFileIndex(t){const e=await this.getCurrentFileIndex(t)+1;return this.db.data[`preview_${t}_current_index`]=e,await this.db.write(),e}getPartName(t,e){return this.getPreviewSegmentName(e,t)}getPartPath(t,e){return H(this.params.outputRoot,this.getPartName(t,e))}syncGetPreviewId(t){return this._syncGetId(t,"preview")}async getPreviewId(t){const e=this.syncGetPreviewId(t);return await this.db.write(),e}getPreviewIdMap(t){return this.db.data[`preview_${t}_id_map`]||{}}syncSetPreviewIdMap(t,e){this._syncSetIdMap(t,"preview",e)}async setPreviewIdMap(t,e){this.syncSetPreviewIdMap(t,e),await this.db.write()}getPreviewSegmentName=(t,e)=>{const a=`preview_${e}_${t}`;if(this.segmentNames[a])return this.segmentNames[a];const i=`p-${u(`preview-${e}-${this.md5}-${t}`)}`;return this.segmentNames[a]=i,i};async calculatePartList(t,e){const a=[],i=await this.getCurrentFileIndex(t);for(let s=0;s<i+1;s++){const i=this.getPartName(t,s),r=this.getPartPath(t,s),o=await Q(r),n=await this.getPartInfo({host_type:t,filename:i,filepath:r,index:s,start:0,end:o-1},e);a.push(n)}return a}getPartListKey(t){return`preview_${t}_part_list`}async completePartList(t){const e=await this.getPartList(t);if(e){const a=[];for(const i of e)if(i.md5)a.push(i);else{const e=await this.getPartInfo({filename:i.file,filepath:i.path,start:i.start,end:i.end,host_type:t,index:i.index},!0);a.push(e)}await this.setPartList(t,a)}}async getPartList(t){const e=this.getPartListKey(t),a=this.preview_common_db_data[e];if(a)return a}async setPartList(t,e){const a=this.getPartListKey(t);this.preview_common_db_data[a]=e,await this.db.write()}async attachCacheData(){const{hosts:t}=this.params;for(const e of t)await this.attachHostCacheData(e),await this.completePartList(e)}getCacheInfo(t){const e=`preview_${t}_cache_info`;return this.preview_common_db_data[e]}async writeCacheFile(t,e){const a=`preview_${t}_cache_info.txt`,i=H(this.params.outputRoot,a);await Z(i,e,"utf-8");return{file_path:i,size:await Q(i)}}async setCacheInfo(t,e){const a=`preview_${t}_cache_info`;this.preview_common_db_data[a]=e,await this.db.write()}async attachHostCacheData(t){if(this.getCacheInfo(t))return;const e=await this.getPartList(t),a=this.getPreviewIdMap(t),{file_path:r,size:o}=await this.writeCacheFile(t,JSON.stringify(a)),h=this.getSizeLimit(t);if(e.length){const a=e[e.length-1],{path:c,size:u,file:p,index:g,end:m}=a;let w;if(u+o<=h){await async function({filepath:t,size:e},a){(await n(t)).size>e&&await d(t,e);const r=i(a),o=s(t,{flags:"a"});await l(r,o)}({filepath:c,size:u},r);const a=await Q(c),h=await this.getPartInfo({host_type:t,filename:p,filepath:c,index:g,start:0,end:a-1});e[e.length-1]=h;const f=m+1,_=m+o;w={id:await this.getPreviewId({file:p,start:f,end:_}),file:p,start:f,end:_}}else{const a=g+1,i=this.getPartName(t,a),s=this.getPartPath(t,a);await W(r,s);const n=await this.getPreviewId({file:i,start:0,end:o-1}),h=await this.getPartInfo({host_type:t,filename:i,filepath:s,index:a,start:0,end:o-1},!1);e.push(h),await this.setPartList(t,e),w={id:n,file:i,start:0,end:o-1}}w&&await this.setCacheInfo(t,w)}}},tt=class extends Y{content_size_1=81920;content_size_2=102400;totalPage=1;hashBuffer=Buffer.from("dpan");get hashBufferLength(){return this.hashBuffer.length}getU8FileName(){return`text_utf8_${this.params.id}.txt`}getU8FilePath(){return U(this.params.outputRoot,this.getU8FileName())}async sendProgress(t){await this.postProgress({type:J.transcode_txt,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.dbData.txt_result)return await this.sendProgress(1),this.dbData.txt_result;await this.txtConvertToUtf8File(),await this.sendProgress(.2);const{length:t}=this.params.hosts;for(let e=0;e<t;e++){const a=this.params.hosts[e];await this.txtConvertToGzipFile(a),await this.sendProgress(.2+(e+1)/t*.6)}await this.attachCacheData();const e=await this.getResult();return await this.clean(),await this.sendProgress(1),e}catch(t){throw K(t,{message:"Error occurred during txt encoding",detail:`Error occurred during txt encoding: ${this.params.input.filepath}`})}}async getResult(){if(this.txtResult)return this.txtResult;const t={meta:{pad:this.hashBufferLength,pages:this.totalPage},data:{}};for(const e of this.params.hosts)t.data[e]={cache:this.getCacheInfo(e),parts:await this.getPartList(e),entrance:await this.getEntranceInfo(e)};return await this.setTxtResult(t),t}async clean(){try{if(this.params.debug)return;const t=this.getU8FilePath();await B(t)}catch(t){}}async setEntranceInfo(t,e){const a=`txt_${t}_entrance`;this.dbData[a]=e,await this.db.write()}async getEntranceInfo(t){const e=`txt_${t}_entrance`,a=this.dbData[e];if(a)return a}async txtConvertToUtf8File(){if(this.dbData.txt_utf8_converted)return;const t=this.params.input.filepath,e=this.getU8FilePath();await X(t,e),this.dbData.txt_utf8_converted=!0,await this.db.write()}async txtConvertToGzipFile(t){if(await this.getEntranceInfo(t))return;const e=this.getSizeLimit(t),a=this.getU8FilePath(),i=await this.calculateSlice(),{length:s}=i,r={};let o=0,n=V(this.getPartPath(t,await this.getCurrentFileIndex(t)));for(let h=0;h<s;h++){const d=h==s-1?0:h+1,c=i[d],{index:l,start:u,end:p}=c,g={page:l+1,text:(await j(a,u,p)).toString("utf8")},m=JSON.stringify(g);let w=Buffer.from(m,"utf8");if(0==d){const t={...g,map:r};w=Buffer.from(JSON.stringify(t),"utf8")}const f=await this.getPreviewId({file:"u8zip",start:u,end:p});await new Promise((a,i)=>{q.gzip(w,async(s,h)=>{if(s)return i(s);const c=h.length<this.hashBufferLength?this.hashBuffer:h.subarray(0,this.hashBufferLength),l=Buffer.concat([c,h]),u=l.length;if(o+u>e){n.end();const e=await this.increaseCurrentFileIndex(t);n=V(this.getPartPath(t,e)),o=0}const p=o,g=o+u-1;if(n.write(l),o+=u,0==d){n.end();const e={id:f,start:p,end:g,file:this.getPartName(t,await this.getCurrentFileIndex(t))};await this.setEntranceInfo(t,e)}else r[`p_${d+1}`]={id:f,f:this.getPartName(t,await this.getCurrentFileIndex(t)),s:p,e:g};this.syncSetPreviewIdMap({id:f,file:this.getPartName(t,await this.getCurrentFileIndex(t)),start:p,end:g},t),a(!0)})})}await this.db.write();const h=await this.calculatePartList(t,!1);await this.setPartList(t,h)}async calculateSlice(){if(this.dbData.txt_slice_list)return this.dbData.txt_slice_list;const t=this.getU8FilePath(),e=await new Promise((e,a)=>{G(t,"utf8",(t,i)=>{if(t)return void a(t);const s=this.content_size_1,r=this.content_size_2,o=[];let n=0,h=0,d=0;for(;h<i.length;){let t=Math.min(h+r,i.length);const e=Math.min(h+s,i.length),a=i.slice(e,t-1).indexOf("#");-1!==a&&(t=e+a);const c=i.slice(h,t),l=Buffer.byteLength(c);o.push({index:n++,start:d,end:d+l-1}),this.totalPage=n,h=t,d+=l}e(o)})});return this.dbData.txt_slice_list=e,await this.db.write(),e}};import{resolve as et}from"path";import{getMetadata as at,compress as it}from"@soga/imgutils";import{gzip as st}from"@soga/utils";import{getFileSize as rt}from"@soga/fileutils";import{buildDError as ot}from"@soga/error";import{UploadProgress as nt}from"@soga/node-types";import{remove as ht}from"fs-extra";var dt=class extends Y{getCompressFileName(){return"img_compress.jpg"}getCompressFilePath(){return et(this.params.outputRoot,this.getCompressFileName())}getGzFileName(){return"compressed_img.zip"}getGzFilePath(){return et(this.params.outputRoot,this.getGzFileName())}async sendProgress(t){await this.postProgress({type:nt.transcode_img,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.imgResult)return await this.sendProgress(1),this.imgResult;await this.compress(),await this.sendProgress(.1),await this.gzip(),await this.sendProgress(.4);const{hosts:t}=this.params,{length:e}=t;for(let a=0;a<e;a++){const e=t[a];await this.splitFile(e),await this.calculatePartList(e,!1)}await this.attachCacheData(),await this.sendProgress(.9);const a=await this.getResult();return await this.clean(),await this.sendProgress(1),a}catch(t){throw ot(t,{message:"Error occurred during image encoding",detail:`Error occurred during image encoding: ${this.params.input.filepath}`})}}getCacheInfoFileName(t){return`img_${t}_cache.json`}async getResult(){if(this.imgResult)return this.imgResult;const{input:t}=this.params,e=t.filepath,{width:a,height:i}=await at(e),s=this.getCompressFilePath(),{width:r,height:o}=await at(s),n=await rt(s),h={meta:{width:a,height:i,size:t.filesize,t_width:r,t_height:o,t_size:n},data:{}},{length:d}=this.params.hosts;for(let t=0;t<d;t++){const e=this.params.hosts[t],a=await this.getPartList(e),i=this.getPreviewList(e);h.data[e]={img:{preview:i},cache:this.getCacheInfo(e),parts:a}}return await this.setImgResult(h),h}async clean(){try{if(this.params.debug)return;const t=this.getCompressFilePath();await ht(t)}catch(t){}}async compress(){if(this.dbData.img_compressed)return;const t=this.getCompressFilePath();await it({ffmpeg_path:this.params.ffmpegPath,input_path:this.params.input.filepath,output_path:t}),this.dbData.img_compressed=!0,await this.db.write()}async gzip(){if(this.dbData.img_gziped)return;const t=this.getCompressFilePath(),e=this.getGzFilePath();await st(t,e),this.dbData.img_gziped=!0,await this.db.write()}async setPreviewList(t,e){const a=`img_${t}_preview_list`;this.dbData[a]=e,await this.db.write()}getPreviewList(t){const e=`img_${t}_preview_list`;return this.dbData[e]}async splitFile(t){if(this.getPreviewList(t))return;const e=this.getGzFilePath(),a=await rt(e),i=this.getSizeLimit(t),s=[],r=[];for(let o=0;o<=a-1;o+=i){0!=o&&await this.increaseCurrentFileIndex(t);const n=Math.min(o+i-1,a-1),h=await this.getCurrentFileIndex(t),d=this.getPartName(t,h),c=this.getPartPath(t,h);await w({input_path:e,target_path:c,start:o,end:n});const l=0,u=n-o,p=await this.getPartInfo({host_type:t,filepath:c,filename:d,start:l,end:u,index:h},!1);s.push(p);const g=await this.getPreviewId({file:d,start:l,end:u});r.push({id:g,file:d,start:l,end:u}),await this.setPreviewIdMap({id:g,file:d,start:l,end:u},t)}await this.setPartList(t,s),await this.setPreviewList(t,r)}};import ct from"fluent-ffmpeg";import{spawn as lt}from"child_process";import{parseMediaInfo as ut}from"@soga/mediainfo";var pt=class extends Y{async getMediainfo(){const{mediainfo:t}=this.db.data;if(t)return t;const e=this.params.input.filepath,a=await ut(e);return this.db.data.mediainfo=a,await this.params.db.write(),a}constructor(t){super(t),ct.setFfmpegPath(t.ffmpegPath)}getFluent(){return ct()}async ffmpeg(t,e){const a=this.params.ffmpegPath;return await new Promise((i,s)=>{const r=lt(a,t,Object.assign({stdio:"ignore"},e));r.on("close",t=>{i(t)}),r.on("error",t=>{s(t)})})}};import{resolve as gt}from"path";import{isValidFile as mt,isVideoSupport as wt}from"@soga/fileutils";import{UploadProgress as ft}from"@soga/node-types";import{buildDError as _t}from"@soga/error";var yt=({type:t,track_order:e,quality:a})=>`audio-${e}-${a}-${t}.${"manifest"===t?"m3u8":"mp4"}`,bt=({width:t,height:e})=>`video-formatted-${t}-${e}.mp4`,vt=t=>`grouper_result_${t}`,Pt=t=>{let e=0,a=0,i=0;t.segments.forEach(t=>{a+=t.duration,e+=t.size;const s=8*t.size/t.duration;s>i&&(i=s)});const s=8*e/a;return{bandwidth:Math.ceil(i),average_bandwidth:Math.ceil(s)}},xt=(t,e)=>{if("number"==typeof t.percent)return t.percent/100;return function(t){const e=t.split(":").map(parseFloat),[a=0,i=0,s=0]=e.reverse();return 3600*s+60*i+a}(t.timemark)/e};var Dt=class extends pt{async start(){try{await this.separateVideo(),await this.postProgress({type:ft.separate_video,percent:1})}catch(t){throw _t(t,{message:"Error occurred during video separation",detail:`Error occurred during video separation: ${this.params.input.filepath}`})}}async separateVideo(){const t="video_separated";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],i=bt({width:a.width,height:a.height}),s=gt(this.params.outputRoot,i),r=wt(a.codec),o=["-sn","-an","-map","0:v:0"];let n="copy";r||(n=a.width*a.height>=2073600?"libx265":"libx264","libx265"==n&&o.push("-pix_fmt","yuv420p")),o.push("-c:v",n);const h=a.duration;o.push("-y"),await new Promise((t,e)=>{const a=this.getFluent().input(this.params.input.filepath).outputOptions(o).on("progress",async t=>{if(!r&&t.frames){const e=xt(t,h);await this.postProgress({type:ft.separate_video,percent:e})}}).on("end",async()=>{t("end"),a.kill("SIGKILL")}).on("error",async t=>{e(t)}).output(s);a.run()});if(!await mt(s))throw new Error("Separate Video track failed");this.db.data[t]=!0,await this.params.db.write()}};import{resolve as Tt}from"path";import{isValidFile as zt,isAudioAdapt as Rt,isAudioHigh as It}from"@soga/fileutils";import{UploadProgress as Mt}from"@soga/node-types";import{buildDError as $t}from"@soga/error";var St=class extends pt{async start(){try{await this.separateTracks(),await this.postProgress({type:Mt.separate_audio,percent:1})}catch(t){throw $t(t,{message:"Error occurred during audio separation",detail:`Error occurred during audio separation: ${this.params.input.filepath}`})}}async separateTracks(){if(this.audioSeparatorResult)return;const t=await this.getMediainfo();if(!t?.audio?.length)return;const{audio:e}=t,a=e.length,i=[];for(let t=0;t<a;t++){const s=e[t],{codec:r,channels:o,lossless:n}=s,h={adapt:{need:!0,codec:"",channels:Math.min(o,2)},high:{need:!1,codec:"flac",channels:0}};Rt(r)?o>2?(h.high.need=!0,h.high.codec="copy",h.adapt.codec=r,h.adapt.need=!0):(h.adapt.need=!0,h.adapt.codec="copy",h.adapt.channels=0):It(r)?(h.high.need=!0,h.high.codec="copy",h.adapt.need=!0,h.adapt.codec="aac"):(h.adapt.need=!0,h.adapt.codec="aac",n&&(h.high.need=!0,h.high.codec="flac")),h.adapt.need&&await this.separateAudioTrack(t,{type:"adapt",codec:h.adapt.codec,tracks:a,channels:h.adapt.channels,need_adapt:!0,need_high:h.high.need}),h.high.need&&await this.separateAudioTrack(t,{type:"high",codec:h.high.codec,tracks:a,channels:h.high.channels,need_adapt:h.adapt.need,need_high:!0}),i.push(h)}await this.setAudioSeparatorResult(i)}async separateAudioTrack(t,e){const a=`audio_separated_${t}_${e.type}`;if(this.db.data[a])return;const i=await this.getMediainfo();if(!i?.audio?.length)return;const s=i.audio[t];if(!s)return;const r=s?.duration??i.general?.duration,o=yt({type:"formatted",track_order:t,quality:e.type}),n=Tt(this.params.outputRoot,o),h=["-sn","-vn","-map",`0:a:${t}`];e.codec&&h.push("-c:a",e.codec),e.channels&&h.push("-ac",e.channels.toString()),h.push("-y"),await new Promise((a,i)=>{const s=this.getFluent().input(this.params.input.filepath).outputOptions(h).on("progress",async a=>{if("copy"!=e.codec){const i=xt(a,r);let s=t;"adapt"==e.type?e.need_high?s+=1/3*i:s+=i:e.need_adapt?(s+=1/3,s+=2/3*i):s+=i;const o=s/e.tracks;await this.postProgress({type:Mt.separate_audio,percent:o})}}).on("end",async()=>{a("end"),s.kill("SIGKILL")}).on("error",async t=>{i(t)}).output(n);s.run()});if(!await zt(n))throw new Error(`Separate audio track failed: [track_order:${t}, track_quality ${e.type}] `);if("copy"==e.codec){let a=t;"adapt"==e.type&&e.need_high?a+=1/3:a+=1;const i=a/e.tracks;await this.postProgress({type:Mt.separate_audio,percent:i})}this.db.data[a]=!0,await this.params.db.write()}};import{resolve as kt}from"path";import{parseMediaInfo as Ft}from"@soga/mediainfo";import{getMp4boxInfo as Et}from"@soga/mp4box";import{parseM3U8 as Nt}from"@soga/m3u8";import{UploadProgress as Lt}from"@soga/node-types";import{isValidFile as Ct,getStandardInfo as At}from"@soga/fileutils";import{remove as Ot}from"fs-extra";import{buildDError as Ut}from"@soga/error";var Vt=class extends pt{getVideoInitName({width:t,height:e}){return`video-init-${t}-${e}.mp4`}getVideoManifestName({width:t,height:e}){return`video-hls-${t}-${e}.m3u8`}async start(){try{await this.transcodeVideo(),await this.saveData(),await this.postProgress({type:Lt.transcode_video,percent:1})}catch(t){throw Ut(t,{message:"Error occurred during video transcoding",detail:`Error occurred during video transcoding: ${this.params.input.filepath}`})}}async saveData(){const t=await this.getMediainfo();if(!t?.video?.length)return;if(this.videoTranscoderResult)return;const{width:e,height:a}=t.video[0],i=bt({width:e,height:a}),s=kt(this.params.outputRoot,i),r=this.getVideoManifestName({width:e,height:a}),o=kt(this.params.outputRoot,r),n=await Nt(o),{videos:h}=await Et(s),{codec:d}=h[0],{bandwidth:c,average_bandwidth:l}=Pt(n),u=(await Ft(s)).video[0],p=At(e,a),g={m3u8:n,m3u8_path:o,codec:d,width:e,height:a,bandwidth:c,average_bandwidth:l,bitdepth:u?.bitdepth,bitrate:u?.bitrate,codec_name:u?.codec??"",framerate:u?.framerate,label:p?.label??"unknown"};await this.setVideoTranscoderResult(g),this.params.debug||await Ot(s)}async transcodeVideo(){const t="video_transcode_state";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],i={width:a.width,height:a.height},s=bt(i),r=this.getVideoInitName(i),o=this.getVideoManifestName({width:a.width,height:a.height}),n=["-i",s,"-an","-sn","-c:v","copy","-hls_list_size","0","-hls_time","6","-hls_segment_type","fmp4","-hls_fmp4_init_filename",r,"-y",o];await this.ffmpeg(n,{cwd:this.params.outputRoot});const h=kt(this.params.outputRoot,o);if(!await Ct(h))throw new Error("Transcode video track failed");this.db.data[t]=!0,await this.db.write()}};import{resolve as Gt}from"path";import{getFileSize as Bt,isValidFile as jt}from"@soga/fileutils";import{getMp4boxInfo as qt}from"@soga/mp4box";import{parseM3U8 as Xt}from"@soga/m3u8";import{parseMediaInfo as Kt}from"@soga/mediainfo";import{remove as Jt}from"fs-extra";import{buildDError as Ht}from"@soga/error";import{UploadProgress as Qt}from"@soga/node-types";var Wt=class extends pt{async start(){try{await this.transcodeAudios(),await this.saveData()}catch(t){throw Ht(t,{message:"Error occurred during audio transcoding",detail:`Error occurred during audio transcoding: ${this.params.input.filepath}`})}}async saveData(){if(this.audioTranscoderResult)return;const t=await this.getMediainfo();if(!t?.audio?.length)return;const e=t.audio.length,a=this.audioSeparatorResult,i=[],s={};for(let t=0;t<e;t++){const e=a[t];e.adapt.need&&(s.adapt=await this.getQualityData({track_order:t,quality:"adapt"})),e.high.need&&(s.high=await this.getQualityData({track_order:t,quality:"high"})),i.push(s)}await this.setAudioTranscoderResult(i);try{if(this.params.debug)return;for(let t=0;t<e;t++){const e=a[t];if(e.adapt.need){const e=yt({type:"formatted",track_order:t,quality:"adapt"}),a=Gt(this.params.outputRoot,e);await Jt(a)}if(e.high.need){const e=yt({type:"formatted",track_order:t,quality:"high"}),a=Gt(this.params.outputRoot,e);await Jt(a)}}}catch(t){}}async getQualityData({track_order:t,quality:e}){const a=yt({type:"formatted",track_order:t,quality:e}),i=Gt(this.params.outputRoot,a),s=await Kt(i);if(!s.audio?.length)throw new Error("parse mediainfo failed!");const r=s.audio[0],o=yt({type:"manifest",track_order:t,quality:e}),n=await Bt(i),h=Gt(this.params.outputRoot,o),d=await qt(i),{audios:c}=d,{language:l,codec:u}=c[0],p=l&&!l.startsWith("un")?{language:l}:void 0,g=await Xt(h),{bandwidth:m,average_bandwidth:w}=Pt(g);return{m3u8:g,m3u8_path:h,codec:u,codec_name:r.codec,...p,order:t,lossless:r.lossless,channels:r.channels,bandwidth:m,size:n,average_bandwidth:w}}async transcodeAudios(){const t="audio_transcoded";if(this.db.data[t])return;const e=await this.getMediainfo();if(!e?.audio?.length)return;const a=e.audio.length,i=this.audioSeparatorResult;for(let t=0;t<a;t++){const e=i[t];e.adapt.need&&await this.transcodeAudio(t,{...e.adapt,type:"adapt"}),e.high.need&&await this.transcodeAudio(t,{...e.high,type:"high"});const s=(t+1)/a;await this.postProgress({type:Qt.transcode_audio,percent:s})}await this.postProgress({type:Qt.transcode_audio,percent:1}),this.db.data[t]=!0,await this.db.write()}async transcodeAudio(t,e){const a=`audio-transcoded-${t}-${e.type}`;if(this.db.data[a])return;const i=yt({type:"formatted",track_order:t,quality:e.type}),s=yt({type:"init",track_order:t,quality:e.type}),r=yt({type:"manifest",track_order:t,quality:e.type}),o=["-i",i,"-vn","-sn","-c:a","copy","-hls_list_size","0","-hls_time","6","-hls_segment_type","fmp4","-hls_fmp4_init_filename",s,"-y",r];await this.ffmpeg(o,{cwd:this.params.outputRoot});const n=Gt(this.params.outputRoot,r);if(!await jt(n))throw new Error(`Transcode audio track failed: [track_order:${t}, track_quality ${e.type}] `);this.db.data[a]=!0,await this.db.write()}};import{resolve as Zt}from"path";import{getFileSize as Yt}from"@soga/fileutils";import{combine as te}from"@soga/imgutils";import{copy as ee}from"fs-extra";import{UploadProgress as ae}from"@soga/node-types";import{buildDError as ie}from"@soga/error";var se=class extends pt{m3u8_data=null;thumbnail_duration=30;thumbnail_group=[];row=8;col=8;screenshot_width=480;screenshot_height=270;getScreenshotName(t){return`video_screenshot_${t}.jpg`}getTileName(t){return`video_tile_${t}.jpg`}getCoverName(){return"video_cover.jpg"}async updateImagePercent(t,e){const a="screenshot"==e?6*t/7:t/7+6/7;await this.postProgress({type:ae.transcode_thumbnail,percent:a})}store;async initStore(){this.store=await this.getStore("thumbnail_store.json")}async start(){if(!this.videoThumbnailerResult)try{const t=await this.getMediainfo();if(!t?.video?.length)return;if(await this.init(),!this.m3u8_data)return;await this.generateScreenshots(),await this.generateTiles(),await this.saveCoverInfo(),await this.saveThumbnailInfo()}catch(t){throw ie(t,{message:"Error occurred during video thumbnail generation",detail:`Error occurred during video thumbnail generation: ${this.params.input.filepath}`})}}async init(){await this.initStore(),await this.initScreenshotSize(),await this.initM3U8Data(),await this.initThumbnailDuration(),await this.initThumbnailGroup()}async saveThumbnailInfo(){if(this.videoThumbnailerResult)return;const{col:t,row:e,thumbnail_group:a,screenshot_width:i,screenshot_height:s}=this,r=a.length,o=[],n=[];for(let h=0;h<r;h++){const r=a[h],d=r.start_time,c=r.end_time,l=Math.floor(h/(e*t)),u=h%e*i,p=Math.floor(h%(t*e)/e)*s,g=this.getTileName(l);n.push(g),o.push({file:g,st:d,et:c,x:u,y:p,w:i,h:s})}const h=[...new Set(n)],d=h.length,c=[];for(let t=0;t<d;t++){const e=h[t],a=Zt(this.params.outputRoot,e),i=await Yt(a);c.push({file:e,file_path:a,size:i})}const l={width:this.screenshot_width,height:this.screenshot_height,row:this.row,col:this.col,tile_list:c,sprite_list:o};await this.setVideoThumbnailerResult(l)}async saveCoverInfo(){if(this.coverResult)return;const t=this.store.data.thumbnail_screenshot_largest,e=t?.index||0,{screenshot_width:a,screenshot_height:i}=this,s=this.getScreenshotName(e),r=Zt(this.params.outputRoot,s),o=this.getCoverName(),n=Zt(this.params.outputRoot,o);await ee(r,n);const h={file:o,path:n,size:await Yt(n),width:a,height:i};await this.setCoverResult(h)}async generateTiles(){const t=this.store.data.thumbnail_tile_index||0,{length:e}=this.thumbnail_group,a=this.col*this.row,i=Math.ceil(e/a);for(let e=t;e<i;e++)await this.generateOneTile(e),await this.updateImagePercent((e+1)/i,"tile")}async generateOneTile(t){const{col:e,row:a}=this,i=this.thumbnail_group.length,s=a*e,r=t*s,o=Math.min(s,i-r),n=[];for(let t=0;t<o;t++){const e=this.getScreenshotName(r+t),a=Zt(this.params.outputRoot,e);n.push(a)}const h=this.getTileName(t),d=Zt(this.params.outputRoot,h);await this.createSpriteSheet(n,d),this.store.data.thumbnail_tile_index=t+1,await this.store.write()}async createSpriteSheet(t,e){await te({col:this.col,inputs:t,output_path:e,width:this.screenshot_width,height:this.screenshot_height})}getKeyFrameParams(t,e=0){if(t<1)return["-vframes","1"];{const a=Math.max(t-e-.3,.1);if(a<1)return["-vframes","1"];return["-ss",`${a.toFixed(3)}`,"-vframes","1"]}}async generateScreenshots(){if(this.store.data.thumbnail_screenshot_state)return;this.store.data.thumbnail_screenshot_index||=0;const t=this.store.data.thumbnail_screenshot_index,e=this.store.data.thumbnail_screenshot_largest,a={index:0,size:0};if(e){const t=e;a.index=t.index,a.size=t.size}const{segments:i}=this.m3u8_data,{thumbnail_group:s,screenshot_width:r}=this,{length:o}=s,n=async(t,{errorTimes:e,fixedSeconds:o})=>{const h=s[t].item.index,d=i[h];try{const e=this.getScreenshotName(t),i=`concat:${d.init_uri}|${d.uri}`,s=this.getKeyFrameParams(d.duration,o),n=r>this.screenshot_height?`${r}:-2`:`-2:${this.screenshot_height}`,h=["-i",i,...s,"-vf",`scale=${n}:flags=lanczos`,"-y",e];await this.ffmpeg(h,{cwd:this.params.outputRoot});const c=Zt(this.params.outputRoot,e),l=await Yt(c);if(0===l)throw new Error(`Generate video thumbnail error: [index: ${t}, start_time: ${d.start_time}, end_time: ${d.end_time}]`);l>=a.size&&(a.index=t,a.size=l,this.store.data.thumbnail_screenshot_largest=a,await this.store.write()),this.store.data.thumbnail_screenshot_index=t+1,await this.store.write()}catch(a){const i=Math.max(10,d.duration);if(!(e<3))throw a;await n(t,{errorTimes:e+1,fixedSeconds:o+i/5})}};for(let e=t;e<o;e++)await n(e,{errorTimes:0,fixedSeconds:0}),await this.updateImagePercent((e+1)/o,"screenshot");this.store.data.thumbnail_screenshot_state=!0,await this.store.write()}async initScreenshotSize(){const{thumbnail_screenshot_size:t}=this.store.data;if(t)return this.screenshot_width=t.width,void(this.screenshot_height=t.height);const e=await this.getMediainfo();if(!e?.video?.length)return;const a=e.video[0],{width:i,height:s}=a,r=i>s?480:270;this.screenshot_width=2*Math.floor(Math.min(r,i)/2),this.screenshot_height=2*Math.floor(this.screenshot_width*(s/i)/2),this.store.data.thumbnail_screenshot_size={width:this.screenshot_width,height:this.screenshot_height}}async initThumbnailGroup(){if(this.store.data.thumbnail_group)return void(this.thumbnail_group=this.store.data.thumbnail_group);const t=[],{segments:e}=this.m3u8_data,{length:a}=e,i=this.thumbnail_duration;let s=0,r=[];for(let o=0;o<a;o++){const n=e[o];if(s+=n.duration,r.push(n),s>=i||o===a-1){const e=r.length,a=r[0],i=r[e-1];t.push({duration:s,start_time:a.start_time,end_time:i.end_time,items:r,item:i}),s=0,r=[]}}if(t.length>1){if(t[t.length-1].duration<1){const e=t.pop(),a=t[t.length-2];a.duration=a.duration+e.duration,a.end_time=e.end_time,a.items=a.items.concat(e.items),a.item=e.item,e.items}}t.forEach(t=>{const{items:e}=t;for(let a=e.length-1;a>=0;a--)if(e[a].duration>1){t.item=e[a];break}}),this.thumbnail_group=t,this.store.data.thumbnail_group=t,await this.store.write()}getVideoM3U8Info(){return this.videoTranscoderResult?.m3u8}async initM3U8Data(){this.m3u8_data=this.getVideoM3U8Info()}async initThumbnailDuration(){if(this.store.data.thumbnail_duration)return this.thumbnail_duration=this.store.data.thumbnail_duration,this.thumbnail_duration;let t=30;const e=await this.getMediainfo(),a=e?.video;if(!a?.length)return t;const i=a[0],s=i.duration||e?.general?.duration,{width:r,height:o}=i;r*o>=518400&&(t=10),r*o>=921600&&(t=20),r*o>=2073600&&(t=30),r*o>=3686400&&(t=40),r*o>=8294400&&(t=60);const n=s??0;if(n&&(n<60&&(t=0),n<300&&(t=Math.ceil(t/4)),n<600&&(t=Math.ceil(t/2)),n>3600)){const e=n/3600;t=Math.ceil(t*e)}return t=Math.min(60,t),this.thumbnail_duration=t,this.store.data.thumbnail_duration=t,await this.store.write(),t}};import{resolve as re}from"path";import{pathExists as oe}from"fs-extra";import{getMetadata as ne}from"@soga/imgutils";import{getFileSize as he}from"@soga/fileutils";import{UploadProgress as de}from"@soga/node-types";import{buildDError as ce}from"@soga/error";var le=class extends pt{get cover_name(){return"audio_cover.png"}async start(){try{await this.generateCover(),this.isAudio&&await this.postProgress({type:de.transcode_thumbnail,percent:1})}catch(t){throw ce(t,{message:"Error occurred during audio cover generation",detail:`Error occurred during audio cover generation: ${this.params.input.filepath}`})}}async generateCover(){const t=await this.getMediainfo();if(t.video?.length)return;const e="audio-covered";try{if(this.coverResult)return this.coverResult;if(this.db.data[e])return;const{cover_name:t}=this,a=["-i",this.params.input.filepath,"-map","0:v","-y",t];await this.ffmpeg(a,{cwd:this.params.outputRoot});const i=re(this.params.outputRoot,t),s=await oe(i),r=await ne(i);if(s){const e={file:t,path:i,size:await he(i),width:r.width??0,height:r.height??0};await this.setCoverResult(e)}}catch(t){throw t}finally{this.db.data[e]=!0,await this.db.write()}}};import{parse as ue,resolve as pe}from"path";import{getFileLanguage as ge,isUtf8File as me,saveFileAsUtf8 as we,gzip as fe}from"@soga/utils";import{isValidFile as _e,getFileSize as ye,isValidPath as be}from"@soga/fileutils";import{copy as ve}from"fs-extra";import{buildDError as Pe}from"@soga/error";import{UploadProgress as xe}from"@soga/node-types";var De=class extends pt{builtin_tracks=0;external_tracks=0;get tracks(){return this.builtin_tracks+this.external_tracks}async sendProgress(t){await this.postProgress({type:xe.separate_subtitle,percent:t})}get dbData(){return this.db.data}async start(){try{if(this.subtitleEncoderResult)return;const t=await this.getMediainfo();if(this.builtin_tracks=t?.text?.length||0,this.external_tracks=this.params.subtitles?.length||0,!this.tracks)return await this.setSubtitleEncoderResult([]),void await this.sendProgress(1);const e=await this.parseBuiltinTextTracks();await this.sendProgress(this.builtin_tracks/this.tracks);const a=await this.parseExternalTextTracks(),i=[...e,...a];await this.setSubtitleEncoderResult(i),await this.sendProgress(1)}catch(t){throw Pe(t,{message:"Error occurred while process subtitle track",detail:`Error occurred while process subtitle track: ${this.params.input.filepath}`})}}async parseBuiltinTextTracks(){const t=await this.getMediainfo(),e=t?.text;if(!e?.length)return[];const{subtitle_builtin_tracks:a}=this.dbData;if(a)return a;const i=e.length,s=[];for(let t=0;t<i;t++){const e=await this.parseBuiltinTextTrack(t);e&&s.push(e),await this.sendProgress((t+1)/this.tracks)}return this.dbData.subtitle_builtin_tracks=s,await this.params.db.write(),s}async parseBuiltinTextTrack(t){const e=this.params.outputRoot,a=`subtitle-builtin-${t}.zip`,i=pe(e,a),s=`subtitle-temp-${t}.vtt`,r=pe(e,s),o=pe(e,`subtitle-builtin-u8-${t}.vtt`),n=["-i",this.params.input.filepath,"-vn","-an","-map",`0:s:${t}`,"-c","webvtt","-y",s];await this.ffmpeg(n,{cwd:this.params.outputRoot});if(await _e(r)){if(await me(r))await ve(r,o);else{await we(r,o);await _e(o)||await ve(r,o)}const e=await ge(o),{label:s,lang:n}=e;await fe(o,i);return{file:a,file_path:i,size:await ye(i),lang:n,name:s||`builtin_${t+1}`,title:s||`builtin_${t+1}`,builtin:!0,source:null}}return!1}async parseExternalTextTracks(){const{subtitles:t}=this.params;if(!t?.length)return[];const{subtitle_external_tracks:e}=this.dbData;if(e)return e;const a=[],i=t.length;for(let e=0;e<i;e++){const i=await this.parseExternalTextTrack(e,t[e]);i&&a.push(i),await this.sendProgress((this.builtin_tracks+(e+1))/this.tracks)}return this.dbData.subtitle_external_tracks=a,await this.params.db.write(),a}async parseExternalTextTrack(t,e){const{ext:a}=ue(e),i=this.params.outputRoot,s=`subtitle-external-${t}.vtt`,r=pe(i,s),o=`subtitle-external-${t}.zip`,n=pe(i,o),h=pe(i,`subtitle-external-u8-${t}${a}`),d=`subtitle-external-source-${t}.zip`,c=pe(i,d);if(!await be(e))return!1;if(await me(e))await ve(e,h);else{await we(e,h);if(!await _e(h))return!1}const l=["-i",h,"-c","webvtt","-y",s];await this.ffmpeg(l,{cwd:this.params.outputRoot});if(await _e(r)){const i=await ge(r),{label:s,lang:h}=i;await fe(e,c),await fe(r,n);const l=await ye(c);return{file:o,size:await ye(n),file_path:n,lang:h,name:s||`external_${t+1}`,title:s||`external_${t+1}`,builtin:!1,source:{file:d,file_path:c,size:l,ext:a}}}return!1}};import{buildDError as Te}from"@soga/error";import{resolve as ze}from"path";import{writeFile as Re}from"fs-extra";import{UploadProgress as Ie}from"@soga/node-types";import{getFileSize as Me}from"@soga/fileutils";import{gzip as $e,getFileBufferSlice as Se}from"@soga/utils";import{buildDError as ke}from"@soga/error";import{resolve as Fe}from"path";import{getFileSize as Ee}from"@soga/fileutils";var Ne=class extends pt{hostType;safe_index=0;file_map={};completed_percent=0;total_percent=0;store;async initStore(t){this.store=await this.getStore(`${t}_grouper_store.json`)}getFileName=t=>this.getPreviewSegmentName(t,this.hostType);getGroupedVideoManifestName(t){return`grouper_video_${this.hostType}_${t}.m3u8`}getAudioManifestName(t,e){return`grouper_audio_${this.hostType}_${e}_${t}.m3u8`}getThumbnailInfoFilename(){return`grouper_thumbnail_${this.hostType}.json`}getCacheInfoFilename(){return`grouper_cache_${this.hostType}.json`}constructor(t){super(t),this.hostType=t.host_type,this.completed_percent=t.completed_percent,this.total_percent=1/t.hosts.length}async generateSafeFile(t){return await async function(t){const e=`safe_${t.type}_${t.file_index}.txt`,a=u(t.filesize),i=c(t.outputRoot,e);return await h(i,a),{file_path:i,size:a.length}}({type:t,file_index:this.safe_index++,outputRoot:this.params.outputRoot,filesize:this.params.input.filesize})}readAudioTracks(){return this.audioTranscoderResult??[]}readVideoTracks(){return this.videoTranscoderResult?[this.videoTranscoderResult]:[]}readThumbnailInfo(){return this.videoThumbnailerResult}readCoverInfo(){return this.coverResult}readSubtitleInfo(){return this.subtitleEncoderResult}async getPartData(){const t=this.store.data.grouper_part_names??[],e=[];for(let a=0;a<t.length;a++){const i=t[a],s=Fe(this.params.outputRoot,i),r=await Ee(s),o=await this.getPartInfo({host_type:this.hostType,filepath:s,start:0,end:r-1,filename:i});e.push(o)}return e}async getAudioData(){const t=this.readAudioTracks();if(!t?.length)return;const e=[];for(let a=0;a<t.length;a++){const i=t[a];if(i.adapt){const{average_bandwidth:t,bandwidth:s,channels:r,codec:o,codec_name:n,language:h,order:d}=i.adapt,c=this.getAudioManifestName("adapt",a),l=this.file_map[c],{file_index:u,start:p,end:g,size:m,hash:w}=l,f=this.getFileName(u),_=await this.getPreviewId({file:c});await this.setPreviewIdMap({id:_,file:f,start:p,end:g},this.hostType);const y={id:_,average_band:t,band:s,channels:r,codec:o,codec_name:n,language:h,order:d,file:f,start:p,end:g,size:m,hash:w};if(i.high){const{average_bandwidth:t,bandwidth:e,channels:s,codec:r,codec_name:o,language:n,order:h}=i.high,d=this.getAudioManifestName("high",a),c=this.file_map[d],{file_index:l,start:u,end:p,size:g,hash:m}=c,w=this.getFileName(l),f=await this.getPreviewId({file:d});await this.setPreviewIdMap({id:f,file:w,start:u,end:p},this.hostType),y.high={id:f,average_band:t,band:e,channels:s,codec:r,codec_name:o,language:n,order:h,file:w,start:u,end:p,size:g,hash:m}}e.push(y)}}return e}async getVideoData(){const t=this.readVideoTracks();if(!t?.length)return;const e=[];for(let a=0;a<t.length;a++){const i=t[a],s=this.getGroupedVideoManifestName(a),r=await this.getPreviewId({file:s}),o=this.file_map[s],{file_index:n,start:h,end:d,size:c,hash:l}=o,u=this.getFileName(n);await this.setPreviewIdMap({id:r,file:u,start:h,end:d},this.hostType);const{average_bandwidth:p,bandwidth:g,codec:m,width:w,height:f,label:_,codec_name:y,bitdepth:b,framerate:v}=i,P={id:r,average_band:p,band:g,codec:m,codec_name:y,bitdepth:b,framerate:Math.round(v),width:w,height:f,file:u,start:h,end:d,size:c,label:_,hash:l};e.push(P)}return e}async getSubtitleData(){const t=this.readSubtitleInfo();if(!t?.length)return;const e=[],{length:a}=t;for(let i=0;i<a;i++){const a=t[i],{builtin:s,file:r,lang:o,title:n,name:h,source:d}=a,c=this.file_map[r],{file_index:l,start:u,end:p,size:g}=c,m=this.getFileName(l),w={uuid:await this.getPreviewId({file:r,start:u,end:p}),builtin:s,lang:o,name:h,title:n,file:m,start:u,end:p,size:g};if(d){const{file:t,ext:e}=d,a=this.file_map[t],{file_index:i,start:s,end:r,size:o}=a,n=this.getFileName(i);w.source={size:o,file:n,start:s,end:r,ext:e}}e.push(w)}return e}async getThumbnailData(){const t=this.readThumbnailInfo();if(!t)return;const{row:e,col:a,width:i,height:s}=t,r=this.getThumbnailInfoFilename(),o=this.file_map[r],{file_index:n,start:h,end:d,size:c}=o,l=this.getFileName(n),u=await this.getPreviewId({file:r});await this.setPreviewIdMap({id:u,file:l,start:h,end:d},this.hostType);return{id:u,row:e,col:a,width:i,height:s,file:l,start:h,end:d,size:c}}async getCoverData(){const t=this.readCoverInfo();if(!t)return;const e=t,{file:a,width:i,height:s}=e,r=this.file_map[a],{file_index:o,start:n,end:h,size:d}=r,c=this.getFileName(o),l=await this.getPreviewId({file:e.path});await this.setPreviewIdMap({id:l,file:c,start:n,end:h},this.hostType);return{id:l,width:i,height:s,file:c,start:n,end:h,size:d}}async getCacheData(){const t=this.getCacheInfoFilename(),e=await this.getPreviewId({file:t}),a=this.file_map[t],{file_index:i,start:s,end:r,size:o}=a,n=this.getFileName(i);await this.setPreviewIdMap({id:e,file:n,start:s,end:r},this.hostType);return{id:e,file:n,start:s,end:r}}async saveData(){const t=vt(this.hostType);if(this.db.data[t])return;const e={},a=await this.getAudioData();a&&(e.audios=a);const i=await this.getVideoData();i&&(e.videos=i);const s=await this.getSubtitleData();s&&(e.subtitles=s);const r=await this.getThumbnailData();r&&(e.thumbnail=r);const o=await this.getCoverData();o&&(e.cover=o),e.parts=await this.getPartData(),e.cache=await this.getCacheData(),this.db.data[t]=e,await this.db.write()}},Le=class extends Ne{current_position=0;current_index=0;group_data=[];async start(){const t=vt(this.hostType);if(this.db.data[t])return this.db.data[t];try{return await this.initStore(this.hostType),await this.calculateData(),await this.postProgress({type:Ie.group_media,percent:this.completed_percent+.5*this.total_percent}),await this.processGroups(),await this.postProgress({type:Ie.group_media,percent:this.completed_percent+.9*this.total_percent}),await this.saveData(),await this.postProgress({type:Ie.group_media,percent:this.completed_percent+this.total_percent}),this.db.data[t]}catch(t){throw ke(t,{message:`Error occurred during media grouping ${this.hostType}`,detail:`Error occurred during media grouping ${this.hostType}: ${this.params.input.filepath}`})}}async processGroups(){const t="grouper_process_state";if(this.store.data[t])return;this.store.data.grouper_process_map||={},this.store.data.grouper_process_index||=0;const{length:e}=this.group_data;for(let t=0;t<e;t++){const a=this.group_data[t];this.store.data.grouper_process_map[a.filename]||(await p({outputRoot:this.params.outputRoot,files:a.files,filename:a.filename}),this.store.data.grouper_process_map[a.filename]=!0,await this.store.write(),await this.postProgress({type:Ie.group_media,percent:this.completed_percent+.5*this.total_percent+this.total_percent*(.4*(t+1)/e)}))}this.store.data[t]=!0,await this.store.write()}async insertSafeFile(){const t=await this.generateSafeFile(this.hostType);this.addOne(t,!0)}async calculateData(){this.store.data.grouper_group_list||=[],this.store.data.grouper_file_map||={},await this.insertSafeFile(),await this.calculateMediaTracks(),await this.calculateThumbnails(),await this.calculateCovers(),await this.calculateCaches(),this.current_index+=1,this.current_position=0,await this.calculateSubtitles(),this.store.data.grouper_group_list=this.group_data,this.store.data.grouper_file_map=this.file_map;const t=this.group_data.map(t=>t.filename);this.store.data.grouper_part_names=t,this.store.data.grouper_calculate_state=!0,await this.store.write()}async calculateSubtitles(){const t=this.readSubtitleInfo();if(!t?.length)return;await this.insertSafeFile();const{length:e}=t;for(let a=0;a<e;a++){const e=t[a],{file:i,file_path:s,size:r}=e,o=this.addOne({file_path:s,size:r});if(this.file_map[i]=o,e.source){const{file:t,file_path:a,size:i}=e.source,s=this.addOne({file_path:a,size:i});this.file_map[t]=s}}}async calculateCaches(){await this.getAudioData(),await this.getVideoData(),await this.getThumbnailData(),await this.getCoverData();const t=this.getPreviewIdMap(this.hostType),e=this.getCacheInfoFilename(),a=await this.writeText(e,JSON.stringify(t));this.file_map[e]=a}async calculateCovers(){const t=this.readCoverInfo();if(!t)return;const{file:e,path:a,size:i}=t,s=this.addOne({file_path:a,size:i});this.file_map[e]=s}async calculateMediaTracks(){const t=this.readAudioTracks(),e=this.readVideoTracks(),a=t?.length;for(let e=0;e<a;e++){const i=t[e];if(i.adapt){const t=await this.calculateOneTrack(i.adapt.m3u8),a=this.getAudioManifestName("adapt",e),s=await this.writeTrackText(a,t);this.file_map[a]=s}if(i.high){const t=await this.calculateOneTrack(i.high.m3u8),a=this.getAudioManifestName("high",e),s=await this.writeTrackText(a,t);this.file_map[a]=s}await this.postProgress({type:Ie.group_media,percent:this.completed_percent+.4*this.total_percent*((e+1)/a)})}const i=e.length;for(let t=0;t<i;t++){const a=e[t],s=await this.calculateOneTrack(a.m3u8),r=this.getGroupedVideoManifestName(t),o=await this.writeTrackText(r,s);this.file_map[r]=o,await this.postProgress({type:Ie.group_media,percent:this.completed_percent+.2*this.total_percent+.2*this.total_percent*((t+1)/i)})}}async calculateThumbnails(){const t=this.readThumbnailInfo();if(!t)return;if(!t)return;const{tile_list:e}=t,{length:a}=e;let i=[...t.sprite_list];for(let t=0;t<a;t++){const a=e[t],s=a.file,r=await this.safelyAddOne({file_path:a.file_path,size:a.size}),o=await this.getPreviewId({file:s}),n=this.getFileName(r.file_index);await this.setPreviewIdMap({id:o,file:n,start:r.start,end:r.end},this.hostType),this.file_map[s]=r,i=i.map(t=>t.file===s?{...t,file:n,id:o,s:r.start,e:r.end}:t)}const s=this.getThumbnailInfoFilename(),r=await this.writeText(s,JSON.stringify(i));this.file_map[s]=r}async calculateOneTrack(t){const{segments:e,init:a,version:i,targetDuration:s,mediaSequence:r,endList:o}=t,n={},h=this.addOne({size:a.size,file_path:a.file_path}),d=await this.getPreviewId({file:a.uri}),c=this.getFileName(h.file_index),l=`${c}?id=${d}`;await this.setPreviewIdMap({id:d,file:c,start:h.start,end:h.end},this.hostType);const u=["#EXTM3U",`#EXT-X-VERSION:${i}`,`#EXT-X-TARGETDURATION:${s}`,`#EXT-X-MEDIA-SEQUENCE:${r}`,`#EXT-X-MAP:URI=${l},BYTERANGE="${h.size}@${h.start}"`];[...e].forEach(t=>{const{uri:e,size:a,duration:i,file_path:s}=t;n[e]=this.addOne({size:a,duration:i,file_path:s})});for(const[t,e]of Object.entries(n)){const a=await this.getPreviewId({file:t}),i=this.getFileName(e.file_index);await this.setPreviewIdMap({id:a,file:i,start:e.start,end:e.end},this.hostType),u.push(`#EXTINF:${e.duration},`),u.push(`#EXT-X-BYTERANGE:${e.size}@${e.start}`),u.push(`${i}?id=${a}`)}o&&u.push("#EXT-X-ENDLIST");return u.join("\n")}async writeTrackText(t,e){const a=ze(this.params.outputRoot,t),r=ze(this.params.outputRoot,`${t}.gz`),o=ze(this.params.outputRoot,`${t}.bin`);await Re(a,e,"utf-8"),await $e(a,r);if(await Me(r)>16){const t=(await Se(r,0,15)).toString("base64");await async function(t,e){await new Promise((a,r)=>{const o=i(t,{start:16}),n=s(e);o.pipe(n),n.on("finish",()=>{a(!0)}),o.on("error",t=>{r(t)}),n.on("error",t=>{r(t)})})}(r,o);return{...this.addOne({file_path:o,size:await Me(o)}),hash:t}}return{...this.addOne({file_path:a,size:await Me(a)}),hash:""}}async writeText(t,e){const a=ze(this.params.outputRoot,t);await Re(a,e,"utf-8");return this.addOne({file_path:a,size:await Me(a)})}addOne({file_path:t,size:e,duration:a=0},i=!1){const s=this.getSizeLimit(this.hostType),{current_position:r,group_data:o}=this;if(i&&o[this.current_index]||!(r+e<=s)){this.current_index+=1;const{current_index:i}=this;o[i]?o[i].files.push(t):o[i]={filename:this.getFileName(i),files:[t]};const s=0,r=e-1;return this.current_position=e,{file_index:i,start:s,end:r,duration:a,size:r-s+1}}{const{current_index:i}=this,s=r,n=r+e-1;return this.current_position=n+1,o[i]?o[i].files.push(t):o[i]={filename:this.getFileName(i),files:[t]},{file_index:i,start:s,end:n,duration:a,size:n-s+1}}}async safelyAddOne(t){const e=this.getSizeLimit(this.hostType),{current_position:a}=this;return a+t.size<=e?0===a?(await this.insertSafeFile(),this.addOne(t)):this.addOne(t):(await this.insertSafeFile(),this.addOne(t))}},Ce=class extends pt{async start(){try{if(this.grouperResult)return this.grouperResult;const t={meta:await this.getMetaData(),data:{}},{length:e}=this.params.hosts;for(let a=0;a<e;a++){const i=this.params.hosts[a],s=this.getSizeLimit(i),r=new Le({...this.params,host_type:i,file_size_limit:s,completed_percent:a/e}),o=await r.start();t.data[i]=o}return await this.setGrouperResult(t),t}catch(t){throw Te(t,{message:t.message||"Error occurred during media grouping",detail:t.detail||`Error occurred during media grouping: ${this.params.input.filepath}`})}}async getMetaData(){const t={},e=this.audioTranscoderResult??[],a=this.videoTranscoderResult?[this.videoTranscoderResult]:[];if(a?.length){const e=await this.getMediainfo(),{duration:i}=e?.general;if(a?.length){const{width:e,height:s,framerate:r,bitdepth:o,label:n,codec:h,codec_name:d}=a[0];t.videos=[{duration:i,bitdepth:o,width:e,height:s,framerate:r,label:n,codec:h,codec_name:d}]}}if(e?.length)for(const a of e){const{high:e,adapt:i}=a,{channels:s,lossless:r}=i,o=await this.getMediainfo(),{duration:n}=o?.general,{codec:h,codec_name:d}=i,c={duration:n,channels:s,lossless:r,codec:h,codec_name:d};e&&(c.high={channels:e.channels,codec:e.codec,codec_name:e.codec_name,lossless:e.lossless}),t.audios=t.audios||[],t.audios.push(c)}return t}},Ae=class extends pt{async start(){if(this.db.data.grouper_result)return this.db.data.grouper_result;const t=await this.getMediainfo();if(!t)return;const e=t.video,a=e?.length,i=t.audio,s=i?.length;if(!s&&!a)return;const r=new De(this.params);if(await r.start(),s){const t=new St(this.params);await t.start();const e=new Wt(this.params);await e.start();const a=new le(this.params);await a.start()}if(a){const t=new Dt(this.params);await t.start();const e=new Vt(this.params);await e.start();const a=new se(this.params);await a.start()}const o=new Ce(this.params);await o.start()}async getResult(){return this.db.data.grouper_result}};import{HostType as Oe}from"@soga/types";import{UploadProgress as Ue}from"@soga/node-types";import{parseMediaInfo as Ve}from"@soga/mediainfo";import{getFileSize as Ge,isAudioAdapt as Be,isAudioHigh as je,isVideoSupport as qe}from"@soga/fileutils";import{ensureDir as Xe}from"fs-extra";import Ke from"check-disk-space";import{buildDError as Je}from"@soga/error";var He=class extends C{async start(){this.prepareResult||(await this.checkStorage(),await this.calculateMeta(),await this.calculateProgress())}async checkStorage(){const{length:t}=this.params.hosts,e=await Ke(this.params.outputRoot),a=e.free,i=e.diskPath;if((3+t)*this.params.input.filesize>a)throw Je(new Error(`${i} have no enough computer disk space, please adjust the temporary path in user settings.`),{message:`${i} have no enough computer disk space, please adjust the temporary path in user settings.`,detail:`${i} have no enough computer disk space to process ${this.params.input.filepath}`})}async calculateMeta(){if(this.meta)return this.meta;const{filename:t,local_btime:e,local_ctime:a,local_mtime:i,filesize:s}=this.params.input,r={file:t,size:s,btime:e,ctime:a,mtime:i,md5:""};return await this.setMeta(r),r}async calculateProgress(){if(this.prepareResult)return;const t={[Ue.prepare]:{weight:0,percent:1},[Ue.calculate_md5]:{weight:0,percent:0},[Ue.separate_video]:{weight:0,percent:0},[Ue.separate_audio]:{weight:0,percent:0},[Ue.separate_subtitle]:{weight:0,percent:0},[Ue.transcode_video]:{weight:0,percent:0},[Ue.transcode_audio]:{weight:0,percent:0},[Ue.transcode_thumbnail]:{weight:0,percent:0},[Ue.transcode_source]:{weight:0,percent:0},[Ue.transcode_txt]:{weight:0,percent:0},[Ue.transcode_img]:{weight:0,percent:0},[Ue.group_media]:{weight:0,percent:0},[Ue.upload_baidu]:{weight:0,percent:0},[Ue.upload_ali]:{weight:0,percent:0},[Ue.end]:{weight:0,percent:0}},e={keep_preview:this.params.keepPreview,keep_source:this.params.keepSource},a=await Ge(this.params.input.filepath);t[Ue.prepare].weight=t[Ue.end].weight=Math.ceil(a/1024/1024/500),t[Ue.calculate_md5].weight=Math.ceil(a/1024/1024/200);let i=0;if(this.isMedia)if(this.params.keepPreview){const s=await Ve(this.params.input.filepath),r=s?.general?.duration??0;if(s.video?.length){const e=s.video[0],{width:a,height:i,codec:r}=e,o=qe(r),{duration:n}=s.general,h=o?n/400:n*(a*i)/1920/1080;t[Ue.separate_video].weight=Math.ceil(h),t[Ue.transcode_video].weight=Math.ceil(.01*n)}if(s.audio?.length){const{duration:e}=s.general;let a=0;s.audio.forEach(t=>{const{codec:i,lossless:s,channels:r}=t,o={high_need:!1,high_transcode:!1,adapt_need:!1,adapt_transcode:!1};Be(i)?r>2?(o.high_need=!0,o.high_transcode=!1,o.adapt_need=!0,o.adapt_transcode=!0):(o.high_need=!1,o.adapt_need=!0,o.adapt_transcode=!1):je(i)?(o.high_need=!0,o.high_transcode=!1,o.adapt_need=!0,o.adapt_transcode=!0):(o.high_need=!1,o.adapt_need=!0,o.adapt_transcode=!1,s&&(o.high_need=!0,o.high_transcode=!0)),o.adapt_need&&(a+=o.adapt_transcode?e/40:5),o.high_need&&(a+=o.high_transcode?e/20:10)}),t[Ue.separate_audio].weight=Math.ceil(a),t[Ue.transcode_audio].weight=Math.ceil(.01*e)}const o=s.video?.length??0,n=s.audio?.length??0;if(o||n){e.keep_preview=!0;const o=(s.text?.length||0)+(this.params.subtitles?.length||0);t[Ue.separate_subtitle].weight=Math.ceil(o),t[Ue.transcode_thumbnail].weight=Math.ceil(.08*r),i+=a,t[Ue.group_media].weight=Math.ceil(a/1024/1024/10)}else e.keep_preview=!1,e.keep_source=!0,i+=a}else e.keep_source=!0,i+=a;else this.isTxt?e.keep_preview?(t[Ue.transcode_txt].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a):this.isImg?e.keep_preview&&(t[Ue.transcode_img].weight=Math.ceil(a/1024/1024/1),i+=a):(e.keep_source=!0,i+=a);e.keep_source&&(t[Ue.transcode_source].weight=Math.ceil(a/1024/1024/30)),this.params.hosts.includes(Oe.BAIDU)&&(t[Ue.upload_baidu].weight=Math.ceil(i/1024/1024/1)),this.params.hosts.includes(Oe.ALI)&&(t[Ue.upload_ali].weight=Math.ceil(i/1024/1024/2));const s={preview:e.keep_preview,source:e.keep_source};await this.setKeeps(s),await this.setPrepareResult(t)}},Qe=async t=>{await Xe(t.outputRoot);const e=await m(t);try{const a=new He({...t,db:e});return await a.start(),a}catch(t){}};import{UploadProgress as We}from"@soga/node-types";import{createHash as Ze}from"crypto";import{createReadStream as Ye}from"fs-extra";var ta=class extends C{async start(){await this.processFile();return await this.getResult()}async calculateMd5(){if(this.md5)return this.md5;const t=this.params.input.filepath,e=this.params.input.filesize;let a=0;const i=await new Promise((i,s)=>{let r=0;const o=Ze("md5"),n=Ye(t,{highWaterMark:4194304});n.on("data",async t=>{o.update(t),r+=t.length;const i=r/e;r-a>104857600&&(a=r,await this.postProgress({type:We.calculate_md5,percent:Math.min(i,1)}))}),n.on("end",()=>{const t=o.digest("hex");i(t)}),n.on("error",t=>{s(t)})});return i&&await this.setMd5(i),await this.postProgress({type:We.calculate_md5,percent:1}),i}async getResult(){if(this.result)return this.result;const{sourceResult:t,grouperResult:e,imgResult:a,txtResult:i,meta:s,keeps:r}=this,{length:o}=this.params.hosts,n={meta:{preview:r.preview,source:r.source,file:s}};for(let s=0;s<o;s++){const r=this.params.hosts[s];n[r]={max_size:0,parts:[]};const o=t=>{n[r].parts=[...n[r].parts,...t]},h=a?.data[r];if(h){h.cache&&(n[r].cache=h?.cache);const t=h.parts?.map(t=>({...t,preview:!0,source:!1}));t&&o(t),n.meta.img=a.meta,h.img&&(n[r].img=h.img)}const d=i?.data[r];if(d){o((d.parts||[]).map(t=>({...t,preview:!0,source:!1}))),n[r].cache=d.cache,n[r].txt={entrance:d.entrance,pad:i?.meta.pad,pages:i?.meta.pages}}const c=e?.data[r];if(c?.parts){o(c.parts.map(t=>({...t,preview:!0,source:!1}))),n.meta.audios=e.meta.audios,n.meta.videos=e.meta.videos,n[r].cache=c.cache,n[r].media={audios:c.audios,videos:c.videos,subtitles:c.subtitles,thumbnail:c.thumbnail,cover:c.cover}}const l=t?.data[r];if(l?.parts){o(l.parts.map(t=>{let e=!0;return(this.isMedia||this.isTxt)&&(e=!1),{...t,preview:e,source:!0}})),n[r].source={head:t.meta.head,download:l.download}}[...n[r]?.parts].forEach(t=>{t.size>n[r].max_size&&(n[r].max_size=t.size)})}return await this.setResult(n),n}async processFile(){const t="encoder_processed";if(this.db.data[t])return;const e=await Qe(this.params),{keeps:a}=e,i={...this.params,keepPreview:a.preview,keepSource:a.source},s=await this.calculateMd5();if(await this.setMd5(s),i.keepSource){const t=new O(this.params);await t.start()}if(e.isMedia&&i.keepPreview){const t=new Ae(this.params);await t.start()}if(e.isTxt&&i.keepPreview){const t=new tt(this.params);await t.start()}if(e.isImg){const t=new dt(this.params);await t.start()}this.db.data[t]=!0,await this.db.write()}},ea=async e=>{try{const t=await m(e),a=new ta({...e,db:t});return a.start()}catch(a){throw t(a,{message:"Error occurred during file encoding",detail:`Error occurred during file encoding: ${e.input.filepath}`})}};export{ea as encode,Qe as getPrepare};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soga/file-encoder",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.13",
|
|
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.
|
|
23
|
+
"@soga/typescript-config": "1.3.13"
|
|
24
24
|
},
|
|
25
25
|
"keywords": [],
|
|
26
26
|
"author": "",
|
|
@@ -32,16 +32,16 @@
|
|
|
32
32
|
"piscina": "^5.0.0",
|
|
33
33
|
"uuid": "^11.1.0",
|
|
34
34
|
"check-disk-space": "^3.4.0",
|
|
35
|
-
"@soga/fileutils": "1.3.
|
|
36
|
-
"@soga/
|
|
37
|
-
"@soga/node-types": "1.3.
|
|
38
|
-
"@soga/
|
|
39
|
-
"@soga/
|
|
40
|
-
"@soga/lowdb": "1.3.
|
|
41
|
-
"@soga/
|
|
42
|
-
"@soga/
|
|
43
|
-
"@soga/
|
|
44
|
-
"@soga/imgutils": "1.3.
|
|
35
|
+
"@soga/fileutils": "1.3.13",
|
|
36
|
+
"@soga/utils": "1.3.13",
|
|
37
|
+
"@soga/node-types": "1.3.13",
|
|
38
|
+
"@soga/error": "1.3.13",
|
|
39
|
+
"@soga/types": "1.3.13",
|
|
40
|
+
"@soga/lowdb": "1.3.13",
|
|
41
|
+
"@soga/mediainfo": "1.3.13",
|
|
42
|
+
"@soga/m3u8": "1.3.13",
|
|
43
|
+
"@soga/mp4box": "1.3.13",
|
|
44
|
+
"@soga/imgutils": "1.3.13"
|
|
45
45
|
},
|
|
46
46
|
"scripts": {
|
|
47
47
|
"demo": "tsx ./demo/demo",
|