Files

86 lines
49 KiB
JavaScript
Raw Permalink Normal View History

2025-11-09 01:28:42 +03:00
#!/usr/bin/env node
2025-12-03 21:55:35 +03:00
import{createRequire as ZF}from"node:module";var CF=Object.create;var{getPrototypeOf:EF,defineProperty:mD,getOwnPropertyNames:BF}=Object;var AF=Object.prototype.hasOwnProperty;var DD=(D,u,C)=>{C=D!=null?CF(EF(D)):{};let F=u||!D||!D.__esModule?mD(C,"default",{value:D,enumerable:!0}):C;for(let E of BF(D))if(!AF.call(F,E))mD(F,E,{get:()=>D[E],enumerable:!0});return F};var R=(D,u)=>()=>(u||D((u={exports:{}}).exports,u),u.exports);var l=ZF(import.meta.url);var Yu=R((a3,Zu)=>{class Au{constructor(D,u,C){this.etaBufferLength=D||100,this.valueBuffer=[C],this.timeBuffer=[u],this.eta="0"}update(D,u,C){this.valueBuffer.push(u),this.timeBuffer.push(D),this.calculate(C-u)}getTime(){return this.eta}calculate(D){let u=this.valueBuffer.length,C=Math.min(this.etaBufferLength,u),F=this.valueBuffer[u-1]-this.valueBuffer[u-C],E=this.timeBuffer[u-1]-this.timeBuffer[u-C],B=F/E;this.valueBuffer=this.valueBuffer.slice(-this.etaBufferLength),this.timeBuffer=this.timeBuffer.slice(-this.etaBufferLength);let A=Math.ceil(D/B/1000);if(isNaN(A))this.eta="NULL";else if(!isFinite(A))this.eta="INF";else if(A>1e7)this.eta="INF";else if(A<0)this.eta=0;else this.eta=A}}Zu.exports=Au});var QD=R((r3,Ju)=>{var m=l("readline");class $u{constructor(D){this.stream=D,this.linewrap=!0,this.dy=0}cursorSave(){if(!this.stream.isTTY)return;this.stream.write("\x1B7")}cursorRestore(){if(!this.stream.isTTY)return;this.stream.write("\x1B8")}cursor(D){if(!this.stream.isTTY)return;if(D)this.stream.write("\x1B[?25h");else this.stream.write("\x1B[?25l")}cursorTo(D=null,u=null){if(!this.stream.isTTY)return;m.cursorTo(this.stream,D,u)}cursorRelative(D=null,u=null){if(!this.stream.isTTY)return;this.dy=this.dy+u,m.moveCursor(this.stream,D,u)}cursorRelativeReset(){if(!this.stream.isTTY)return;m.moveCursor(this.stream,0,-this.dy),m.cursorTo(this.stream,0,null),this.dy=0}clearRight(){if(!this.stream.isTTY)return;m.clearLine(this.stream,1)}clearLine(){if(!this.stream.isTTY)return;m.clearLine(this.stream,0)}clearBottom(){if(!this.stream.isTTY)return;m.clearScreenDown(this.stream)}newline(){this.stream.write(`
`),this.dy++}write(D,u=!1){if(this.linewrap===!0&&u===!1)this.stream.write(D.substr(0,this.getWidth()));else this.stream.write(D)}lineWrapping(D){if(!this.stream.isTTY)return;if(this.linewrap=D,D)this.stream.write("\x1B[?7h");else this.stream.write("\x1B[?7l")}isTTY(){return this.stream.isTTY===!0}getWidth(){return this.stream.columns||(this.stream.isTTY?80:200)}}Ju.exports=$u});var Xu=R((i3,Ku)=>{Ku.exports=({onlyFirst:D=!1}={})=>{let u=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"].join("|");return new RegExp(u,D?void 0:"g")}});var ku=R((o3,Gu)=>{var NF=Xu();Gu.exports=(D)=>typeof D==="string"?D.replace(NF(),""):D});var _u=R((t3,qD)=>{var Uu=(D)=>{if(Number.isNaN(D))return!1;if(D>=4352&&(D<=4447||D===9001||D===9002||11904<=D&&D<=12871&&D!==12351||12880<=D&&D<=19903||19968<=D&&D<=42182||43360<=D&&D<=43388||44032<=D&&D<=55203||63744<=D&&D<=64255||65040<=D&&D<=65049||65072<=D&&D<=65131||65281<=D&&D<=65376||65504<=D&&D<=65510||110592<=D&&D<=110593||127488<=D&&D<=127569||131072<=D&&D<=262141))return!0;return!1};qD.exports=Uu;qD.exports.default=Uu});var Hu=R((e3,Wu)=>{Wu.exports=function(){return/\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F|\uD83D\uDC68(?:\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68\uD83C\uDFFB|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|[\u2695\u2696\u2708]\uFE0F|\uD83D[\uDC66\uDC67]|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708])\uFE0F|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C[\uDFFB-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)\uD83C\uDFFB|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])|\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)(?:\uD83C[\uDFFB\uDFFC])|\uD83D\uDC69(?:\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD
=== FFmpeg Command [${new Date().toISOString()}] ===
ffmpeg ${D.join(" ")}
2025-12-03 21:55:35 +03:00
`;return await v(E),new Promise((B,A)=>{let $=p("ffmpeg",D),Z="";$.stderr.on("data",(X)=>{let G=X.toString();if(Z+=G,u&&C){let J=G.match(/time=(\d{2}):(\d{2}):(\d{2}\.\d{2})/);if(J){let Y=parseInt(J[1]),K=parseInt(J[2]),_=parseFloat(J[3]),k=Y*3600+K*60+_,U=Math.min(100,k/C*100);u(U)}}}),$.on("error",(X)=>{v(`ERROR: ${X.message}
`),A(Error(`FFmpeg error: ${X.message}`))}),$.on("close",(X)=>{if(X===0){let J=Z.split(`
`).filter((Y)=>Y.trim()).slice(-10).join(`
`);v(`SUCCESS: Exit code ${X}
--- Last 10 lines of output ---
${J}
`),B()}else v(`FAILED: Exit code ${X}
--- Full error output ---
${Z}
`),A(Error(`FFmpeg failed with exit code ${X}
${Z}`))})})}async function XD(D){let C=`
=== MP4Box Command [${new Date().toISOString()}] ===
MP4Box ${D.join(" ")}
2025-12-03 21:55:35 +03:00
`;return await v(C),new Promise((F,E)=>{let B=p("MP4Box",D),A="",$="";B.stdout.on("data",(Z)=>{A+=Z.toString()}),B.stderr.on("data",(Z)=>{$+=Z.toString()}),B.on("error",(Z)=>{v(`ERROR: ${Z.message}
`),E(Error(`MP4Box error: ${Z.message}`))}),B.on("close",(Z)=>{if(Z===0){let J=(A||$).split(`
`).filter((Y)=>Y.trim()).slice(-10).join(`
`);v(`SUCCESS: Exit code ${Z}
--- Last 10 lines of output ---
${J}
`),F()}else{let X=$||A;v(`FAILED: Exit code ${Z}
--- Full error output ---
${X}
`),E(Error(`MP4Box failed with exit code ${Z}
${X}`))}})})}import{spawn as $F}from"node:child_process";async function i(D){return new Promise((u,C)=>{let F=$F("ffprobe",["-v","error","-show_entries","stream=width,height,duration,r_frame_rate,codec_name,codec_type,bit_rate","-show_entries","format=duration","-of","json",D]),E="";F.stdout.on("data",(B)=>{E+=B.toString()}),F.on("error",(B)=>{C(Error(`ffprobe error: ${B.message}`))}),F.on("close",(B)=>{if(B!==0){C(Error(`ffprobe failed with exit code ${B}`));return}try{let A=JSON.parse(E),$=A.streams.find((_)=>_.codec_type==="video"),Z=A.streams.find((_)=>_.codec_type==="audio"&&_.bit_rate),X=A.format;if(!$){C(Error("No video stream found in input file"));return}let G=30;if($.r_frame_rate){let[_,k]=$.r_frame_rate.split("/").map(Number);if(_&&k&&k!==0)G=_/k}let J=parseFloat($.duration||X.duration||"0"),Y=Z?.bit_rate?Math.round(parseInt(Z.bit_rate)/1000):void 0,K=$.bit_rate?Math.round(parseInt($.bit_rate)/1000):void 0;u({width:$.width,height:$.height,duration:J,fps:G,codec:$.codec_name,audioBitrate:Y,videoBitrate:K})}catch(A){C(Error(`Failed to parse ffprobe output: ${A}`))}})})}function uD(D,u=256){if(!D)return`${u}k`;let C=Math.min(D,u);if(C<=64)return"64k";if(C<=96)return"96k";if(C<=128)return"128k";if(C<=192)return"192k";return"256k"}function FD(D){let u=Math.floor(D/3600),C=Math.floor(D%3600/60),F=D%60;return`${String(u).padStart(2,"0")}:${String(C).padStart(2,"0")}:${F.toFixed(3).padStart(6,"0")}`}import{mkdir as JF,access as KF,constants as XF}from"node:fs/promises";async function g(D){try{await KF(D,XF.F_OK)}catch{await JF(D,{recursive:!0})}}function GF(D,u){let C=D*u;if(C<=230400)return 0.08;if(C<=409920)return 0.075;if(C<=921600)return 0.07;if(C<=2073600)return 0.065;if(C<=3686400)return 0.06;return 0.055}function y(D,u,C=30,F){let E=GF(D,u),B=Math.round(D*u*C*E/1000);if(F&&B>F)B=F;return`${B}k`}var GD=[{name:"360p",width:640,height:360,videoBitrate:y(640,360,30),audioBitrate:"192k"},{name:"480p",width:854,height:480,videoBitrate:y(854,480,30),audioBitrate:"192k"},{name:"720p",width:1280,height:720,videoBitrate:y(1280,720,30),audioBitrate:"192k"},{name:"1080p",width:1920,height:1080,videoBitrate:y(1920,1080,30),audioBitrate:"256k"},{name:"1440p",width:2560,height:1440,videoBitrate:y(2560,1440,30),audioBitrate:"256k"},{name:"2160p",width:3840,height:2160,videoBitrate:y(3840,2160,30),audioBitrate:"256k"}];function kD(D,u,C=30,F){let E=[],B=GD.filter((A)=>{return A.width<=D&&A.height<=u});for(let A of B)E.push({...A,videoBitrate:y(A.width,A.height,30,F),fps:30});return E}function kF(D,u,C){return{...D,name:`${D.name}-${u}`,videoBitrate:y(D.width,D.height,u,C),fps:u}}function cD(D){let C=D.trim().match(/^(\d+)p?(?:[@-](\d+))?$/i);if(!C)return null;let F=C[1]+"p",E=C[2]?parseInt(C[2]):30;return{resolution:F,fps:E}}function dD(D,u=30,C){let F=GD.find((E)=>E.name===D);if(!F)return null;if(u===30)return{...F,videoBitrate:y(F.width,F.height,30,C),fps:30};return kF(F,u,C)}function UF(D,u,C,F){let E=cD(D);if(!E)return{error:`Invalid profile format: ${D}. Use format like: 360, 720@60, 1080-60`};let B=dD(E.resolution,E.fps);if(!B)return{error:`Unknown resolution: ${E.resolution}. Available: 360, 480, 720, 1080, 1440, 2160`};if(B.width>u||B.height>C)return{error:`Source resolution (${u}x${C}) is lower than ${D} (${B.width}x${B.height})`};let A=120,$=E.fps,Z;if(E.fps>F)$=Math.min(F,A),Z=`Requested ${E.fps} FPS in ${D}, but source is ${F} FPS. Using ${$} FPS instead`;else if(E.fps>A)$=A,Z=`Requested ${E.fps} FPS in ${D} exceeds maximum ${A} FPS. Using ${$} FPS instead`;return Z?{warning:Z,adjustedFps:$}:{}}function lD(D,u,C,F,E){let B=[],A=[],$=[];for(let Z of D){let X=UF(Z,u,C,F);if(X.error){A.push(X.error);continue}if(X.warning)$.push(X.warning);let G=cD(Z);if(!G)continue;let J=X.adjustedFps!==void 0?X.adjustedFps:G.fps,Y=dD(G.resolution,J,E);if(Y)B.push(Y)}return{profiles:B,errors:A,warnings:$}}import{join as h}from"node:path";import{readdir as _F,unlink as pD,rmdir as WF,writeFile as nD}from"node:fs/promises";async function sD(D,u,C="00:00:01"){let F=h(u,"poster.jpg"),E=/^\d+(\.\d+)?$/.test(C)?C:C;return await f(["-ss",E,"
2025-11-09 01:28:42 +03:00
2025-12-03 21:55:35 +03:00
`;for(let $=0;$<D;$++){let Z=$*u,X=($+1)*u,G=Math.floor($/E),Y=$%E*C,K=G*F;A+=`${FD(Z)} --> ${FD(X)}
`,A+=`${B}#xywh=${Y},${K},${C},${F}
2025-11-09 01:28:42 +03:00
2025-12-03 21:55:35 +03:00
`}return A}import{join as IF}from"node:path";function QF(D,u,C){if(C)if(u==="h264")return 32;else return 42;else if(u==="h264"){if(D<=360)return 25;if(D<=480)return 24;if(D<=720)return 23;if(D<=1080)return 22;if(D<=1440)return 21;return 20}else{if(D<=360)return 40;if(D<=480)return 38;if(D<=720)return 35;if(D<=1080)return 32;if(D<=1440)return 30;return 28}}async function rD(D,u,C,F,E,B,A,$,Z,X,G,J){let Y=IF(u,`video_${Z}_${C.name}.mp4`),K=["-y","-i",D,"-c:v",F],_=F.includes("nvenc")||F.includes("qsv")||F.includes("amf"),k;if(_&&X?.cq!==void 0)k=X.cq;else if(!_&&X?.crf!==void 0)k=X.crf;else k=QF(C.height,Z,_);if(F==="h264_nvenc")K.push("-rc:v","vbr"),K.push("-cq",String(k)),K.push("-preset",E),K.push("-2pass","0");else if(F==="av1_nvenc")K.push("-rc:v","vbr"),K.push("-cq",String(k)),K.push("-preset",E),K.push("-2pass","0");else if(F==="av1_qsv")K.push("-preset",E),K.push("-global_quality",String(k));else if(F==="av1_amf")K.push("-quality","balanced"),K.push("-rc","cqp"),K.push("-qp_i",String(k)),K.push("-qp_p",String(k));else if(F==="libsvtav1")K.push("-crf",String(k)),K.push("-preset",E),K.push("-svtav1-params","tune=0:enable-overlays=1");else if(F==="libx264")K.push("-crf",String(k)),K.push("-preset",E);else K.push("-preset",E);let U=Z==="av1"?0.6:1,Q=Math.round(parseInt(C.videoBitrate)*U*1.5);K.push("-maxrate",`${Q}k`),K.push("-bufsize",`${Q*2}k`);let x=C.fps||30,V=Math.round(x*A);K.push("-g",String(V),"-keyint_min",String(V),"-sc_threshold","0");let H=[`scale=${C.width}:${C.height}`];if(G){if(G.deinterlace)H.push("yadif");if(G.denoise)H.push("hqdn3d");if(G.customFilters)H.push(...G.customFilters)}K.push("-vf",H.join(","));let S=parseInt(C.audioBitrate)||256,L=uD($,S);if(K.push("-c:a","aac","-b:a",L),G?.audioNormalize)K.push("-af","loudnorm");return K.push("-f","mp4",Y),await f(K,J,B),Y}async function iD(D,u,C,F,E,B,A,$,Z,X,G,J,Y,K){let _=new Map;if(Z&&C.length>1)for(let k=0;k<C.length;k+=X){let U=C.slice(k,k+X),Q=U.map((V)=>rD(D,u,V,F,E,B,A,$,G,J,Y,(H)=>{if(K)K(V.name,H)}));(await Promise.all(Q)).forEach((V,H)=>{let S=U[H];_.set(S.name,V)})}else for(let k of C){let U=await rD(D,u,k,F,E,B,A,$,G,J,Y,(Q)=>{if(K)K(k.name,Q)});_.set(k.name,U)}return _}import{join as N}from"node:path";import{readdir as uu,rename as j3,mkdir as b3,writeFile as HD}from"node:fs/promises";import{readFile as UD,writeFile as _D}from"node:fs/promises";async function oD(D){let u=await UD(D,"utf-8");u=u.replace(/\/\/>/g,"/>"),u=u.replace(/\/\s+\/>/g,"/>"),u=u.replace(/(<Representation[^>]+)\s+\/>/g,"$1/>"),u=u.replace(/<Representation\s+([^>]+)\/>\s*<\/Representation>/g,"<Representation $1/>"),u=u.replace(/<Representation\s+([^>]+)\/>\s*(<AudioChannelConfiguration[^>]*\/>)/g,`<Representation $1>
$2
</Representation>`),u=u.replace(/<Representation\s+([^>]+)>\s*(?=<(?:Representation|\/AdaptationSet))/g,`<Representation $1/>
`),await _D(D,u,"utf-8")}async function tD(D,u,C){let F=await UD(D,"utf-8");F=F.replace(/media="\$RepresentationID\$_\$Number\$\.m4s"/g,'media="$RepresentationID$/$RepresentationID$_$Number$.m4s"'),F=F.replace(/initialization="\$RepresentationID\$_\.mp4"/g,'initialization="$RepresentationID$/$RepresentationID$_.mp4"'),await _D(D,F,"utf-8")}async function eD(D){let C=(await UD(D,"utf-8")).split(`
`),F=[],E=0;while(E<C.length){let B=C[E];if(B.includes("<AdaptationSet")&&B.includes("maxWidth")){let A=E,$=[B],Z=[],X=[],G=[],J=!1;E++;while(E<C.length&&!C[E].includes("</AdaptationSet>")){let Y=C[E];if(Y.includes("<SegmentTemplate"))J=!0;if(J){if(Z.push(Y),Y.includes("</SegmentTemplate>"))J=!1}else if(Y.includes("<Representation")&&Y.includes("-h264"))X.push(Y);else if(Y.includes("<Representation")&&Y.includes("-av1"))G.push(Y);E++}if(X.length>0&&G.length>0)F.push(B),Z.forEach((Y)=>F.push(Y)),X.forEach((Y)=>F.push(Y)),F.push(" </AdaptationSet>"),F.push(B),Z.forEach((Y)=>F.push(Y)),G.forEach((Y)=>F.push(Y)),F.push(" </AdaptationSet>");else{F.push(B);for(let Y=A+1;Y<E;Y++)F.push(C[Y]);F.push(C[E])}E++}else F.push(B),E++}await _D(D,F.join(`
`),"utf-8")}function WD(D,u,C){let F=`#EXTM3U
`;F+=`#EXT-X-VERSION:6
`,F+=`#EXT-X-TARGETDURATION:${Math.ceil(C)}
`,F+=`#EXT-X-MEDIA-SEQUENCE:1
`,F+=`#EXT-X-INDEPENDENT-SEGMENTS
`,F+=`#EXT-X-MAP:URI="${u}"
`;for(let E of D)F+=`#EXTINF:${C},
`,F+=`${E}
`;return F+=`#EXT-X-ENDLIST
`,F}function Du(D,u){let C=`#EXTM3U
`;if(C+=`#EXT-X-VERSION:6
`,C+=`#EXT-X-INDEPENDENT-SEGMENTS
2025-12-03 21:55:35 +03:00
`,u)C+=`#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="audio",AUTOSELECT=YES,URI="audio/playlist.m3u8",CHANNELS="2"
2025-12-03 21:55:35 +03:00
`;for(let F of D){if(C+=`#EXT-X-STREAM-INF:BANDWIDTH=${F.bandwidth},CODECS="avc1.4D4020,mp4a.40.2",RESOLUTION=${F.resolution},FRAME-RATE=${F.fps}`,u)C+=',AUDIO="audio"';C+=`
`,C+=`${F.path}
2025-12-03 21:55:35 +03:00
`}return C}async function qF(D,u,C,F,E){let B=N(u,"manifest.mpd"),A=["-dash",String(F*1000),"-frag",String(F*1000),"-rap","-segment-timeline","-segment-name","$RepresentationID$_$Number$","-out",B],$=!0;for(let[Z,X]of D.entries())for(let G of C){let J=X.get(G.name);if(!J)throw Error(`MP4 file not found for profile: ${G.name}, codec: ${Z}`);let Y=E==="dual"?`${G.name}-${Z}`:G.name;if(A.push(`${J}#video:id=${Y}`),$)A.push(`${J}#audio:id=audio`),$=!1}if(await XD(A),await zF(u,C,E),await tD(B,C,E),E==="dual")await eD(B);return await oD(B),B}async function zF(D,u,C){let{readdir:F,rename:E,mkdir:B}=await import("node:fs/promises"),A=[];if(C==="h264"||C==="dual")A.push("h264");if(C==="av1"||C==="dual")A.push("av1");let $=[];for(let G of A)for(let J of u){let Y=C==="dual"?`${J.name}-${G}`:J.name;$.push(Y);let K=N(D,Y);await B(K,{recursive:!0})}let Z=N(D,"audio");await B(Z,{recursive:!0});let X=await F(D);for(let G of X){if(G==="manifest.mpd")continue;if(G.startsWith("audio_")||G==="audio_init.m4s"){let J=N(D,G),Y=N(Z,G);await E(J,Y);continue}for(let J of $)if(G.startsWith(`${J}_`)){let Y=N(D,G),K=N(D,J,G);await E(Y,K);break}}}async function Fu(D,u,C,F,E,B){let A,$;if(B==="dash"||B==="both")A=await qF(D,u,C,F,E);if(B==="hls"||B==="both")$=await RF(u,C,F,E);return{manifestPath:A,hlsManifestPath:$}}async function RF(D,u,C,F){let E=N(D,"master.m3u8"),B=[];for(let J of u){let Y=F==="dual"?`${J.name}-h264`:J.name,K=N(D,Y),_=await uu(K),k=_.filter((H)=>H.endsWith(".m4s")).sort((H,S)=>{let L=parseInt(H.match(/_(\d+)\.m4s$/)?.[1]||"0"),M=parseInt(S.match(/_(\d+)\.m4s$/)?.[1]||"0");return L-M}),U=_.find((H)=>H.endsWith("_.mp4"));if(!U||k.length===0)continue;let Q=WD(k,U,C),x=N(K,"playlist.m3u8");await HD(x,Q,"utf-8");let V=parseInt(J.videoBitrate)*1000;B.push({path:`${Y}/playlist.m3u8`,bandwidth:V,resolution:`${J.width}x${J.height}`,fps:J.fps||30})}let A=N(D,"audio"),$=await uu(A),Z=$.filter((J)=>J.endsWith(".m4s")).sort((J,Y)=>{let K=parseInt(J.match(/_(\d+)\.m4s$/)?.[1]||"0"),_=parseInt(Y.match(/_(\d+)\.m4s$/)?.[1]||"0");return K-_}),X=$.find((J)=>J.endsWith("_.mp4"));if(X&&Z.length>0){let J=WD(Z,X,C);await HD(N(A,"playlist.m3u8"),J,"utf-8")}let G=Du(B,X!==void 0&&Z.length>0);return await HD(E,G,"utf-8"),E}async function ID(D){let{input:u,outputDir:C,segmentDuration:F=2,profiles:E,customProfiles:B,codec:A="dual",format:$="both",useNvenc:Z,quality:X,generateThumbnails:G=!0,thumbnailConfig:J={},generatePoster:Y=!0,posterTimecode:K="00:00:01",parallel:_=!0,onProgress:k}=D,U=CD("/tmp",`dash-converter-${VF()}`);await g(U);let Q=Cu(u,Eu(u)),x=CD(C,Q);await g(x);let V=CD(x,"conversion.log");KD(V);let{writeFile:H}=await import("node:fs/promises"),S=`===========================================
DASH Conversion Log
Started: ${new Date().toISOString()}
Input: ${u}
2025-12-03 21:55:35 +03:00
Output: ${x}
Codec: ${A}
Format: ${$}
===========================================
2025-12-03 21:55:35 +03:00
`;await H(V,S,"utf-8");try{return await xF(u,C,U,F,E,B,A,$,Z,X,G,J,Y,K,_,k)}finally{let{appendFile:L}=await import("node:fs/promises");try{await L(V,`
Completed: ${new Date().toISOString()}
2025-12-03 21:55:35 +03:00
`,"utf-8")}catch(M){}try{await Bu(U,{recursive:!0,force:!0})}catch(M){console.warn(`Warning: Failed to cleanup temp directory: ${U}`)}}}async function xF(D,u,C,F,E,B,A,$,Z,X,G,J,Y,K,_,k){if(!await n())throw Error("FFmpeg is not installed or not in PATH");if(!await s())throw Error("MP4Box is not installed or not in PATH. Install gpac package.");let U=(q,z,o,$D)=>{if(k)k({stage:q,percent:z,message:o,currentProfile:$D})};U("analyzing",0,"Analyzing input video...");let Q=await i(D),x=Z!==!1?await a():!1,V=Z===!0?!0:Z===!1?!1:x;if(Z===!0&&!x)throw Error("NVENC requested but not available. Check NVIDIA drivers and GPU support.");let H;if(B&&B.length>0){let q=lD(B,Q.width,Q.height,Q.fps,Q.videoBitrate);if(q.errors.length>0){console.warn(`
Profile errors:`);for(let z of q.errors)console.warn(` - ${z}`);console.warn("")}if(q.warnings.length>0){console.warn(`
Profile warnings:`);for(let z of q.warnings)console.warn(` - ${z}`);console.warn("")}if(H=q.profiles,H.length===0)throw Error("No valid profiles found in custom list. Check errors above.")}else if(E)H=E;else H=kD(Q.width,Q.height,Q.fps,Q.videoBitrate);if(H.length===0)throw Error("No suitable profiles found for input video resolution");let S=Cu(D,Eu(D)),L=CD(u,S);try{await Bu(L,{recursive:!0,force:!0})}catch(q){}await g(L);let M=[];if(A==="h264"||A==="dual"){let q=V?"h264_nvenc":"libx264",z=V?"p4":"medium";M.push({type:"h264",codec:q,preset:z})}if(A==="av1"||A==="dual"){let q=await r(),z=q.available?q.encoder:"libsvtav1",o=q.available?z==="av1_nvenc"?"p4":"medium":"8";M.push({type:"av1",codec:z,preset:o})}let ru=M.map((q)=>q.type.toUpperCase()).join(" + ");U("analyzing",20,`Using ${ru} encoding (${V?"GPU":"CPU"})`,void 0);let iu=V?3:2,YD=new Map;for(let q=0;q<M.length;q++){let{type:z,codec:o,preset:$D}=M[q],hD=q/M.length,eu=1/M.length;U("encoding",25+hD*40,`Stage 1: Encoding ${z.toUpperCase()} (${H.length} profiles)...`);let DF=z==="h264"?X?.h264:X?.av1,uF=await iD(D,C,H,o,$D,Q.duration,F,Q.audioBitrate,_,iu,z,DF,void 0,(t,PD)=>{let C3=H.findIndex((FF)=>FF.name===t),fD=25+hD*40,gD=PD/100*(40*eu/H.length);if(U("encoding",fD+gD,`Encoding ${z.toUpperCase()} ${t}...`,`${z}-${t}`),k)k({stage:"encoding",percent:fD+gD,currentProfile:`${z}-${t}`,profilePercent:PD,message:`Encoding ${z.toUpperCase()} ${t}...`})});YD.set(z,uF)}U("encoding",65,"Stage 1 complete: All codecs and profiles encoded"),U("encoding",70,"Stage 2: Creating segments and manifests...");let{manifestPath:ou,hlsManifestPath:tu}=await Fu(YD,L,H,F,A,$),TD=[];for(let q of YD.values())TD.push(...Array.from(q.values()));U("encoding",80,"Stage 2 complete: All formats packaged");let SD,yD;if(G){U("thumbnails",80,"Generating thumbnail sprites...");let q={width:J.width||160,height:J.height||90,interval:J.interval||1,columns:J.columns||10},z=await aD(D,L,Q.duration,q);SD=z.spritePath,yD=z.vttPath,U("thumbnails",90,"Thumbnails generated")}let vD;if(Y)U("thumbnails",92,"Generating poster image..."),vD=await sD(D,L,K),U("thumbnails",95,"Poster generated");return U("manifest",95,"Finalizing..."),U("complete",100,"Conversion complete!"),{manifestPath:ou,hlsManifestPath:tu,videoPaths:TD,thumbnailSpritePath:SD,thumbnailVttPath:yD,posterPath:vD,duration:Q.duration,profiles:H,usedNvenc:V,codecType:A,format:$}}var wD=DD(lu(),1);import{statSync as D3}from"node:fs";var W=process.argv.slice(2),AD,ZD,d="dual",c="both",bD=[],O,w,j,b;for(let D=0;D<W.length;D++)if(W[D]==="-r"||W[D]==="--resolutions"){let u=[];for(let F=D+1;F<W.length;F++){if(W[F].startsWith("-"))break;u.push(W[F]),D=F}AD=u.join(",").split(/[,\s]+/).map((F)=>F.trim()).filter((F)=>F.length>0)}else if(W[D]==="-p"||W[D]==="--poster")ZD=W[D+1],D++;else if(W[D]==="-c"||W[D]==="--codec"){let u=W[D+1];if(u==="av1"||u==="h264"||u==="dual")d=u;else console.error(` Invalid codec: ${u}. Valid options: av1, h264, dual`),process.exit(1);D++}else if(W[D]==="-f"||W[D]==="--format"){let u=W[D+1];if(u==="dash"||u==="hls"||u==="both")c=u;else console.error(` Invalid format: ${u}. Valid options: dash, hls, both`),process.exit(1);D++}else if(W[D]==="--h264-cq"){if(O=parseInt(W[D+1]),isNaN(O)||O<0||O>51)console.error(` Invalid H.264 CQ value: ${W[D+1]}. Must be 0-51`),process.exit(1);D++}else if(W[D]==="--h264-crf"){if(w=parseInt(W[D+1]),isNaN(w)||w<0||w>51)console.error(` Invalid H.264 CRF value: ${W[D+1]}. Must be 0-51`),process.exit(1);D++}else if(W[D]==="--av1-cq"){if(j=parseInt(W[D+1]),isNaN(j)||j<0||j>51)console.error(` Invalid AV1 CQ value: ${W[D+1]}. Must be 0-51`),process.exit(1);D++}else if(W[D]==="--av1-crf"){if(b=parseInt(W[D+1]),isNaN(b)||b<0||b>63)console.error(` Invalid AV1 CRF value: ${W[D+1]}. Must be 0-63`),process.exit(1);D++}else if(!W[D].startsWith("-"))bD.push(W[D]);var e=bD[0],pu=bD[1]||".";if(!e)console.error("❌ Usage: avc <input-video> [output-dir] [options]"),console.error(`
Options:`),console.error(" -r, --resolutions Video resolutions (e.g., 360,480,720 or 720@60,1080@60)"),console.error(" -c, --codec Video codec: av1, h264, or dual (default: dual)"),console.error(" -f, --format Streaming format: dash, hls, or both (default: both)"),console.error(" -p, --poster Poster timecode (e.g., 00:00:05 or 10)"),console.error(`
Quality Options (override defaults):`),console.error(" --h264-cq <value> H.264 GPU CQ value (0-51, lower = better, default: auto)"),console.error(" --h264-crf <value> H.264 CPU CRF value (0-51, lower = better, default: auto)"),console.error(" --av1-cq <value> AV1 GPU CQ value (0-51, lower = better, default: auto)"),console.error(" --av1-crf <value> AV1 CPU CRF value (0-63, lower = better, default: auto)"),console.error(`
2025-12-03 21:55:35 +03:00
Examples:`),console.error(" avc video.mp4"),console.error(" avc video.mp4 ./output"),console.error(" avc video.mp4 -r 360,480,720"),console.error(" avc video.mp4 -c av1 --av1-cq 40"),console.error(" avc video.mp4 -c dual --h264-cq 30 --av1-cq 39"),console.error(" avc video.mp4 -f hls"),console.error(" avc video.mp4 -c dual -f both"),console.error(" avc video.mp4 -r 720@60,1080@60,2160@60 -c av1 -f dash"),console.error(" avc video.mp4 -p 00:00:05"),console.error(" avc video.mp4 ./output -r 720,1080 -c dual -f both -p 10 --h264-cq 28 --av1-cq 37"),process.exit(1);console.log(`\uD83D\uDD0D Checking system...
`);var nu=await n(),su=await a(),jD=await r(),au=await s();console.log(`FFmpeg: ${nu?"✅":"❌"}`);console.log(`NVENC (H.264): ${su?"✅ (GPU acceleration)":"⚠️ (CPU only)"}`);if(jD.available)console.log(`AV1 Encoder: ${jD.encoder} (GPU acceleration)`);else console.log("AV1 Encoder: ⚠️ (not available, will use CPU fallback)");console.log(`MP4Box: ${au?"✅":"❌"}
`);if(!nu)console.error("❌ FFmpeg not found. Please install FFmpeg first."),process.exit(1);if(!au)console.error("❌ MP4Box not found. Please install: sudo pacman -S gpac"),process.exit(1);if((d==="av1"||d==="dual")&&!jD.available)console.error("⚠️ Warning: AV1 encoding requested but no hardware AV1 encoder found."),console.error(" CPU-based AV1 encoding (libsvtav1) will be VERY slow."),console.error(` Consider using --codec h264 for faster encoding.
`);if((c==="hls"||c==="both")&&d==="av1")console.error("❌ Error: HLS format requires H.264 codec for Safari/iOS compatibility."),console.error(` Please use --codec h264 or --codec dual with --format hls
`),process.exit(1);console.log(`\uD83D\uDCCA Analyzing video...
2025-12-03 21:55:35 +03:00
`);var T=await i(e),u3=D3(e),F3=(u3.size/1048576).toFixed(2);console.log("\uD83D\uDCF9 Video Information:");console.log(` File: ${e}`);console.log(` Size: ${F3} MB`);console.log(` Resolution: ${T.width}x${T.height}`);console.log(` FPS: ${T.fps.toFixed(2)}`);console.log(` Duration: ${Math.floor(T.duration/60)}m ${Math.floor(T.duration%60)}s`);console.log(` Codec: ${T.codec}`);if(T.videoBitrate)console.log(` Video Bitrate: ${(T.videoBitrate/1000).toFixed(2)} Mbps`);if(T.audioBitrate)console.log(` Audio Bitrate: ${T.audioBitrate} kbps`);console.log(`
\uD83D\uDCC1 Output: ${pu}`);console.log(`\uD83C\uDFAC Codec: ${d}${d==="dual"?" (AV1 + H.264 for maximum compatibility)":""}`);console.log(`\uD83D\uDCFA Format: ${c}${c==="both"?" (DASH + HLS for maximum compatibility)":c==="hls"?" (H.264 only for Safari/iOS)":""}`);if(AD)console.log(`\uD83C\uDFAF Custom profiles: ${AD.join(", ")}`);if(ZD)console.log(`\uD83D\uDDBC Poster timecode: ${ZD}`);var P;if(O!==void 0||w!==void 0||j!==void 0||b!==void 0){if(P={},O!==void 0||w!==void 0){if(P.h264={},O!==void 0)P.h264.cq=O;if(w!==void 0)P.h264.crf=w;console.log(`\uD83C\uDF9A H.264 Quality: ${O!==void 0?`CQ ${O}`:""}${w!==void 0?` CRF ${w}`:""}`)}if(j!==void 0||b!==void 0){if(P.av1={},j!==void 0)P.av1.cq=j;if(b!==void 0)P.av1.crf=b;console.log(`\uD83C\uDF9A AV1 Quality: ${j!==void 0?`CQ ${j}`:""}${b!==void 0?` CRF ${b}`:""}`)}}console.log(`
2025-11-09 13:24:10 +03:00
\uD83D\uDE80 Starting conversion...
2025-12-03 21:55:35 +03:00
`);var BD=new wD.default.MultiBar({format:"{stage} | {bar} | {percentage}% | {name}",barCompleteChar:"█",barIncompleteChar:"░",hideCursor:!0,clearOnComplete:!1,stopOnComplete:!0},wD.default.Presets.shades_classic),MD={},OD=null;try{let D=await ID({input:e,outputDir:pu,customProfiles:AD,posterTimecode:ZD,codec:d,format:c,segmentDuration:2,useNvenc:su,quality:P,generateThumbnails:!0,generatePoster:!0,parallel:!0,onProgress:(u)=>{let C=u.stage==="encoding"?"Encoding":u.stage==="thumbnails"?"Thumbnails":u.stage==="manifest"?"Manifest":u.stage==="analyzing"?"Analyzing":"Complete";if(u.stage==="encoding"&&u.currentProfile){if(!MD[u.currentProfile])MD[u.currentProfile]=BD.create(100,0,{stage:"Encode",name:u.currentProfile});let F=u.profilePercent??u.percent;MD[u.currentProfile].update(F,{stage:"Encode",name:u.currentProfile})}if(!OD)OD=BD.create(100,0,{stage:C,name:"Overall"});OD.update(u.percent,{stage:C,name:u.message||"Overall"})}});if(BD.stop(),console.log(`
2025-11-09 01:28:42 +03:00
Conversion completed successfully!
`),console.log("\uD83D\uDCCA Results:"),D.manifestPath)console.log(` DASH Manifest: ${D.manifestPath}`);if(D.hlsManifestPath)console.log(` HLS Manifest: ${D.hlsManifestPath}`);if(console.log(` Duration: ${D.duration.toFixed(2)}s`),console.log(` Profiles: ${D.profiles.map((u)=>u.name).join(", ")}`),console.log(` Format: ${D.format}`),console.log(` Codec: ${D.codecType}${D.codecType==="dual"?" (AV1 + H.264)":""}`),console.log(` Encoder: ${D.usedNvenc?"⚡ GPU accelerated":"\uD83D\uDD27 CPU"}`),D.posterPath)console.log(` Poster: ${D.posterPath}`);if(D.thumbnailSpritePath)console.log(` Thumbnails: ${D.thumbnailSpritePath}`),console.log(` VTT file: ${D.thumbnailVttPath}`);console.log(`
2025-12-03 21:55:35 +03:00
\uD83C\uDF89 Done! You can now use the manifest file(s) in your video player.`)}catch(D){BD.stop(),console.error(`
2025-11-09 01:28:42 +03:00
Error during conversion:`),console.error(D),process.exit(1)}