Files
ArtPlayer/document/assets/advanced_class.md.BE9Wp7q6.js
T
糖猫猫andrionzhao 0896841d23 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>
2026-09-10 17:19:38 +08:00

9 lines
13 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import{_ as e,o as n,c as l,ak as s,j as a}from"./chunks/framework.xxfEszSJ.js";const u=JSON.parse('{"title":"静态属性","description":"","frontmatter":{},"headers":[],"relativePath":"advanced/class.md","filePath":"advanced/class.md","lastUpdated":1682233868000}'),t={name:"advanced/class.md"};function p(d,i,r,h,o,c){return n(),l("div",null,i[0]||(i[0]=[s('<h1 id="静态属性" tabindex="-1">静态属性 <a class="header-anchor" href="#静态属性" aria-label="Permalink to &quot;静态属性&quot;">​</a></h1><p>这里的 <code>静态属性</code> 是指挂载在 <code>构造函数</code> 的 <code>一级属性</code>,非常少使用</p><h2 id="instances" tabindex="-1"><code>instances</code> <a class="header-anchor" href="#instances" aria-label="Permalink to &quot;`instances`&quot;">​</a></h2><p>返回全部播放器实例的数组,假如你想同时管理多个播放器的时候,可以用到该属性</p>',4),a("div",{className:"run-code"},"▶ Run Code",-1),s(`<div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">info</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">([</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">Artplayer.instances]);</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">var</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> art </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> new</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Artplayer</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> container: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;.artplayer-app&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> url: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;/assets/sample/video.mp4&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">info</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">([</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">Artplayer.instances]);</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><h2 id="version" tabindex="-1"><code>version</code> <a class="header-anchor" href="#version" aria-label="Permalink to &quot;\`version\`&quot;">​</a></h2><p>返回播放器的版本信息</p>`,3),a("div",{className:"run-code"},"▶ Run Code",-1),s('<div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">info</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(Artplayer.version);</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><h2 id="env" tabindex="-1"><code>env</code> <a class="header-anchor" href="#env" aria-label="Permalink to &quot;`env`&quot;">​</a></h2><p>返回播放器的环境变量</p>',3),a("div",{className:"run-code"},"▶ Run Code",-1),s('<div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">info</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(Artplayer.env);</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><h2 id="build" tabindex="-1"><code>build</code> <a class="header-anchor" href="#build" aria-label="Permalink to &quot;`build`&quot;">​</a></h2><p>返回播放器的打包时间</p>',3),a("div",{className:"run-code"},"▶ Run Code",-1),s('<div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">info</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(Artplayer.build);</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><h2 id="config" tabindex="-1"><code>config</code> <a class="header-anchor" href="#config" aria-label="Permalink to &quot;`config`&quot;">​</a></h2><p>返回视频的默认配置</p>',3),a("div",{className:"run-code"},"▶ Run Code",-1),s('<div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">info</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(Artplayer.config);</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><h2 id="utils" tabindex="-1"><code>utils</code> <a class="header-anchor" href="#utils" aria-label="Permalink to &quot;`utils`&quot;">​</a></h2><p>返回播放器的工具函数集合</p>',3),a("div",{className:"run-code"},"▶ Run Code",-1),s('<div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">info</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(Artplayer.utils);</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><div class="warning custom-block"><p class="custom-block-title">全部工具函数请参考以下地址:</p><p><a href="https://github.com/zhw2590582/ArtPlayer/blob/master/packages/artplayer/types/utils.d.ts" target="_blank" rel="noreferrer">artplayer/types/utils.d.ts</a></p></div><h2 id="scheme" tabindex="-1"><code>scheme</code> <a class="header-anchor" href="#scheme" aria-label="Permalink to &quot;`scheme`&quot;">​</a></h2><p>返回播放器选项的校验方案</p>',4),a("div",{className:"run-code"},"▶ Run Code",-1),s('<div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">info</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(Artplayer.scheme);</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><h2 id="emitter" tabindex="-1"><code>Emitter</code> <a class="header-anchor" href="#emitter" aria-label="Permalink to &quot;`Emitter`&quot;">​</a></h2><p>返回事件分发器的构造函数</p>',3),a("div",{className:"run-code"},"▶ Run Code",-1),s('<div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">info</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(Artplayer.Emitter);</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><h2 id="validator" tabindex="-1"><code>validator</code> <a class="header-anchor" href="#validator" aria-label="Permalink to &quot;`validator`&quot;">​</a></h2><p>返回选项的校验函数</p>',3),a("div",{className:"run-code"},"▶ Run Code",-1),s('<div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">info</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(Artplayer.validator);</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><h2 id="kindof" tabindex="-1"><code>kindOf</code> <a class="header-anchor" href="#kindof" aria-label="Permalink to &quot;`kindOf`&quot;">​</a></h2><p>返回类型检测的函数工具</p>',3),a("div",{className:"run-code"},"▶ Run Code",-1),s('<div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">info</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(Artplayer.kindOf);</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><h2 id="html" tabindex="-1"><code>html</code> <a class="header-anchor" href="#html" aria-label="Permalink to &quot;`html`&quot;">​</a></h2><p>返回播放器所需的 <code>html</code> 字符串</p>',3),a("div",{className:"run-code"},"▶ Run Code",-1),s('<div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">info</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(Artplayer.html);</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><h2 id="option" tabindex="-1"><code>option</code> <a class="header-anchor" href="#option" aria-label="Permalink to &quot;`option`&quot;">​</a></h2><p>返回播放器的默认选项</p>',3),a("div",{className:"run-code"},"▶ Run Code",-1),s('<div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">info</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(Artplayer.option);</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div>',1)]))}const _=e(t,[["render",p]]);export{u as __pageData,_ as default};