mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-28 02:01:20 -08:00
feat: batch video upscaling with folder upload, directory save, and result comparison (#1051)
* feat: support batch video upscaling with folder upload and directory save - Add multi-file selection and entire folder upload (webkitdirectory) - Support drag & drop of both files and folders via FileSystemEntry API - Add save directory picker using File System Access API (showDirectoryPicker) - Process videos sequentially with per-file progress and status tracking - Add right-side result list with click-to-compare functionality - Add per-video duration and total batch duration display - Add retry button for failed items with error detail display - Remove auto-play on comparison viewer load - Fix worker error handling: handle "error" command to reject stale promises - Fix event listener accumulation in video comparison (AbortController) - Fix XSS risk by escaping HTML in all innerHTML injections - Fix URL revocation timing in download to prevent large file truncation - Extract writeToSaveDirectory and truncateName helpers to reduce duplication - Add Usage Guide panel explaining single/multiple/folder upload options Files changed: docs/upscaler/index.html (+1110/-181) docs/upscaler/upscaler.js (+110) * fix: prevent auto-play and resource consumption during upscaling - Set preload="metadata" on preview and comparison video elements - Explicitly pause preview video after setting src in showVideoPreview - Remove preview video seek sync from batch processing progress callbacks (was causing continuous decode during upscaling, wasting GPU resources) - Remove preview video seek sync from retry progress callback - All videos now require manual play; no background resource usage * fix: improve upscaled video quality with higher bitrate and codec support - Raise base bitrate from 2.5 Mbps (25e5) to 8 Mbps (8e6) for standard and firefox processors, preventing quality loss when source videos have high bitrates (e.g. 720p @ 16.7 Mbps was producing 1440p @ 10 Mbps, smaller than the original file) - Double the bitrate for mediabunny processor (X.n1 * 2) to account for the 4x pixel increase from 2x upscaling - Add H.264 Level 5.1 (avc1.640033) and Level 5.2 (avc1.640034) codecs to the fallback lists, since Level 4.0 (avc1.640028, ~24.6 Mbps) cannot support the higher bitrates for 1440p+ outputs - Add latencyMode: "quality" to VideoEncoder configs for both standard and firefox processors, prioritizing encoding quality over latency (suitable for offline processing) * feat: add video data comparison panel for original vs upscaled metrics - Add a comparison data table below the file info bar showing 6 metrics: Resolution, File Size, Duration, Est. Bitrate, Pixels, Process Time - Display per-metric change percentage with color-coded indicators: green (↑) for improvements, red (↓) for regressions, gray for neutral - Estimated bitrate calculated from file size × 8 / video duration - Table renders after both original and upscaled video metadata loads - Auto-hide panel on reset * fix: make video data comparison panel full-width and responsive - Move comparison data table from inside the left column to the full-width area below the left/right layout, so it is no longer constrained by the comparison viewer column width - Remove table-fixed colgroup and overflow-x-auto that caused horizontal scrolling on smaller screens - Table now uses w-full auto-layout, displaying all 4 columns (Metric, Original, Upscaled, Change) without requiring horizontal scrolling --------- Co-authored-by: rionzhao <rionzhao@tencent.com>
This commit is contained in:
commit
0896841d23
538 files changed
+379715
No files matched your search
@@ -0,0 +1,7 @@
|
||||
/*!
|
||||
* artplayer-proxy-mediabunny.js v1.2.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerProxyMediabunny=t(),define(function(){return t.artplayerProxyMediabunny})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyMediabunny=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.defineProperties,i=Object.getOwnPropertyDescriptors,r=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,a=(e,t)=>(t=Symbol[e])?t:Symbol.for("Symbol."+e),o=Math.pow,l=(t,i,r)=>i in t?e(t,i,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[i]=r,c=(e,t)=>{for(var i in t||(t={}))n.call(t,i)&&l(e,i,t[i]);if(r)for(var i of r(t))s.call(t,i)&&l(e,i,t[i]);return e},u=(e,r)=>t(e,i(r)),d=(e,t,i)=>new Promise((r,n)=>{var s=e=>{try{o(i.next(e))}catch(t){n(t)}},a=e=>{try{o(i.throw(e))}catch(t){n(t)}},o=e=>e.done?r(e.value):Promise.resolve(e.value).then(s,a);o((i=i.apply(e,t)).next())}),h=function(e,t){this[0]=e,this[1]=t},f=(e,t,i)=>{var r=(e,t,n,s)=>{try{var a=i[e](t),o=(t=a.value)instanceof h,l=a.done;Promise.resolve(o?t[0]:t).then(i=>o?r("return"===e?e:"next",t[1]?{done:i.done,value:i.value}:i,n,s):n({value:i,done:l})).catch(e=>r("throw",e,n,s))}catch(c){s(c)}},n=e=>s[e]=t=>new Promise((i,n)=>r(e,t,i,n)),s={};return i=i.apply(e,t),s[a("asyncIterator")]=()=>s,n("next"),n("throw"),n("return"),s},m=e=>{var t,i=e[a("asyncIterator")],r=!1,n={};return null==i?(i=e[a("iterator")](),t=e=>n[e]=t=>i[e](t)):(i=i.call(e),t=e=>n[e]=t=>{if(r){if(r=!1,"throw"===e)throw t;return t}return r=!0,{done:!1,value:new h(new Promise(r=>{var n=i[e](t);n instanceof Object||(e=>{throw TypeError(e)})("Object expected"),r(n)}),1)}}),n[a("iterator")]=()=>n,t("next"),"throw"in i?t("throw"):n.throw=e=>{throw e},"return"in i&&t("return"),n},p=(e,t,i)=>(t=e[a("asyncIterator")])?t.call(e):(e=e[a("iterator")](),t={},(i=(i,r)=>(r=e[i])&&(t[i]=t=>new Promise((i,n,s)=>(t=r.call(e,t),s=t.done,Promise.resolve(t.value).then(e=>i({value:e,done:s}),n)))))("next"),i("return"),t);function g(e,t){const i=new Map;return e.filter(e=>{const r=e[t];return void 0===r||!i.has(r)&&i.set(r,1)})}class k{constructor(){this.listeners=new Map}addEventListener(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t)}removeEventListener(e,t){const i=this.listeners.get(e);if(!i)return;const r=i.indexOf(t);r>=0&&i.splice(r,1)}emit(e,t){const i=new Event(e);i.detail=t;const r=this.listeners.get(e);r&&r.forEach(e=>e(i))}}function y(e){if(!e)throw new Error("Assertion failed.")}const b=e=>{const t=(e%360+360)%360;if(0===t||90===t||180===t||270===t)return t;throw new Error(`Invalid rotation ${e}.`)},T=e=>e&&e[e.length-1],S=e=>{let t=0;for(;0===e.readBits(1)&&t<32;)t++;if(t>=32)throw new Error("Invalid exponential-Golomb code.");return(1<<t)-1+e.readBits(t)},v=e=>{const t=S(e);return 0===(1&t)?-(t>>1):t+1>>1},w=e=>e.constructor===Uint8Array?e:ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e),P=e=>e.constructor===DataView?e:ArrayBuffer.isView(e)?new DataView(e.buffer,e.byteOffset,e.byteLength):new DataView(e),I=new TextDecoder,x=e=>Object.fromEntries(Object.entries(e).map(([e,t])=>[t,e])),C={bt709:1,bt470bg:5,smpte170m:6,bt2020:9,smpte432:12},B=x(C),E={bt709:1,smpte170m:6,linear:8,"iec61966-2-1":13,pq:16,hlg:18},_=x(E),A={rgb:0,bt709:1,bt470bg:5,smpte170m:6,"bt2020-ncl":9},F=x(A),R=e=>e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e);class D{constructor(){this.currentPromise=Promise.resolve(),this.pending=0}acquire(){return d(this,null,function*(){let e;const t=new Promise(t=>{let i=!1;e=()=>{i||(t(),this.pending--,i=!0)}}),i=this.currentPromise;return this.currentPromise=t,this.pending++,yield i,e})}}const M=/^[0-9a-fA-F]+$/,N=e=>[...e].map(e=>e.toString(16).padStart(2,"0")).join(""),O=e=>(e=(e=(e=(e=(e=e>>1&1431655765|(1431655765&e)<<1)>>2&858993459|(858993459&e)<<2)>>4&252645135|(252645135&e)<<4)>>8&16711935|(16711935&e)<<8)>>16&65535|(65535&e)<<16)>>>0,L=(e,t,i)=>{let r=0,n=e.length-1,s=-1;for(;r<=n;){const a=r+n>>1,o=i(e[a]);o===t?(s=a,n=a-1):o<t?r=a+1:n=a-1}return s},z=(e,t,i)=>{let r=0,n=e.length-1,s=-1;for(;r<=n;){const a=r+(n-r+1)/2|0;i(e[a])<=t?(s=a,r=a+1):n=a-1}return s},U=(e,t,i)=>{const r=z(e,i(t),i);e.splice(r+1,0,t)},q=()=>{let e,t;return{promise:new Promise((i,r)=>{e=i,t=r}),resolve:e,reject:t}},W=(e,t)=>{for(let i=e.length-1;i>=0;i--)if(t(e[i]))return e[i]},V=(e,t)=>{for(let i=e.length-1;i>=0;i--)if(t(e[i]))return i;return-1},H=e=>{throw new Error(`Unexpected value: ${e}`)},K=(e,t,i)=>{const r=e.getUint8(t),n=e.getUint8(t+1),s=e.getUint8(t+2);return i?r|n<<8|s<<16:r<<16|n<<8|s},j=(e,t,i,r)=>{i>>>=0,i&=16777215,e.setUint8(t,i>>>16&255),e.setUint8(t+1,i>>>8&255),e.setUint8(t+2,255&i)},X=(e,t)=>({next(){return d(this,null,function*(){const i=yield e.next();return i.done?{value:void 0,done:!0}:{value:t(i.value),done:!1}})}Line truncated
|
||||
Reference in new issue
Block a user