docs(site): [SITE-04] document Iframe and Thumbnail tools

This commit is contained in:
Harvey Zhao committed 2026-09-16 03:49:38 +08:00
1 parent 3aad294aa5
commit 484a8c903c
111 files changed
+5088 -2141

No files matched your search

+342
View File
@@ -8214,6 +8214,348 @@ var art = new Artplayer({
});
```
===== packages/artplayer-vitepress/docs/en/tool/iframe.md =====
# Iframe communication tool
[简体中文](../../tool/iframe.md)
Control a player inside an iframe and receive child-page notifications. This is a standalone constructor, not an ArtPlayer plugins-array factory. This page describes the unreleased branch; deploy both parent and child pages yourself.
## Install and connect both pages
```sh
yarn add artplayer-tool-iframe
```
The parent uses `import ArtplayerToolIframe from 'artplayer-tool-iframe'`. For scripts, load `dist/artplayer-tool-iframe.js`; its global is `ArtplayerToolIframe`.
The child must also load the tool and call inject. To create a player there, load ArtPlayer and provide a container too. The repository's `/iframe.html` uses:
```html
<div class="artplayer-app" style="width:100%;height:100%"></div>
<script src="./uncompiled/artplayer/index.js"></script>
<script src="./uncompiled/artplayer-tool-iframe/index.js"></script>
<script>ArtplayerToolIframe.inject();</script>
```
These are this site's development paths; replace them with deployed build paths. The [original parent example](https://artplayer.org/?libs=./uncompiled/artplayer-tool-iframe/index.js&example=iframe) below creates an iframe pointing to `/iframe.html`:
<div className="run-code" data-libs="./uncompiled/artplayer-tool-iframe/index.js">▶ Run Code</div>
```js
// npm i artplayer-tool-iframe
// import ArtplayerToolIframe from 'artplayer-tool-iframe';
const $iframe = document.createElement('iframe')
$iframe.allowFullscreen = true
$iframe.width = '100%'
$iframe.height = '100%'
const $container = document.querySelector('.artplayer-app')
$container.innerHTML = ''
$container.appendChild($iframe)
const iframe = new ArtplayerToolIframe({
iframe: $iframe,
url: '/iframe.html',
})
window.addEventListener('artplayer:example:cleanup', () => {
iframe.destroy()
$iframe.remove()
}, { once: true })
iframe.message(({ type, data }) => {
switch (type) {
case 'fullscreenWeb':
if (data) {
$iframe.classList.add('fullscreenWeb')
}
else {
$iframe.classList.remove('fullscreenWeb')
}
break
default:
break
}
})
iframe.commit(() => {
const art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
fullscreen: true,
fullscreenWeb: true,
})
art.on('fullscreenWeb', (state) => {
ArtplayerToolIframe.postMessage({
type: 'fullscreenWeb',
data: state,
})
})
}).catch((error) => {
if (!iframe.destroyed)
console.error(error)
})
```
## Parent instance
Both options are required: `{ iframe: HTMLIFrameElement, url: string }`. Construction sets iframe.src and subscribes to messages; it does not install scripts in the child. The caller creates and removes the iframe element.
| Member | Behavior |
| --- | --- |
| `commit(callback)` | Extract the function body and execute it in the child; returns a response Promise |
| `postMessage({ type, data, id? })` | Send a request and await its response; allocate a numeric id when sending, ignoring a supplied id |
| `message(callback)` | Set one notification callback; the next call replaces it; synchronous void |
| `onMessage(event)` | Parent receiver, normally invoked by the installed native message listener |
| `destroy()` | Synchronous and idempotent; remove owned listeners/navigation observation and reject sent/waiting requests |
| `url` / `$iframe` | Initial configured address and element; changing url alone does not navigate |
| `injected` / `destroyed` | Injection and destruction state |
| `promises` | Pending request object, retaining the historical `resove` and `reject` callback keys |
| `messageCallback` | Current callback; initially a function, also nullable at runtime |
Notifications receive only `{ type, data }`, with the tool as this, without id or private document metadata. Any matching non-error response settles its request; error responses reject with Error. Custom message types remain valid, but the application must implement their child responses. There is no default response timeout.
Before injection, requests poll every200ms; inject does not flush them synchronously. IDs are correlation numbers, not necessarily Date.now. Destruction rejects unfinished requests with `The instance has been destroyed`; handle Promise failures.
## How commit executes
A normal function body can return a structured-cloneable result. Asynchronous results use the historical literal `resolve(...)` convention:
```js
const title = await iframe.commit(() => {
return document.title; // Read in the child page.
});
const answer = await iframe.commit((resolve) => {
setTimeout(() => resolve(42), 100);
});
```
The body is sliced from a string and evaluated with new Function. Closures, parent locals, function arguments and imports are not transferred. Keep braces; do not use expression arrows, async function bodies, top-level await or a renamed asynchronous resolve parameter. Detection is a text match, not a JavaScript parser. Results must support postMessage; a Promise object itself cannot be sent as a normal result. Execution errors send an error response and also reject the child's receiver.
## Child statics and trust
| Member | Behavior |
| --- | --- |
| `ArtplayerToolIframe.iframe` | Runtime readonly getter: whether this page is inside an iframe |
| `inject()` | Announce injection and install the receiver; repeated calls retain one listener set |
| `postMessage({ type, data, id? })` | Send a parent notification/response; id defaults0; returns void |
| `onMessage(event)` | Actually async; handles commit, while custom types need application handling |
The three methods require an iframe context; top-level use throws or rejects. Receivers check the selected window peer and basic packet shape, retaining wildcard targetOrigin rather than pinning the initial URL's origin. Trust the parent and child content. Commit executes code and requires a compatible CSP; it is neither a sandbox nor a payload validator.
## Navigation, cleanup and types
Upgraded peers negotiate document markers to reject obsolete replies and cancel work when document departure is confirmed. These markers are not authentication credentials. A src replacement pauses sends; confirmed cross-document departure cancels old requests, while a matching same-document hash change preserves them. Work queued for the next page is tracked separately. Legacy children cannot identify same-address reloads or internal navigation reliably; ordinary navigation tests do not establish BFCache restoration.
Destroy does not remove the iframe, destroy its player or provide a new static child destroy method. The parent can remove its iframe after releasing the tool. Player events, fullscreen permissions and physical devices require actual integration checks.
Root and `/legacy` preserve the historical class, including required Message.data, readonly fields, void static onMessage and ReturnType-based commit inference. Import accurate erased views from the same entry; there is no `/runtime` subpath:
```ts
import Iframe from 'artplayer-tool-iframe';
import type { ResolverInstance, RuntimeConstructor } from 'artplayer-tool-iframe';
function connectFrame(element: HTMLIFrameElement) {
const Runtime = Iframe as RuntimeConstructor;
const tool = new Runtime({ iframe: element, url: '/iframe.html' }) as ResolverInstance;
tool.message(function (message) { console.log(this.url, message.type, message.data); });
const answer = tool.commit<number>((resolve) => { resolve(42); });
return { tool, answer };
}
```
Public types are Option, Message, Callbacks, Notification, MessageCallback, OutboundMessage, ProtocolMessage, Resolve, ResolverCallback, RuntimeInstance, ResolverInstance and RuntimeConstructor. Views neither validate responses nor alter execution. Modern CommonJS TS can use `import Iframe = require('artplayer-tool-iframe')`; ESM uses the default import. The constructor has no `.default` self-alias. The old `artplayer-plugin-iframe` name, namespace and separate helper are not identical to this tool; renaming the dependency alone does not preserve every old entrypoint.
===== packages/artplayer-vitepress/docs/en/tool/thumbnail.md =====
# Local video thumbnail tool
[简体中文](../../tool/thumbnail.md)
Generate a PNG thumbnail sheet from a selected local video, then download it or use it with the player's thumbnails option. This is a standalone constructor, not the Auto Thumbnail plugin. This page describes the unreleased branch and its approved compatibility modes.
## Install and example
```sh
yarn add artplayer-tool-thumbnail
```
ESM uses `import ArtplayerToolThumbnail from 'artplayer-tool-thumbnail'`. Scripts load `dist/artplayer-tool-thumbnail.js`, exposing `ArtplayerToolThumbnail`. The tool does not depend on the player; the [original example](https://artplayer.org/?libs=./uncompiled/artplayer-tool-thumbnail/index.js&example=tool.thumbnail) below uses this site's DOM and ArtPlayer to display the result:
<div className="run-code" data-libs="./uncompiled/artplayer-tool-thumbnail/index.js">▶ Run Code</div>
```js
if (window.lastThumbnail) {
window.lastThumbnail.destroy();
}
var $popups = document.querySelector('.popups');
var $popinner = document.querySelector('.popinner');
var $artplayer = document.querySelector('.artplayer-app');
$artplayer.innerHTML = 'Drop video file here or click to upload.';
var thumbnail = new ArtplayerToolThumbnail({
fileInput: $artplayer,
number: 60, // 数量
width: 160, // 宽度
column: 10, // 列数
begin: 0, // 开始
end: NaN, // 结束
});
window.lastThumbnail = thumbnail;
thumbnail.on('file', function (file) {
console.log('Read video successfully: ' + file.name);
});
thumbnail.on('video', function (video) {
console.log('Video size: ' + video.videoWidth + ' x ' + video.videoHeight);
console.log('Video duration: ' + video.duration + 's');
thumbnail.start();
});
thumbnail.on('canvas', function (canvas) {
console.log('Build canvas successfully');
console.log('Canvas size: ' + canvas.width + ' x ' + canvas.height);
console.log('Preview density: ' + thumbnail.density + ' p/s');
});
thumbnail.on('update', function (url, percentage) {
console.log('Processing: ' + Math.floor(percentage.toFixed(2) * 100) + '%');
$popups.style.display = 'flex';
$popinner.style.backgroundImage = 'url(' + url + ')';
});
thumbnail.on('download', function (name) {
console.log('Start download preview: ' + name);
});
thumbnail.on('done', function () {
$popups.style.display = 'none';
thumbnail.download();
console.log('Build preview image complete');
[...Artplayer.instances].forEach(function (art) {
art.destroy(true);
});
new Artplayer({
container: $artplayer,
url: thumbnail.videoUrl,
autoSize: true,
poster: thumbnail.thumbnailUrl,
thumbnails: {
url: thumbnail.thumbnailUrl,
number: thumbnail.option.number,
column: thumbnail.option.column,
},
});
console.log('Build player complete');
});
```
File selection loads the video without automatically extracting images; the example calls start from the video event. Application code should handle both synchronous start errors and Promise rejection. The video notification does not guarantee metadata readiness; start waits for it. Subscribe before loading, especially with synchronous workspace-mode notifications.
## Options and defaults
Successful construction needs fileInput: an existing file input or an Element upload wrapper. Missing input throws synchronously even though the type allows omitted constructor options. A wrapper receives an owned transparent input; caller inputs remain caller-owned. Selection/drop reads only the first file.
| Field | Default | Meaning |
| --- | --- | --- |
| `fileInput` | Required for construction | File input or upload wrapper |
| `compatibility` | published-3.5 behavior | Alternatively choose `workspace-4.4` |
| `number` | `60` | Frame count, numerically clamped to10–1000 |
| `width` | `160` | Frame width, clamped to10–1000 |
| `height` | `90` | Fixed default-mode height, clamped to10–1000 |
| `column` | `10` | Columns, clamped to1–1000 |
| `begin` | `0` | Start time in seconds |
| `end` | `NaN` | End time in seconds; NaN/0 uses media duration |
| `delay` | `300` | Default-mode milliseconds, clamped to10–1000 |
Use valid finite dimensions and integer counts/columns; historical numeric checks are not integer validation. Start normalizes the interval against media duration and requires end greater than begin, finite duration and `number / intervalSeconds <= 1`. The default60 frames therefore needs an interval of at least60 seconds; change the count for shorter files.
| Behavior | Default / published-3.5 | workspace-4.4 |
| --- | --- | --- |
| Height | Keep configured height | Derive from video aspect ratio at start and update option.height |
| video event | After src assignment plus delay | Synchronously after src assignment |
| Frame wait | Policy delay after each seek plus frame readiness | Frame readiness without a fixed extra delay |
| done | Another delay × 2 after the last update | No fixed final wait |
| Input value | Retained | Cleared after reading the selected file |
Consumers of unpublished4.4 workspace behavior add `compatibility: 'workspace-4.4'`; this mode ignores delay. Static DEFAULTS returns a fresh default object including published delay on every access, regardless of instance mode. Browser scheduling means delays are not exact timestamps.
## Methods, state and output
| Method | Behavior |
| --- | --- |
| `setup(options?)` | Merge partial options, retain extra fields and transfer input listeners when needed; returns this |
| `loadVideo(file?)` | Accept File; absent input is a no-op; check canPlayType and create a Blob URL |
| `start()` | One extraction job returning `Promise<void>`; duplicates and ready-metadata preflight can throw synchronously |
| `creatScreenshotDate()` | Historical spelling; return `{ time, x, y }[]`, with time in seconds |
| `creatCanvas()` | Historical spelling; create the sheet with black background and footer text |
| `download()` | Trigger PNG download when idle with file/image available; returns this, throws if not ready |
| `inputChange(event)` / `ondrop(event)` | Bound input handlers, normally installed by the tool |
| `errorHandle(condition, message)` | Emit error and throw when the condition fails |
| `destroy()` | Synchronous, idempotent cancellation and owned-resource cleanup |
Static creatVideo creates an offscreen muted/controls video in the document; callers invoking it directly own that extra node. Static ondragover calls preventDefault. Historical creat* names remain unchanged.
Fields include processing, option, video, duration, density, file, videoUrl, thumbnailUrl and optional event registry e. Duration is the selected interval, not necessarily full media duration; density is frames per interval second. File/URLs/density may be absent before their operation. Canvas listeners observe processing=false, update listeners true, and done listeners false.
Frames sample interval midpoints: `begin + (i + 0.5) * duration / number`. Sheet width is width × column; height is ceil(number / column) × height + 30. The30px footer retains source/layout text. Fractional coordinates keep historical behavior. Each frame produces a PNG update; previous thumbnail Blob URLs are revoked, leaving the latest thumbnailUrl. Download naming removes the last extension segment and adds `.png`; extensionless names retain the historical `.png` result.
## Events and cleanup
on/once/emit/off return this. The third on/once argument sets callback this. off(name) removes all listeners for that event; off(name, callback) removes matches. Custom string, number and symbol events are supported. A listener exception stops the remaining callbacks in that dispatch.
| Event | Arguments and timing |
| --- | --- |
| `file` | File, synchronously before video.src assignment |
| `video` | HTMLVideoElement; timing depends on mode |
| `canvas` | HTMLCanvasElement before extraction |
| `update` | Latest URL and0–1 progress |
| `done` | No arguments, before the start Promise resolves |
| `download` | Filename after link click; not proof of completed disk writing |
| `error` | Usually a message string; user callback failures can carry other values |
| `destroy` | No arguments, once after resource cleanup |
Start can wait for the first file selection with no new metadata deadline. Replacing an existing source or destroying the instance rejects old work with AbortError without an error event for cancellation. Source, seek, draw, encoding and callback failures settle the job. Stale callbacks cannot update a newer result.
Destroy removes the owned video/generated input/listeners/Blob URLs and restores wrapper position if the tool still owns that write. Caller inputs and the emitter registry remain. Cleanup attempts all steps, then throws its first failure. Destroyed instances cannot recreate input/source resources; start rejects cancellation. Keep the tool alive while a player depends on videoUrl/thumbnailUrl: those URLs remain tool-owned.
MIME canPlayType, actual decoding, Canvas encoding and Blob URL support are separate conditions. Windows WebKit has a recorded native Blob-loading gap; successful guide navigation or HTTP video playback is not proof of local-file extraction.
## TypeScript
Root and `/legacy` share one class declaration, with no `/runtime` or runtime `.default` self-alias. CommonJS TS supports `import Thumbnail = require('artplayer-tool-thumbnail')`; ESM uses default/type imports:
```ts
import Thumbnail, { type Option } from 'artplayer-tool-thumbnail';
function createTool(input: HTMLInputElement) {
const options: Option = { fileInput: input, number: 10, height: 90 };
const tool = new Thumbnail(options);
tool.on('update', (url, progress) => console.log(url, progress));
tool.on('video', () => {
void (async () => {
try { await tool.start(); }
catch (error) { console.error(error); }
})();
});
return tool;
}
```
Types include SheetOptions, Compatibility, DefaultOptions, Option, ResolvedOption, ScreenshotPoint, Events, EventArgs, Listener and EventRegistry. Known events have precise arguments; custom protocols remain application-defined. The old workspace referenced a missing declaration, so the new types are not claimed as a recovered historical TS baseline. Missing complete old npm archives and rollback acceptance remain separately tracked.
===== Type Definitions Overview =====
===== docs/assets/ts/artplayer-plugin-ads.d.ts =====