mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-09 11:56:15 -08:00
Compare commits
400
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fec539dbe3 | ||
|
|
78e3107b68 | ||
|
|
58a648fd05 | ||
|
|
d71b6fea38 | ||
|
|
5795492f0f | ||
|
|
783d1e3fd4 | ||
|
|
681eccfa76 | ||
|
|
8aa99ef03f | ||
|
|
fb78328c43 | ||
|
|
6b580d1667 | ||
|
|
61fe8deb59 | ||
|
|
54e5cbf49c | ||
|
|
e8b48cbaed | ||
|
|
cec5049c40 | ||
|
|
24011ea266 | ||
|
|
8d2ec199d7 | ||
|
|
0a060e6088 | ||
|
|
9afbf9940d | ||
|
|
bd3f3c0689 | ||
|
|
de45f5b978 | ||
|
|
5bf1a36183 | ||
|
|
96962a69a4 | ||
|
|
bb2fec8dd1 | ||
|
|
5910c3f179 | ||
|
|
a1488f11bb | ||
|
|
9f454ecd1d | ||
|
|
b029062ace | ||
|
|
4db9789014 | ||
|
|
e2bd7c9742 | ||
|
|
484a8c903c | ||
|
|
3aad294aa5 | ||
|
|
558e946ae5 | ||
|
|
2305f9d7c7 | ||
|
|
3317230f2e | ||
|
|
94adb77fd6 | ||
|
|
3138812610 | ||
|
|
dba354f8cd | ||
|
|
6d7900df95 | ||
|
|
1b81888347 | ||
|
|
e54fc998ea | ||
|
|
aa146f07e4 | ||
|
|
6f7fd7931d | ||
|
|
2983cb7c51 | ||
|
|
69ad6fb17e | ||
|
|
267b21226a | ||
|
|
b5f8b5e28e | ||
|
|
490e157717 | ||
|
|
bb2c12df30 | ||
|
|
9cfb6c8b9f | ||
|
|
b3344a7c6d | ||
|
|
5e0447fc51 | ||
|
|
5862f60b0e | ||
|
|
ae56937d3b | ||
|
|
4545c43679 | ||
|
|
01f3d00e4c | ||
|
|
00c131bff1 | ||
|
|
210484c443 | ||
|
|
876fa4c328 | ||
|
|
9ba3c82f99 | ||
|
|
d3349e83f2 | ||
|
|
6af43208af | ||
|
|
eba8c29fa7 | ||
|
|
319dccb605 | ||
|
|
4ea0ba94ae | ||
|
|
2802cbacc5 | ||
|
|
e0c5cf27de | ||
|
|
ea3174daa2 | ||
|
|
520727d762 | ||
|
|
25faf88e80 | ||
|
|
1c522f181b | ||
|
|
2a38067911 | ||
|
|
ca967ea1a2 | ||
|
|
f37658d657 | ||
|
|
9cf4a58480 | ||
|
|
3c89b48514 | ||
|
|
65368809ee | ||
|
|
1fed96a909 | ||
|
|
3eb5500525 | ||
|
|
bf56d09178 | ||
|
|
8dcbe9441e | ||
|
|
42ddead0cd | ||
|
|
d3aa4bbfe4 | ||
|
|
d2b2f76db8 | ||
|
|
23ac6f7128 | ||
|
|
0cfdf4a7e3 | ||
|
|
244695e726 | ||
|
|
426fee8faa | ||
|
|
bc9cb61aaf | ||
|
|
99c208aeee | ||
|
|
11c9fefadd | ||
|
|
0d3ddbf355 | ||
|
|
11296975f1 | ||
|
|
fb1faffbe9 | ||
|
|
4bef084328 | ||
|
|
0503fe8aa8 | ||
|
|
3136eb2402 | ||
|
|
d2a83f8a69 | ||
|
|
199021c8a9 | ||
|
|
63e4e8ad92 | ||
|
|
ba1dbd430f | ||
|
|
b47ede011a | ||
|
|
3dba82a453 | ||
|
|
6cd2d0ffbe | ||
|
|
7cf6f33130 | ||
|
|
d2f4261aa7 | ||
|
|
bf432ed62a | ||
|
|
a4234230e6 | ||
|
|
ce67eaa73e | ||
|
|
4a9ef16b16 | ||
|
|
92b04d75c0 | ||
|
|
54169fdca1 | ||
|
|
25a0c6303d | ||
|
|
8379ac7bbf | ||
|
|
b90de99bc2 | ||
|
|
7094cf6f9c | ||
|
|
2d45135873 | ||
|
|
34e4136b43 | ||
|
|
a03e5acc50 | ||
|
|
18215b97c0 | ||
|
|
ddf3d6ccbc | ||
|
|
d0c33f6258 | ||
|
|
aa29dc9212 | ||
|
|
09459955c6 | ||
|
|
75da50a454 | ||
|
|
e5c73fa620 | ||
|
|
c162d2b3b3 | ||
|
|
314a1c3163 | ||
|
|
475d38043e | ||
|
|
30363a5346 | ||
|
|
b54a890832 | ||
|
|
88ce836f85 | ||
|
|
30f646be97 | ||
|
|
442e1dcc96 | ||
|
|
fc566f14d5 | ||
|
|
37ebb7a034 | ||
|
|
c3967bcbf4 | ||
|
|
d89728c0a6 | ||
|
|
492e58a345 | ||
|
|
765ddb816f | ||
|
|
e7f31b6fc8 | ||
|
|
838c3eb432 | ||
|
|
72d2b9c36b | ||
|
|
b1e0b976b0 | ||
|
|
48a7f1ecb0 | ||
|
|
23a4f22b72 | ||
|
|
7b0e1d156b | ||
|
|
04060aa8b6 | ||
|
|
3316b8a867 | ||
|
|
fe5534ac24 | ||
|
|
eb6402fdca | ||
|
|
a8d19ce5ef | ||
|
|
318de37e8a | ||
|
|
8ae2762a23 | ||
|
|
31f9024bff | ||
|
|
efed847cdf | ||
|
|
b5dee252d4 | ||
|
|
675b095b27 | ||
|
|
4acf85ea69 | ||
|
|
afb632d16f | ||
|
|
772d79a671 | ||
|
|
401d4cdd65 | ||
|
|
28c7abb2bb | ||
|
|
07d5bfef2e | ||
|
|
4fa5c68be9 | ||
|
|
2f130c58f1 | ||
|
|
a468cb2c39 | ||
|
|
078cd9ef72 | ||
|
|
647f3e7f12 | ||
|
|
76499e7a3e | ||
|
|
1a5440a67f | ||
|
|
d74ecc43cc | ||
|
|
d62ab13a35 | ||
|
|
4df9689364 | ||
|
|
e0d785662d | ||
|
|
3e39fc745f | ||
|
|
f30c701d88 | ||
|
|
c4f5dcf17f | ||
|
|
7be628a983 | ||
|
|
e93d3cbb67 | ||
|
|
814bdc11db | ||
|
|
7ef605fba7 | ||
|
|
7f185f698d | ||
|
|
b4b0276fe9 | ||
|
|
0f3c068aae | ||
|
|
5e445b1af6 | ||
|
|
38e7b37878 | ||
|
|
944e2cc9d0 | ||
|
|
0cf56b64d2 | ||
|
|
8abd49bc9c | ||
|
|
aca4bc1cd2 | ||
|
|
aba125262a | ||
|
|
6c989deccd | ||
|
|
00e81309ca | ||
|
|
4f559cb31d | ||
|
|
df6a6fe82e | ||
|
|
24b883d862 | ||
|
|
abc8008da7 | ||
|
|
053d211fb0 | ||
|
|
12332df221 | ||
|
|
0b2efb07f1 | ||
|
|
d3c91af92c | ||
|
|
ccf3d6ed14 | ||
|
|
d81b881085 | ||
|
|
7d44bce06f | ||
|
|
8ec9fbe83a | ||
|
|
b0cfbfe3a0 | ||
|
|
87cfcf5a6c | ||
|
|
58d2c95d8e | ||
|
|
c4c7491e16 | ||
|
|
1117107032 | ||
|
|
c723c70251 | ||
|
|
30de007102 | ||
|
|
d5562b05b7 | ||
|
|
146b78d576 | ||
|
|
5ab7da6e1f | ||
|
|
2cede66933 | ||
|
|
6d7b9292f8 | ||
|
|
3e3bed2b93 | ||
|
|
93208e59e1 | ||
|
|
0cf2af4840 | ||
|
|
53c295819d | ||
|
|
a22586a172 | ||
|
|
3b016970f2 | ||
|
|
4a299eb2d4 | ||
|
|
38355ae4cf | ||
|
|
585e11c53c | ||
|
|
2c73e2b105 | ||
|
|
d44e81ce22 | ||
|
|
7f226ff822 | ||
|
|
da64aae267 | ||
|
|
beaa93d6cc | ||
|
|
36cd151095 | ||
|
|
5a0d94cb89 | ||
|
|
0c5bb2bd7a | ||
|
|
db358a3ae4 | ||
|
|
7f2906ae52 | ||
|
|
80588a3046 | ||
|
|
524ddf784f | ||
|
|
05244d1104 | ||
|
|
d4ede650e8 | ||
|
|
8c57d56f17 | ||
|
|
a128706fe7 | ||
|
|
84721f19ed | ||
|
|
9cd6659ab4 | ||
|
|
cdc252b158 | ||
|
|
17befee4b1 | ||
|
|
3bff236145 | ||
|
|
15485b6420 | ||
|
|
efd9f42fb9 | ||
|
|
426c0c5d42 | ||
|
|
1cb7779192 | ||
|
|
0338e0b8b1 | ||
|
|
cb6c767731 | ||
|
|
b35183c7af | ||
|
|
047e2df945 | ||
|
|
1342de94ef | ||
|
|
b8cdafedd1 | ||
|
|
b8d03e7366 | ||
|
|
b3f22652c2 | ||
|
|
a52f79a0cc | ||
|
|
7e37fd4d0e | ||
|
|
401c5e9684 | ||
|
|
190fdb2776 | ||
|
|
fb9fb23f53 | ||
|
|
5e28dfee95 | ||
|
|
8a2b56e829 | ||
|
|
ccee9157a7 | ||
|
|
9d037dcbf9 | ||
|
|
5d0b128483 | ||
|
|
9af253a5a9 | ||
|
|
adba8a3d12 | ||
|
|
03451c029b | ||
|
|
63c8938dd7 | ||
|
|
1cfd2e17f3 | ||
|
|
1f93bb9ba1 | ||
|
|
ef976136a1 | ||
|
|
80d37d66f8 | ||
|
|
202351934b | ||
|
|
efbbdb4782 | ||
|
|
224572032a | ||
|
|
2b319109cd | ||
|
|
e931520e66 | ||
|
|
5e26d2298d | ||
|
|
20f062bc90 | ||
|
|
959cccf515 | ||
|
|
6caee44dbf | ||
|
|
43f0e9a8c6 | ||
|
|
06032a6906 | ||
|
|
c57c7e4b16 | ||
|
|
f35fb87615 | ||
|
|
6abac891ce | ||
|
|
e0aacc5d6a | ||
|
|
4f324a8438 | ||
|
|
d5e1feadf5 | ||
|
|
4f39d6f2b9 | ||
|
|
29692d2815 | ||
|
|
fb1cfa701d | ||
|
|
39e2d4cdfb | ||
|
|
069ad4aae1 | ||
|
|
c6b82c3392 | ||
|
|
bafbf2c8b0 | ||
|
|
a9cf50bc4e | ||
|
|
2ad00730ee | ||
|
|
c4b5f5f454 | ||
|
|
6840544e0e | ||
|
|
7de04573b6 | ||
|
|
762cc63431 | ||
|
|
3d4c636101 | ||
|
|
e0d47ea74b | ||
|
|
d18c545675 | ||
|
|
0218196df9 | ||
|
|
b5e96664ee | ||
|
|
13c898c149 | ||
|
|
9c07ea830c | ||
|
|
803e87252e | ||
|
|
8c0a2feed3 | ||
|
|
26b2983daf | ||
|
|
2f9bee4ee0 | ||
|
|
ba93b98be5 | ||
|
|
33f6d19b77 | ||
|
|
cbbdc03a7c | ||
|
|
adec20213f | ||
|
|
5efc7f7699 | ||
|
|
4a9a26d4fc | ||
|
|
8ed0a5228c | ||
|
|
faaa3e8c2d | ||
|
|
ee895a558f | ||
|
|
ccf77c4ed2 | ||
|
|
98a1800032 | ||
|
|
a842058136 | ||
|
|
88aef830df | ||
|
|
1b83081e8f | ||
|
|
64d1939daa | ||
|
|
697817eceb | ||
|
|
9eb7c945ca | ||
|
|
b8039ad1f1 | ||
|
|
5e31274f1d | ||
|
|
44f4e083a9 | ||
|
|
874dac9f22 | ||
|
|
f9707bad71 | ||
|
|
ee859e4804 | ||
|
|
97d320bd74 | ||
|
|
4eec8112fa | ||
|
|
3e38dd0d19 | ||
|
|
362c616998 | ||
|
|
d3c695024a | ||
|
|
e005e5f249 | ||
|
|
913215885a | ||
|
|
bab80ff886 | ||
|
|
48660c4e12 | ||
|
|
a0286c4e95 | ||
|
|
12b047f9a6 | ||
|
|
701749520b | ||
|
|
7318d33822 | ||
|
|
458bc3215d | ||
|
|
b53461da1c | ||
|
|
771482426f | ||
|
|
09902b8b8c | ||
|
|
ed293231dc | ||
|
|
e01f39ffa0 | ||
|
|
c7a375e146 | ||
|
|
2b7054d8a5 | ||
|
|
9489392905 | ||
|
|
b382ec08f7 | ||
|
|
833cc11674 | ||
|
|
9a6cfe5c6b | ||
|
|
9d1d5fda3d | ||
|
|
3781e6bda1 | ||
|
|
3c759f14c2 | ||
|
|
1d705b3056 | ||
|
|
7a5354e356 | ||
|
|
9b9739ab61 | ||
|
|
a9197f59b1 | ||
|
|
21fd40ec07 | ||
|
|
3af9becff9 | ||
|
|
1fa0a57831 | ||
|
|
d7b348f3a6 | ||
|
|
570600d2f6 | ||
|
|
40fcda6a37 | ||
|
|
bb82f899ff | ||
|
|
59d3c9f50c | ||
|
|
37cbb6f600 | ||
|
|
72cf3551e2 | ||
|
|
cb69e4ad66 | ||
|
|
42c4ca735d | ||
|
|
0f47e11d63 | ||
|
|
0b9c31a8cf | ||
|
|
02d1ded7b8 | ||
|
|
014b21566c | ||
|
|
4c7d0aa9fa | ||
|
|
fc90d4a0df | ||
|
|
26841c5b1c | ||
|
|
d6c1e5d25b | ||
|
|
63c8966ed7 | ||
|
|
23c8f46878 | ||
|
|
4b75df286a | ||
|
|
7e0b84ba7c | ||
|
|
6aa6f9ad53 | ||
|
|
4501ec2907 | ||
|
|
6c79148da5 |
No files matched your search
+54
-1
@@ -1,2 +1,55 @@
|
||||
* text=auto
|
||||
*.js text eol=lf
|
||||
*.js text eol=lf
|
||||
test/browser/media/hls/*.m3u8 text eol=lf
|
||||
test/browser/fixtures/hls-grouped.m3u8 text eol=lf
|
||||
test/browser/media/hls/*.mpegts binary
|
||||
# Preserve generated XML whitespace and its frozen playback-input hashes.
|
||||
test/browser/media/dash/*.mpd text eol=lf whitespace=-blank-at-eol
|
||||
test/browser/media/dash/*.m4s binary
|
||||
test/browser/media/*.m4a binary
|
||||
refactor/baselines/core-vendor/*.txt text eol=lf
|
||||
refactor/baselines/thumbnail-vendor/* text eol=lf whitespace=-blank-at-eof
|
||||
# Preserve the exact upstream WebVTT reference bytes, including license trailing lines.
|
||||
refactor/baselines/multiple-subtitles-vendor/* text eol=lf whitespace=-blank-at-eof
|
||||
# Preserve upstream documentation-site license bytes, including final blank lines.
|
||||
refactor/baselines/site-vendor/*.txt text eol=lf whitespace=-blank-at-eof
|
||||
docs/licenses/** text eol=lf whitespace=-blank-at-eof
|
||||
docs/THIRD_PARTY_NOTICES.md text eol=lf
|
||||
|
||||
# Preserve historical Codicons archive notice bytes, including CRLF.
|
||||
refactor/baselines/site-vendor/codicons-0.0.26/LICENSE* -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/site-vendor/codicons-0.0.26/README.txt -text whitespace=-trailing-space,cr-at-eol
|
||||
docs/licenses/monaco-editor/codicons/LICENSE* -text whitespace=-trailing-space,cr-at-eol
|
||||
docs/licenses/monaco-editor/codicons/README.md -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/site-vendor/codicons-0.0.26/ATTRIBUTION.txt text eol=lf
|
||||
refactor/baselines/site-vendor/vconsole-3.15.0/** text eol=lf whitespace=-blank-at-eof
|
||||
refactor/baselines/site-vendor/console-original.js text eol=lf
|
||||
refactor/baselines/site-vendor/console-commonjs/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/site-vendor/console-esm/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/site-vendor/console-embedded/** -text whitespace=-trailing-space,cr-at-eol
|
||||
docs/licenses/console/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/site-vendor/console-attribution/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/site-vendor/console-stackoverflow/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/site-vendor/monaco-typescript/** -text whitespace=-trailing-space,cr-at-eol
|
||||
docs/licenses/monaco-editor/typescript/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/site-vendor/monaco-languages/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/site-vendor/monaco-language-notices/** -text whitespace=-trailing-space,cr-at-eol
|
||||
docs/licenses/monaco-editor/language-services/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/site-vendor/monaco-modes/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/site-vendor/monaco-basic/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/monaco-basic-fixtures.json text eol=lf
|
||||
refactor/baselines/site-vendor/monaco-core-origins/** -text whitespace=-trailing-space,cr-at-eol
|
||||
docs/licenses/monaco-editor/core-origins/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/site-vendor/monaco-core-build/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/monaco-core-locales.json text eol=lf
|
||||
refactor/baselines/site-vendor/monaco-contributions/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/site-vendor/monaco-css-build/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/site-vendor/monaco-node-path/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/site-vendor/monaco-dom/** -text whitespace=-trailing-space,cr-at-eol
|
||||
docs/licenses/monaco-editor/core-dom/** -text whitespace=-trailing-space,cr-at-eol
|
||||
docs/licenses/monaco-editor/core-path/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/monaco-node-path-fixtures.json text eol=lf
|
||||
refactor/baselines/site-vendor/monaco-unicode/** -text whitespace=-trailing-space,cr-at-eol
|
||||
docs/licenses/monaco-editor/core-unicode/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/site-vendor/jassub-fonts/** -text whitespace=-trailing-space,cr-at-eol
|
||||
docs/licenses/jassub-fonts/** -text whitespace=-trailing-space,cr-at-eol
|
||||
+357
-28
@@ -1,41 +1,370 @@
|
||||
name: Node CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
branches: [ master, 'codex/**' ]
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
inputs:
|
||||
pages-artifact:
|
||||
description: Prepare the checked docs directory for the separate Pages workflow
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: checks-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' || github.event_name == 'push' }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
coverage:
|
||||
name: TS coverage (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [20.x]
|
||||
|
||||
os: [ ubuntu-latest, windows-latest ]
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
env:
|
||||
CI: true
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: install, lint, build, and test
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
package-manager-cache: false
|
||||
- name: Record source and cache inputs
|
||||
id: context
|
||||
run: node scripts/ci-context.mjs
|
||||
- name: Cache locked Yarn downloads
|
||||
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 ref verified 2026-09-13; node24
|
||||
with:
|
||||
path: ${{ steps.context.outputs.yarn_cache }}
|
||||
key: yarn-${{ runner.os }}-${{ runner.arch }}-node-${{ steps.context.outputs.node }}-yarn-${{ steps.context.outputs.yarn }}-${{ github.ref }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Install the pinned toolchain and dependencies
|
||||
run: |
|
||||
yarn
|
||||
yarn lint
|
||||
yarn build:all
|
||||
env:
|
||||
CI: true
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
if: success()
|
||||
npm install --global --force yarn@1.22.22 2>&1 | tee refactor/.cache/ci/toolchain-install.log
|
||||
yarn install --frozen-lockfile --non-interactive 2>&1 | tee refactor/.cache/ci/install.log
|
||||
yarn check:toolchain --strict
|
||||
- name: Verify source maps and critical lifecycle coverage
|
||||
run: yarn test:coverage 2>&1 | tee refactor/.cache/ci/coverage.log
|
||||
- name: Upload coverage and source-map evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: coverage-${{ matrix.os }}-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
path: |
|
||||
refactor/.cache/ci/
|
||||
refactor/.cache/coverage/latest.json
|
||||
refactor/.cache/coverage/run-*/
|
||||
include-hidden-files: true
|
||||
retention-days: 14
|
||||
if-no-files-found: warn
|
||||
browser-consumers:
|
||||
name: Browser consumers (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: true
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
package-manager-cache: false
|
||||
- name: Record source and cache inputs
|
||||
id: context
|
||||
run: node scripts/ci-context.mjs
|
||||
- name: Cache locked Yarn downloads
|
||||
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 ref verified 2026-09-13; node24
|
||||
with:
|
||||
path: ${{ steps.context.outputs.yarn_cache }}
|
||||
key: yarn-${{ runner.os }}-${{ runner.arch }}-node-${{ steps.context.outputs.node }}-yarn-${{ steps.context.outputs.yarn }}-${{ github.ref }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Install the pinned package manager and dependencies
|
||||
run: |
|
||||
git config --global user.name 'github-actions[bot]'
|
||||
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
|
||||
git add -f docs
|
||||
git commit -m 'Deploy to GitHub Pages'
|
||||
git subtree split --prefix docs master -b gh-pages-temp
|
||||
git push origin gh-pages-temp:refs/heads/gh-pages --force
|
||||
npm install --global --force yarn@1.22.22 2>&1 | tee refactor/.cache/ci/toolchain-install.log
|
||||
yarn install --frozen-lockfile --non-interactive 2>&1 | tee refactor/.cache/ci/install.log
|
||||
- name: Cache versioned browser downloads
|
||||
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 ref verified 2026-09-13; node24
|
||||
with:
|
||||
path: ${{ steps.context.outputs.browser_cache }}
|
||||
key: playwright-${{ runner.os }}-${{ runner.arch }}-node-${{ steps.context.outputs.node }}-yarn-${{ steps.context.outputs.yarn }}-${{ github.ref }}-${{ hashFiles('yarn.lock') }}-${{ steps.context.outputs.playwright }}
|
||||
- name: Install test browsers
|
||||
run: yarn test:browser:install --with-deps 2>&1 | tee refactor/.cache/ci/browser-install.log
|
||||
- name: Build and check installed tarballs
|
||||
run: |
|
||||
yarn test:package 2>&1 | tee refactor/.cache/ci/package.log
|
||||
node --input-type=module -e 'import fs from "node:fs"; const { output } = JSON.parse(fs.readFileSync("refactor/.cache/packages/latest.json")); fs.appendFileSync(process.env.GITHUB_ENV, `ARTPLAYER_BROWSER_ARTIFACTS=${output}/browser-artifacts.json\n`);'
|
||||
- name: Select Node 20 consumer runtime
|
||||
id: consumer-node-20
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: 20.19.0
|
||||
package-manager-cache: false
|
||||
- name: Verify Node 20 installed consumers
|
||||
run: node scripts/package-runtime.mjs --expected-node 20.19.0 2>&1 | tee refactor/.cache/ci/consumer-node-20.log
|
||||
- name: Select Node 22 consumer runtime
|
||||
id: consumer-node-22
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: 22.12.0
|
||||
package-manager-cache: false
|
||||
- name: Verify Node 22 installed consumers
|
||||
run: node scripts/package-runtime.mjs --expected-node 22.12.0 2>&1 | tee refactor/.cache/ci/consumer-node-22.log
|
||||
- name: Restore canonical runtime for browser tools
|
||||
id: restore-canonical-node
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
package-manager-cache: false
|
||||
- name: Verify canonical installed consumers
|
||||
run: node scripts/package-runtime.mjs --canonical 2>&1 | tee refactor/.cache/ci/consumer-node-canonical.log
|
||||
- name: Verify React installed consumers
|
||||
run: yarn test:react-consumer 2>&1 | tee refactor/.cache/ci/react-consumer.log
|
||||
- name: Verify Vue installed consumers
|
||||
run: yarn test:vue-consumer 2>&1 | tee refactor/.cache/ci/vue-consumer.log
|
||||
- name: Verify iframe cached history and interrupted navigation
|
||||
run: yarn test:iframe-history 2>&1 | tee refactor/.cache/ci/iframe-history.log
|
||||
- name: Compare installed performance and verify resource cleanup
|
||||
run: yarn test:performance 2>&1 | tee refactor/.cache/ci/performance.log
|
||||
- name: Verify all installed library type contracts
|
||||
run: yarn test:ecosystem-types 2>&1 | tee refactor/.cache/ci/ecosystem-types.log
|
||||
- name: Upload browser evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: browser-consumers-${{ matrix.os }}-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
path: |
|
||||
refactor/.cache/ci/
|
||||
refactor/.cache/iframe-history/
|
||||
refactor/.cache/react-consumer-*/
|
||||
refactor/.cache/vue-consumer-*/
|
||||
refactor/.cache/performance/
|
||||
refactor/.cache/ecosystem-types/
|
||||
refactor/.cache/*-package-types-*/*.json
|
||||
refactor/.cache/*-package-types-*/*.log
|
||||
refactor/.cache/packages/latest.json
|
||||
refactor/.cache/packages/run-*/*.json
|
||||
refactor/.cache/packages/run-*/*.log
|
||||
refactor/.cache/packages/run-*/*.tgz
|
||||
refactor/.cache/packages/run-*/artifacts/
|
||||
include-hidden-files: true
|
||||
retention-days: 14
|
||||
if-no-files-found: warn
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 3
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
- macos-latest
|
||||
browser-smoke:
|
||||
name: Browser playback (${{ matrix.os }}, ${{ matrix.browser }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: true
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
package-manager-cache: false
|
||||
- name: Record source and cache inputs
|
||||
id: context
|
||||
run: node scripts/ci-context.mjs
|
||||
- name: Cache locked Yarn downloads
|
||||
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 ref verified 2026-09-13; node24
|
||||
with:
|
||||
path: ${{ steps.context.outputs.yarn_cache }}
|
||||
key: yarn-${{ runner.os }}-${{ runner.arch }}-node-${{ steps.context.outputs.node }}-yarn-${{ steps.context.outputs.yarn }}-${{ github.ref }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Install the pinned package manager and dependencies
|
||||
run: |
|
||||
npm install --global --force yarn@1.22.22 2>&1 | tee refactor/.cache/ci/toolchain-install.log
|
||||
yarn install --frozen-lockfile --non-interactive 2>&1 | tee refactor/.cache/ci/install.log
|
||||
- name: Cache versioned browser downloads
|
||||
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 ref verified 2026-09-13; node24
|
||||
with:
|
||||
path: ${{ steps.context.outputs.browser_cache }}
|
||||
key: playwright-${{ runner.os }}-${{ runner.arch }}-node-${{ steps.context.outputs.node }}-yarn-${{ steps.context.outputs.yarn }}-${{ github.ref }}-${{ hashFiles('yarn.lock') }}-${{ steps.context.outputs.playwright }}
|
||||
- name: Install test browsers
|
||||
run: yarn test:browser:install --with-deps 2>&1 | tee refactor/.cache/ci/browser-install.log
|
||||
- name: Prepare installed browser plugin packages
|
||||
# Each engine builds and freezes its own complete installed browser roster.
|
||||
# Other ecosystem installation/SDK gates remain tracked by CI-01.
|
||||
run: |
|
||||
yarn test:package --browser 2>&1 | tee refactor/.cache/ci/browser-packages.log
|
||||
node --input-type=module -e 'import fs from "node:fs"; const { output } = JSON.parse(fs.readFileSync("refactor/.cache/packages/latest.json")); fs.appendFileSync(process.env.GITHUB_ENV, `ARTPLAYER_BROWSER_ARTIFACTS=${output}/browser-artifacts.json\n`);'
|
||||
- name: Run all source browser checks
|
||||
if: ${{ !cancelled() }}
|
||||
run: yarn test:browser:source --project=${{ matrix.browser }} 2>&1 | tee refactor/.cache/ci/browser-source.log
|
||||
- name: Run installed browser checks
|
||||
if: ${{ !cancelled() }}
|
||||
run: yarn test:browser:installed --project=${{ matrix.browser }} 2>&1 | tee refactor/.cache/ci/browser-installed.log
|
||||
- name: Upload browser evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: browser-smoke-${{ matrix.os }}-${{ matrix.browser }}-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
path: |
|
||||
refactor/.cache/ci/
|
||||
refactor/.cache/browser-source/
|
||||
refactor/.cache/browser-installed/
|
||||
refactor/.cache/packages/latest.json
|
||||
refactor/.cache/packages/run-*/*.json
|
||||
refactor/.cache/packages/run-*/*.log
|
||||
refactor/.cache/packages/run-*/*.tgz
|
||||
refactor/.cache/packages/run-*/artifacts/
|
||||
include-hidden-files: true
|
||||
retention-days: 14
|
||||
if-no-files-found: warn
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 6
|
||||
matrix:
|
||||
browser: [chromium, firefox, webkit]
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
- macos-latest
|
||||
checks:
|
||||
name: Checks and build (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 45
|
||||
env:
|
||||
CI: true
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
package-manager-cache: false
|
||||
- name: Record source and cache inputs
|
||||
id: context
|
||||
run: node scripts/ci-context.mjs
|
||||
- name: Cache locked Yarn downloads
|
||||
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 ref verified 2026-09-13; node24
|
||||
with:
|
||||
path: ${{ steps.context.outputs.yarn_cache }}
|
||||
key: yarn-${{ runner.os }}-${{ runner.arch }}-node-${{ steps.context.outputs.node }}-yarn-${{ steps.context.outputs.yarn }}-${{ github.ref }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Install the pinned package manager
|
||||
run: npm install --global --force yarn@1.22.22 2>&1 | tee refactor/.cache/ci/toolchain-install.log
|
||||
- name: Validate workflow syntax
|
||||
run: |
|
||||
curl --fail --silent --show-error --location https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_linux_amd64.tar.gz --output "$RUNNER_TEMP/actionlint.tar.gz"
|
||||
printf '%s %s\n' '8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8' "$RUNNER_TEMP/actionlint.tar.gz" | sha256sum --check
|
||||
tar -xzf "$RUNNER_TEMP/actionlint.tar.gz" -C "$RUNNER_TEMP" actionlint
|
||||
"$RUNNER_TEMP/actionlint" -color
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
- name: Frozen install
|
||||
run: |
|
||||
mkdir -p refactor/.cache/ci
|
||||
yarn install --frozen-lockfile --non-interactive 2>&1 | tee refactor/.cache/ci/install.log
|
||||
- name: Read-only checks and tests
|
||||
run: yarn ci:check 2>&1 | tee refactor/.cache/ci/check.log
|
||||
- name: Build libraries and documentation
|
||||
run: yarn ci:build 2>&1 | tee refactor/.cache/ci/build.log
|
||||
- name: Validate and stage Pages paths
|
||||
id: pages
|
||||
if: inputs.pages-artifact && github.ref == 'refs/heads/master' && matrix.os == 'ubuntu-latest'
|
||||
run: yarn prepare:pages 2>&1 | tee refactor/.cache/ci/pages.log
|
||||
- name: Install staged Pages browser dependencies
|
||||
if: inputs.pages-artifact && github.ref == 'refs/heads/master' && matrix.os == 'ubuntu-latest'
|
||||
run: yarn test:browser:install --with-deps 2>&1 | tee refactor/.cache/ci/pages-browser-install.log
|
||||
- name: Verify staged Pages entrypoints
|
||||
if: inputs.pages-artifact && github.ref == 'refs/heads/master' && matrix.os == 'ubuntu-latest'
|
||||
run: yarn test:pages:browser 2>&1 | tee refactor/.cache/ci/pages-browser.log
|
||||
- name: Record source and tool versions
|
||||
if: always()
|
||||
run: |
|
||||
mkdir -p refactor/.cache/ci
|
||||
git rev-parse HEAD > refactor/.cache/ci/source.txt
|
||||
node --version > refactor/.cache/ci/node.txt
|
||||
yarn --version > refactor/.cache/ci/yarn.txt
|
||||
sha256sum yarn.lock > refactor/.cache/ci/lock.sha256
|
||||
git diff --stat > refactor/.cache/ci/generated-diff.txt
|
||||
- name: Upload available logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: checks-${{ matrix.os }}-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
path: |
|
||||
refactor/.cache/ci/
|
||||
refactor/.cache/pages/run-*/report.json
|
||||
refactor/.cache/pages/run-*/browser.json
|
||||
include-hidden-files: true
|
||||
retention-days: 14
|
||||
if-no-files-found: warn
|
||||
- name: Prepare Pages artifact
|
||||
if: inputs.pages-artifact && github.ref == 'refs/heads/master' && matrix.os == 'ubuntu-latest'
|
||||
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
|
||||
with:
|
||||
path: ${{ steps.pages.outputs.site }}
|
||||
include-hidden-files: true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 2
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
ci-result:
|
||||
name: CI result
|
||||
if: always()
|
||||
needs:
|
||||
- checks
|
||||
- coverage
|
||||
- browser-smoke
|
||||
- browser-consumers
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
package-manager-cache: false
|
||||
- name: Require every matrix job to succeed
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ARTPLAYER_CI_NEEDS: ${{ toJSON(needs) }}
|
||||
run: node scripts/ci-summary.mjs
|
||||
- name: Upload final status
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: ci-result-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
path: refactor/.cache/ci/
|
||||
include-hidden-files: true
|
||||
retention-days: 14
|
||||
if-no-files-found: warn
|
||||
@@ -0,0 +1,34 @@
|
||||
name: Deploy Pages
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: pages
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
if: github.ref == 'refs/heads/master' && vars.PAGES_DEPLOY_ENABLED == 'true'
|
||||
uses: ./.github/workflows/nodejs.yml
|
||||
with:
|
||||
pages-artifact: true
|
||||
|
||||
deploy:
|
||||
if: github.ref == 'refs/heads/master' && vars.PAGES_DEPLOY_ENABLED == 'true'
|
||||
needs: validate
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
pages: write
|
||||
id-token: write
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- name: Deploy the validated artifact
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
|
||||
+2
-2
@@ -2,6 +2,6 @@
|
||||
.vscode
|
||||
.DS_Store
|
||||
node_modules
|
||||
package-lock.json
|
||||
**/package-lock.json
|
||||
lerna-debug.log
|
||||
yarn.lock
|
||||
refactor/.cache/
|
||||
@@ -0,0 +1 @@
|
||||
24.21.0
|
||||
@@ -0,0 +1,362 @@
|
||||
# AGENTS.md
|
||||
|
||||
## Compatibility Refactor
|
||||
|
||||
2026-09-16 user scope update: stop autonomous refactor implementation and hand off for
|
||||
the user's extended self-testing. Read [refactor/self-test-handoff.md](refactor/self-test-handoff.md)
|
||||
first. Remaining tasks are deferred, not passed; do not resume long tests, new fixes,
|
||||
full matrices, release preparation, or formal reviews without a new user instruction.
|
||||
Existing compatibility requirements and future publication gates remain in force.
|
||||
|
||||
The compatibility modernization plan is maintained in [refactor/README.md](refactor/README.md).
|
||||
For refactor work, read its compatibility contract, task plan, and progress log before editing.
|
||||
Use `refactor/tasks.json` as the task status source and regenerate the readable plan with
|
||||
`node refactor/scripts/plan.mjs --write`; validate it with `node refactor/scripts/plan.mjs --check`.
|
||||
Preserve existing public APIs, event behavior, types, DOM/CSS hooks, and distribution entrypoints.
|
||||
The planned TypeScript migration permits incremental JS/TS coexistence; it does not authorize
|
||||
changing consumer APIs or treating planned validation as completed validation.
|
||||
Apply [refactor/quality-contract.md](refactor/quality-contract.md) to every implementation task:
|
||||
the user authorizes improving unreasonable internals while preserving old public contracts.
|
||||
Refactor responsibilities and dependencies alongside TypeScript migration, add meaningful
|
||||
risk-based tests, and update package architecture/maintenance documentation in the same change.
|
||||
The user requires one separate local Git commit for each completed refactor task.
|
||||
Include the task ID in the commit subject and include its implementation, tests, documentation,
|
||||
and status updates together. Verify the commit before starting the next task. Do not bundle
|
||||
multiple newly completed tasks or include unrelated work. This does not authorize pushing or publishing.
|
||||
Use Yarn Classic 1.22.22 as packageManager and maintain only the root yarn.lock.
|
||||
Core public declarations are authored in packages/artplayer/public/ and generated
|
||||
with yarn build:types into the existing types/ entrypoints. Do not hand-edit the
|
||||
generated core declarations; yarn check:types is read-only and rejects drift.
|
||||
Use Node from .node-version; frozen Yarn installs and strict toolchain checks are required.
|
||||
Bun remains an isolated evaluation and must not replace Yarn without a new user decision.
|
||||
The user also authorizes installing needed dependencies and adding or improving reasonable
|
||||
project scripts for the refactor without asking again for routine tooling choices.
|
||||
Record their purpose and versions, use the appropriate workspace/dependency category, update
|
||||
the lockfile when applicable, and verify compatibility and reproducible execution.
|
||||
After implementation and its necessary tests, hand off the results and wait for the
|
||||
user to guide and start the review phase. Do not automatically begin REVIEW-01/02/03,
|
||||
including an early first review. Follow [refactor/release-reviews.md](refactor/release-reviews.md):
|
||||
the three review rounds and closure of blocking findings remain required before candidate publication.
|
||||
Connected Chrome interaction checks complement committed automated browser tests; neither
|
||||
connection availability nor mocks replace actual playback or required device evidence.
|
||||
If Chrome is unavailable, use the Codex in-app browser for supported real-page tests.
|
||||
The user explicitly authorizes this fallback; record the actual browser/version and limitations.
|
||||
Do not block ordinary browser checks solely on the Chrome extension connection.
|
||||
Each review fix remains a separate task and commit. Revalidate changed candidate contents.
|
||||
The user explicitly includes GitHub CI/CD modernization in this refactor.
|
||||
Follow [refactor/github-ci-cd.md](refactor/github-ci-cd.md) for PR checks, regression matrices,
|
||||
artifacts, Pages and npm workflows. Distinguish local configuration from verified remote runs.
|
||||
The user requires every workspace package to move to its own next major version for this
|
||||
refactor (M.m.p -> (M+1).0.0). Follow refactor/version-policy.md; independent versions and
|
||||
old API compatibility remain mandatory. This version policy is not publication authorization.
|
||||
|
||||
## Project Summary
|
||||
|
||||
ArtPlayer is a monorepo for a modern HTML5 video player and its ecosystem packages.
|
||||
|
||||
- Homepage: `https://artplayer.org`
|
||||
- Local dev site: `http://localhost:8082`
|
||||
- API docs: `https://artplayer.org/document`
|
||||
- Packaging model: workspace monorepo with per-package versioning and per-package build output
|
||||
|
||||
The repository contains:
|
||||
|
||||
- `packages/artplayer`: the core player
|
||||
- `packages/artplayer-plugin-*`: UI and playback plugins
|
||||
- `packages/artplayer-proxy-*`: proxy renderers and playback adapters
|
||||
- `packages/artplayer-tool-*`: helper tools
|
||||
- `packages/artplayer-vitepress`: docs site package
|
||||
- `docs/`: local demo site, examples, compiled assets, generated docs
|
||||
- `scripts/`: custom build/dev/doc tooling
|
||||
|
||||
## Working Style For This Repo
|
||||
|
||||
- Verify the real implementation before editing docs or examples.
|
||||
- Prefer changing the source package first, then regenerate build artifacts only when needed.
|
||||
- Keep package APIs small and consistent with existing ArtPlayer plugin conventions.
|
||||
- Preserve the existing visual and API style of sibling packages instead of inventing a new pattern.
|
||||
- When touching demo examples, make sure the example still works in `http://localhost:8082`.
|
||||
- Do not hand-edit `dist/`, `docs/compiled/`, or `docs/uncompiled/` unless a build step generated them.
|
||||
- Desktop editor sources live in `packages/artplayer-vitepress/browser/`; `docs/assets/js/common.js`,
|
||||
`bootstrap.js`, `loader.js`, `mobile.js` and `packages/artplayer-vitepress/docs/public/main.js`
|
||||
are generated with `yarn build:site-assets`. `editor-libraries.ts` is generated by `yarn build:ts`.
|
||||
|
||||
## Primary Commands
|
||||
|
||||
Use the repo scripts rather than ad hoc bundler commands.
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
Starts the local dev site on port `8082` and interactively selects a package to watch. The selected package is built into:
|
||||
|
||||
- `docs/uncompiled/<package>/`
|
||||
|
||||
### Production Build
|
||||
|
||||
```bash
|
||||
yarn build
|
||||
```
|
||||
|
||||
Interactive build for one package. Outputs:
|
||||
|
||||
- `packages/<name>/dist/*.js|*.legacy.js|*.mjs`
|
||||
- copied artifacts into `docs/compiled/`
|
||||
|
||||
Build all packages:
|
||||
|
||||
```bash
|
||||
yarn build all
|
||||
```
|
||||
|
||||
### Other Project Scripts
|
||||
|
||||
```bash
|
||||
yarn build:i18n
|
||||
yarn build:ts
|
||||
yarn build:docs
|
||||
yarn build:llm
|
||||
yarn build:test
|
||||
yarn lint
|
||||
yarn build:all
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `yarn lint` is read-only; `yarn lint:fix` explicitly fixes the same source/type/script range.
|
||||
- `yarn ci:check` runs strict toolchain/plan/lint/tests; `yarn ci:build` generates outputs and checks imports.
|
||||
- See `refactor/ci-setup.md` for CI and separate Pages deployment; remote activation is tracked separately.
|
||||
- `yarn build:all` is expensive; use it when a change truly spans builds/docs/types/lint together.
|
||||
|
||||
## Useful Local URLs
|
||||
|
||||
- Root demo index: `http://localhost:8082`
|
||||
- Demo by package/example:
|
||||
- `http://localhost:8082/?libs=./uncompiled/<package>/index.js&example=<example>`
|
||||
- Docs: `http://localhost:8082/document/`
|
||||
|
||||
For proxy/plugin work, prefer validating on the local demo page rather than reasoning only from source.
|
||||
|
||||
## Repository Layout
|
||||
|
||||
### Core package
|
||||
|
||||
- `packages/artplayer/src/index.ts`: player entry
|
||||
- `packages/artplayer/src/player/`: playback mixins and player-facing behavior
|
||||
- `packages/artplayer/src/control/`: bottom controls
|
||||
- `packages/artplayer/src/setting/`: settings panel
|
||||
- `packages/artplayer/src/contextmenu/`: context menu items
|
||||
- `packages/artplayer/src/plugins/`: built-in plugins
|
||||
- `packages/artplayer/src/utils/`: shared helpers, component base classes, DOM utilities
|
||||
- `packages/artplayer/public/`: public TypeScript declaration sources
|
||||
- `packages/artplayer/types/`: generated public declarations and compatibility documentation
|
||||
|
||||
### Ecosystem packages
|
||||
|
||||
Migrated ecosystem packages follow this pattern:
|
||||
|
||||
```text
|
||||
packages/<package>/
|
||||
src/index.ts
|
||||
src/*.ts # internal modules; see the package maintenance map
|
||||
src/*.less # optional
|
||||
types/*.d.ts # public compatibility declarations
|
||||
ARCHITECTURE.md # maintenance map, or a maintenance section in README.md
|
||||
README.md
|
||||
package.json
|
||||
dist/*
|
||||
```
|
||||
|
||||
Read the package maintenance map before changing module ownership. Some packages
|
||||
also expose accurate types through `/runtime`, with `.d.mts`/`.d.cts` declarations.
|
||||
Do not replace historical root declarations with internal implementation types;
|
||||
follow [the approved type policy](refactor/type-compatibility-policy.md) and each
|
||||
package's recorded compatibility decisions. Check package.json for exact exports.
|
||||
|
||||
### Demo and docs assets
|
||||
|
||||
- `docs/assets/example/*.js`: runnable browser examples
|
||||
- `docs/assets/ts/*.js`: TypeScript demo assets targeted by lint/docs flows
|
||||
- `docs/uncompiled/`: dev output
|
||||
- `docs/compiled/`: production-copied output
|
||||
- `docs/document/`: generated docs content
|
||||
|
||||
## Architecture Notes
|
||||
|
||||
### Core player
|
||||
|
||||
ArtPlayer composes many subsystems during construction. Common integration points:
|
||||
|
||||
- `art.template`
|
||||
- `art.events`
|
||||
- `art.controls`
|
||||
- `art.setting`
|
||||
- `art.contextmenu`
|
||||
- `art.layers`
|
||||
- `art.plugins`
|
||||
- `art.player`
|
||||
|
||||
When extending behavior, prefer integrating with these existing systems rather than bypassing them.
|
||||
|
||||
### Control and setting components
|
||||
|
||||
Controls and setting entries are managed through component registries.
|
||||
|
||||
Relevant implementation:
|
||||
|
||||
- `packages/artplayer/src/control/index.ts`
|
||||
- `packages/artplayer/src/setting/index.ts`
|
||||
- `packages/artplayer/src/utils/component.ts`
|
||||
|
||||
Important behavior:
|
||||
|
||||
- `art.controls.update(...)` and `art.setting.update(...)` replace existing entries by `name`
|
||||
- `art.controls.remove(name)` and `art.setting.remove(name)` are the correct cleanup APIs
|
||||
- selector-style controls rely on `default` flags to determine highlighted items
|
||||
|
||||
If a plugin conditionally shows UI, it must also clean that UI up when the condition no longer holds.
|
||||
|
||||
### Plugin shape
|
||||
|
||||
Standard plugin/export shape:
|
||||
|
||||
```js
|
||||
export default function somePlugin(option = {}) {
|
||||
return (art) => {
|
||||
return {
|
||||
name: 'somePlugin',
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Naming conventions:
|
||||
|
||||
- package: `artplayer-plugin-<name>`
|
||||
- global: `artplayerPlugin<Name>`
|
||||
- exported function name should match the global naming convention
|
||||
|
||||
### Proxy packages
|
||||
|
||||
Proxy packages usually return a non-video element or video-like shim and emulate media element behavior for ArtPlayer.
|
||||
|
||||
Examples:
|
||||
|
||||
- `packages/artplayer-proxy-canvas`
|
||||
- `packages/artplayer-proxy-mediabunny`
|
||||
|
||||
When editing proxy packages:
|
||||
|
||||
- keep the HTMLMediaElement-like surface coherent
|
||||
- keep event ordering stable
|
||||
- treat `loadedmetadata`, `loadeddata`, `canplay`, `seeked`, `waiting`, and `pause/play` semantics carefully
|
||||
- ensure UI state is updated and cleaned up when source topology changes
|
||||
|
||||
### HLS / adaptive playback controls
|
||||
|
||||
The reference implementation for adaptive selector UI is:
|
||||
|
||||
- `packages/artplayer-plugin-hls-control/src/index.ts`
|
||||
- `packages/artplayer-plugin-dash-control/src/index.ts` (SDK 4.x/5.x capability adapter)
|
||||
|
||||
If adding HLS-like quality/audio selection elsewhere:
|
||||
|
||||
- follow the selector format used there
|
||||
- derive highlighted items from actual current tracks, not only from mode flags
|
||||
- avoid stale selectors when changing to streams without the same topology
|
||||
|
||||
## Build and Artifact Rules
|
||||
|
||||
- Always edit source first: core runtime in `src/`, core declarations in `public/`;
|
||||
other packages retain `types/` until their own declaration source migration.
|
||||
- Rebuild package artifacts after source changes that should ship.
|
||||
- Do not treat `dist/` as source of truth.
|
||||
- If a change affects demo behavior, also verify the matching file in `docs/assets/example/`.
|
||||
|
||||
For package-specific builds, the normal flow is:
|
||||
|
||||
1. `yarn dev` and pick the package for fast local iteration
|
||||
2. validate in `http://localhost:8082`
|
||||
3. `yarn build` and pick the package when ready to update shippable artifacts
|
||||
|
||||
## Documentation Expectations
|
||||
|
||||
If a public package API changes, check whether these also need updates:
|
||||
|
||||
- the package `README.md`
|
||||
- `docs/assets/example/<name>.js`
|
||||
- `types/<name>.d.ts`
|
||||
- any generated compiled outputs if you built the package
|
||||
|
||||
Keep examples realistic and runnable. Prefer local demo URLs or stable public sample streams.
|
||||
|
||||
## Code Quality Expectations
|
||||
|
||||
- Follow the existing TypeScript style for migrated production modules and the
|
||||
existing JavaScript style for tests, launchers and documented legacy exceptions.
|
||||
- Use ASCII unless a file already requires otherwise.
|
||||
- Match the minimal-comment style of neighboring files.
|
||||
- Avoid unnecessary abstraction; this codebase generally prefers direct implementation.
|
||||
- Respect current browser targets:
|
||||
- modern build: `es2020`
|
||||
- legacy build: `es2015`
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
For most package changes, validate as many of these as apply:
|
||||
|
||||
- source file lint passes
|
||||
- local demo page loads
|
||||
- expected events fire once and in the correct order
|
||||
- controls/settings render correctly
|
||||
- cleanup works after restart, source switch, or destroy
|
||||
- package build succeeds
|
||||
|
||||
For playback/proxy changes specifically:
|
||||
|
||||
- test initial load
|
||||
- test play/pause
|
||||
- test seek
|
||||
- test switching source or track topology
|
||||
- test whether UI reflects the actual selected track/quality
|
||||
|
||||
## Notes Specific To `artplayer-proxy-mediabunny`
|
||||
|
||||
This package now depends on modern `mediabunny` and supports HLS through `mediabunny` input handling.
|
||||
|
||||
Files to understand first:
|
||||
|
||||
- `packages/artplayer-proxy-mediabunny/ARCHITECTURE.md`
|
||||
- `packages/artplayer-proxy-mediabunny/src/index.ts`
|
||||
- `packages/artplayer-proxy-mediabunny/src/VideoShim.ts`
|
||||
- `packages/artplayer-proxy-mediabunny/src/MediaBunnyEngine.ts`
|
||||
- `packages/artplayer-proxy-mediabunny/src/input.ts`
|
||||
- `packages/artplayer-proxy-mediabunny/src/m3u8.ts`
|
||||
|
||||
Key expectations:
|
||||
|
||||
- HLS source detection should happen in `input.ts`
|
||||
- track selection should use actual pairable audio/video relationships
|
||||
- selector UI should mirror the behavior of `artplayer-plugin-hls-control`
|
||||
- selector cleanup is required when a later source no longer supports the same controls
|
||||
- avoid duplicate readiness events during load and track switches
|
||||
|
||||
For sustained playback, use `yarn test:mediabunny-soak` with explicit artifacts and
|
||||
media; see [the long-test procedure](refactor/changes/2026-09-16-PKG-MB-09-hour-soak.md).
|
||||
It shares port 8084 with ordinary browser tests. Do not start another browser
|
||||
server or change the measured source, artifacts or media during a live run.
|
||||
Use its live process handle and per-case progress samples to check progress;
|
||||
an old report or a start snapshot does not prove current execution or completion.
|
||||
|
||||
## When Unsure
|
||||
|
||||
Start with the nearest sibling implementation instead of inventing a new pattern:
|
||||
|
||||
- control/setting UI: `artplayer-plugin-hls-control`, `artplayer-plugin-dash-control`
|
||||
- proxy behavior: `artplayer-proxy-canvas`, `artplayer-proxy-mediabunny`
|
||||
- component lifecycle: `packages/artplayer/src/utils/component.ts`
|
||||
|
||||
If a change spans source, examples, and packaging, make all three consistent in the same pass.
|
||||
@@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- Fix safe area issue when enter web fullscreen [#1033](https://github.com/zhw2590582/ArtPlayer/issues/1033)
|
||||
|
||||
## [5.4.0] - 2026-03-12
|
||||
|
||||
- Refactor `Parcel` to `Vite`
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
ArtPlayer.js is a modern, full-featured HTML5 video player. It's organized as a monorepo using Lerna with independent versioning.
|
||||
|
||||
- **Homepage**: https://artplayer.org
|
||||
- **Online Editor**: https://artplayer.org (for testing examples)
|
||||
- **API Docs**: https://artplayer.org/document
|
||||
|
||||
## Repository Structure
|
||||
|
||||
```
|
||||
packages/
|
||||
artplayer/ # Core player package
|
||||
artplayer-plugin-*/ # 17+ plugins (danmuku, ads, chromecast, etc.)
|
||||
artplayer-proxy-*/ # Canvas, Mediabunny proxies
|
||||
artplayer-tool-*/ # iframe, thumbnail tools
|
||||
artplayer-vitepress/ # Documentation site
|
||||
|
||||
docs/ # Documentation and demo site
|
||||
assets/ # Example assets and TypeScript demos
|
||||
compiled/ # Built packages output
|
||||
document/ # Generated API documentation
|
||||
uncompiled/ # Development build output
|
||||
test/ # Browser test files
|
||||
|
||||
scripts/ # Build tooling
|
||||
build.js # Production build
|
||||
dev.js # Development server
|
||||
build-i18n.js # I18n bundle builder
|
||||
build-docs.js # Documentation generator
|
||||
build-llm.js # LLMs.txt generator
|
||||
plugin/create.js # New plugin scaffolding
|
||||
```
|
||||
|
||||
## Common Commands
|
||||
|
||||
### Development
|
||||
```bash
|
||||
# Start dev server on port 8082 with hot reload
|
||||
npm run dev
|
||||
|
||||
# Build for production (interactive prompt to select package)
|
||||
npm run build
|
||||
|
||||
# Build all packages
|
||||
npm run build all
|
||||
|
||||
# Build everything (packages, i18n, types, docs) + lint
|
||||
npm run build:all
|
||||
```
|
||||
|
||||
### Code Quality
|
||||
```bash
|
||||
# Lint with auto-fix (covers packages, scripts, tests, docs assets)
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Plugin Development
|
||||
```bash
|
||||
# Create new plugin from template
|
||||
npm run create:plugin <kebab-case-name>
|
||||
|
||||
# Example:
|
||||
npm run create:plugin my-feature
|
||||
```
|
||||
|
||||
### I18n
|
||||
```bash
|
||||
# Build i18n bundles for all languages
|
||||
npm run build:i18n
|
||||
```
|
||||
|
||||
### TypeScript
|
||||
```bash
|
||||
# Generate TypeScript declaration files
|
||||
npm run build:ts
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
### Core Player (`packages/artplayer`)
|
||||
|
||||
The main `Artplayer` class extends `Emitter` and initializes sub-components:
|
||||
|
||||
```javascript
|
||||
// Key components instantiated in constructor:
|
||||
this.template = new Template(this) // DOM structure
|
||||
this.events = new Events(this) // Event handling
|
||||
this.player = new Player(this) // Video playback
|
||||
this.controls = new Control(this) // Control bar
|
||||
this.layers = new Layer(this) // Custom layers
|
||||
this.contextmenu = new Contextmenu(this)
|
||||
this.subtitle = new Subtitle(this)
|
||||
this.setting = new Setting(this)
|
||||
this.plugins = new Plugins(this) // Plugin manager
|
||||
// ... and more
|
||||
```
|
||||
|
||||
Source organization in `src/`:
|
||||
- `config/` - Default configuration values
|
||||
- `control/` - UI controls (play, progress, volume, etc.)
|
||||
- `events/` - Event handling (click, hover, resize, etc.)
|
||||
- `i18n/` - Localization files
|
||||
- `icons/` - SVG icons
|
||||
- `player/` - Video playback logic (hls, flv, dash, etc.)
|
||||
- `plugins/` - Built-in plugins
|
||||
- `setting/` - Settings panel components
|
||||
- `style/` - LESS stylesheets
|
||||
- `template.js` - HTML template generation
|
||||
- `utils/` - Utility functions
|
||||
|
||||
### Plugin Architecture
|
||||
|
||||
Plugins are functions that receive the player instance and options:
|
||||
|
||||
```javascript
|
||||
// Template from scripts/plugin/template/src/index.js
|
||||
export default function artplayerPluginTemplate(option = {}) {
|
||||
return (art) => {
|
||||
// Plugin initialization
|
||||
// Access: art.player, art.controls, art.template, etc.
|
||||
|
||||
return {
|
||||
name: 'artplayerPluginTemplate',
|
||||
// Expose methods to art.plugins['artplayerPluginTemplate']
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Plugin naming convention:
|
||||
- Package: `artplayer-plugin-<name>`
|
||||
- Global variable: `artplayerPlugin<Name>` (camelCase)
|
||||
- Exported function uses same name as global
|
||||
|
||||
### Styling
|
||||
|
||||
Uses LESS with inline imports:
|
||||
```javascript
|
||||
import style from './style/index.less?inline'
|
||||
```
|
||||
|
||||
Styles are injected at runtime via `utils.setStyleText()`.
|
||||
|
||||
### Build System
|
||||
|
||||
Uses Vite via custom Node.js scripts:
|
||||
|
||||
**Development** (`scripts/dev.js`):
|
||||
- Builds IIFE bundle to `docs/uncompiled/<package>/`
|
||||
- Serves `docs/` directory on port 8082
|
||||
- Watches source files for changes
|
||||
|
||||
**Production** (`scripts/build.js`):
|
||||
- Builds 3 formats: UMD (`.js`), UMD legacy (`.legacy.js`), ESM (`.mjs`)
|
||||
- Outputs to `packages/<name>/dist/`
|
||||
- Copies to `docs/compiled/`
|
||||
|
||||
### I18n System
|
||||
|
||||
Language files in `packages/artplayer/src/i18n/`:
|
||||
- Base language: `zh-cn.js`
|
||||
- Additional languages: `en.js`, `fr.js`, etc.
|
||||
- Built as separate UMD/ESM bundles via `build-i18n.js`
|
||||
- Global naming: `artplayerI18n<Language>` (e.g., `artplayerI18nEn`)
|
||||
|
||||
### Creating New Plugins
|
||||
|
||||
The `npm run create:plugin <name>` command:
|
||||
1. Copies `scripts/plugin/template/` to `packages/artplayer-plugin-<name>/`
|
||||
2. Replaces placeholders in filenames and content
|
||||
3. Creates example file at `docs/assets/example/<name>.js`
|
||||
|
||||
Plugin template structure:
|
||||
```
|
||||
src/
|
||||
index.js # Main plugin code
|
||||
style.less # Plugin styles
|
||||
package.json
|
||||
README.md
|
||||
types/
|
||||
<name>.d.ts # TypeScript declarations (optional)
|
||||
```
|
||||
|
||||
### Utility Functions
|
||||
|
||||
Core utilities in `packages/artplayer/src/utils/`:
|
||||
- `utils.js` - Common helpers (isMobile, isSafari, query, etc.)
|
||||
- `emitter.js` - Event emitter base class
|
||||
- `scheme.js` - Option validation schema
|
||||
|
||||
## Development Notes
|
||||
|
||||
- **Package manager**: Uses Yarn with Lerna
|
||||
- **Node version**: >= 20.0.0
|
||||
- **ESLint**: Uses @antfu/eslint-config
|
||||
- **Browser support**: Last 1 Chrome version (ES2020), legacy builds target ES2015
|
||||
- **UMD builds**: Always expose global even in AMD/RequireJS environments
|
||||
@@ -63,6 +63,18 @@ Or install with `yarn`:
|
||||
$ yarn add artplayer
|
||||
```
|
||||
|
||||
Or install with `pnpm`:
|
||||
|
||||
```bash
|
||||
$ pnpm add artplayer
|
||||
```
|
||||
|
||||
Or install with `bun`:
|
||||
|
||||
```bash
|
||||
$ bun add artplayer
|
||||
```
|
||||
|
||||
```js
|
||||
import Artplayer from 'artplayer'
|
||||
```
|
||||
@@ -104,7 +116,7 @@ let art = new Artplayer({
|
||||
| :--- | :--- | :--- |
|
||||
| [artplayer-plugin-danmuku](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-danmuku/index.js&example=danmuku) | Danmuku (bullet comment) system | <img src="https://img.shields.io/npm/v/artplayer-plugin-danmuku.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-danmuku.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-hls-control](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.5.17/hls.min.js%0A./uncompiled/artplayer-plugin-hls-control/index.js&example=hls.control) | HLS quality control | <img src="https://img.shields.io/npm/v/artplayer-plugin-hls-control.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-hls-control.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-dash-control](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/dashjs/4.5.2/dash.all.min.js%0A./uncompiled/artplayer-plugin-dash-control/index.js&example=dash.control) | DASH quality control | <img src="https://img.shields.io/npm/v/artplayer-plugin-dash-control.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-dash-control.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-dash-control](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/dashjs/5.2.1/modern/umd/dash.all.min.js%0A./uncompiled/artplayer-plugin-dash-control/index.js&example=dash.control) | DASH quality control | <img src="https://img.shields.io/npm/v/artplayer-plugin-dash-control.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-dash-control.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-vtt-thumbnail](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-vtt-thumbnail/index.js&example=vtt.thumbnail) | VTT thumbnail preview | <img src="https://img.shields.io/npm/v/artplayer-plugin-vtt-thumbnail.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-vtt-thumbnail.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-multiple-subtitles](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-multiple-subtitles/index.js&example=multiple.subtitles) | Multiple subtitles support | <img src="https://img.shields.io/npm/v/artplayer-plugin-multiple-subtitles.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-multiple-subtitles.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-chromecast](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-chromecast/index.js&example=chromecast) | Google Chromecast support | <img src="https://img.shields.io/npm/v/artplayer-plugin-chromecast.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-chromecast.svg?sanitize=true"> |
|
||||
@@ -124,7 +136,7 @@ let art = new Artplayer({
|
||||
| Name | Describe | State |
|
||||
| :--- | :--- | :--- |
|
||||
| [hls.js](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.5.17/hls.min.js&example=hls) | HLS client | <img src="https://img.shields.io/npm/v/hls.js.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/hls.js.svg?sanitize=true"> |
|
||||
| [dash.js](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/dashjs/4.5.2/dash.all.min.js&example=dash) | MPEG DASH player | <img src="https://img.shields.io/npm/v/dashjs.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/dashjs.svg?sanitize=true"> |
|
||||
| [dash.js](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/dashjs/5.2.1/modern/umd/dash.all.min.js&example=dash) | MPEG DASH player | <img src="https://img.shields.io/npm/v/dashjs.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/dashjs.svg?sanitize=true"> |
|
||||
| [flv.js](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/flv.js/1.6.2/flv.min.js&example=flv) | HTML5 FLV Player | <img src="https://img.shields.io/npm/v/flv.js.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/flv.js.svg?sanitize=true"> |
|
||||
| [mpegts.js](https://artplayer.org/?libs=https://cdn.jsdelivr.net/npm/mpegts.js@1.7.3/dist/mpegts.min.js&example=mpegts) | MPEG-TS/FLV Player | <img src="https://img.shields.io/npm/v/mpegts.js.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/mpegts.js.svg?sanitize=true"> |
|
||||
| [webtorrent.js](https://artplayer.org/?libs=https://cdn.jsdelivr.net/npm/webtorrent@1/webtorrent.min.js&example=webtorrent) | Streaming torrent client | <img src="https://img.shields.io/npm/v/webtorrent.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/webtorrent.svg?sanitize=true"> |
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
artplayer.org
|
||||
github.artplayer.org
|
||||
@@ -0,0 +1,420 @@
|
||||
# Verified site component notices
|
||||
|
||||
Frozen source identities and complete upstream notice texts for selected site components and font references. Unresolved font/media and embedded provenance gates remain open; this inventory is not publication clearance.
|
||||
|
||||
Generated by yarn build:site-notices. Runtime asset URLs are retained; reviewed local patches are identified below.
|
||||
|
||||
## vconsole 3.15.0
|
||||
|
||||
Source: https://registry.npmjs.org/vconsole/-/vconsole-3.15.0.tgz
|
||||
|
||||
The original 3.15.0 LICENSE is preserved unchanged; its missing MIT body is supplemented separately using the MIT text explicitly referenced by upstream. Exact reconstruction from the pinned source and lockfile establishes eight bundled package dependencies and webpack bootstrap; their complete notices and attribution are distributed below. ArtPlayer retains its reproducible lifecycle patch and the original script URL/UMD/CSS contracts.
|
||||
|
||||
Included component: @babel/runtime 7.17.9
|
||||
|
||||
Source: https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz
|
||||
|
||||
Included component: core-js 3.21.1
|
||||
|
||||
Source: https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz
|
||||
|
||||
Included component: copy-text-to-clipboard 3.0.1
|
||||
|
||||
Source: https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.0.1.tgz
|
||||
|
||||
Included component: mutation-observer 1.0.3
|
||||
|
||||
Source: https://registry.npmjs.org/mutation-observer/-/mutation-observer-1.0.3.tgz
|
||||
|
||||
Included component: svelte 3.47.0
|
||||
|
||||
Source: https://registry.npmjs.org/svelte/-/svelte-3.47.0.tgz
|
||||
|
||||
Included component: regenerator-runtime 0.13.9
|
||||
|
||||
Source: https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz
|
||||
|
||||
Included component: style-loader 3.3.1
|
||||
|
||||
Source: https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz
|
||||
|
||||
Included component: css-loader 6.7.1
|
||||
|
||||
Source: https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz
|
||||
|
||||
Included component: webpack 5.72.0
|
||||
|
||||
Source: https://registry.npmjs.org/webpack/-/webpack-5.72.0.tgz
|
||||
|
||||
- licenses/vconsole/LICENSE
|
||||
- licenses/vconsole/babel-runtime/LICENSE
|
||||
- licenses/vconsole/core-js/LICENSE
|
||||
- licenses/vconsole/copy-text-to-clipboard/LICENSE
|
||||
- licenses/vconsole/mutation-observer/LICENSE
|
||||
- licenses/vconsole/svelte/LICENSE
|
||||
- licenses/vconsole/regenerator-runtime/LICENSE
|
||||
- licenses/vconsole/style-loader/LICENSE
|
||||
- licenses/vconsole/css-loader/LICENSE
|
||||
- licenses/vconsole/webpack/LICENSE
|
||||
- licenses/vconsole/MIT-LICENSE
|
||||
- licenses/vconsole/ATTRIBUTION.md
|
||||
|
||||
## monaco-editor 0.30.1
|
||||
|
||||
Source: https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.30.1.tgz
|
||||
|
||||
The complete upstream Monaco LICENSE/ThirdPartyNotices are retained. The unmodified bundled Codicons font exactly matches @vscode/codicons 0.0.26; its historical README, CC BY 4.0 content license, MIT code license and added attribution are distributed below. Other site assets remain subject to their separate provenance reviews.
|
||||
|
||||
Included component: @vscode/codicons 0.0.26
|
||||
|
||||
Source: https://registry.npmjs.org/@vscode/codicons/-/codicons-0.0.26.tgz
|
||||
|
||||
Included component: typescript (Monaco worker) 4.4.4
|
||||
|
||||
Source: https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz
|
||||
|
||||
Included component: jsonc-parser 3.0.0
|
||||
|
||||
Source: https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz
|
||||
|
||||
Included component: vscode-css-languageservice 5.1.8
|
||||
|
||||
Source: https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-5.1.8.tgz
|
||||
|
||||
Included component: vscode-html-languageservice 4.1.1
|
||||
|
||||
Source: https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-4.1.1.tgz
|
||||
|
||||
Included component: vscode-json-languageservice 4.1.9
|
||||
|
||||
Source: https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.1.9.tgz
|
||||
|
||||
Included component: vscode-languageserver-textdocument 1.0.2
|
||||
|
||||
Source: https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.2.tgz
|
||||
|
||||
Included component: vscode-languageserver-types 3.16.0
|
||||
|
||||
Source: https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz
|
||||
|
||||
Included component: vscode-uri 3.0.2
|
||||
|
||||
Source: https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.2.tgz
|
||||
|
||||
Included component: js-beautify (Monaco HTML embedded) embedded sources in vscode-html-languageservice 4.1.1
|
||||
|
||||
Source: https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-4.1.1.tgz
|
||||
|
||||
Included component: glob-to-regexp (Monaco JSON fork) embedded source in vscode-json-languageservice 4.1.9
|
||||
|
||||
Source: https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.1.9.tgz
|
||||
|
||||
Included component: dompurify (Monaco core) 2.3.1
|
||||
|
||||
Source: https://registry.npmjs.org/dompurify/-/dompurify-2.3.1.tgz
|
||||
|
||||
Included component: marked (Monaco core) 3.0.2
|
||||
|
||||
Source: https://registry.npmjs.org/marked/-/marked-3.0.2.tgz
|
||||
|
||||
Included component: nodejs path (Monaco core) 14.16.0
|
||||
|
||||
Source: https://github.com/nodejs/node/blob/bd60e93357a118204ea238d94e7a9e4209d93062/lib/path.js
|
||||
|
||||
Included component: WinJS-derived DOM helpers (Monaco core) unversioned adaptation; reference WinJS 4.4.5
|
||||
|
||||
Source: https://github.com/winjs/winjs/tree/4329b1133b243d9ded3b5a1f98d096ee8e80e889
|
||||
|
||||
Included component: Unicode data (Monaco core) mixed historical inputs: 10.0.0d5, 13.0 drafts, Emoji 13.1
|
||||
|
||||
Source: https://github.com/alexdima/unicode-utils
|
||||
|
||||
- licenses/monaco-editor/LICENSE
|
||||
- licenses/monaco-editor/ThirdPartyNotices.txt
|
||||
- licenses/monaco-editor/codicons/LICENSE
|
||||
- licenses/monaco-editor/codicons/LICENSE-CODE
|
||||
- licenses/monaco-editor/codicons/README.md
|
||||
- licenses/monaco-editor/codicons/ATTRIBUTION.md
|
||||
- licenses/monaco-editor/typescript/LICENSE.txt
|
||||
- licenses/monaco-editor/typescript/CopyrightNotice.txt
|
||||
- licenses/monaco-editor/typescript/ThirdPartyNoticeText.txt
|
||||
- licenses/monaco-editor/typescript/ATTRIBUTION.md
|
||||
- licenses/monaco-editor/language-services/jsonc-parser/LICENSE.md
|
||||
- licenses/monaco-editor/language-services/vscode-css-languageservice/LICENSE.md
|
||||
- licenses/monaco-editor/language-services/vscode-html-languageservice/LICENSE.md
|
||||
- licenses/monaco-editor/language-services/vscode-html-languageservice/thirdpartynotices.txt
|
||||
- licenses/monaco-editor/language-services/vscode-json-languageservice/LICENSE.md
|
||||
- licenses/monaco-editor/language-services/vscode-languageserver-textdocument/License.txt
|
||||
- licenses/monaco-editor/language-services/vscode-languageserver-textdocument/thirdpartynotices.txt
|
||||
- licenses/monaco-editor/language-services/vscode-languageserver-types/License.txt
|
||||
- licenses/monaco-editor/language-services/vscode-uri/LICENSE.md
|
||||
- licenses/monaco-editor/language-services/beautify-css-NOTICE.txt
|
||||
- licenses/monaco-editor/language-services/beautify-html-NOTICE.txt
|
||||
- licenses/monaco-editor/language-services/ATTRIBUTION.md
|
||||
- licenses/monaco-editor/core-origins/DOMPurify-LICENSE
|
||||
- licenses/monaco-editor/core-origins/marked-LICENSE
|
||||
- licenses/monaco-editor/core-origins/marked-vscode-license.txt
|
||||
- licenses/monaco-editor/core-origins/ATTRIBUTION.md
|
||||
- licenses/monaco-editor/core-path/ATTRIBUTION.md
|
||||
- licenses/monaco-editor/core-dom/LICENSE.txt
|
||||
- licenses/monaco-editor/core-dom/ATTRIBUTION.md
|
||||
- licenses/monaco-editor/core-unicode/LICENSE.txt
|
||||
- licenses/monaco-editor/core-unicode/ATTRIBUTION.md
|
||||
|
||||
## console legacy-vendor-with-TS-adapter
|
||||
|
||||
Source: https://github.com/zhw2590582/ArtPlayer/blob/5d6b2f22bc75213ac97cff0bcffa4a1ce2bc786c/docs/assets/js/console.js
|
||||
|
||||
The 100 third-party Parcel modules and loader have exact source reproduction. The two owned adapter modules are built from TypeScript. Preserved notices also cover two embedded license headers, all 17 react-inspector external source-map members, and all seven HTML tokenizer sources from its fixed Git dependency. The identified embedded-source and attribution review is complete for this frozen vendor boundary. Source records bind each component to its original notices; this inventory is not publication clearance. The original full lockfile and historical online Closure service are not recovered. Modified replicator and Emotion/Stylis copies retain upstream author licenses; the original Emotion online Closure stage is not claimed to be reproducible. MurmurHash credits include Gary Court and Austin Appleby. The customStringify snippet matches Stack Overflow answer revision 5 under CC BY-SA 4.0; its separate attribution, source and full license are supplied. This is a mixed-license bundle, not MIT-only.
|
||||
|
||||
Included component: console-feed 3.2.2
|
||||
|
||||
Source: https://registry.npmjs.org/console-feed/-/console-feed-3.2.2.tgz
|
||||
|
||||
Included component: react 17.0.2
|
||||
|
||||
Source: https://registry.npmjs.org/react/-/react-17.0.2.tgz
|
||||
|
||||
Included component: react-dom 17.0.2
|
||||
|
||||
Source: https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz
|
||||
|
||||
Included component: scheduler 0.20.2
|
||||
|
||||
Source: https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz
|
||||
|
||||
Included component: object-assign 4.1.1
|
||||
|
||||
Source: https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz
|
||||
|
||||
Included component: react-is 16.13.1
|
||||
|
||||
Source: https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz
|
||||
|
||||
Included component: prop-types 15.7.2
|
||||
|
||||
Source: https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz
|
||||
|
||||
Included component: shallowequal 1.1.0
|
||||
|
||||
Source: https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz
|
||||
|
||||
Included component: process 0.11.10
|
||||
|
||||
Source: https://registry.npmjs.org/process/-/process-0.11.10.tgz
|
||||
|
||||
Included component: hoist-non-react-statics 3.3.2
|
||||
|
||||
Source: https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz
|
||||
|
||||
Included component: is-dom 1.1.0
|
||||
|
||||
Source: https://registry.npmjs.org/is-dom/-/is-dom-1.1.0.tgz
|
||||
|
||||
Included component: is-object 1.0.2
|
||||
|
||||
Source: https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz
|
||||
|
||||
Included component: is-window 1.0.2
|
||||
|
||||
Source: https://registry.npmjs.org/is-window/-/is-window-1.0.2.tgz
|
||||
|
||||
Included component: linkifyjs 2.1.9
|
||||
|
||||
Source: https://registry.npmjs.org/linkifyjs/-/linkifyjs-2.1.9.tgz
|
||||
|
||||
Included component: @emotion/core 10.3.0
|
||||
|
||||
Source: https://registry.npmjs.org/@emotion/core/-/core-10.3.0.tgz
|
||||
|
||||
Included component: @emotion/css 10.0.27
|
||||
|
||||
Source: https://registry.npmjs.org/@emotion/css/-/css-10.0.27.tgz
|
||||
|
||||
Included component: @emotion/cache 10.0.29
|
||||
|
||||
Source: https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz
|
||||
|
||||
Included component: @emotion/styled 10.0.27
|
||||
|
||||
Source: https://registry.npmjs.org/@emotion/styled/-/styled-10.0.27.tgz
|
||||
|
||||
Included component: @emotion/styled-base 10.3.0
|
||||
|
||||
Source: https://registry.npmjs.org/@emotion/styled-base/-/styled-base-10.3.0.tgz
|
||||
|
||||
Included component: emotion-theming 10.3.0
|
||||
|
||||
Source: https://registry.npmjs.org/emotion-theming/-/emotion-theming-10.3.0.tgz
|
||||
|
||||
Included component: styled-components 5.3.3
|
||||
|
||||
Source: https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz
|
||||
|
||||
Included component: @babel/runtime 7.16.3
|
||||
|
||||
Source: https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz
|
||||
|
||||
Included component: @emotion/sheet 0.9.4
|
||||
|
||||
Source: https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz
|
||||
|
||||
Included component: @emotion/stylis 0.8.5
|
||||
|
||||
Source: https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz
|
||||
|
||||
Included component: @emotion/weak-memoize 0.2.5
|
||||
|
||||
Source: https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz
|
||||
|
||||
Included component: @emotion/utils 0.11.3
|
||||
|
||||
Source: https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz
|
||||
|
||||
Included component: @emotion/hash 0.8.0
|
||||
|
||||
Source: https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz
|
||||
|
||||
Included component: @emotion/unitless 0.7.5
|
||||
|
||||
Source: https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz
|
||||
|
||||
Included component: @emotion/memoize 0.7.4
|
||||
|
||||
Source: https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz
|
||||
|
||||
Included component: @emotion/serialize 0.11.16
|
||||
|
||||
Source: https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz
|
||||
|
||||
Included component: @emotion/is-prop-valid 0.8.8
|
||||
|
||||
Source: https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz
|
||||
|
||||
Included component: react-inspector 5.1.1
|
||||
|
||||
Source: https://registry.npmjs.org/react-inspector/-/react-inspector-5.1.1.tgz
|
||||
|
||||
Included component: parcel-bundler 1.12.5
|
||||
|
||||
Source: https://registry.npmjs.org/parcel-bundler/-/parcel-bundler-1.12.5.tgz
|
||||
|
||||
Included component: chromium-string-utils embedded in console-feed-3.2.2
|
||||
|
||||
Source: https://registry.npmjs.org/console-feed/-/console-feed-3.2.2.tgz
|
||||
|
||||
Included component: stylis-rule-sheet embedded in styled-components-5.3.3
|
||||
|
||||
Source: https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz
|
||||
|
||||
Included component: @babel/runtime (react-inspector embedded) 7.13.10
|
||||
|
||||
Source: https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz
|
||||
|
||||
Included component: regenerator-runtime 0.13.7
|
||||
|
||||
Source: https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz
|
||||
|
||||
Included component: simple-html-tokenizer git-04799f4638ec5ed903a4e5aa6e832269fa59be6b
|
||||
|
||||
Source: https://api.github.com/repos/nfrasser/simple-html-tokenizer/tarball/04799f4638ec5ed903a4e5aa6e832269fa59be6b
|
||||
|
||||
Included component: replicator (console-feed fork) modified; upstream 1.0.x license
|
||||
|
||||
Source: https://registry.npmjs.org/replicator/-/replicator-1.0.1.tgz
|
||||
|
||||
Included component: stylis (Emotion fork) 3.5.4-derived
|
||||
|
||||
Source: https://registry.npmjs.org/stylis/-/stylis-3.5.4.tgz
|
||||
|
||||
Included component: murmurhash-js (Gary Court) license commit 23dc2e7
|
||||
|
||||
Source: https://github.com/garycourt/murmurhash-js/blob/23dc2e7008582ca3ef69d8623f02bba4c8dd05e5/README.md
|
||||
|
||||
Included component: murmurhash2 (Austin Appleby) 61a0530
|
||||
|
||||
Source: https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash2.cpp
|
||||
|
||||
Included component: stackoverflow-custom-stringify answer 48254637 revision 5 (CC BY-SA 4.0)
|
||||
|
||||
Source: https://api.stackexchange.com/2.3/revisions/8FD5F52A-B16F-4C66-AB48-830EABB36CC0?site=stackoverflow&filter=withbody
|
||||
|
||||
Included component: react-pure-render (shallowequal origin) source commit 729cdbd
|
||||
|
||||
Source: https://github.com/gaearon/react-pure-render/blob/729cdbd51df00068816376544738cc1fc4720cf2/LICENSE
|
||||
|
||||
- licenses/console/console-feed/console-feed-3.2.2-LICENSE
|
||||
- licenses/console/react/react-17.0.2-LICENSE
|
||||
- licenses/console/react-dom/react-dom-17.0.2-LICENSE
|
||||
- licenses/console/scheduler/scheduler-0.20.2-LICENSE
|
||||
- licenses/console/object-assign/object-assign-4.1.1-license
|
||||
- licenses/console/react-is/react-is-16.13.1-LICENSE
|
||||
- licenses/console/prop-types/prop-types-15.7.2-LICENSE
|
||||
- licenses/console/shallowequal/shallowequal-1.1.0-LICENSE
|
||||
- licenses/console/process/process-0.11.10-LICENSE
|
||||
- licenses/console/hoist-non-react-statics/hoist-non-react-statics-3.3.2-LICENSE.md
|
||||
- licenses/console/is-dom/is-dom-1.1.0-LICENSE
|
||||
- licenses/console/is-object/is-object-1.0.2-LICENSE
|
||||
- licenses/console/is-window/is-window-1.0.2-LICENSE
|
||||
- licenses/console/linkifyjs/linkifyjs-2.1.9-LICENSE
|
||||
- licenses/console/emotion-core/emotion-core-10.3.0-LICENSE
|
||||
- licenses/console/emotion-css/emotion-css-10.0.27-LICENSE
|
||||
- licenses/console/emotion-cache/emotion-cache-10.0.29-LICENSE
|
||||
- licenses/console/emotion-styled/emotion-styled-10.0.27-LICENSE
|
||||
- licenses/console/emotion-styled-base/emotion-styled-base-10.3.0-LICENSE
|
||||
- licenses/console/emotion-theming/emotion-theming-10.3.0-LICENSE
|
||||
- licenses/console/styled-components/styled-components-5.3.3-UPSTREAM-LICENSE
|
||||
- licenses/console/babel-runtime/babel-runtime-7.16.3-LICENSE
|
||||
- licenses/console/emotion-sheet/emotion-sheet-0.9.4-LICENSE
|
||||
- licenses/console/emotion-stylis/emotion-stylis-0.8.5-LICENSE
|
||||
- licenses/console/emotion-weak-memoize/emotion-weak-memoize-0.2.5-LICENSE
|
||||
- licenses/console/emotion-utils/emotion-utils-0.11.3-LICENSE
|
||||
- licenses/console/emotion-hash/emotion-hash-0.8.0-LICENSE
|
||||
- licenses/console/emotion-unitless/emotion-unitless-0.7.5-LICENSE
|
||||
- licenses/console/emotion-memoize/emotion-memoize-0.7.4-LICENSE
|
||||
- licenses/console/emotion-serialize/emotion-serialize-0.11.16-LICENSE
|
||||
- licenses/console/emotion-is-prop-valid/emotion-is-prop-valid-0.8.8-LICENSE
|
||||
- licenses/console/react-inspector/react-inspector-5.1.1-LICENSE
|
||||
- licenses/console/parcel-bundler/parcel-bundler-1.12.5-LICENSE
|
||||
- licenses/console/chromium-string-utils/LICENSE
|
||||
- licenses/console/stylis-rule-sheet/LICENSE
|
||||
- licenses/console/react-inspector-babel/LICENSE
|
||||
- licenses/console/regenerator-runtime/LICENSE
|
||||
- licenses/console/simple-html-tokenizer/LICENSE
|
||||
- licenses/console/replicator/LICENSE
|
||||
- licenses/console/stylis/LICENSE
|
||||
- licenses/console/murmurhash-js/README.md
|
||||
- licenses/console/murmurhash2/PUBLIC-DOMAIN.txt
|
||||
- licenses/console/stackoverflow/LICENSE
|
||||
- licenses/console/stackoverflow/SOURCE.js
|
||||
- licenses/console/stackoverflow/ATTRIBUTION.md
|
||||
- licenses/console/react-pure-render/LICENSE
|
||||
- licenses/console/react-pure-render/ATTRIBUTION.md
|
||||
|
||||
## jassub-fonts selected historical references
|
||||
|
||||
Source: https://github.com/ThaUnknown/jassub/tree/25d1ea7ca1f827dbed2c8ea539c9bc917ccbfab1
|
||||
|
||||
Four selected font families only. CHAWP matches author bytes; other full notice references have explicit font-table differences. Other fonts and complete redistribution provenance remain open under SITE-07/VENDOR-05.
|
||||
|
||||
Included component: Liberation Sans 2.00.5 reference
|
||||
|
||||
Source: https://github.com/liberationfonts/liberation-fonts/files/2926169/liberation-fonts-ttf-2.00.5.tar.gz
|
||||
|
||||
Included component: Averia Sans Libre Light 1.002 reference
|
||||
|
||||
Source: https://github.com/google/fonts/blob/0f81bc90462b862dbfe3d16403ff284a68473833/ofl/averiasanslibre/AveriaSansLibre-Light.ttf
|
||||
|
||||
Included component: Lato Regular 2.015 reference
|
||||
|
||||
Source: https://github.com/google/fonts/blob/f3b885d5590e307e02542f1a724cec55d567fdaa/ofl/lato/Lato-Regular.ttf
|
||||
|
||||
Included component: CHAWP 1.000 exact bytes
|
||||
|
||||
Source: https://github.com/awp/chawp/blob/3c4f6317bebd6783c8d0db3bc9206aa62d602f90/chawp.otf
|
||||
|
||||
- licenses/jassub-fonts/liberation/OFL.txt
|
||||
- licenses/jassub-fonts/averia-sans/OFL.txt
|
||||
- licenses/jassub-fonts/lato/OFL.txt
|
||||
- licenses/jassub-fonts/chawp/OFL.txt
|
||||
- licenses/jassub-fonts/ATTRIBUTION.md
|
||||
@@ -0,0 +1,68 @@
|
||||
/* global Artplayer, artplayerPluginAsr */
|
||||
// Local audio capture demo. The subtitles below are simulated, not recognized speech.
|
||||
// No audio is uploaded; only the sample media is loaded from this local site.
|
||||
const statistics = document.createElement('div')
|
||||
statistics.textContent = 'Local ASR demo: press play. No recognition service is used.'
|
||||
let chunks = 0
|
||||
let pcmBytes = 0
|
||||
let wavBytes = 0
|
||||
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/steve-jobs.mp4',
|
||||
autoSize: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
layers: [{
|
||||
name: 'asr-local-statistics',
|
||||
html: statistics,
|
||||
style: {
|
||||
position: 'absolute',
|
||||
top: '12px',
|
||||
left: '12px',
|
||||
right: '12px',
|
||||
padding: '8px 12px',
|
||||
background: 'rgba(0, 0, 0, 0.65)',
|
||||
color: '#fff',
|
||||
fontSize: '12px',
|
||||
whiteSpace: 'pre-line',
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
}],
|
||||
controls: [{
|
||||
name: 'asr-local-stop',
|
||||
position: 'right',
|
||||
html: 'Stop ASR',
|
||||
tooltip: 'Stop capture; pause and play to restart',
|
||||
async click() {
|
||||
await art.plugins.artplayerPluginAsr.stop()
|
||||
if (!art.isDestroy)
|
||||
statistics.textContent = 'Local capture stopped. Pause and play to restart. Nothing was uploaded.'
|
||||
},
|
||||
}],
|
||||
plugins: [artplayerPluginAsr({
|
||||
length: 2,
|
||||
interval: 250,
|
||||
sampleRate: 16000,
|
||||
autoHideTimeout: 5000,
|
||||
onAudioChunk({ pcm, wav }) {
|
||||
if (art.isDestroy)
|
||||
return
|
||||
chunks++
|
||||
pcmBytes += pcm.byteLength
|
||||
wavBytes += wav.byteLength
|
||||
const sampleRate = new DataView(wav).getUint32(24, true)
|
||||
const samples = new DataView(pcm)
|
||||
let peak = 0
|
||||
for (let offset = 0; offset < pcm.byteLength; offset += 2)
|
||||
peak = Math.max(peak, Math.abs(samples.getInt16(offset, true)))
|
||||
const duration = (pcmBytes / 2 / sampleRate).toFixed(2)
|
||||
statistics.textContent = [
|
||||
'Local capture only - simulated subtitles, no speech recognition',
|
||||
`Chunks: ${chunks} | ${sampleRate} Hz mono PCM16 | ${duration} seconds captured`,
|
||||
`PCM: ${pcmBytes} bytes | WAV: ${wavBytes} bytes | Current peak: ${peak}`,
|
||||
].join('\n')
|
||||
return `Simulated local subtitle: audio chunk ${chunks} received.`
|
||||
},
|
||||
})],
|
||||
})
|
||||
@@ -20,6 +20,9 @@ const art = new Artplayer({
|
||||
miniProgressBar: true,
|
||||
autoPlayback: true,
|
||||
autoOrientation: true,
|
||||
subtitle: {
|
||||
url: '/assets/sample/subtitle.srt',
|
||||
},
|
||||
thumbnails: {
|
||||
url: '/assets/sample/thumbnails.png',
|
||||
number: 60,
|
||||
|
||||
@@ -4,45 +4,55 @@
|
||||
// import dashjs from 'dashjs';
|
||||
// import artplayerPluginDashControl from 'artplayer-plugin-dash-control';
|
||||
|
||||
const useDash = dashjs.supportsMediaSource()
|
||||
let dash
|
||||
|
||||
function destroyDash() {
|
||||
const previous = dash
|
||||
dash = undefined
|
||||
if (previous)
|
||||
previous.destroy()
|
||||
}
|
||||
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: 'https://media.axprod.net/TestVectors/v7-Clear/Manifest_1080p.mpd',
|
||||
setting: true,
|
||||
plugins: [
|
||||
artplayerPluginDashControl({
|
||||
quality: {
|
||||
// Show qualitys in control
|
||||
control: true,
|
||||
// Show qualitys in setting
|
||||
setting: true,
|
||||
// Get the quality name from level
|
||||
getName: level => `${level.height}P`,
|
||||
// I18n
|
||||
title: 'Quality',
|
||||
auto: 'Auto',
|
||||
},
|
||||
audio: {
|
||||
// Show audios in control
|
||||
control: true,
|
||||
// Show audios in setting
|
||||
setting: true,
|
||||
// Get the audio name from track
|
||||
getName: track => track.lang.toUpperCase(),
|
||||
// I18n
|
||||
title: 'Audio',
|
||||
auto: 'Auto',
|
||||
},
|
||||
}),
|
||||
],
|
||||
plugins: useDash
|
||||
? [
|
||||
artplayerPluginDashControl({
|
||||
quality: {
|
||||
// Show quality choices in the controls
|
||||
control: true,
|
||||
// Show quality choices in settings
|
||||
setting: true,
|
||||
// Get the quality name from level
|
||||
getName: level => `${level.height}P`,
|
||||
// I18n
|
||||
title: 'Quality',
|
||||
auto: 'Auto',
|
||||
},
|
||||
audio: {
|
||||
// Show audios in control
|
||||
control: true,
|
||||
// Show audios in setting
|
||||
setting: true,
|
||||
// Get the audio name from track
|
||||
getName: track => track.lang?.toUpperCase() || String(track.id ?? 'Audio'),
|
||||
// I18n
|
||||
title: 'Audio',
|
||||
auto: 'Auto',
|
||||
},
|
||||
}),
|
||||
]
|
||||
: [],
|
||||
customType: {
|
||||
mpd: function playMpd(video, url, art) {
|
||||
if (dashjs.supportsMediaSource()) {
|
||||
if (art.dash)
|
||||
art.dash.destroy()
|
||||
const dash = dashjs.MediaPlayer().create()
|
||||
dash.initialize(video, url, art.option.autoplay)
|
||||
destroyDash()
|
||||
if (useDash) {
|
||||
dash = dashjs.MediaPlayer().create()
|
||||
art.dash = dash
|
||||
art.on('destroy', () => dash.destroy())
|
||||
dash.initialize(video, url, art.option.autoplay)
|
||||
}
|
||||
else {
|
||||
art.notice.show = 'Unsupported playback format: mpd'
|
||||
@@ -50,3 +60,5 @@ const art = new Artplayer({
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
art.on('destroy', destroyDash)
|
||||
@@ -4,46 +4,56 @@
|
||||
// import Hls from 'hls.js';
|
||||
// import artplayerPluginHlsControl from 'artplayer-plugin-hls-control';
|
||||
|
||||
const useHls = Hls.isSupported()
|
||||
let hls
|
||||
|
||||
function destroyHls() {
|
||||
const previous = hls
|
||||
hls = undefined
|
||||
if (previous)
|
||||
previous.destroy()
|
||||
}
|
||||
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: 'https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8',
|
||||
setting: true,
|
||||
plugins: [
|
||||
artplayerPluginHlsControl({
|
||||
quality: {
|
||||
// Show qualitys in control
|
||||
control: true,
|
||||
// Show qualitys in setting
|
||||
setting: true,
|
||||
// Get the quality name from level
|
||||
getName: level => `${level.height}P`,
|
||||
// I18n
|
||||
title: 'Quality',
|
||||
auto: 'Auto',
|
||||
},
|
||||
audio: {
|
||||
// Show audios in control
|
||||
control: true,
|
||||
// Show audios in setting
|
||||
setting: true,
|
||||
// Get the audio name from track
|
||||
getName: track => track.name,
|
||||
// I18n
|
||||
title: 'Audio',
|
||||
auto: 'Auto',
|
||||
},
|
||||
}),
|
||||
],
|
||||
plugins: useHls
|
||||
? [
|
||||
artplayerPluginHlsControl({
|
||||
quality: {
|
||||
// Show quality choices in the controls
|
||||
control: true,
|
||||
// Show quality choices in settings
|
||||
setting: true,
|
||||
// Get the quality name from level
|
||||
getName: level => `${level.height}P`,
|
||||
// I18n
|
||||
title: 'Quality',
|
||||
auto: 'Auto',
|
||||
},
|
||||
audio: {
|
||||
// Show audios in control
|
||||
control: true,
|
||||
// Show audios in setting
|
||||
setting: true,
|
||||
// Get the audio name from track
|
||||
getName: track => track.name || track.lang || 'Audio',
|
||||
// I18n
|
||||
title: 'Audio',
|
||||
auto: 'Auto',
|
||||
},
|
||||
}),
|
||||
]
|
||||
: [],
|
||||
customType: {
|
||||
m3u8: function playM3u8(video, url, art) {
|
||||
if (Hls.isSupported()) {
|
||||
if (art.hls)
|
||||
art.hls.destroy()
|
||||
const hls = new Hls()
|
||||
destroyHls()
|
||||
if (useHls) {
|
||||
hls = new Hls()
|
||||
art.hls = hls
|
||||
hls.loadSource(url)
|
||||
hls.attachMedia(video)
|
||||
art.hls = hls
|
||||
art.on('destroy', () => hls.destroy())
|
||||
}
|
||||
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
||||
video.src = url
|
||||
@@ -54,3 +64,5 @@ const art = new Artplayer({
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
art.on('destroy', destroyHls)
|
||||
@@ -15,6 +15,11 @@ const iframe = new ArtplayerToolIframe({
|
||||
url: '/iframe.html',
|
||||
})
|
||||
|
||||
window.addEventListener('artplayer:example:cleanup', () => {
|
||||
iframe.destroy()
|
||||
$iframe.remove()
|
||||
}, { once: true })
|
||||
|
||||
iframe.message(({ type, data }) => {
|
||||
switch (type) {
|
||||
case 'fullscreenWeb':
|
||||
@@ -44,4 +49,7 @@ iframe.commit(() => {
|
||||
data: state,
|
||||
})
|
||||
})
|
||||
}).catch((error) => {
|
||||
if (!iframe.destroyed)
|
||||
console.error(error)
|
||||
})
|
||||
@@ -2,24 +2,34 @@
|
||||
// import artplayerProxyMediabunny from 'artplayer-proxy-mediabunny';
|
||||
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: 'https://artplayer.org/assets/sample/frag_bunny.mp4',
|
||||
autoSize: true,
|
||||
screenshot: true,
|
||||
setting: true,
|
||||
loop: true,
|
||||
flip: true,
|
||||
playbackRate: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
miniProgressBar: true,
|
||||
autoPlayback: true,
|
||||
autoOrientation: true,
|
||||
thumbnails: {
|
||||
url: '/assets/sample/frag_bunny.png',
|
||||
number: 60,
|
||||
column: 10,
|
||||
scale: 0.85,
|
||||
container: '.artplayer-app',
|
||||
url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
|
||||
autoSize: true,
|
||||
setting: true,
|
||||
loop: true,
|
||||
flip: true,
|
||||
playbackRate: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
miniProgressBar: true,
|
||||
autoPlayback: true,
|
||||
autoOrientation: true,
|
||||
proxy: artplayerProxyMediabunny({
|
||||
m3u8: {
|
||||
quality: {
|
||||
control: true,
|
||||
setting: true,
|
||||
getName: level => level.height ? `${level.height}P` : level.name,
|
||||
title: 'Quality',
|
||||
auto: 'Auto',
|
||||
},
|
||||
audio: {
|
||||
control: true,
|
||||
setting: true,
|
||||
getName: track => track.name || track.language,
|
||||
title: 'Audio',
|
||||
auto: 'Auto',
|
||||
},
|
||||
},
|
||||
proxy: artplayerProxyMediabunny(),
|
||||
})
|
||||
}),
|
||||
})
|
||||
Vendored
+42
@@ -0,0 +1,42 @@
|
||||
// Generated by yarn build:site-assets. Do not edit.
|
||||
"use strict";
|
||||
(() => {
|
||||
// packages/artplayer-vitepress/browser/editor-preferences.ts
|
||||
function readPreference(key, storage = () => localStorage) {
|
||||
try {
|
||||
return storage().getItem(key) === "true";
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// packages/artplayer-vitepress/browser/bootstrap.ts
|
||||
function loadScript(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const script = document.createElement("script");
|
||||
const clear = () => {
|
||||
script.onload = null;
|
||||
script.onerror = null;
|
||||
};
|
||||
script.onload = () => {
|
||||
clear();
|
||||
resolve();
|
||||
};
|
||||
script.onerror = () => {
|
||||
clear();
|
||||
script.remove();
|
||||
reject(new Error(`Editor bootstrap failed: ${url}`));
|
||||
};
|
||||
script.src = url;
|
||||
document.body.appendChild(script);
|
||||
});
|
||||
}
|
||||
async function bootstrap() {
|
||||
await loadScript(
|
||||
readPreference("prod") ? "./compiled/artplayer.js" : "./uncompiled/artplayer/index.js"
|
||||
);
|
||||
await loadScript("./assets/js/vs/loader.js");
|
||||
await loadScript("./assets/js/common.js");
|
||||
}
|
||||
void bootstrap().catch((error) => console.error(error));
|
||||
})();
|
||||
+402
-295
@@ -1,312 +1,419 @@
|
||||
(function () {
|
||||
Artplayer.DEBUG = true
|
||||
|
||||
if (Artplayer.utils.isMobile) {
|
||||
window.location.href = `./mobile.html${location.search}`
|
||||
// Generated by yarn build:site-assets. Do not edit.
|
||||
"use strict";
|
||||
(() => {
|
||||
// packages/artplayer-vitepress/browser/editor-files.ts
|
||||
function readEditorFile(file, signal, createReader = () => new FileReader()) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = createReader();
|
||||
function clear() {
|
||||
reader.onload = null;
|
||||
reader.onerror = null;
|
||||
reader.onabort = null;
|
||||
signal.removeEventListener("abort", cancel);
|
||||
}
|
||||
function fail(error) {
|
||||
clear();
|
||||
reject(error);
|
||||
}
|
||||
function cancel() {
|
||||
reader.abort();
|
||||
fail(new Error(`File import cancelled: ${file.name}`));
|
||||
}
|
||||
reader.onload = () => {
|
||||
if (typeof reader.result !== "string") {
|
||||
fail(new Error(`File is not text: ${file.name}`));
|
||||
return;
|
||||
}
|
||||
const value = reader.result;
|
||||
clear();
|
||||
resolve(value);
|
||||
};
|
||||
reader.onerror = () => fail(reader.error || new Error(`Reading file failed: ${file.name}`));
|
||||
reader.onabort = () => fail(new Error(`File import cancelled: ${file.name}`));
|
||||
signal.addEventListener("abort", cancel, { once: true });
|
||||
try {
|
||||
if (signal.aborted)
|
||||
cancel();
|
||||
else reader.readAsText(file);
|
||||
} catch (error) {
|
||||
fail(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let $codeMirror = document.querySelector('.codeMirrorWrap')
|
||||
let $lib = document.querySelector('.libsInput')
|
||||
let $run = document.querySelector('.run')
|
||||
let $popups = document.querySelector('.popups')
|
||||
let $console = document.querySelector('.console')
|
||||
let $prod = document.querySelector('#prod')
|
||||
let $ts = document.querySelector('#ts')
|
||||
let $code = document.querySelector('#code')
|
||||
let $log = document.querySelector('#log')
|
||||
let $file = document.querySelector('#file')
|
||||
let $editor = document.querySelector('#editor')
|
||||
|
||||
window.consoleLog($console)
|
||||
|
||||
// Helper functions for localStorage
|
||||
const getStorageBoolean = (key) => localStorage.getItem(key) === 'true'
|
||||
const setStorageBoolean = (key, value) => localStorage.setItem(key, value ? 'true' : 'false')
|
||||
|
||||
$prod.checked = getStorageBoolean('prod')
|
||||
$ts.checked = getStorageBoolean('ts')
|
||||
$code.checked = getStorageBoolean('code')
|
||||
$log.checked = getStorageBoolean('log')
|
||||
|
||||
if ($code.checked) {
|
||||
$editor.style.display = 'none'
|
||||
}
|
||||
|
||||
if ($log.checked) {
|
||||
$console.style.display = 'none'
|
||||
}
|
||||
|
||||
let editor = null
|
||||
let loadedLibs = []
|
||||
require.config({ paths: { vs: './assets/js/vs' } })
|
||||
require(['vs/editor/editor.main'], async () => {
|
||||
monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
|
||||
noSemanticValidation: true,
|
||||
noSyntaxValidation: false,
|
||||
})
|
||||
|
||||
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
|
||||
target: monaco.languages.typescript.ScriptTarget.ES6,
|
||||
allowNonTsExtensions: true,
|
||||
})
|
||||
|
||||
let libUris = [
|
||||
'./assets/ts/artplayer-plugin-ads.d.ts',
|
||||
'./assets/ts/artplayer-plugin-ambilight.d.ts',
|
||||
'./assets/ts/artplayer-plugin-asr.d.ts',
|
||||
'./assets/ts/artplayer-plugin-audio-track.d.ts',
|
||||
'./assets/ts/artplayer-plugin-auto-thumbnail.d.ts',
|
||||
'./assets/ts/artplayer-plugin-chapter.d.ts',
|
||||
'./assets/ts/artplayer-plugin-chromecast.d.ts',
|
||||
'./assets/ts/artplayer-plugin-danmuku-mask.d.ts',
|
||||
'./assets/ts/artplayer-plugin-danmuku.d.ts',
|
||||
'./assets/ts/artplayer-plugin-dash-control.d.ts',
|
||||
'./assets/ts/artplayer-plugin-document-pip.d.ts',
|
||||
'./assets/ts/artplayer-plugin-hls-control.d.ts',
|
||||
'./assets/ts/artplayer-plugin-jassub.d.ts',
|
||||
'./assets/ts/artplayer-plugin-multiple-subtitles.d.ts',
|
||||
'./assets/ts/artplayer-plugin-vast.d.ts',
|
||||
'./assets/ts/artplayer-plugin-vtt-thumbnail.d.ts',
|
||||
'./assets/ts/artplayer-proxy-canvas.d.ts',
|
||||
'./assets/ts/artplayer-proxy-mediabunny.d.ts',
|
||||
'./assets/ts/artplayer-tool-iframe.d.ts',
|
||||
'./assets/ts/artplayer.d.ts',
|
||||
]
|
||||
|
||||
for (let index = 0; index < libUris.length; index++) {
|
||||
let libUri = libUris[index]
|
||||
let libSource = await (await fetch(libUri)).text()
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(libSource, libUri)
|
||||
monaco.editor.createModel(libSource, 'typescript', monaco.Uri.parse(libUri))
|
||||
}
|
||||
|
||||
const disposable = monaco.editor.onDidCreateEditor(() => {
|
||||
disposable.dispose()
|
||||
setTimeout(initApp, 1000)
|
||||
})
|
||||
|
||||
editor = monaco.editor.create($codeMirror, {
|
||||
theme: 'vs-dark',
|
||||
folding: true,
|
||||
automaticLayout: true,
|
||||
quickSuggestions: {
|
||||
other: true,
|
||||
comments: true,
|
||||
strings: true,
|
||||
function createFileImports(document, label) {
|
||||
const controller = new AbortController();
|
||||
const elements = [];
|
||||
let queue = Promise.resolve();
|
||||
return {
|
||||
add(files) {
|
||||
const work = queue.then(async () => {
|
||||
for (const file of files) {
|
||||
const name = file.name.toLowerCase().trim();
|
||||
if (!name.endsWith(".js") && !name.endsWith(".css"))
|
||||
continue;
|
||||
const text = await readEditorFile(file, controller.signal);
|
||||
if (controller.signal.aborted)
|
||||
return;
|
||||
const element = document.createElement(
|
||||
name.endsWith(".css") ? "style" : "script"
|
||||
);
|
||||
element.textContent = text;
|
||||
document.body.appendChild(element);
|
||||
elements.push(element);
|
||||
label(name);
|
||||
}
|
||||
});
|
||||
queue = work.catch(() => {
|
||||
});
|
||||
return work;
|
||||
},
|
||||
model: monaco.editor.createModel(
|
||||
dispose() {
|
||||
controller.abort();
|
||||
for (const element of elements) element.remove();
|
||||
elements.length = 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// packages/artplayer-vitepress/browser/editor-libraries.ts
|
||||
var libUris = [
|
||||
"./assets/ts/artplayer-plugin-ads.d.ts",
|
||||
"./assets/ts/artplayer-plugin-ambilight.d.ts",
|
||||
"./assets/ts/artplayer-plugin-asr.d.ts",
|
||||
"./assets/ts/artplayer-plugin-audio-track.d.ts",
|
||||
"./assets/ts/artplayer-plugin-auto-thumbnail.d.ts",
|
||||
"./assets/ts/artplayer-plugin-chapter.d.ts",
|
||||
"./assets/ts/artplayer-plugin-chromecast.d.ts",
|
||||
"./assets/ts/artplayer-plugin-danmuku-mask.d.ts",
|
||||
"./assets/ts/artplayer-plugin-danmuku.d.ts",
|
||||
"./assets/ts/artplayer-plugin-dash-control.d.ts",
|
||||
"./assets/ts/artplayer-plugin-document-pip.d.ts",
|
||||
"./assets/ts/artplayer-plugin-hls-control.d.ts",
|
||||
"./assets/ts/artplayer-plugin-jassub.d.ts",
|
||||
"./assets/ts/artplayer-plugin-multiple-subtitles.d.ts",
|
||||
"./assets/ts/artplayer-plugin-vast.d.ts",
|
||||
"./assets/ts/artplayer-plugin-vtt-thumbnail.d.ts",
|
||||
"./assets/ts/artplayer-proxy-canvas.d.ts",
|
||||
"./assets/ts/artplayer-proxy-mediabunny.d.ts",
|
||||
"./assets/ts/artplayer-tool-iframe.d.ts",
|
||||
"./assets/ts/artplayer-tool-thumbnail.d.ts",
|
||||
"./assets/ts/artplayer.d.ts",
|
||||
"./assets/ts/artplayer-i18n.d.ts"
|
||||
];
|
||||
|
||||
// packages/artplayer-vitepress/browser/editor-monaco.ts
|
||||
async function createMonaco(host, container, typescript, signal) {
|
||||
host.require.config({ paths: { vs: "./assets/js/vs" } });
|
||||
await new Promise(
|
||||
(resolve, reject) => host.require(["vs/editor/editor.main"], resolve, reject)
|
||||
);
|
||||
await new Promise(
|
||||
(resolve, reject) => host.require(
|
||||
[
|
||||
'var art = new Artplayer({',
|
||||
'\tcontainer: \'.artplayer-app\',',
|
||||
'\turl: \'/assets/sample/video.mp4\',',
|
||||
'});',
|
||||
].join('\n'),
|
||||
$ts.checked ? 'typescript' : 'javascript',
|
||||
),
|
||||
})
|
||||
})
|
||||
|
||||
function getURLParameters(url) {
|
||||
return (url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce((params, pair) => {
|
||||
const index = pair.indexOf('=')
|
||||
params[pair.slice(0, index)] = pair.slice(index + 1)
|
||||
return params
|
||||
}, {})
|
||||
}
|
||||
|
||||
function getExt(url) {
|
||||
if (url.includes('?')) {
|
||||
return getExt(url.split('?')[0])
|
||||
}
|
||||
|
||||
if (url.includes('#')) {
|
||||
return getExt(url.split('#')[0])
|
||||
}
|
||||
|
||||
return url.trim().toLowerCase().split('.').pop()
|
||||
}
|
||||
|
||||
function loadScript(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const originalDefine = window.define
|
||||
window.define = undefined
|
||||
const script = document.createElement('script')
|
||||
script.type = 'text/javascript'
|
||||
script.src = url
|
||||
script.onload = () => {
|
||||
window.define = originalDefine
|
||||
resolve(url)
|
||||
"vs/basic-languages/typescript/typescript",
|
||||
"vs/basic-languages/javascript/javascript",
|
||||
"vs/language/typescript/tsMode"
|
||||
],
|
||||
resolve,
|
||||
reject
|
||||
)
|
||||
);
|
||||
if (signal.aborted)
|
||||
throw new Error("Editor initialization cancelled");
|
||||
const api = host.monaco;
|
||||
const types = api.languages.typescript;
|
||||
const resources = [];
|
||||
const temporary = /* @__PURE__ */ new Set();
|
||||
let editor;
|
||||
let disposed = false;
|
||||
const dispose = () => {
|
||||
if (disposed)
|
||||
return;
|
||||
disposed = true;
|
||||
signal.removeEventListener("abort", dispose);
|
||||
editor?.dispose();
|
||||
editor = void 0;
|
||||
for (const model of temporary) model.dispose();
|
||||
temporary.clear();
|
||||
for (const resource of resources.splice(0).reverse()) resource.dispose();
|
||||
};
|
||||
signal.addEventListener("abort", dispose, { once: true });
|
||||
try {
|
||||
for (const defaults of [
|
||||
types.javascriptDefaults,
|
||||
types.typescriptDefaults
|
||||
]) {
|
||||
defaults.setDiagnosticsOptions({
|
||||
noSemanticValidation: defaults === types.javascriptDefaults,
|
||||
noSyntaxValidation: false
|
||||
});
|
||||
defaults.setCompilerOptions({
|
||||
target: types.ScriptTarget.ES2015,
|
||||
module: types.ModuleKind.None,
|
||||
allowNonTsExtensions: true,
|
||||
noEmit: false
|
||||
});
|
||||
}
|
||||
script.onerror = () => {
|
||||
window.define = originalDefine
|
||||
reject(new Error(`Loading script failed: ${url}`))
|
||||
for (const uri of libUris) {
|
||||
const response = await host.fetch(uri, { signal });
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Loading editor declaration failed: ${uri} (${response.status})`
|
||||
);
|
||||
}
|
||||
const source = await response.text();
|
||||
if (signal.aborted)
|
||||
throw new Error("Editor initialization cancelled");
|
||||
resources.push(
|
||||
types.javascriptDefaults.addExtraLib(source, uri),
|
||||
types.typescriptDefaults.addExtraLib(source, uri)
|
||||
);
|
||||
resources.push(
|
||||
api.editor.createModel(source, "typescript", api.Uri.parse(uri))
|
||||
);
|
||||
}
|
||||
document.head.appendChild(script)
|
||||
})
|
||||
const model = api.editor.createModel(
|
||||
"var art = new Artplayer({\n container: '.artplayer-app',\n url: '/assets/sample/video.mp4',\n});",
|
||||
typescript ? "typescript" : "javascript"
|
||||
);
|
||||
resources.push(model);
|
||||
editor = api.editor.create(container, {
|
||||
theme: "vs-dark",
|
||||
folding: true,
|
||||
automaticLayout: true,
|
||||
quickSuggestions: { other: true, comments: true, strings: true },
|
||||
model
|
||||
});
|
||||
return {
|
||||
editor,
|
||||
async compile(source) {
|
||||
if (disposed)
|
||||
throw new Error("Editor was disposed");
|
||||
if (!typescript)
|
||||
return source;
|
||||
const model2 = api.editor.createModel(source, "typescript");
|
||||
temporary.add(model2);
|
||||
try {
|
||||
const worker = await (await types.getTypeScriptWorker())(model2.uri);
|
||||
const file = model2.uri.toString();
|
||||
const syntax = await worker.getSyntacticDiagnostics(file);
|
||||
if (syntax.length) {
|
||||
throw new Error(
|
||||
`TypeScript syntax error: ${syntax.map((item) => typeof item.messageText === "string" ? item.messageText : item.messageText.messageText).join("; ")}`
|
||||
);
|
||||
}
|
||||
const output = await worker.getEmitOutput(file);
|
||||
const script = output.outputFiles.find(
|
||||
(file2) => file2.name.endsWith(".js")
|
||||
);
|
||||
if (output.emitSkipped || !script)
|
||||
throw new Error("TypeScript worker did not emit JavaScript");
|
||||
return script.text;
|
||||
} finally {
|
||||
temporary.delete(model2);
|
||||
if (!model2.isDisposed())
|
||||
model2.dispose();
|
||||
}
|
||||
},
|
||||
dispose
|
||||
};
|
||||
} catch (error) {
|
||||
dispose();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function loadStyle(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const link = document.createElement('link')
|
||||
link.rel = 'stylesheet'
|
||||
link.href = url
|
||||
link.onload = () => resolve(url)
|
||||
link.onerror = () => reject(new Error(`Loading style failed: ${url}`))
|
||||
document.head.appendChild(link)
|
||||
})
|
||||
// packages/artplayer-vitepress/browser/editor-preferences.ts
|
||||
function readPreference(key, storage = () => localStorage) {
|
||||
try {
|
||||
return storage().getItem(key) === "true";
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function writePreference(key, value, storage = () => localStorage) {
|
||||
try {
|
||||
storage().setItem(key, value ? "true" : "false");
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function loadLib(libs) {
|
||||
const libPromises = []
|
||||
const libsDecoded = decodeURIComponent(libs || '')
|
||||
const urls = libsDecoded
|
||||
.split(/\r?\n/)
|
||||
.filter((url) => url.trim() && !loadedLibs.includes(url))
|
||||
|
||||
urls.forEach((url) => {
|
||||
const ext = getExt(url)
|
||||
if (ext === 'js') {
|
||||
libPromises.push(loadScript(url))
|
||||
} else if (ext === 'css') {
|
||||
libPromises.push(loadStyle(url))
|
||||
// packages/artplayer-vitepress/browser/editor-session.ts
|
||||
function createEditorSession(options) {
|
||||
let generation = 0;
|
||||
let disposed = false;
|
||||
return {
|
||||
async run({
|
||||
libs = "",
|
||||
code,
|
||||
example
|
||||
}) {
|
||||
const current = ++generation;
|
||||
const active = () => !disposed && current === generation;
|
||||
if (!active())
|
||||
return;
|
||||
await options.loadLibraries(libs);
|
||||
if (!active())
|
||||
return;
|
||||
const source = example ? await options.exampleSource(example) : code ? decodeURIComponent(code).trim() : await options.exampleSource("index");
|
||||
if (!active())
|
||||
return;
|
||||
options.writeCode(source);
|
||||
const executable = await options.compile(source);
|
||||
if (active())
|
||||
options.execute(executable);
|
||||
},
|
||||
dispose() {
|
||||
disposed = true;
|
||||
generation++;
|
||||
}
|
||||
})
|
||||
|
||||
$lib.value = libsDecoded
|
||||
return Promise.all(libPromises)
|
||||
};
|
||||
}
|
||||
function executeClassic(code) {
|
||||
new Function(code)();
|
||||
}
|
||||
|
||||
function runExample(name) {
|
||||
fetch(`./assets/example/${name}.js`)
|
||||
.then((response) => {
|
||||
return response.text()
|
||||
})
|
||||
.then((text) => {
|
||||
editor.setValue(text)
|
||||
runCode()
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
function loadCode(code, example) {
|
||||
if (example) {
|
||||
runExample(example)
|
||||
// packages/artplayer-vitepress/browser/editor.ts
|
||||
async function installEditor(host) {
|
||||
const document = host.document;
|
||||
const element = (selector) => {
|
||||
const node = document.querySelector(selector);
|
||||
if (!node)
|
||||
throw new Error(`Missing editor element: ${selector}`);
|
||||
return node;
|
||||
};
|
||||
host.Artplayer.DEBUG = true;
|
||||
if (host.Artplayer.utils.isMobile) {
|
||||
host.location.href = `./mobile.html${host.location.search}`;
|
||||
return;
|
||||
}
|
||||
else if (code) {
|
||||
editor.setValue(decodeURIComponent(code).trim())
|
||||
runCode()
|
||||
const run = element(".run");
|
||||
const libs = element(".libsInput");
|
||||
const file = element("#file");
|
||||
const popup = element(".popups");
|
||||
const output = element(".console");
|
||||
host.consoleLog(output);
|
||||
const controller = new AbortController();
|
||||
const cleanups = [];
|
||||
cleanups.push(() => {
|
||||
host.consoleLog.unmount?.(output);
|
||||
});
|
||||
const listen = (target, type, callback) => {
|
||||
target.addEventListener(type, callback);
|
||||
cleanups.push(() => target.removeEventListener(type, callback));
|
||||
};
|
||||
const report = (error) => {
|
||||
if (!controller.signal.aborted)
|
||||
host.console.error(error);
|
||||
};
|
||||
listen(host, "error", (event) => host.console.error(event));
|
||||
listen(host, "unhandledrejection", (event) => host.console.error(event));
|
||||
for (const key of ["prod", "ts", "code", "log"]) {
|
||||
const checkbox = element(`#${key}`);
|
||||
checkbox.checked = readPreference(key, () => host.localStorage);
|
||||
listen(checkbox, "change", () => {
|
||||
if (writePreference(key, checkbox.checked, () => host.localStorage)) {
|
||||
host.location.reload();
|
||||
} else {
|
||||
checkbox.checked = readPreference(key, () => host.localStorage);
|
||||
report(
|
||||
new Error("Browser storage is unavailable; preference was not saved")
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
runExample('index')
|
||||
}
|
||||
}
|
||||
|
||||
function runCode() {
|
||||
// Destroy all existing instances
|
||||
Artplayer.instances.forEach((art) => art.destroy(true))
|
||||
|
||||
const value = editor.getValue()
|
||||
eval(value)
|
||||
window.art = Artplayer.instances[0]
|
||||
}
|
||||
|
||||
function initApp() {
|
||||
const urlParams = getURLParameters(window.location.href)
|
||||
const { code, libs, example } = urlParams
|
||||
|
||||
loadLib(libs)
|
||||
.then((result) => {
|
||||
loadedLibs.push(...result)
|
||||
loadCode(code, example)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Failed to initialize app:', err)
|
||||
})
|
||||
}
|
||||
|
||||
function restart() {
|
||||
const libs = encodeURIComponent($lib.value)
|
||||
const code = encodeURIComponent(editor.getValue())
|
||||
const url = `${window.location.origin}${window.location.pathname}?libs=${libs}&code=${code}`
|
||||
history.pushState(null, null, url)
|
||||
initApp()
|
||||
}
|
||||
|
||||
function readFile(file) {
|
||||
return new Promise((resolve) => {
|
||||
const reader = new FileReader()
|
||||
reader.onload = () => resolve(reader.result)
|
||||
reader.readAsText(file)
|
||||
})
|
||||
}
|
||||
|
||||
$run.addEventListener('click', () => {
|
||||
restart()
|
||||
})
|
||||
|
||||
$popups.addEventListener('click', function (event) {
|
||||
if (event.target === this) {
|
||||
this.style.display = 'none'
|
||||
}
|
||||
})
|
||||
|
||||
$prod.addEventListener('change', () => {
|
||||
setStorageBoolean('prod', $prod.checked)
|
||||
window.location.reload()
|
||||
})
|
||||
|
||||
$ts.addEventListener('change', () => {
|
||||
setStorageBoolean('ts', $ts.checked)
|
||||
window.location.reload()
|
||||
})
|
||||
|
||||
$code.addEventListener('change', () => {
|
||||
setStorageBoolean('code', $code.checked)
|
||||
window.location.reload()
|
||||
})
|
||||
|
||||
$log.addEventListener('change', () => {
|
||||
setStorageBoolean('log', $log.checked)
|
||||
window.location.reload()
|
||||
})
|
||||
|
||||
$file.addEventListener('change', async () => {
|
||||
for (let index = 0; index < $file.files.length; index++) {
|
||||
const file = $file.files[index]
|
||||
const name = file.name.toLowerCase().trim()
|
||||
if (name.endsWith('.css')) {
|
||||
const text = await readFile(file)
|
||||
const $style = document.createElement('style')
|
||||
$style.textContent = text
|
||||
document.body.appendChild($style)
|
||||
$lib.value = `\n[${name}]`
|
||||
$lib.value = $lib.value.trim()
|
||||
if (element("#code").checked)
|
||||
element("#editor").style.display = "none";
|
||||
if (element("#log").checked)
|
||||
output.style.display = "none";
|
||||
const imports = createFileImports(document, (name) => {
|
||||
libs.value = `[${name}]`;
|
||||
});
|
||||
cleanups.push(() => imports.dispose());
|
||||
cleanups.push(() => {
|
||||
host.dispatchEvent(new Event("artplayer:example:cleanup"));
|
||||
for (const art of host.Artplayer.instances.slice()) {
|
||||
try {
|
||||
art.destroy(true);
|
||||
} catch (error) {
|
||||
host.console.error(error);
|
||||
}
|
||||
}
|
||||
if (name.endsWith('.js')) {
|
||||
const text = await readFile(file)
|
||||
const $script = document.createElement('script')
|
||||
$script.textContent = text
|
||||
document.body.appendChild($script)
|
||||
$lib.value = `\n[${name}]`
|
||||
$lib.value = $lib.value.trim()
|
||||
host.art = void 0;
|
||||
});
|
||||
listen(file, "change", () => {
|
||||
void imports.add(Array.from(file.files || [])).catch(report);
|
||||
});
|
||||
listen(popup, "click", (event) => {
|
||||
if (event.target === popup)
|
||||
popup.style.display = "none";
|
||||
});
|
||||
const onPageHide = (event) => {
|
||||
if (event.persisted)
|
||||
return;
|
||||
controller.abort();
|
||||
for (const cleanup of cleanups.reverse()) {
|
||||
try {
|
||||
cleanup();
|
||||
} catch (error) {
|
||||
host.console.error(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
host.addEventListener("pagehide", onPageHide);
|
||||
cleanups.push(() => host.removeEventListener("pagehide", onPageHide));
|
||||
run.setAttribute("aria-disabled", "true");
|
||||
try {
|
||||
let restart2 = function() {
|
||||
const code = encodeURIComponent(monaco.editor.getValue());
|
||||
const dependencies = encodeURIComponent(libs.value);
|
||||
host.history.pushState(
|
||||
null,
|
||||
"",
|
||||
`${host.location.origin}${host.location.pathname}?libs=${dependencies}&code=${code}`
|
||||
);
|
||||
void session.run({ libs: dependencies, code }).catch(report);
|
||||
};
|
||||
var restart = restart2;
|
||||
const monaco = await createMonaco(
|
||||
host,
|
||||
element(".codeMirrorWrap"),
|
||||
element("#ts").checked,
|
||||
controller.signal
|
||||
);
|
||||
const session = createEditorSession({
|
||||
loadLibraries: (encoded) => {
|
||||
libs.value = decodeURIComponent(encoded);
|
||||
return host.ArtplayerDocsLoader.loadLibraries(encoded);
|
||||
},
|
||||
exampleSource: (name) => host.ArtplayerDocsLoader.exampleSource(name),
|
||||
writeCode: (code) => monaco.editor.setValue(code),
|
||||
compile: monaco.compile,
|
||||
execute: (code) => {
|
||||
host.dispatchEvent(new Event("artplayer:example:cleanup"));
|
||||
for (const art of host.Artplayer.instances.slice()) art.destroy(true);
|
||||
executeClassic(code);
|
||||
host.art = host.Artplayer.instances[0];
|
||||
}
|
||||
});
|
||||
cleanups.push(() => session.dispose(), monaco.dispose);
|
||||
listen(run, "click", restart2);
|
||||
listen(document, "keydown", (event) => {
|
||||
const key = event;
|
||||
if ((key.ctrlKey || key.metaKey) && key.key === "s") {
|
||||
key.preventDefault();
|
||||
restart2();
|
||||
}
|
||||
});
|
||||
run.removeAttribute("aria-disabled");
|
||||
await session.run(host.ArtplayerDocsLoader.parameters(host.location.href));
|
||||
} catch (error) {
|
||||
report(error);
|
||||
}
|
||||
})
|
||||
|
||||
window.addEventListener('error', (err) => {
|
||||
console.error(err)
|
||||
})
|
||||
|
||||
window.addEventListener('unhandledrejection', (err) => {
|
||||
console.error(err)
|
||||
})
|
||||
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if ((event.ctrlKey || event.metaKey) && event.key === 's') {
|
||||
event.preventDefault()
|
||||
restart()
|
||||
}
|
||||
})
|
||||
})()
|
||||
}
|
||||
void installEditor(window).catch(
|
||||
(error) => console.error(error)
|
||||
);
|
||||
})();
|
||||
@@ -202,8 +202,47 @@ var t,e,n=module.exports={};function r(){throw new Error("setTimeout has not bee
|
||||
var process = require("process");
|
||||
var e=require("process");Object.defineProperty(exports,"__esModule",{value:!0}),exports.StyleSheetContext=exports.StyleSheetConsumer=exports.ServerStyleSheet=void 0,exports.StyleSheetManager=fe,exports.ThemeContext=exports.ThemeConsumer=void 0,exports.ThemeProvider=Fe,exports.__PRIVATE__=void 0,exports.createGlobalStyle=We,exports.css=we,exports.default=void 0,exports.isStyledComponent=S,exports.keyframes=$e,exports.withTheme=exports.version=exports.useTheme=void 0;var t=require("react-is"),r=c(require("react")),n=u(require("shallowequal")),o=u(require("@emotion/stylis")),i=u(require("@emotion/unitless")),s=u(require("@emotion/is-prop-valid")),a=u(require("hoist-non-react-statics"));function u(e){return e&&e.__esModule?e:{default:e}}function l(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,r=new WeakMap;return(l=function(e){return e?r:t})(e)}function c(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var r=l(t);if(r&&r.has(e))return r.get(e);var n={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if("default"!==i&&Object.prototype.hasOwnProperty.call(e,i)){var s=o?Object.getOwnPropertyDescriptor(e,i):null;s&&(s.get||s.set)?Object.defineProperty(n,i,s):n[i]=e[i]}return n.default=e,r&&r.set(e,n),n}function f(e){return(f="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function h(){return(h=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e}).apply(this,arguments)}var d=function(e,t){for(var r=[e[0]],n=0,o=t.length;n<o;n+=1)r.push(t[n],e[n+1]);return r},p=function(e){return null!==e&&"object"==f(e)&&"[object Object]"===(e.toString?e.toString():Object.prototype.toString.call(e))&&!(0,t.typeOf)(e)},v=Object.freeze([]),g=Object.freeze({});function m(e){return"function"==typeof e}function y(e){return e.displayName||e.name||"Component"}function S(e){return e&&"string"==typeof e.styledComponentId}var b="data-styled",w="5.3.3",x="undefined"!=typeof window&&"HTMLElement"in window,C=Boolean("boolean"==typeof SC_DISABLE_SPEEDY&&SC_DISABLE_SPEEDY),I={},A={};function P(){for(var e=arguments.length<=0?void 0:arguments[0],t=[],r=1,n=arguments.length;r<n;r+=1)t.push(r<0||arguments.length<=r?void 0:arguments[r]);return t.forEach(function(t){e=e.replace(/%[a-z]/,t)}),e}function j(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n<t;n++)r[n-1]=arguments[n];throw new Error("An error occurred. See https://git.io/JUIaE#"+e+" for more information."+(r.length>0?" Args: "+r.join(", "):""))}exports.version=w;var R=function(){function e(e){this.groupSizes=new Uint32Array(512),this.length=512,this.tag=e}var t=e.prototype;return t.indexOfGroup=function(e){for(var t=0,r=0;r<e;r++)t+=this.groupSizes[r];return t},t.insertRules=function(e,t){if(e>=this.groupSizes.length){for(var r=this.groupSizes,n=r.length,o=n;e>=o;)(o<<=1)<0&&j(16,""+e);this.groupSizes=new Uint32Array(o),this.groupSizes.set(r),this.length=o;for(var i=n;i<o;i++)this.groupSizes[i]=0}for(var s=this.indexOfGroup(e+1),a=0,u=t.length;a<u;a++)this.tag.insertRule(s,t[a])&&(this.groupSizes[e]++,s++)},t.clearGroup=function(e){if(e<this.length){var t=this.groupSizes[e],r=this.indexOfGroup(e),n=r+t;this.groupSizes[e]=0;for(var o=r;o<n;o++)this.tag.deleteRule(r)}},t.getGroup=function(e){var t="";if(e>=this.length||0===this.groupSizes[e])return t;for(var r=this.groupSizes[e],n=this.indexOfGroup(e),o=n+r,i=n;i<o;i++)t+=this.tag.getRule(i)+"/*!sc*/\n";return t},e}(),_=new Map,O=new Map,N=1,E=function(e){if(_.has(e))return _.get(e);for(;O.has(N);)N++;var t=N++;return _.set(e,t),O.set(t,e),t},T=function(e){return O.get(e)},k=function(e,t){t>=N&&(N=t+1),_.set(e,t),O.set(t,e)},M="style["+b+'][data-styled-version="5.3.3"]',z=new RegExp("^"+b+'\\.g(\\d+)\\[id="([\\w\\d-]+)"\\].*?"([^"]*)'),F=function(e,t,r){for(var n,o=r.split(","),i=0,s=o.length;i<s;i++)(n=o[i])&&e.registerName(t,n)},q=function(e,t){for(var r=(t.textContent||"").split("/*!sc*/\n"),n=[],o=0,i=r.length;o<i;o++){var s=r[o].trim();if(s){var a=s.match(z);if(a){var u=0|parseInt(a[1],10),l=a[2];0!==u&&(k(l,u),F(e,l,a[3]),e.getTag().insertRules(u,n)),n.length=0}else n.push(s)}}},G=function(){return"undefined"!=typeof window&&void 0!==window.__webpack_nonce__?window.__webpack_nonce__:null},B=function(e){var t=document.head,r=e||t,n=document.createElement("style"),o=function(e){for(var t=e.childNodes,r=t.length;r>=0;r--){var n=t[r];if(n&&1===n.nodeType&&n.hasAttribute(b))return n}}(r),i=void 0!==o?o.nextSibling:null;n.setAttribute(b,"active"),n.setAttribute("data-styled-version","5.3.3");var s=G();return s&&n.setAttribute("nonce",s),r.insertBefore(n,i),n},D=function(){function e(e){var t=this.element=B(e);t.appendChild(document.createTextNode("")),this.sheet=functionLine truncated
|
||||
},{"react-is":"H1RQ","react":"n8MK","shallowequal":"NKxe","@emotion/stylis":"uxSu","@emotion/unitless":"qy56","@emotion/is-prop-valid":"m5O0","hoist-non-react-statics":"LCQI","process":"KIG8"}],"W5CS":[function(require,module,exports) {
|
||||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var e,t=r(require("react")),n=require("console-feed"),o=r(require("styled-components"));function r(e){return e&&e.__esModule?e:{default:e}}function l(e){return(l="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e){return s(e)||u(e)||a(e)||c()}function c(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function a(e,t){if(e){if("string"==typeof e)return f(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?f(e,t):void 0}}function u(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}function s(e){if(Array.isArray(e))return f(e)}function f(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,o=new Array(t);n<t;n++)o[n]=e[n];return o}function d(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function p(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}function y(e,t,n){return t&&p(e.prototype,t),n&&p(e,n),e}function h(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&m(e,t)}function m(e,t){return(m=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}function v(e){var t=w();return function(){var n,o=E(e);if(t){var r=E(this).constructor;n=Reflect.construct(o,arguments,r)}else n=o.apply(this,arguments);return b(this,n)}}function b(e,t){if(t&&("object"===l(t)||"function"==typeof t))return t;if(void 0!==t)throw new TypeError("Derived constructors may only return object or undefined");return g(e)}function g(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function w(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}function E(e){return(E=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function O(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}var j=o.default.div(e||(e=O(["\n position: relative;\n height: 100%;\n display: flex;\n flex-direction: column;\n background-color: #242424;\n .console-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n color: #eee;\n padding: 7px 10px;\n font-size: 12px;\n background-color: #111;\n border-bottom: 1px solid rgb(255 255 255 / 10%);\n user-select: none;\n .console-header-left {\n display: flex;\n align-items: center;\n .console-header-number {\n margin-left: 5px;\n color: rgba(255, 255, 255, 0.4);\n }\n }\n .console-header-right {\n cursor: pointer;\n }\n }\n .console-component {\n scroll-behavior: smooth;\n position: relative;\n overflow: auto;\n height: 200px;\n flex: 1;\n }\n"]))),x=function(e){h(r,t.default.Component);var o=v(r);function r(e){var n;return d(this,r),(n=o.call(this,e)).scrollTimer=null,n.consoleRef=t.default.createRef(),n.onClear=n.onClear.bind(g(n)),n.onMouseEnter=n.onMouseEnter.bind(g(n)),n.onMouseLeave=n.onMouseLeave.bind(g(n)),n.state={logs:[],hover:!1},n}return y(r,[{key:"componentDidMount",value:function(){var e=this;(0,n.Hook)(window.console,function(t){return e.add(t)},!1)}},{key:"add",value:function(e){this.setState({logs:[].concat(i(this.state.logs),[e])});var t=this.consoleRef.current;!this.state.hover&&t&&(clearTimeout(this.scrollTimer),this.scrollTimer=setTimeout(function(){t.scrollTop=t.scrollHeight},200))}},{key:"onClear",value:function(){this.setState({logs:[]})}},{key:"onMouseEnter",value:function(){this.setState({hover:!0})}},{key:"onMouseLeave",value:function(){this.setState({hover:!1})}},{key:"componentWillUnmount",value:function(){(0,n.Unhook)(window.console)}},{key:"render",value:function(){return t.default.createElement(j,null,t.default.createElement("div",{className:"console-header"},t.default.createElement("div",{className:"console-header-left"},"Console"," ",t.default.createElement("span",{className:"console-header-number"},this.state.logs.length)),t.default.createElement("div",{className:"console-header-right",onClick:this.onClear},"Clear")),t.default.createLine truncated
|
||||
"use strict";"use strict";var __consoleOwned=(()=>{var v=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var O=(e,o)=>{for(var s in o)v(e,s,{get:o[s],enumerable:!0})},j=(e,o,s,i)=>{if(o&&typeof o=="object"||typeof o=="function")for(let n of E(o))!L.call(e,n)&&n!==s&&v(e,n,{get:()=>o[n],enumerable:!(i=C(o,n))||i.enumerable});return e};var P=e=>j(v({},"__esModule",{value:!0}),e);var D={};O(D,{createView:()=>N});var w=`
|
||||
position: relative;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #242424;
|
||||
.console-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
color: #eee;
|
||||
padding: 7px 10px;
|
||||
font-size: 12px;
|
||||
background-color: #111;
|
||||
border-bottom: 1px solid rgb(255 255 255 / 10%);
|
||||
user-select: none;
|
||||
.console-header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.console-header-number {
|
||||
margin-left: 5px;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
}
|
||||
.console-header-right {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.console-component {
|
||||
scroll-behavior: smooth;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
height: 200px;
|
||||
flex: 1;
|
||||
}
|
||||
`;function k(e){try{if(Object.prototype.toString.call(e)!=="[object Error]")return e;let o=e,s=o.stack,i=o.message;if(typeof s!="string"||!i)return e;let n=o.name?`${o.name}: ${i}`:i;return s.startsWith(n)?e:`${n}
|
||||
${s}`}catch(o){return e}}function x(e,o,s,i){let n;function p(l){for(let r of l.pending)i.clearTimeout(r);l.pending.clear();for(let r of l.saved)e[r.name]===r.wrapper&&(r.descriptor?Object.defineProperty(e,r.name,r.descriptor):delete e[r.name]);e.feed===l.feed&&(l.previousFeed?Object.defineProperty(e,"feed",l.previousFeed):delete e.feed)}return l=>{if(!n){let c={listeners:new Set,pending:new Set,saved:[],previousFeed:Object.getOwnPropertyDescriptor(e,"feed"),feed:{pointers:{},src:{npm:"https://npmjs.com/package/console-feed",github:"https://github.com/samdenty99/console-feed"}}};n=c;try{for(let t of o){let a=e[t],d=function(...u){Reflect.apply(a,this,u);let h=[...c.listeners];if(!h.length)return;let m=i.setTimeout(()=>{var T;c.pending.delete(m);let y=s(t,t==="error"?u.map(k):u);if(y){let g=!1,M;for(let b of h)try{(T=b.callback)==null||T.call(b,y)}catch(S){g?i.setTimeout(()=>{throw S},0):(g=!0,M=S)}if(g)throw M}},0);c.pending.add(m)};c.feed.pointers[t]=a,c.saved.push({name:t,descriptor:Object.getOwnPropertyDescriptor(e,t),wrapper:d}),e[t]=d}e.feed=c.feed}catch(t){throw p(c),n=void 0,t}}let r=n,f={callback:l};return r.listeners.add(f),()=>{f.callback=void 0,r.listeners.delete(f),!r.listeners.size&&n===r&&(n=void 0,p(r))}}}function N(e,o,s,i,n){let p=Object.freeze(Object.defineProperty([w],"raw",{value:Object.freeze([w])})),l=s.div(p),r=x(window.console,n,i,window);return class extends e.Component{constructor(t){super(t);this.scrollTimer=null;this.consoleRef=e.createRef();this.mounted=!1;this.onClear=this.onClear.bind(this),this.onMouseEnter=this.onMouseEnter.bind(this),this.onMouseLeave=this.onMouseLeave.bind(this),this.state={logs:[],hover:!1}}componentDidMount(){this.mounted=!0,this.unsubscribe=r(t=>this.add(t))}add(t){if(!this.mounted)return;this.setState(d=>({logs:[...d.logs,t]}));let a=this.consoleRef.current;!this.state.hover&&a&&(this.scrollTimer!==null&&window.clearTimeout(this.scrollTimer),this.scrollTimer=window.setTimeout(()=>{this.scrollTimer=null,this.mounted&&this.consoleRef.current===a&&(a.scrollTop=a.scrollHeight)},200))}onClear(){this.setState({logs:[]})}onMouseEnter(){this.setState({hover:!0})}onMouseLeave(){this.setState({hover:!1})}componentWillUnmount(){var t;this.mounted=!1,(t=this.unsubscribe)==null||t.call(this),this.unsubscribe=void 0,this.scrollTimer!==null&&window.clearTimeout(this.scrollTimer),this.scrollTimer=null}render(){let t=e.createElement("span",{className:"console-header-number"},this.state.logs.length),a=e.createElement("div",{className:"console-header-left"},"Console"," ",t),d=e.createElement("div",{className:"console-header-right",onClick:this.onClear},"Clear"),u=e.createElement("div",{className:"console-header"},a,d),h=e.createElement(o.Console,{logs:this.state.logs,variant:"dark"}),m=e.createElement("div",{ref:this.consoleRef,className:"console-component",onMouseEnter:this.onMouseEnter,onMouseLeave:this.onMouseLeave},h);return e.createElement(l,null,u,m)}}}return P(D);})();
|
||||
Object.defineProperty(exports,"__esModule",{value:true});exports.default=__consoleOwned.createView(require("react"),require("console-feed"),require("styled-components").default,require("RxPG").default,require("V2JG").default);
|
||||
},{"react":"n8MK","console-feed":"m6b6","styled-components":"tFSs"}],"Focm":[function(require,module,exports) {
|
||||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var e=u(require("react")),t=u(require("react-dom")),r=u(require("./Console"));function u(e){return e&&e.__esModule?e:{default:e}}var o=function(u){return t.default.render(e.default.createElement(r.default,null),u)};window.React=e.default,window.ReactDOM=t.default,window.consoleLog=o;var a=o;exports.default=a;
|
||||
"use strict";"use strict";var __consoleOwned=(()=>{var r=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var R=Object.prototype.hasOwnProperty;var l=(e,n)=>{for(var o in n)r(e,o,{get:n[o],enumerable:!0})},p=(e,n,o,m)=>{if(n&&typeof n=="object"||typeof n=="function")for(let t of c(n))!R.call(e,t)&&t!==o&&r(e,t,{get:()=>n[t],enumerable:!(m=i(n,t))||m.enumerable});return e};var s=e=>p(r({},"__esModule",{value:!0}),e);var d={};l(d,{install:()=>a});function a(e,n,o,m){let t=u=>n.render(e.createElement(o),u);return t.unmount=u=>n.unmountComponentAtNode(u),m.React=e,m.ReactDOM=n,m.consoleLog=t,t}return s(d);})();
|
||||
Object.defineProperty(exports,"__esModule",{value:true});exports.default=__consoleOwned.install(require("react"),require("react-dom"),require("./Console").default,window);
|
||||
},{"react":"n8MK","react-dom":"NKHc","./Console":"W5CS"}]},{},["Focm"], null)
|
||||
//# sourceMappingURL=/index.js.map
|
||||
|
||||
/*! customStringify: Alexander Mills, with credit to Rob W. CC BY-SA 4.0: https://creativecommons.org/licenses/by-sa/4.0/ . Source revision: https://api.stackexchange.com/2.3/revisions/8FD5F52A-B16F-4C66-AB48-830EABB36CC0?site=stackoverflow&filter=withbody . ES3 compilation and minification; notices and source: /licenses/console/stackoverflow/ATTRIBUTION.md . Other component notices: /THIRD_PARTY_NOTICES.md */
|
||||
@@ -0,0 +1,135 @@
|
||||
// Generated by yarn build:site-assets. Do not edit.
|
||||
"use strict";
|
||||
(() => {
|
||||
// packages/artplayer-vitepress/browser/loader.ts
|
||||
function parameters(url) {
|
||||
const result = {};
|
||||
for (const part of new URL(url).search.slice(1).split("&")) {
|
||||
const index = part.indexOf("=");
|
||||
if (index >= 0)
|
||||
result[part.slice(0, index)] = part.slice(index + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function suspendDefine(host) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(host, "define");
|
||||
if (descriptor?.configurable === false) {
|
||||
if (!("value" in descriptor) || !descriptor.writable)
|
||||
throw new Error("Cannot temporarily suspend the AMD loader");
|
||||
Object.defineProperty(host, "define", { value: void 0 });
|
||||
} else {
|
||||
Object.defineProperty(host, "define", { value: void 0, configurable: true, writable: true, enumerable: descriptor?.enumerable ?? true });
|
||||
}
|
||||
return () => {
|
||||
if (descriptor)
|
||||
Object.defineProperty(host, "define", descriptor);
|
||||
else Reflect.deleteProperty(host, "define");
|
||||
};
|
||||
}
|
||||
function createLibraryLoader(host = window) {
|
||||
const loaded = /* @__PURE__ */ new Set();
|
||||
let queue = Promise.resolve();
|
||||
let cancel;
|
||||
let disposed = false;
|
||||
const ensureActive = () => {
|
||||
if (disposed)
|
||||
throw new Error("Documentation loader was disposed");
|
||||
};
|
||||
function load(url, script) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const element = host.document.createElement(script ? "script" : "link");
|
||||
let restore;
|
||||
let settled = false;
|
||||
function finish(error) {
|
||||
if (settled)
|
||||
return;
|
||||
settled = true;
|
||||
element.removeEventListener("load", success);
|
||||
element.removeEventListener("error", failure);
|
||||
cancel = void 0;
|
||||
try {
|
||||
restore?.();
|
||||
} catch (cause) {
|
||||
error = new Error(`Failed to restore AMD loader: ${String(cause)}`);
|
||||
}
|
||||
if (error) {
|
||||
element.remove();
|
||||
reject(error);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
function success() {
|
||||
finish();
|
||||
}
|
||||
function failure() {
|
||||
finish(new Error(`Loading ${script ? "script" : "style"} failed: ${url}`));
|
||||
}
|
||||
element.addEventListener("load", success);
|
||||
element.addEventListener("error", failure);
|
||||
cancel = () => finish(new Error(`Cancelled documentation dependency: ${url}`));
|
||||
try {
|
||||
ensureActive();
|
||||
if (script) {
|
||||
restore = suspendDefine(host);
|
||||
const node = element;
|
||||
node.type = "text/javascript";
|
||||
node.src = url;
|
||||
node.async = false;
|
||||
} else {
|
||||
const node = element;
|
||||
node.rel = "stylesheet";
|
||||
node.href = url;
|
||||
}
|
||||
host.document.head.appendChild(element);
|
||||
} catch (cause) {
|
||||
finish(cause instanceof Error ? cause : new Error(String(cause)));
|
||||
}
|
||||
});
|
||||
}
|
||||
return {
|
||||
loadLibraries(encoded = "") {
|
||||
const work = queue.then(async () => {
|
||||
ensureActive();
|
||||
const urls = decodeURIComponent(encoded).split(/\r?\n/).map((url) => url.trim()).filter(Boolean);
|
||||
const result = [];
|
||||
for (const url of urls) {
|
||||
ensureActive();
|
||||
const absolute = new URL(url, host.location.href);
|
||||
const extension = absolute.pathname.toLowerCase().split(".").pop();
|
||||
if (extension !== "js" && extension !== "css")
|
||||
continue;
|
||||
if (!loaded.has(absolute.href)) {
|
||||
await load(absolute.href, extension === "js");
|
||||
loaded.add(absolute.href);
|
||||
}
|
||||
result.push(url);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
queue = work.catch(() => {
|
||||
});
|
||||
return work;
|
||||
},
|
||||
dispose() {
|
||||
disposed = true;
|
||||
cancel?.();
|
||||
loaded.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
async function exampleSource(name, request = fetch) {
|
||||
const response = await request(`./assets/example/${name}.js`);
|
||||
if (!response.ok)
|
||||
throw new Error(`Loading example failed: ${name} (${response.status})`);
|
||||
return response.text();
|
||||
}
|
||||
|
||||
// packages/artplayer-vitepress/browser/editor-loader.ts
|
||||
var loader = createLibraryLoader();
|
||||
Object.assign(window, { ArtplayerDocsLoader: { ...loader, exampleSource, parameters } });
|
||||
window.addEventListener("pagehide", (event) => {
|
||||
if (!event.persisted)
|
||||
loader.dispose();
|
||||
});
|
||||
})();
|
||||
+137
-95
@@ -1,100 +1,142 @@
|
||||
(function () {
|
||||
Artplayer.DEBUG = true;
|
||||
|
||||
function getURLParameters(url) {
|
||||
return (url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce(function (a, v) {
|
||||
return (a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1)), a;
|
||||
}, {});
|
||||
// Generated by yarn build:site-assets. Do not edit.
|
||||
"use strict";
|
||||
(() => {
|
||||
// packages/artplayer-vitepress/browser/loader.ts
|
||||
function parameters(url) {
|
||||
const result = {};
|
||||
for (const part of new URL(url).search.slice(1).split("&")) {
|
||||
const index = part.indexOf("=");
|
||||
if (index >= 0)
|
||||
result[part.slice(0, index)] = part.slice(index + 1);
|
||||
}
|
||||
|
||||
function getExt(url) {
|
||||
if (url.includes('?')) {
|
||||
return getExt(url.split('?')[0]);
|
||||
}
|
||||
|
||||
if (url.includes('#')) {
|
||||
return getExt(url.split('#')[0]);
|
||||
}
|
||||
|
||||
return url.trim().toLowerCase().split('.').pop();
|
||||
return result;
|
||||
}
|
||||
function suspendDefine(host) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(host, "define");
|
||||
if (descriptor?.configurable === false) {
|
||||
if (!("value" in descriptor) || !descriptor.writable)
|
||||
throw new Error("Cannot temporarily suspend the AMD loader");
|
||||
Object.defineProperty(host, "define", { value: void 0 });
|
||||
} else {
|
||||
Object.defineProperty(host, "define", { value: void 0, configurable: true, writable: true, enumerable: descriptor?.enumerable ?? true });
|
||||
}
|
||||
|
||||
function loadScript(url) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var define2 = window.define;
|
||||
window.define = undefined;
|
||||
var script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
script.src = url;
|
||||
script.onload = function () {
|
||||
window.define = define2;
|
||||
resolve(url);
|
||||
};
|
||||
script.onerror = function () {
|
||||
reject(new Error('Loading script failed:' + url));
|
||||
};
|
||||
document.querySelector('head').appendChild(script);
|
||||
return () => {
|
||||
if (descriptor)
|
||||
Object.defineProperty(host, "define", descriptor);
|
||||
else Reflect.deleteProperty(host, "define");
|
||||
};
|
||||
}
|
||||
function createLibraryLoader(host = window) {
|
||||
const loaded = /* @__PURE__ */ new Set();
|
||||
let queue = Promise.resolve();
|
||||
let cancel;
|
||||
let disposed = false;
|
||||
const ensureActive = () => {
|
||||
if (disposed)
|
||||
throw new Error("Documentation loader was disposed");
|
||||
};
|
||||
function load(url, script) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const element = host.document.createElement(script ? "script" : "link");
|
||||
let restore;
|
||||
let settled = false;
|
||||
function finish(error) {
|
||||
if (settled)
|
||||
return;
|
||||
settled = true;
|
||||
element.removeEventListener("load", success);
|
||||
element.removeEventListener("error", failure);
|
||||
cancel = void 0;
|
||||
try {
|
||||
restore?.();
|
||||
} catch (cause) {
|
||||
error = new Error(`Failed to restore AMD loader: ${String(cause)}`);
|
||||
}
|
||||
if (error) {
|
||||
element.remove();
|
||||
reject(error);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
function success() {
|
||||
finish();
|
||||
}
|
||||
function failure() {
|
||||
finish(new Error(`Loading ${script ? "script" : "style"} failed: ${url}`));
|
||||
}
|
||||
element.addEventListener("load", success);
|
||||
element.addEventListener("error", failure);
|
||||
cancel = () => finish(new Error(`Cancelled documentation dependency: ${url}`));
|
||||
try {
|
||||
ensureActive();
|
||||
if (script) {
|
||||
restore = suspendDefine(host);
|
||||
const node = element;
|
||||
node.type = "text/javascript";
|
||||
node.src = url;
|
||||
node.async = false;
|
||||
} else {
|
||||
const node = element;
|
||||
node.rel = "stylesheet";
|
||||
node.href = url;
|
||||
}
|
||||
host.document.head.appendChild(element);
|
||||
} catch (cause) {
|
||||
finish(cause instanceof Error ? cause : new Error(String(cause)));
|
||||
}
|
||||
});
|
||||
}
|
||||
return {
|
||||
loadLibraries(encoded = "") {
|
||||
const work = queue.then(async () => {
|
||||
ensureActive();
|
||||
const urls = decodeURIComponent(encoded).split(/\r?\n/).map((url) => url.trim()).filter(Boolean);
|
||||
const result = [];
|
||||
for (const url of urls) {
|
||||
ensureActive();
|
||||
const absolute = new URL(url, host.location.href);
|
||||
const extension = absolute.pathname.toLowerCase().split(".").pop();
|
||||
if (extension !== "js" && extension !== "css")
|
||||
continue;
|
||||
if (!loaded.has(absolute.href)) {
|
||||
await load(absolute.href, extension === "js");
|
||||
loaded.add(absolute.href);
|
||||
}
|
||||
result.push(url);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
function loadStyle(url) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.href = url;
|
||||
link.onload = function () {
|
||||
resolve(url);
|
||||
};
|
||||
link.onerror = function () {
|
||||
reject(new Error('Loading style failed:' + url));
|
||||
};
|
||||
document.querySelector('head').appendChild(link);
|
||||
queue = work.catch(() => {
|
||||
});
|
||||
}
|
||||
return work;
|
||||
},
|
||||
dispose() {
|
||||
disposed = true;
|
||||
cancel?.();
|
||||
loaded.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
async function exampleSource(name, request = fetch) {
|
||||
const response = await request(`./assets/example/${name}.js`);
|
||||
if (!response.ok)
|
||||
throw new Error(`Loading example failed: ${name} (${response.status})`);
|
||||
return response.text();
|
||||
}
|
||||
|
||||
function loadLib(libs) {
|
||||
var libPromise = [];
|
||||
var libsDecode = decodeURIComponent(libs || '');
|
||||
libsDecode
|
||||
.split(/\r?\n/)
|
||||
.forEach(function (url) {
|
||||
var ext = getExt(url);
|
||||
if (ext === 'js') {
|
||||
libPromise.push(loadScript(url));
|
||||
} else if (ext === 'css') {
|
||||
libPromise.push(loadStyle(url));
|
||||
}
|
||||
});
|
||||
return Promise.all(libPromise);
|
||||
}
|
||||
|
||||
function runExample(name) {
|
||||
fetch('./assets/example/' + name + '.js')
|
||||
.then(function (response) {
|
||||
return response.text();
|
||||
})
|
||||
.then(function (text) {
|
||||
eval(text);
|
||||
})
|
||||
}
|
||||
|
||||
function loadCode(code, example) {
|
||||
if (example) {
|
||||
runExample(example);
|
||||
} else if (code) {
|
||||
eval(decodeURIComponent(code).trim());
|
||||
} else {
|
||||
runExample('mobile');
|
||||
}
|
||||
}
|
||||
|
||||
var _getURLParameters = getURLParameters(window.location.href),
|
||||
code = _getURLParameters.code,
|
||||
libs = _getURLParameters.libs;
|
||||
example = _getURLParameters.example;
|
||||
|
||||
loadLib(libs)
|
||||
.then(function () {
|
||||
loadCode(code, example);
|
||||
})
|
||||
})();
|
||||
// packages/artplayer-vitepress/browser/mobile.ts
|
||||
window.Artplayer.DEBUG = true;
|
||||
var loader = createLibraryLoader();
|
||||
window.addEventListener("pagehide", (event) => {
|
||||
if (!event.persisted)
|
||||
loader.dispose();
|
||||
});
|
||||
async function start() {
|
||||
const { code, libs, example } = parameters(location.href);
|
||||
await loader.loadLibraries(libs);
|
||||
const source = example ? await exampleSource(example) : code ? decodeURIComponent(code).trim() : await exampleSource("mobile");
|
||||
new Function(source)();
|
||||
}
|
||||
start().catch((error) => console.error("Failed to initialize mobile example:", error));
|
||||
})();
|
||||
Vendored
+1
-1
@@ -7,4 +7,4 @@
|
||||
* http://opensource.org/licenses/MIT
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define("VConsole",[],n):"object"==typeof exports?exports.VConsole=n():t.VConsole=n()}(this||self,(function(){return function(){var __webpack_modules__={4264:function(t,n,e){t.exports=e(7588)},5036:function(t,n,e){e(1719),e(5677),e(6394),e(5334),e(6969),e(2021),e(8328),e(2129);var o=e(1287);t.exports=o.Promise},2582:function(t,n,e){e(1646),e(6394),e(2004),e(462),e(8407),e(2429),e(1172),e(8288),e(1274),e(8201),e(6626),e(3211),e(9952),e(15),e(9831),e(7521),e(2972),e(6956),e(5222),e(2257);var o=e(1287);t.exports=o.Symbol},8257:function(t,n,e){var o=e(7583),r=e(9212),i=e(5637),a=o.TypeError;t.exports=function(t){if(r(t))return t;throw a(i(t)+" is not a function")}},1186:function(t,n,e){var o=e(7583),r=e(2097),i=e(5637),a=o.TypeError;t.exports=function(t){if(r(t))return t;throw a(i(t)+" is not a constructor")}},9882:function(t,n,e){var o=e(7583),r=e(9212),i=o.String,a=o.TypeError;t.exports=function(t){if("object"==typeof t||r(t))return t;throw a("Can't set "+i(t)+" as a prototype")}},6288:function(t,n,e){var o=e(3649),r=e(3590),i=e(4615),a=o("unscopables"),c=Array.prototype;null==c[a]&&i.f(c,a,{configurable:!0,value:r(null)}),t.exports=function(t){c[a][t]=!0}},4761:function(t,n,e){var o=e(7583),r=e(2447),i=o.TypeError;t.exports=function(t,n){if(r(n,t))return t;throw i("Incorrect invocation")}},2569:function(t,n,e){var o=e(7583),r=e(794),i=o.String,a=o.TypeError;t.exports=function(t){if(r(t))return t;throw a(i(t)+" is not an object")}},5766:function(t,n,e){var o=e(2977),r=e(6782),i=e(1825),a=function(t){return function(n,e,a){var c,u=o(n),s=i(u),l=r(a,s);if(t&&e!=e){for(;s>l;)if((c=u[l++])!=c)return!0}else for(;s>l;l++)if((t||l in u)&&u[l]===e)return t||l||0;return!t&&-1}};t.exports={includes:a(!0),indexOf:a(!1)}},4805:function(t,n,e){var o=e(2938),r=e(7386),i=e(5044),a=e(1324),c=e(1825),u=e(4822),s=r([].push),l=function(t){var n=1==t,e=2==t,r=3==t,l=4==t,f=6==t,d=7==t,v=5==t||f;return function(h,p,g,m){for(var _,b,y=a(h),w=i(y),E=o(p,g),L=c(w),T=0,x=m||u,C=n?x(h,L):e||d?x(h,0):void 0;L>T;T++)if((v||T in w)&&(b=E(_=w[T],T,y),t))if(n)C[T]=b;else if(b)switch(t){case 3:return!0;case 5:return _;case 6:return T;case 2:s(C,_)}else switch(t){case 4:return!1;case 7:s(C,_)}return f?-1:r||l?l:C}};t.exports={forEach:l(0),map:l(1),filter:l(2),some:l(3),every:l(4),find:l(5),findIndex:l(6),filterReject:l(7)}},9269:function(t,n,e){var o=e(6544),r=e(3649),i=e(4061),a=r("species");t.exports=function(t){return i>=51||!o((function(){var n=[];return(n.constructor={})[a]=function(){return{foo:1}},1!==n[t](Boolean).foo}))}},4546:function(t,n,e){var o=e(7583),r=e(6782),i=e(1825),a=e(5999),c=o.Array,u=Math.max;t.exports=function(t,n,e){for(var o=i(t),s=r(n,o),l=r(void 0===e?o:e,o),f=c(u(l-s,0)),d=0;s<l;s++,d++)a(f,d,t[s]);return f.length=d,f}},6917:function(t,n,e){var o=e(7386);t.exports=o([].slice)},5289:function(t,n,e){var o=e(7583),r=e(4521),i=e(2097),a=e(794),c=e(3649)("species"),u=o.Array;t.exports=function(t){var n;return r(t)&&(n=t.constructor,(i(n)&&(n===u||r(n.prototype))||a(n)&&null===(n=n[c]))&&(n=void 0)),void 0===n?u:n}},4822:function(t,n,e){var o=e(5289);t.exports=function(t,n){return new(o(t))(0===n?0:n)}},3616:function(t,n,e){var o=e(3649)("iterator"),r=!1;try{var i=0,a={next:function(){return{done:!!i++}},return:function(){r=!0}};a[o]=function(){return this},Array.from(a,(function(){throw 2}))}catch(t){}t.exports=function(t,n){if(!n&&!r)return!1;var e=!1;try{var i={};i[o]=function(){return{next:function(){return{done:e=!0}}}},t(i)}catch(t){}return e}},9624:function(t,n,e){var o=e(7386),r=o({}.toString),i=o("".slice);t.exports=function(t){return i(r(t),8,-1)}},3058:function(t,n,e){var o=e(7583),r=e(8191),i=e(9212),a=e(9624),c=e(3649)("toStringTag"),u=o.Object,s="Arguments"==a(function(){return arguments}());t.exports=r?a:function(t){var n,e,o;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(e=function(t,n){try{return t[n]}catch(t){}}(n=u(t),c))?e:s?a(n):"Object"==(o=a(n))&&i(n.callee)?"Arguments":o}},1509:function(t,n,e){var o=e(7386)("".replace),r=String(Error("zxcasd").stack),i=/\n\s*at [^:]*:[^\n]*/,a=i.test(r);t.exports=function(t,n){if(a&&"string"==typeof t)for(;n--;)t=o(t,i,"");return t}},3478:function(t,n,e){var o=e(2870),r=e(929),i=e(6683),a=e(4615);t.exports=function(t,n,e){for(var c=r(n),u=a.f,s=i.f,l=0;l<c.length;l++){var f=c[l];o(t,f)||e&&o(e,f)||u(t,f,s(n,f))}}},926:function(t,n,e){var o=e(6544);t.exports=!o((function(){function t(){}return t.prototype.constructor=null,Object.getPrototypeOf(new t)!==t.prototype}))},4683:function(t,n,e){"use strict";var o=e(2365).IteratorPrototype,r=e(3590),i=e(4677),a=e(8821),c=e(339),u=function(){return this};t.exports=function(t,n,e,s){var l=n+" Iterator";return t.prototype=r(o,{next:i(+!s,e)}),a(t,l,!1,!0),c[l]=u,t}},57:function(t,n,e){var o=e(8494),r=e(4615),i=e(4677);t.exports=o?function(t,n,e){return r.f(t,n,i(1,e))}:function(t,n,e){reLine truncated
|
||||
!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define("VConsole",[],n):"object"==typeof exports?exports.VConsole=n():t.VConsole=n()}(this||self,(function(){var __artplayerVConsoleLogLifecycle=(function(){var o=Object.defineProperty;var t=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var p=Object.prototype.hasOwnProperty;var s=function(e,n){for(var u in n)o(e,u,{get:n[u],enumerable:!0})},L=function(e,n,u,i){if(n&&typeof n=="object"||typeof n=="function")for(var r=g(n),a=0,c=r.length,l;a<c;a++)l=r[a],!p.call(e,l)&&l!==u&&o(e,l,{get:function(d){return n[d]}.bind(null,l),enumerable:!(i=t(n,l))||i.enumerable});return e};var m=function(e){return L(o({},"__esModule",{value:!0}),e)};var D={};s(D,{enqueue:function(){return v},renderTab:function(){return h},unbind:function(){return A}});var f=[];function h(e,n,u){setTimeout(function(){e.isInited&&e.pluginList[n.id]===n&&u()},0)}function v(e,n,u){if(e.ADDED_LOG_PLUGIN_ID.length!==0){if(!e.flushLogScheduled){var i={host:e,id:0};f.push(i),e.flushLogScheduled=!0,i.id=u.requestAnimationFrame(function(){var r=f.indexOf(i);r!==-1&&(f.splice(r,1),e.flushLogScheduled=!1,e._flushLogs())})}e.logQueue.push(n)}}function A(e,n){for(var u,i=0;i<f.length;i++)if(f[i].host===e){u=f[i],f.splice(i,1);break}e.logQueue=[],e.flushLogScheduled=!1;try{u&&typeof n.cancelAnimationFrame=="function"&&n.cancelAnimationFrame(u.id)}finally{e.unmockConsole()}}return m(D);})();return function(){var __webpack_modules__={4264:function(t,n,e){t.exports=e(7588)},5036:function(t,n,e){e(1719),e(5677),e(6394),e(5334),e(6969),e(2021),e(8328),e(2129);var o=e(1287);t.exports=o.Promise},2582:function(t,n,e){e(1646),e(6394),e(2004),e(462),e(8407),e(2429),e(1172),e(8288),e(1274),e(8201),e(6626),e(3211),e(9952),e(15),e(9831),e(7521),e(2972),e(6956),e(5222),e(2257);var o=e(1287);t.exports=o.Symbol},8257:function(t,n,e){var o=e(7583),r=e(9212),i=e(5637),a=o.TypeError;t.exports=function(t){if(r(t))return t;throw a(i(t)+" is not a function")}},1186:function(t,n,e){var o=e(7583),r=e(2097),i=e(5637),a=o.TypeError;t.exports=function(t){if(r(t))return t;throw a(i(t)+" is not a constructor")}},9882:function(t,n,e){var o=e(7583),r=e(9212),i=o.String,a=o.TypeError;t.exports=function(t){if("object"==typeof t||r(t))return t;throw a("Can't set "+i(t)+" as a prototype")}},6288:function(t,n,e){var o=e(3649),r=e(3590),i=e(4615),a=o("unscopables"),c=Array.prototype;null==c[a]&&i.f(c,a,{configurable:!0,value:r(null)}),t.exports=function(t){c[a][t]=!0}},4761:function(t,n,e){var o=e(7583),r=e(2447),i=o.TypeError;t.exports=function(t,n){if(r(n,t))return t;throw i("Incorrect invocation")}},2569:function(t,n,e){var o=e(7583),r=e(794),i=o.String,a=o.TypeError;t.exports=function(t){if(r(t))return t;throw a(i(t)+" is not an object")}},5766:function(t,n,e){var o=e(2977),r=e(6782),i=e(1825),a=function(t){return function(n,e,a){var c,u=o(n),s=i(u),l=r(a,s);if(t&&e!=e){for(;s>l;)if((c=u[l++])!=c)return!0}else for(;s>l;l++)if((t||l in u)&&u[l]===e)return t||l||0;return!t&&-1}};t.exports={includes:a(!0),indexOf:a(!1)}},4805:function(t,n,e){var o=e(2938),r=e(7386),i=e(5044),a=e(1324),c=e(1825),u=e(4822),s=r([].push),l=function(t){var n=1==t,e=2==t,r=3==t,l=4==t,f=6==t,d=7==t,v=5==t||f;return function(h,p,g,m){for(var _,b,y=a(h),w=i(y),E=o(p,g),L=c(w),T=0,x=m||u,C=n?x(h,L):e||d?x(h,0):void 0;L>T;T++)if((v||T in w)&&(b=E(_=w[T],T,y),t))if(n)C[T]=b;else if(b)switch(t){case 3:return!0;case 5:return _;case 6:return T;case 2:s(C,_)}else switch(t){case 4:return!1;case 7:s(C,_)}return f?-1:r||l?l:C}};t.exports={forEach:l(0),map:l(1),filter:l(2),some:l(3),every:l(4),find:l(5),findIndex:l(6),filterReject:l(7)}},9269:function(t,n,e){var o=e(6544),r=e(3649),i=e(4061),a=r("species");t.exports=function(t){return i>=51||!o((function(){var n=[];return(n.constructor={})[a]=function(){return{foo:1}},1!==n[t](Boolean).foo}))}},4546:function(t,n,e){var o=e(7583),r=e(6782),i=e(1825),a=e(5999),c=o.Array,u=Math.max;t.exports=function(t,n,e){for(var o=i(t),s=r(n,o),l=r(void 0===e?o:e,o),f=c(u(l-s,0)),d=0;s<l;s++,d++)a(f,d,t[s]);return f.length=d,f}},6917:function(t,n,e){var o=e(7386);t.exports=o([].slice)},5289:function(t,n,e){var o=e(7583),r=e(4521),i=e(2097),a=e(794),c=e(3649)("species"),u=o.Array;t.exports=function(t){var n;return r(t)&&(n=t.constructor,(i(n)&&(n===u||r(n.prototype))||a(n)&&null===(n=n[c]))&&(n=void 0)),void 0===n?u:n}},4822:function(t,n,e){var o=e(5289);t.exports=function(t,n){return new(o(t))(0===n?0:n)}},3616:function(t,n,e){var o=e(3649)("iterator"),r=!1;try{var i=0,a={next:function(){return{done:!!i++}},return:function(){r=!0}};a[o]=function(){return this},Array.from(a,(function(){throw 2}))}catch(t){}t.exports=function(t,n){if(!n&&!r)return!1;var e=!1;try{var i={};i[o]=function(){return{next:function(){return{done:e=!0}}}},t(i)}catch(t){}return e}},9624:function(t,n,e){var o=e(7386),r=o({}.toString),i=o("".slice);t.exports=function(t){return i(r(t),8,-Line truncated
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
declare module 'artplayer/i18n/*' {
|
||||
const language: NonNullable<Artplayer.I18n['en']>
|
||||
export default language
|
||||
}
|
||||
+75
-49
@@ -1,52 +1,78 @@
|
||||
interface Option {
|
||||
/**
|
||||
* 广告源文本,支持视频链接、图片链接、HTML文本
|
||||
*/
|
||||
source: string
|
||||
|
||||
/**
|
||||
* 知名广告的类型:'video' | 'image' | 'html'
|
||||
*/
|
||||
type: 'video' | 'image' | 'html'
|
||||
|
||||
/**
|
||||
* 广告必看的时长,单位为秒
|
||||
*/
|
||||
playDuration?: number
|
||||
|
||||
/**
|
||||
* 广告总的时长,单位为秒
|
||||
*/
|
||||
totalDuration?: number
|
||||
|
||||
/**
|
||||
* 视频广告是否默认静音
|
||||
*/
|
||||
muted?: boolean
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerPluginAds {
|
||||
interface Translations {
|
||||
close: string
|
||||
countdown: string
|
||||
detail: string
|
||||
canBeClosed: string
|
||||
}
|
||||
/** Implemented options. Video takes precedence over HTML. */
|
||||
interface Option {
|
||||
html?: string
|
||||
video?: string
|
||||
url?: string
|
||||
/** Seconds before the close button becomes available. @default 5 */
|
||||
playDuration?: number
|
||||
/** Total advertisement duration in seconds. @default 10 */
|
||||
totalDuration?: number
|
||||
/** Initial ad-video mute state. @default false */
|
||||
muted?: boolean
|
||||
/** All four fields replace the default translation object together. */
|
||||
i18n?: Translations
|
||||
}
|
||||
/** Historical published declaration. String durations still fail runtime validation. */
|
||||
interface LegacyOption extends Omit<Option, 'totalDuration'> {
|
||||
/** @deprecated Incorrect in the old declaration; use a numeric duration. */
|
||||
totalDuration?: string
|
||||
}
|
||||
/** Historical unpublished workspace declaration; these fields are not runtime aliases. */
|
||||
interface WorkspaceOption extends Option {
|
||||
/** @deprecated Ignored by the runtime. Use html or video instead. */
|
||||
source: string
|
||||
/** @deprecated Ignored by the runtime. Images are supplied through html. */
|
||||
type: 'video' | 'image' | 'html'
|
||||
}
|
||||
/** Input acceptance for both historical declaration families. */
|
||||
interface CompatOption extends Omit<Option, 'totalDuration'> {
|
||||
/** @deprecated The string branch exists for old types only and is rejected at runtime. */
|
||||
totalDuration?: number | string
|
||||
/** @deprecated Ignored by the runtime. Use html or video instead. */
|
||||
source?: string
|
||||
/** @deprecated Ignored by the runtime. Images are supplied through html. */
|
||||
type?: 'video' | 'image' | 'html'
|
||||
}
|
||||
interface Result {
|
||||
name: 'artplayerPluginAds'
|
||||
/** Complete once; before initialization this cancels the pending preroll. */
|
||||
skip: () => void
|
||||
/** Pause only the countdown, leaving ad video playback unchanged. */
|
||||
pause: () => void
|
||||
/** Resume only the countdown without adding extra timers. */
|
||||
play: () => void
|
||||
}
|
||||
interface Callable {
|
||||
(option?: Option): (art: Artplayer) => Result
|
||||
/** @deprecated Compatibility with erroneous old string-duration declarations only. */
|
||||
(option: LegacyOption): (art: Artplayer) => Result
|
||||
(option: WorkspaceOption): (art: Artplayer) => Result
|
||||
(option?: CompatOption): (art: Artplayer) => Result
|
||||
/** Required final signature keeps Parameters extraction free of top-level undefined. */
|
||||
(option: CompatOption): (art: Artplayer) => Result
|
||||
}
|
||||
interface Factory extends Callable {
|
||||
/** Same function; supports historical require(package).default calls. */
|
||||
readonly default: Callable
|
||||
}
|
||||
interface RuntimeCallable {
|
||||
(option?: Option): (art: Artplayer) => Result
|
||||
(option: Option): (art: Artplayer) => Result
|
||||
}
|
||||
/** Accurate typing for the identical implementation at /runtime. */
|
||||
interface RuntimeFactory extends RuntimeCallable {
|
||||
readonly default: RuntimeCallable
|
||||
}
|
||||
}
|
||||
|
||||
interface Ads {
|
||||
name: 'artplayerPluginAds'
|
||||
|
||||
/**
|
||||
* 跳过广告
|
||||
*/
|
||||
skip: () => void
|
||||
|
||||
/**
|
||||
* 暂停广告
|
||||
*/
|
||||
pause: () => void
|
||||
|
||||
/**
|
||||
* 播放广告
|
||||
*/
|
||||
play: () => void
|
||||
}
|
||||
|
||||
declare const artplayerPluginAds: (option: Option) => (art: Artplayer) => Ads
|
||||
|
||||
export default artplayerPluginAds
|
||||
|
||||
declare const artplayerPluginAds: artplayerPluginAds.Factory
|
||||
export = artplayerPluginAds
|
||||
export as namespace artplayerPluginAds;
|
||||
+38
-16
@@ -1,20 +1,42 @@
|
||||
interface Option {
|
||||
blur?: string
|
||||
opacity?: number
|
||||
frequency?: number
|
||||
zIndex?: number
|
||||
duration?: number
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerPluginAmbilightDefinitions {
|
||||
export interface Option {
|
||||
/** CSS blur radius. @default '50px' */
|
||||
blur?: string
|
||||
/** Grid cell opacity. @default 0.5 */
|
||||
opacity?: number
|
||||
/** Maximum sampling frequency in frames per second. @default 10 */
|
||||
frequency?: number
|
||||
/** Historical input retained for compatibility; runtime uses a fixed z-index of 9. */
|
||||
zIndex?: number
|
||||
/** Background color transition duration in seconds. @default 0.3 */
|
||||
duration?: number
|
||||
}
|
||||
export interface Result {
|
||||
name: 'artplayerPluginAmbilight'
|
||||
/** Start sampling; does nothing after the player is destroyed. */
|
||||
start: () => void
|
||||
/** Stop sampling while retaining the last colors. */
|
||||
stop: () => void
|
||||
}
|
||||
/** Published 1.1.0 factory shape; the options argument remains required. */
|
||||
export type Callable = (option: Option) => (art: Artplayer) => Result
|
||||
export type Factory = Callable
|
||||
/** Accurate optional invocation and CommonJS self alias, exposed by /runtime. */
|
||||
export interface RuntimeFactory {
|
||||
(option?: Option): (art: Artplayer) => Result
|
||||
readonly default: RuntimeFactory
|
||||
}
|
||||
export const artplayerPluginAmbilight: (option: Option) => (art: Artplayer) => Result
|
||||
}
|
||||
|
||||
interface Result {
|
||||
name: 'artplayerPluginAmbilight'
|
||||
start: () => void
|
||||
stop: () => void
|
||||
declare const artplayerPluginAmbilight: typeof artplayerPluginAmbilightDefinitions.artplayerPluginAmbilight
|
||||
declare namespace artplayerPluginAmbilight {
|
||||
export type Option = artplayerPluginAmbilightDefinitions.Option
|
||||
export type Result = artplayerPluginAmbilightDefinitions.Result
|
||||
export type Callable = artplayerPluginAmbilightDefinitions.Callable
|
||||
export type Factory = artplayerPluginAmbilightDefinitions.Factory
|
||||
export type RuntimeFactory = artplayerPluginAmbilightDefinitions.RuntimeFactory
|
||||
}
|
||||
|
||||
declare const artplayerPluginAmbilight: (option: Option) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginAmbilight
|
||||
|
||||
export = artplayerPluginAmbilight
|
||||
export as namespace artplayerPluginAmbilight;
|
||||
+47
-22
@@ -1,26 +1,51 @@
|
||||
interface AudioChunk {
|
||||
pcm: ArrayBuffer
|
||||
wav: ArrayBuffer
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerPluginAsrDefinitions {
|
||||
export interface AudioChunk {
|
||||
pcm: ArrayBuffer
|
||||
wav: ArrayBuffer
|
||||
}
|
||||
export interface AsrPluginOption {
|
||||
length?: number
|
||||
interval?: number
|
||||
sampleRate?: number
|
||||
autoHideTimeout?: number
|
||||
onAudioChunk?: (chunk: AudioChunk) => void | Promise<void>
|
||||
}
|
||||
export interface AsrPluginInstance {
|
||||
name: 'artplayerPluginAsr'
|
||||
stop: () => void
|
||||
hide: () => void
|
||||
append: (subtitle: string) => void
|
||||
}
|
||||
/** Historical factory shape, including void stop and callback results. */
|
||||
export type Factory = (option?: AsrPluginOption) => (art: Artplayer) => AsrPluginInstance
|
||||
/** Accurate asynchronous view available through the /runtime entry. */
|
||||
export interface RuntimeOption extends Omit<AsrPluginOption, 'onAudioChunk'> {
|
||||
/** Capture the media stream without taking ownership of its playback route. */
|
||||
audioInput?: {
|
||||
type: 'capture'
|
||||
}
|
||||
onAudioChunk?: (chunk: AudioChunk) => string | void | null | Promise<string | void | null>
|
||||
}
|
||||
export interface RuntimeResult extends Omit<AsrPluginInstance, 'stop'> {
|
||||
stop: () => Promise<void>
|
||||
}
|
||||
export interface RuntimeFactory {
|
||||
(option?: RuntimeOption): (art: Artplayer) => RuntimeResult
|
||||
readonly default: RuntimeFactory
|
||||
}
|
||||
export function artplayerPluginAsr(option?: AsrPluginOption): (art: Artplayer) => AsrPluginInstance
|
||||
}
|
||||
|
||||
interface AsrPluginOption {
|
||||
length?: number
|
||||
interval?: number
|
||||
sampleRate?: number
|
||||
autoHideTimeout?: number
|
||||
onAudioChunk?: (chunk: AudioChunk) => void | Promise<void>
|
||||
declare const artplayerPluginAsr: typeof artplayerPluginAsrDefinitions.artplayerPluginAsr
|
||||
declare namespace artplayerPluginAsr {
|
||||
export type AudioChunk = artplayerPluginAsrDefinitions.AudioChunk
|
||||
export type AsrPluginOption = artplayerPluginAsrDefinitions.AsrPluginOption
|
||||
export type AsrPluginInstance = artplayerPluginAsrDefinitions.AsrPluginInstance
|
||||
export type Factory = artplayerPluginAsrDefinitions.Factory
|
||||
export type RuntimeOption = artplayerPluginAsrDefinitions.RuntimeOption
|
||||
export type RuntimeResult = artplayerPluginAsrDefinitions.RuntimeResult
|
||||
export type RuntimeFactory = artplayerPluginAsrDefinitions.RuntimeFactory
|
||||
}
|
||||
|
||||
interface AsrPluginInstance {
|
||||
name: 'artplayerPluginAsr'
|
||||
stop: () => void
|
||||
hide: () => void
|
||||
append: (subtitle: string) => void
|
||||
}
|
||||
|
||||
declare function artplayerPluginAsr(option?: AsrPluginOption): (art: Artplayer) => AsrPluginInstance
|
||||
|
||||
export default artplayerPluginAsr
|
||||
|
||||
export = artplayerPluginAsr
|
||||
export as namespace artplayerPluginAsr;
|
||||
+48
-36
@@ -1,40 +1,52 @@
|
||||
interface Option {
|
||||
/**
|
||||
* Audio track URL
|
||||
*/
|
||||
url: string
|
||||
|
||||
/**
|
||||
* Time offset in seconds between video and audio
|
||||
* Positive value means audio plays ahead of video
|
||||
* Negative value means audio plays behind video
|
||||
* @default 0
|
||||
*/
|
||||
offset?: number
|
||||
|
||||
/**
|
||||
* Synchronization threshold in seconds
|
||||
* @default 0.3
|
||||
*/
|
||||
sync?: number
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerPluginAudioTrackDefinitions {
|
||||
export interface Option {
|
||||
/**
|
||||
* Audio track URL
|
||||
*/
|
||||
url: string
|
||||
/**
|
||||
* Time offset in seconds between video and audio
|
||||
* Positive value means audio plays ahead of video
|
||||
* Negative value means audio plays behind video
|
||||
* @default 0
|
||||
*/
|
||||
offset?: number
|
||||
/**
|
||||
* Synchronization threshold in seconds
|
||||
* @default 0.3
|
||||
*/
|
||||
sync?: number
|
||||
}
|
||||
export type UpdateOption = Partial<Option>
|
||||
export interface Result {
|
||||
name: 'artplayerPluginAudioTrack'
|
||||
/**
|
||||
* The audio element
|
||||
*/
|
||||
audio: HTMLAudioElement
|
||||
/**
|
||||
* Historical update signature. Runtime also accepts partial options.
|
||||
* Import the /runtime entry for the precise partial-update signature.
|
||||
*/
|
||||
update: (option: Option) => void
|
||||
}
|
||||
export interface RuntimeResult extends Result {
|
||||
/** Update selected fields without replacing the audio element. */
|
||||
update: (option: UpdateOption) => void
|
||||
}
|
||||
/** Precise typing for the same runtime factory, without changing legacy inference. */
|
||||
export type RuntimeFactory = (option: Option) => (art: Artplayer) => RuntimeResult
|
||||
export function artplayerPluginAudioTrack(option: Option): (art: Artplayer) => Result
|
||||
}
|
||||
|
||||
interface Result {
|
||||
name: 'artplayerPluginAudioTrack'
|
||||
/**
|
||||
* The audio element
|
||||
*/
|
||||
audio: HTMLAudioElement
|
||||
|
||||
/**
|
||||
* Update option
|
||||
*/
|
||||
update: (option: Option) => void
|
||||
declare const artplayerPluginAudioTrack: typeof artplayerPluginAudioTrackDefinitions.artplayerPluginAudioTrack
|
||||
declare namespace artplayerPluginAudioTrack {
|
||||
export type Option = artplayerPluginAudioTrackDefinitions.Option
|
||||
export type UpdateOption = artplayerPluginAudioTrackDefinitions.UpdateOption
|
||||
export type Result = artplayerPluginAudioTrackDefinitions.Result
|
||||
export type RuntimeResult = artplayerPluginAudioTrackDefinitions.RuntimeResult
|
||||
export type RuntimeFactory = artplayerPluginAudioTrackDefinitions.RuntimeFactory
|
||||
}
|
||||
|
||||
declare const artplayerPluginAudioTrack: (option: Option) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginAudioTrack
|
||||
|
||||
export = artplayerPluginAudioTrack
|
||||
export as namespace artplayerPluginAudioTrack;
|
||||
+15
-14
@@ -1,17 +1,18 @@
|
||||
interface Option {
|
||||
url?: string
|
||||
width?: number
|
||||
number?: number
|
||||
scale?: number
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerPluginAutoThumbnailDefinitions {
|
||||
export interface Option {
|
||||
url?: string
|
||||
width?: number
|
||||
number?: number
|
||||
scale?: number
|
||||
}
|
||||
export interface Result {
|
||||
name: 'artplayerPluginAutoThumbnail'
|
||||
}
|
||||
export const artplayerPluginAutoThumbnail: (option: Option) => (art: Artplayer) => Result
|
||||
}
|
||||
|
||||
interface Result {
|
||||
name: 'artplayerPluginAutoThumbnail'
|
||||
}
|
||||
|
||||
declare const artplayerPluginAutoThumbnail: (option: Option) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginAutoThumbnail
|
||||
|
||||
declare const artplayerPluginAutoThumbnail: typeof artplayerPluginAutoThumbnailDefinitions.artplayerPluginAutoThumbnail
|
||||
declare namespace artplayerPluginAutoThumbnail { }
|
||||
export = artplayerPluginAutoThumbnail
|
||||
export as namespace artplayerPluginAutoThumbnail;
|
||||
+21
-17
@@ -1,21 +1,25 @@
|
||||
type Chapters = {
|
||||
start: number
|
||||
end: number
|
||||
title: string
|
||||
}[]
|
||||
|
||||
interface Option {
|
||||
chapters?: Chapters
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerPluginChapterDefinitions {
|
||||
export type Chapters = {
|
||||
start: number
|
||||
end: number
|
||||
title: string
|
||||
}[]
|
||||
export interface Option {
|
||||
chapters?: Chapters
|
||||
}
|
||||
export interface Result {
|
||||
name: 'artplayerPluginChapter'
|
||||
update: (option: Option) => void
|
||||
}
|
||||
export const artplayerPluginChapter: (option?: Option) => (art: Artplayer) => Result
|
||||
}
|
||||
|
||||
interface Result {
|
||||
name: 'artplayerPluginChapter'
|
||||
update: (option: Option) => void
|
||||
declare const artplayerPluginChapter: typeof artplayerPluginChapterDefinitions.artplayerPluginChapter
|
||||
declare namespace artplayerPluginChapter {
|
||||
export type Chapters = artplayerPluginChapterDefinitions.Chapters
|
||||
export type Option = artplayerPluginChapterDefinitions.Option
|
||||
export type Result = artplayerPluginChapterDefinitions.Result
|
||||
}
|
||||
|
||||
declare const artplayerPluginChapter: (option: Option) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginChapter
|
||||
|
||||
export = artplayerPluginChapter
|
||||
export as namespace artplayerPluginChapter;
|
||||
+43
-13
@@ -1,17 +1,47 @@
|
||||
interface Option {
|
||||
url?: string
|
||||
sdk?: string
|
||||
icon?: string
|
||||
mimeType?: string
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerPluginChromecastDefinitions {
|
||||
export interface Option {
|
||||
url?: string
|
||||
sdk?: string
|
||||
icon?: string
|
||||
mimeType?: string
|
||||
}
|
||||
export interface Chromecast {
|
||||
name: 'artplayerPluginChromecast'
|
||||
}
|
||||
/** Published 1.1.0 result; actual registration is asynchronous. */
|
||||
export type Result = Chromecast
|
||||
export type Factory = (option: Option) => (art: Artplayer) => Chromecast
|
||||
export type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'disconnecting'
|
||||
export interface RuntimeOption extends Option {
|
||||
onStateChange?: (this: RuntimeOption, state: ConnectionState) => void
|
||||
onCastAvailable?: (this: RuntimeOption, available: boolean) => void
|
||||
onCastStart?: (this: RuntimeOption) => void
|
||||
onError?: (this: RuntimeOption, error: unknown) => void
|
||||
}
|
||||
export interface RuntimeResult extends Chromecast {
|
||||
/** Last raw SDK SessionState, initially null; not the normalized callback state. */
|
||||
getCastState: () => string | null
|
||||
/** Whether this controller retains a session; does not prove receiver playback. */
|
||||
isCasting: () => boolean
|
||||
}
|
||||
export interface RuntimeFactory {
|
||||
(option: RuntimeOption): (art: Artplayer) => Promise<RuntimeResult>
|
||||
default: RuntimeFactory
|
||||
}
|
||||
export const artplayerPluginChromecast: (option: Option) => (art: Artplayer) => Chromecast
|
||||
}
|
||||
|
||||
interface Chromecast {
|
||||
name: 'artplayerPluginChromecast'
|
||||
declare const artplayerPluginChromecast: typeof artplayerPluginChromecastDefinitions.artplayerPluginChromecast
|
||||
declare namespace artplayerPluginChromecast {
|
||||
export type Option = artplayerPluginChromecastDefinitions.Option
|
||||
export type Chromecast = artplayerPluginChromecastDefinitions.Chromecast
|
||||
export type Result = artplayerPluginChromecastDefinitions.Result
|
||||
export type Factory = artplayerPluginChromecastDefinitions.Factory
|
||||
export type ConnectionState = artplayerPluginChromecastDefinitions.ConnectionState
|
||||
export type RuntimeOption = artplayerPluginChromecastDefinitions.RuntimeOption
|
||||
export type RuntimeResult = artplayerPluginChromecastDefinitions.RuntimeResult
|
||||
export type RuntimeFactory = artplayerPluginChromecastDefinitions.RuntimeFactory
|
||||
}
|
||||
|
||||
declare const artplayerPluginChromecast: (option: Option) => (art: Artplayer) => Chromecast
|
||||
|
||||
export default artplayerPluginChromecast
|
||||
|
||||
export = artplayerPluginChromecast
|
||||
export as namespace artplayerPluginChromecast;
|
||||
+23
-22
@@ -1,25 +1,26 @@
|
||||
interface Option {
|
||||
solutionPath?: string
|
||||
modelSelection?: number
|
||||
smoothSegmentation?: boolean
|
||||
minDetectionConfidence?: number
|
||||
minTrackingConfidence?: number
|
||||
selfieMode?: boolean
|
||||
drawContour?: boolean
|
||||
foregroundThreshold?: number
|
||||
opacity?: number
|
||||
maskBlurAmount?: number
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerPluginDanmukuMaskDefinitions {
|
||||
export interface Option {
|
||||
solutionPath?: string
|
||||
modelSelection?: number
|
||||
smoothSegmentation?: boolean
|
||||
minDetectionConfidence?: number
|
||||
minTrackingConfidence?: number
|
||||
selfieMode?: boolean
|
||||
drawContour?: boolean
|
||||
foregroundThreshold?: number
|
||||
opacity?: number
|
||||
maskBlurAmount?: number
|
||||
}
|
||||
export interface Result {
|
||||
name: 'artplayerPluginDanmukuMask'
|
||||
start: () => Promise<void>
|
||||
stop: () => void
|
||||
}
|
||||
export const artplayerPluginDanmukuMask: (option?: Option) => (art: Artplayer) => Result
|
||||
}
|
||||
|
||||
interface Result {
|
||||
name: 'artplayerPluginDanmukuMask'
|
||||
start: () => Promise<void>
|
||||
stop: () => void
|
||||
}
|
||||
|
||||
declare const artplayerPluginDanmukuMask: (option?: Option) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginDanmukuMask
|
||||
|
||||
declare const artplayerPluginDanmukuMask: typeof artplayerPluginDanmukuMaskDefinitions.artplayerPluginDanmukuMask
|
||||
declare namespace artplayerPluginDanmukuMask { }
|
||||
export = artplayerPluginDanmukuMask
|
||||
export as namespace artplayerPluginDanmukuMask;
|
||||
+209
-244
@@ -1,114 +1,96 @@
|
||||
export type Mode = 0 | 1 | 2
|
||||
export type Danmuku
|
||||
= | Danmu[]
|
||||
| string // URL
|
||||
| (() => Promise<Danmu[]>)
|
||||
| Promise<Danmu[]>
|
||||
|
||||
export interface Slider {
|
||||
min?: number
|
||||
max?: number
|
||||
steps?: {
|
||||
name?: string
|
||||
value?: number | string
|
||||
show?: boolean
|
||||
}[]
|
||||
}
|
||||
|
||||
export interface Danmu {
|
||||
/**
|
||||
* 弹幕文本
|
||||
*/
|
||||
text: string
|
||||
|
||||
/**
|
||||
* 弹幕发送模式: 0: 滚动,1: 顶部,2: 底部
|
||||
*/
|
||||
mode?: Mode
|
||||
|
||||
/**
|
||||
* 弹幕颜色
|
||||
*/
|
||||
color?: string
|
||||
|
||||
/**
|
||||
* 弹幕出现的时间,单位为秒
|
||||
*/
|
||||
time?: number
|
||||
|
||||
/**
|
||||
* 弹幕是否有描边, 默认为 false
|
||||
*/
|
||||
border?: boolean
|
||||
|
||||
/**
|
||||
* 弹幕自定义样式
|
||||
*/
|
||||
style?: Partial<CSSStyleDeclaration>
|
||||
}
|
||||
|
||||
export interface Option {
|
||||
/**
|
||||
* 弹幕数据: 函数,数组,Promise,URL
|
||||
*/
|
||||
danmuku: Danmuku
|
||||
|
||||
/**
|
||||
* 弹幕持续时间,范围在[1 ~ 10]
|
||||
*/
|
||||
speed?: number
|
||||
|
||||
/**
|
||||
* 弹幕上下边距,支持像素数字和百分比
|
||||
*/
|
||||
margin?: [number | `${number}%`, number | `${number}%`]
|
||||
|
||||
/**
|
||||
* 弹幕透明度,范围在[0 ~ 1]
|
||||
*/
|
||||
opacity?: number
|
||||
|
||||
/**
|
||||
* 默认弹幕颜色,可以被单独弹幕项覆盖
|
||||
*/
|
||||
color?: string
|
||||
|
||||
/**
|
||||
* 弹幕模式: 0: 滚动,1: 顶部,2: 底部
|
||||
*/
|
||||
mode?: Mode
|
||||
|
||||
/**
|
||||
* 弹幕可见的模式
|
||||
*/
|
||||
modes?: Mode[]
|
||||
|
||||
/**
|
||||
* 弹幕字体大小,支持像素数字和百分比
|
||||
*/
|
||||
fontSize?: number | `${number}%`
|
||||
|
||||
/**
|
||||
* 弹幕是否防重叠
|
||||
*/
|
||||
antiOverlap?: boolean
|
||||
|
||||
/**
|
||||
* 是否同步播放速度
|
||||
*/
|
||||
synchronousPlayback?: boolean
|
||||
|
||||
/**
|
||||
* 弹幕发射器挂载点, 默认为播放器控制栏中部
|
||||
*/
|
||||
mount?: HTMLDivElement | string
|
||||
|
||||
/**
|
||||
* 是否开启弹幕热度图
|
||||
*/
|
||||
heatmap?:
|
||||
| boolean
|
||||
| {
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerPluginDanmukuDefinitions {
|
||||
export type Mode = 0 | 1 | 2
|
||||
export type Danmuku = Danmu[] | string // URL
|
||||
| (() => Promise<Danmu[]>) | Promise<Danmu[]>
|
||||
export interface Slider {
|
||||
min?: number
|
||||
max?: number
|
||||
steps?: {
|
||||
name?: string
|
||||
value?: number | string
|
||||
show?: boolean
|
||||
}[]
|
||||
}
|
||||
export interface Danmu {
|
||||
/**
|
||||
* 弹幕文本
|
||||
*/
|
||||
text: string
|
||||
/**
|
||||
* 弹幕发送模式: 0: 滚动,1: 顶部,2: 底部
|
||||
*/
|
||||
mode?: Mode
|
||||
/**
|
||||
* 弹幕颜色
|
||||
*/
|
||||
color?: string
|
||||
/**
|
||||
* 弹幕出现的时间,单位为秒
|
||||
*/
|
||||
time?: number
|
||||
/**
|
||||
* 弹幕是否有描边, 默认为 false
|
||||
*/
|
||||
border?: boolean
|
||||
/**
|
||||
* 弹幕自定义样式
|
||||
*/
|
||||
style?: Partial<CSSStyleDeclaration>
|
||||
}
|
||||
export interface Option {
|
||||
/**
|
||||
* 弹幕数据: 函数,数组,Promise,URL
|
||||
*/
|
||||
danmuku: Danmuku
|
||||
/**
|
||||
* 弹幕持续时间,范围在[1 ~ 10]
|
||||
*/
|
||||
speed?: number
|
||||
/**
|
||||
* 弹幕上下边距,支持像素数字和百分比
|
||||
*/
|
||||
margin?: [
|
||||
number | `${number}%`,
|
||||
number | `${number}%`,
|
||||
]
|
||||
/**
|
||||
* 弹幕透明度,范围在[0 ~ 1]
|
||||
*/
|
||||
opacity?: number
|
||||
/**
|
||||
* 默认弹幕颜色,可以被单独弹幕项覆盖
|
||||
*/
|
||||
color?: string
|
||||
/**
|
||||
* 弹幕模式: 0: 滚动,1: 顶部,2: 底部
|
||||
*/
|
||||
mode?: Mode
|
||||
/**
|
||||
* 弹幕可见的模式
|
||||
*/
|
||||
modes?: Mode[]
|
||||
/**
|
||||
* 弹幕字体大小,支持像素数字和百分比
|
||||
*/
|
||||
fontSize?: number | `${number}%`
|
||||
/**
|
||||
* 弹幕是否防重叠
|
||||
*/
|
||||
antiOverlap?: boolean
|
||||
/**
|
||||
* 是否同步播放速度
|
||||
*/
|
||||
synchronousPlayback?: boolean
|
||||
/**
|
||||
* 弹幕发射器挂载点, 默认为播放器控制栏中部
|
||||
*/
|
||||
mount?: HTMLDivElement | string
|
||||
/**
|
||||
* 是否开启弹幕热度图
|
||||
*/
|
||||
heatmap?: boolean | {
|
||||
xMin?: number
|
||||
xMax?: number
|
||||
yMin?: number
|
||||
@@ -120,140 +102,123 @@ export interface Option {
|
||||
smoothing?: number
|
||||
flattening?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 当播放器宽度小于此值时,弹幕发射器置于播放器底部
|
||||
*/
|
||||
width?: number
|
||||
|
||||
/**
|
||||
* 热力图数据
|
||||
*/
|
||||
points?: { time: number, value: number }[]
|
||||
|
||||
/**
|
||||
* 弹幕载入前的过滤器,只支持返回布尔值
|
||||
*/
|
||||
filter?: (danmu: Danmu) => boolean
|
||||
|
||||
/**
|
||||
* 弹幕发送前的过滤器,支持返回 Promise
|
||||
*/
|
||||
beforeEmit?: (danmu: Danmu) => boolean | Promise<boolean>
|
||||
|
||||
/**
|
||||
* 弹幕显示前的过滤器,支持返回 Promise
|
||||
*/
|
||||
beforeVisible?: (danmu: Danmu) => boolean | Promise<boolean>
|
||||
|
||||
/**
|
||||
* 弹幕是否可见
|
||||
*/
|
||||
visible?: boolean
|
||||
|
||||
/**
|
||||
* 是否开启弹幕发射器
|
||||
*/
|
||||
emitter?: boolean
|
||||
|
||||
/**
|
||||
* 弹幕输入框最大长度, 范围在[1 ~ 1000]
|
||||
*/
|
||||
maxLength?: number
|
||||
|
||||
/**
|
||||
* 输入框锁定时间,范围在[1 ~ 60]
|
||||
*/
|
||||
lockTime?: number
|
||||
|
||||
/**
|
||||
* 弹幕主题,只在自定义挂载时生效
|
||||
*/
|
||||
theme?: 'light' | 'dark'
|
||||
|
||||
/**
|
||||
* 不透明度配置项
|
||||
*/
|
||||
OPACITY?: Slider
|
||||
|
||||
/**
|
||||
* 弹幕速度配置项
|
||||
*/
|
||||
SPEED?: Slider
|
||||
|
||||
/**
|
||||
* 显示区域配置项
|
||||
*/
|
||||
MARGIN?: Slider
|
||||
|
||||
/**
|
||||
* 弹幕字号配置项
|
||||
*/
|
||||
FONT_SIZE?: Slider
|
||||
|
||||
/**
|
||||
* 颜色列表配置项
|
||||
*/
|
||||
COLOR?: string[]
|
||||
/**
|
||||
* 当播放器宽度小于此值时,弹幕发射器置于播放器底部
|
||||
*/
|
||||
width?: number
|
||||
/**
|
||||
* 热力图数据
|
||||
*/
|
||||
points?: {
|
||||
time: number
|
||||
value: number
|
||||
}[]
|
||||
/**
|
||||
* 弹幕载入前的过滤器,只支持返回布尔值
|
||||
*/
|
||||
filter?: (danmu: Danmu) => boolean
|
||||
/**
|
||||
* 弹幕发送前的过滤器,支持返回 Promise
|
||||
*/
|
||||
beforeEmit?: (danmu: Danmu) => boolean | Promise<boolean>
|
||||
/**
|
||||
* 弹幕显示前的过滤器,支持返回 Promise
|
||||
*/
|
||||
beforeVisible?: (danmu: Danmu) => boolean | Promise<boolean>
|
||||
/**
|
||||
* 弹幕是否可见
|
||||
*/
|
||||
visible?: boolean
|
||||
/**
|
||||
* 是否开启弹幕发射器
|
||||
*/
|
||||
emitter?: boolean
|
||||
/**
|
||||
* 弹幕输入框最大长度, 范围在[1 ~ 1000]
|
||||
*/
|
||||
maxLength?: number
|
||||
/**
|
||||
* 输入框锁定时间,范围在[1 ~ 60]
|
||||
*/
|
||||
lockTime?: number
|
||||
/**
|
||||
* 弹幕主题,只在自定义挂载时生效
|
||||
*/
|
||||
theme?: 'light' | 'dark'
|
||||
/**
|
||||
* 不透明度配置项
|
||||
*/
|
||||
OPACITY?: Slider
|
||||
/**
|
||||
* 弹幕速度配置项
|
||||
*/
|
||||
SPEED?: Slider
|
||||
/**
|
||||
* 显示区域配置项
|
||||
*/
|
||||
MARGIN?: Slider
|
||||
/**
|
||||
* 弹幕字号配置项
|
||||
*/
|
||||
FONT_SIZE?: Slider
|
||||
/**
|
||||
* 颜色列表配置项
|
||||
*/
|
||||
COLOR?: string[]
|
||||
}
|
||||
export interface Result {
|
||||
name: 'artplayerPluginDanmuku'
|
||||
/**
|
||||
* 发送一条实时弹幕
|
||||
*/
|
||||
emit: (danmu: Danmu) => Result
|
||||
/**
|
||||
* 重载弹幕源,或者切换新弹幕
|
||||
*/
|
||||
load: (danmuku?: Danmuku) => Promise<Result>
|
||||
/**
|
||||
* 实时改变弹幕配置
|
||||
*/
|
||||
config: (option: Option) => Result
|
||||
/**
|
||||
* 隐藏弹幕层
|
||||
*/
|
||||
hide: () => Result
|
||||
/**
|
||||
* 显示弹幕层
|
||||
*/
|
||||
show: () => Result
|
||||
/**
|
||||
* 挂载弹幕输入框
|
||||
*/
|
||||
mount: (el?: HTMLDivElement | string) => void
|
||||
/**
|
||||
* 重置弹幕
|
||||
*/
|
||||
reset: () => Result
|
||||
/**
|
||||
* 弹幕配置
|
||||
*/
|
||||
option: Option
|
||||
/**
|
||||
* 是否隐藏弹幕层
|
||||
*/
|
||||
isHide: boolean
|
||||
/**
|
||||
* 是否弹幕层停止状态
|
||||
*/
|
||||
isStop: boolean
|
||||
}
|
||||
export const artplayerPluginDanmuku: (option: Option) => (art: Artplayer) => Result
|
||||
}
|
||||
|
||||
export interface Result {
|
||||
name: 'artplayerPluginDanmuku'
|
||||
|
||||
/**
|
||||
* 发送一条实时弹幕
|
||||
*/
|
||||
emit: (danmu: Danmu) => Result
|
||||
|
||||
/**
|
||||
* 重载弹幕源,或者切换新弹幕
|
||||
*/
|
||||
load: (danmuku?: Danmuku) => Promise<Result>
|
||||
|
||||
/**
|
||||
* 实时改变弹幕配置
|
||||
*/
|
||||
config: (option: Option) => Result
|
||||
|
||||
/**
|
||||
* 隐藏弹幕层
|
||||
*/
|
||||
hide: () => Result
|
||||
|
||||
/**
|
||||
* 显示弹幕层
|
||||
*/
|
||||
show: () => Result
|
||||
|
||||
/**
|
||||
* 挂载弹幕输入框
|
||||
*/
|
||||
mount: (el?: HTMLDivElement | string) => void
|
||||
|
||||
/**
|
||||
* 重置弹幕
|
||||
*/
|
||||
reset: () => Result
|
||||
|
||||
/**
|
||||
* 弹幕配置
|
||||
*/
|
||||
option: Option
|
||||
|
||||
/**
|
||||
* 是否隐藏弹幕层
|
||||
*/
|
||||
isHide: boolean
|
||||
|
||||
/**
|
||||
* 是否弹幕层停止状态
|
||||
*/
|
||||
isStop: boolean
|
||||
declare const artplayerPluginDanmuku: typeof artplayerPluginDanmukuDefinitions.artplayerPluginDanmuku
|
||||
declare namespace artplayerPluginDanmuku {
|
||||
export type Mode = artplayerPluginDanmukuDefinitions.Mode
|
||||
export type Danmuku = artplayerPluginDanmukuDefinitions.Danmuku
|
||||
export type Slider = artplayerPluginDanmukuDefinitions.Slider
|
||||
export type Danmu = artplayerPluginDanmukuDefinitions.Danmu
|
||||
export type Option = artplayerPluginDanmukuDefinitions.Option
|
||||
export type Result = artplayerPluginDanmukuDefinitions.Result
|
||||
}
|
||||
|
||||
declare const artplayerPluginDanmuku: (option: Option) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginDanmuku
|
||||
|
||||
export = artplayerPluginDanmuku
|
||||
export as namespace artplayerPluginDanmuku;
|
||||
+42
-13
@@ -1,17 +1,46 @@
|
||||
interface Config {
|
||||
control?: boolean
|
||||
setting?: boolean
|
||||
title?: string
|
||||
auto?: string
|
||||
getName?: (level: object) => string
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerPluginDashControlDefinitions {
|
||||
export interface QualityLevel {
|
||||
height: number
|
||||
width?: number
|
||||
id?: string | number
|
||||
qualityIndex?: number
|
||||
bitrate?: number
|
||||
bitrateInKbit?: number
|
||||
}
|
||||
export interface AudioTrack {
|
||||
id?: string | number | null
|
||||
index?: number | null
|
||||
lang?: string | null
|
||||
}
|
||||
export interface Config<Item extends object = object> {
|
||||
control?: boolean
|
||||
setting?: boolean
|
||||
title?: string
|
||||
auto?: string
|
||||
/** Called without a receiver or index, with the original SDK object. */
|
||||
getName?: (item: Item) => string
|
||||
}
|
||||
export interface Option<Level extends object = QualityLevel, Track extends object = AudioTrack> {
|
||||
quality?: Config<Level>
|
||||
audio?: Config<Track>
|
||||
}
|
||||
export interface Result {
|
||||
name: 'artplayerPluginDashControl'
|
||||
update: () => void
|
||||
}
|
||||
export function artplayerPluginDashControl<Level extends object = QualityLevel, Track extends object = AudioTrack>(option?: Option<Level, Track>): (art: Artplayer) => Result
|
||||
// Preserve the required last signature for historical Parameters<typeof factory>[0] consumers.
|
||||
export function artplayerPluginDashControl<Level extends object = QualityLevel, Track extends object = AudioTrack>(option: Option<Level, Track>): (art: Artplayer) => Result
|
||||
}
|
||||
|
||||
declare const artplayerPluginDashControl: (option: { quality?: Config, audio?: Config }) => (art: Artplayer) => {
|
||||
name: 'artplayerPluginDashControl'
|
||||
update: () => void
|
||||
declare const artplayerPluginDashControl: typeof artplayerPluginDashControlDefinitions.artplayerPluginDashControl
|
||||
declare namespace artplayerPluginDashControl {
|
||||
export type QualityLevel = artplayerPluginDashControlDefinitions.QualityLevel
|
||||
export type AudioTrack = artplayerPluginDashControlDefinitions.AudioTrack
|
||||
export type Config<Item extends object = object> = artplayerPluginDashControlDefinitions.Config<Item>
|
||||
export type Option<Level extends object = QualityLevel, Track extends object = AudioTrack> = artplayerPluginDashControlDefinitions.Option<Level, Track>
|
||||
export type Result = artplayerPluginDashControlDefinitions.Result
|
||||
}
|
||||
|
||||
export default artplayerPluginDashControl
|
||||
|
||||
export = artplayerPluginDashControl
|
||||
export as namespace artplayerPluginDashControl;
|
||||
+49
-18
@@ -1,22 +1,53 @@
|
||||
interface Option {
|
||||
width?: number
|
||||
height?: number
|
||||
placeholder?: string
|
||||
fallbackToVideoPiP?: boolean
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerPluginDocumentPipDefinitions {
|
||||
export interface Option {
|
||||
/** Requested window width. @default 480 */
|
||||
width?: number
|
||||
/** Requested window height. @default 270 */
|
||||
height?: number
|
||||
/** Text displayed in the original player container while the window is active. */
|
||||
placeholder?: string
|
||||
/** Use the core video PiP property when Document PiP is unavailable. @default true */
|
||||
fallbackToVideoPiP?: boolean
|
||||
}
|
||||
/** Historical assignable result; preserved for direct and extracted return types. */
|
||||
export interface Result {
|
||||
name: 'artplayerPluginDocumentPip'
|
||||
/** Runtime is a readonly capability snapshot; the published field stays assignable. */
|
||||
isSupported: boolean
|
||||
/** Runtime is a readonly live getter; the published field stays assignable. */
|
||||
isActive: boolean
|
||||
/** Runtime returns Promise<void>; the published void action remains assignable here. */
|
||||
open: () => void
|
||||
/** Runtime returns Promise<void>; the published void action remains assignable here. */
|
||||
close: () => void
|
||||
toggle: () => void
|
||||
}
|
||||
/** Exact view of an unmodified runtime result. */
|
||||
export interface AsyncResult extends Omit<Result, 'isSupported' | 'isActive' | 'open' | 'close'> {
|
||||
readonly isSupported: boolean
|
||||
readonly isActive: boolean
|
||||
open: () => Promise<void>
|
||||
close: () => Promise<void>
|
||||
}
|
||||
/** Exact published factory signature, including compatibility with replacement functions. */
|
||||
export type Factory = (option: Option) => (art: Artplayer) => Result
|
||||
/** Opt-in runtime view with omitted options, self default and precise async actions. */
|
||||
export interface RuntimeFactory {
|
||||
(option?: Option): (art: Artplayer) => AsyncResult
|
||||
readonly default: RuntimeFactory
|
||||
}
|
||||
/** Keep the published callable type; use RuntimeFactory explicitly for its broader runtime shape. */
|
||||
export function artplayerPluginDocumentPip(option: Option): (art: Artplayer) => Result
|
||||
}
|
||||
|
||||
interface Result {
|
||||
name: 'artplayerPluginDocumentPip'
|
||||
isSupported: boolean
|
||||
isActive: boolean
|
||||
open: () => void
|
||||
close: () => void
|
||||
toggle: () => void
|
||||
declare const artplayerPluginDocumentPip: typeof artplayerPluginDocumentPipDefinitions.artplayerPluginDocumentPip
|
||||
declare namespace artplayerPluginDocumentPip {
|
||||
export type Option = artplayerPluginDocumentPipDefinitions.Option
|
||||
export type Result = artplayerPluginDocumentPipDefinitions.Result
|
||||
export type AsyncResult = artplayerPluginDocumentPipDefinitions.AsyncResult
|
||||
export type Factory = artplayerPluginDocumentPipDefinitions.Factory
|
||||
export type RuntimeFactory = artplayerPluginDocumentPipDefinitions.RuntimeFactory
|
||||
}
|
||||
|
||||
declare const artplayerPluginDocumentPip: (option: Option) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginDocumentPip
|
||||
|
||||
export = artplayerPluginDocumentPip
|
||||
export as namespace artplayerPluginDocumentPip;
|
||||
+39
-13
@@ -1,17 +1,43 @@
|
||||
interface Config {
|
||||
control?: boolean
|
||||
setting?: boolean
|
||||
title?: string
|
||||
auto?: string
|
||||
getName?: (level: object) => string
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerPluginHlsControlDefinitions {
|
||||
export interface QualityLevel {
|
||||
height: number
|
||||
name?: string
|
||||
}
|
||||
export interface AudioTrack {
|
||||
id: number
|
||||
name: string
|
||||
lang?: string
|
||||
language?: string
|
||||
}
|
||||
export interface Config<Item extends object = object> {
|
||||
control?: boolean
|
||||
setting?: boolean
|
||||
title?: string
|
||||
auto?: string
|
||||
/** Plain callback; current-label calls omit index. SDK objects retain their identity. */
|
||||
getName?: (item: Item, index?: number) => string
|
||||
}
|
||||
export interface Option<Level extends object = QualityLevel, Track extends object = AudioTrack> {
|
||||
quality?: Config<Level>
|
||||
audio?: Config<Track>
|
||||
}
|
||||
export interface Result {
|
||||
name: 'artplayerPluginHlsControl'
|
||||
update: () => void
|
||||
}
|
||||
export function artplayerPluginHlsControl<Level extends object = QualityLevel, Track extends object = AudioTrack>(option?: Option<Level, Track>): (art: Artplayer) => Result
|
||||
// Keep the required last signature for historical Parameters<typeof factory>[0] consumers.
|
||||
export function artplayerPluginHlsControl<Level extends object = QualityLevel, Track extends object = AudioTrack>(option: Option<Level, Track>): (art: Artplayer) => Result
|
||||
}
|
||||
|
||||
declare const artplayerPluginHlsControl: (option: { quality?: Config, audio?: Config }) => (art: Artplayer) => {
|
||||
name: 'artplayerPluginHlsControl'
|
||||
update: () => void
|
||||
declare const artplayerPluginHlsControl: typeof artplayerPluginHlsControlDefinitions.artplayerPluginHlsControl
|
||||
declare namespace artplayerPluginHlsControl {
|
||||
export type QualityLevel = artplayerPluginHlsControlDefinitions.QualityLevel
|
||||
export type AudioTrack = artplayerPluginHlsControlDefinitions.AudioTrack
|
||||
export type Config<Item extends object = object> = artplayerPluginHlsControlDefinitions.Config<Item>
|
||||
export type Option<Level extends object = QualityLevel, Track extends object = AudioTrack> = artplayerPluginHlsControlDefinitions.Option<Level, Track>
|
||||
export type Result = artplayerPluginHlsControlDefinitions.Result
|
||||
}
|
||||
|
||||
export default artplayerPluginHlsControl
|
||||
|
||||
export = artplayerPluginHlsControl
|
||||
export as namespace artplayerPluginHlsControl;
|
||||
+37
-34
@@ -1,38 +1,41 @@
|
||||
export interface JassubOption {
|
||||
workerUrl: string
|
||||
wasmUrl: string
|
||||
modernWasmUrl: string
|
||||
subUrl?: string
|
||||
subContent?: string
|
||||
timeOffset?: number
|
||||
debug?: boolean
|
||||
prescaleFactor?: number
|
||||
prescaleHeightLimit?: number
|
||||
maxRenderHeight?: number
|
||||
fonts?: string[] | Uint8Array[]
|
||||
availableFonts?: Record<string, Uint8Array | string>
|
||||
fallbackFont?: string
|
||||
useLocalFonts?: boolean
|
||||
libassMemoryLimit?: number
|
||||
libassGlyphLimit?: number
|
||||
[key: string]: any
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerPluginJassubDefinitions {
|
||||
export interface JassubOption {
|
||||
workerUrl: string
|
||||
wasmUrl: string
|
||||
modernWasmUrl: string
|
||||
subUrl?: string
|
||||
subContent?: string
|
||||
timeOffset?: number
|
||||
debug?: boolean
|
||||
prescaleFactor?: number
|
||||
prescaleHeightLimit?: number
|
||||
maxRenderHeight?: number
|
||||
fonts?: string[] | Uint8Array[]
|
||||
availableFonts?: Record<string, Uint8Array | string>
|
||||
fallbackFont?: string
|
||||
useLocalFonts?: boolean
|
||||
libassMemoryLimit?: number
|
||||
libassGlyphLimit?: number
|
||||
[key: string]: any
|
||||
}
|
||||
export interface JassubInstance {
|
||||
resize: (force?: boolean, width?: number, height?: number, top?: number, left?: number) => Promise<void>
|
||||
setVideo: (video: HTMLVideoElement) => Promise<void>
|
||||
destroy: () => Promise<void>
|
||||
[key: string]: any
|
||||
}
|
||||
export interface Result {
|
||||
name: 'artplayerPluginJassub'
|
||||
instance: JassubInstance
|
||||
}
|
||||
export const artplayerPluginJassub: (option: JassubOption) => (art: Artplayer) => Result
|
||||
}
|
||||
|
||||
export interface JassubInstance {
|
||||
resize: (force?: boolean, width?: number, height?: number, top?: number, left?: number) => Promise<void>
|
||||
setVideo: (video: HTMLVideoElement) => Promise<void>
|
||||
destroy: () => Promise<void>
|
||||
[key: string]: any
|
||||
declare const artplayerPluginJassub: typeof artplayerPluginJassubDefinitions.artplayerPluginJassub
|
||||
declare namespace artplayerPluginJassub {
|
||||
export type JassubOption = artplayerPluginJassubDefinitions.JassubOption
|
||||
export type JassubInstance = artplayerPluginJassubDefinitions.JassubInstance
|
||||
}
|
||||
|
||||
interface Result {
|
||||
name: 'artplayerPluginJassub'
|
||||
instance: JassubInstance
|
||||
}
|
||||
|
||||
declare const artplayerPluginJassub: (option: JassubOption) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginJassub
|
||||
|
||||
export = artplayerPluginJassub
|
||||
export as namespace artplayerPluginJassub;
|
||||
+37
-8
@@ -1,16 +1,45 @@
|
||||
declare const artplayerPluginMultipleSubtitles: (option: {
|
||||
subtitles: {
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerPluginMultipleSubtitlesDefinitions {
|
||||
export interface TrackOption {
|
||||
url?: string
|
||||
name?: string
|
||||
type?: 'vtt' | 'srt' | 'ass'
|
||||
encoding?: string
|
||||
onParser?: (...args: object[]) => object
|
||||
}[]
|
||||
}) => (art: Artplayer) => {
|
||||
name: 'multipleSubtitles'
|
||||
}
|
||||
export interface Option {
|
||||
subtitles: TrackOption[]
|
||||
}
|
||||
export interface RuntimeOption {
|
||||
subtitles?: TrackOption[]
|
||||
}
|
||||
export interface LegacyResult {
|
||||
name: 'multipleSubtitles'
|
||||
}
|
||||
export interface Result extends LegacyResult {
|
||||
tracks: (names?: string[]) => void
|
||||
reset: () => void
|
||||
}
|
||||
/** Historical synchronous extraction; actual registration is asynchronous. */
|
||||
export type Factory = (option: Option) => (art: Artplayer) => LegacyResult
|
||||
/** Accurate runtime view available through the /runtime entry. */
|
||||
export interface RuntimeFactory {
|
||||
(option: RuntimeOption): (art: Artplayer) => Promise<Result>
|
||||
default: RuntimeFactory
|
||||
}
|
||||
/** Preserve existing parameter extraction and replacement-function compatibility. */
|
||||
export function artplayerPluginMultipleSubtitles(option: Option): (art: Artplayer) => LegacyResult
|
||||
}
|
||||
declare const artplayerPluginMultipleSubtitles: typeof artplayerPluginMultipleSubtitlesDefinitions.artplayerPluginMultipleSubtitles
|
||||
declare namespace artplayerPluginMultipleSubtitles {
|
||||
export type TrackOption = artplayerPluginMultipleSubtitlesDefinitions.TrackOption
|
||||
export type Option = artplayerPluginMultipleSubtitlesDefinitions.Option
|
||||
export type RuntimeOption = artplayerPluginMultipleSubtitlesDefinitions.RuntimeOption
|
||||
export type LegacyResult = artplayerPluginMultipleSubtitlesDefinitions.LegacyResult
|
||||
export type Result = artplayerPluginMultipleSubtitlesDefinitions.Result
|
||||
export type Factory = artplayerPluginMultipleSubtitlesDefinitions.Factory
|
||||
export type RuntimeFactory = artplayerPluginMultipleSubtitlesDefinitions.RuntimeFactory
|
||||
}
|
||||
|
||||
export default artplayerPluginMultipleSubtitles
|
||||
|
||||
export = artplayerPluginMultipleSubtitles
|
||||
export as namespace artplayerPluginMultipleSubtitles;
|
||||
@@ -0,0 +1,224 @@
|
||||
@glomex/vast-ima-player
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2020 glomex GmbH
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
@alugha/ima
|
||||
# The MIT License (MIT)
|
||||
|
||||
**Copyright 2020 Alugha GmbH**
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+15
-34
@@ -1,36 +1,17 @@
|
||||
declare global {
|
||||
interface Window {
|
||||
artplayerPluginVast?: typeof artplayerPluginVast
|
||||
}
|
||||
}
|
||||
|
||||
type PlayUrlFn = (url: string, config?: any) => void
|
||||
type PlayResFn = (res: string, config?: any) => void
|
||||
|
||||
interface VastPluginContext {
|
||||
art: Artplayer
|
||||
ima: any
|
||||
imaPlayer: Player | null
|
||||
playUrl: PlayUrlFn
|
||||
playRes: PlayResFn
|
||||
init: () => Player
|
||||
adsRenderingSettings: any
|
||||
playerOptions: PlayerOptions
|
||||
container: HTMLDivElement | null
|
||||
}
|
||||
|
||||
export type ArtplayerPluginVastOption = (params: VastPluginContext) => void | Promise<void>
|
||||
|
||||
export interface ArtplayerPluginVastInstance {
|
||||
name: 'artplayerPluginVast'
|
||||
destroy?: () => void
|
||||
}
|
||||
|
||||
declare function artplayerPluginVast(
|
||||
option: ArtplayerPluginVastOption,
|
||||
): (art: Artplayer) => ArtplayerPluginVastInstance
|
||||
|
||||
export default artplayerPluginVast
|
||||
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-use-before-define, ts/consistent-type-definitions -- Preserve historical export ordering and private aliases. */
|
||||
export = artplayerPluginVast
|
||||
export as namespace artplayerPluginVast;
|
||||
type Option = (params: {
|
||||
art: Artplayer
|
||||
id: string
|
||||
ima: any
|
||||
imaPlayer: any
|
||||
$container: HTMLDivElement
|
||||
playUrl: (url: string) => void
|
||||
playRes: (res: string) => void
|
||||
}) => void
|
||||
type Result = {
|
||||
name: 'artplayerPluginVast'
|
||||
}
|
||||
declare const artplayerPluginVast: (option: Option) => (art: Artplayer) => Result
|
||||
+26
-7
@@ -1,10 +1,29 @@
|
||||
declare const artplayerPluginVttThumbnail: (option: { vtt?: string, style?: Partial<CSSStyleDeclaration> }) => (
|
||||
art: Artplayer,
|
||||
) => {
|
||||
name: 'artplayerPluginVttThumbnail'
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerPluginVttThumbnailDefinitions {
|
||||
export interface Option {
|
||||
vtt?: string
|
||||
style?: Partial<CSSStyleDeclaration>
|
||||
}
|
||||
export interface Result {
|
||||
name: 'artplayerPluginVttThumbnail'
|
||||
}
|
||||
/** Historical factory type. Actual registration is asynchronous. */
|
||||
export type Factory = (option: Option) => (art: Artplayer) => Result
|
||||
/** Accurate runtime view available without casts through the /runtime entry. */
|
||||
export interface RuntimeFactory {
|
||||
(option: Option): (art: Artplayer) => Promise<Result>
|
||||
default: RuntimeFactory
|
||||
}
|
||||
/** Preserve historical extraction and replacement-function compatibility. */
|
||||
export function artplayerPluginVttThumbnail(option: Option): (art: Artplayer) => Result
|
||||
}
|
||||
declare const artplayerPluginVttThumbnail: typeof artplayerPluginVttThumbnailDefinitions.artplayerPluginVttThumbnail
|
||||
declare namespace artplayerPluginVttThumbnail {
|
||||
export type Option = artplayerPluginVttThumbnailDefinitions.Option
|
||||
export type Result = artplayerPluginVttThumbnailDefinitions.Result
|
||||
export type Factory = artplayerPluginVttThumbnailDefinitions.Factory
|
||||
export type RuntimeFactory = artplayerPluginVttThumbnailDefinitions.RuntimeFactory
|
||||
}
|
||||
|
||||
export default artplayerPluginVttThumbnail
|
||||
|
||||
export = artplayerPluginVttThumbnail
|
||||
export as namespace artplayerPluginVttThumbnail;
|
||||
+26
-8
@@ -1,10 +1,28 @@
|
||||
type Option = (ctx: CanvasRenderingContext2D, video: HTMLVideoElement) => void
|
||||
|
||||
type Result = HTMLCanvasElement
|
||||
|
||||
declare const artplayerProxyCanvas: (option?: Option) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerProxyCanvas
|
||||
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerProxyCanvasDefinitions {
|
||||
/** Runs after drawing and bitmap release, before the draw event. */
|
||||
export type Option = (ctx: CanvasRenderingContext2D, video: HTMLVideoElement) => void
|
||||
/** Preserve the exact published 1.1.0 return type and its assignability. */
|
||||
export type Result = HTMLCanvasElement
|
||||
export type Factory = (option?: Option) => (art: Artplayer) => Result
|
||||
export type Callable = Factory
|
||||
/** Explicit view of forwarded media members; native Canvas members win. */
|
||||
export type MediaCanvas = HTMLCanvasElement & Pick<HTMLVideoElement, Exclude<keyof HTMLVideoElement, keyof HTMLCanvasElement>>
|
||||
/** Opt-in runtime identity; the historical root factory has no required properties. */
|
||||
export interface RuntimeFactory extends Factory {
|
||||
readonly default: RuntimeFactory
|
||||
}
|
||||
export const artplayerProxyCanvas: (option?: Option) => (art: Artplayer) => Result
|
||||
}
|
||||
declare const artplayerProxyCanvas: typeof artplayerProxyCanvasDefinitions.artplayerProxyCanvas
|
||||
declare namespace artplayerProxyCanvas {
|
||||
export type Option = artplayerProxyCanvasDefinitions.Option
|
||||
export type Result = artplayerProxyCanvasDefinitions.Result
|
||||
export type Factory = artplayerProxyCanvasDefinitions.Factory
|
||||
export type Callable = artplayerProxyCanvasDefinitions.Callable
|
||||
export type MediaCanvas = artplayerProxyCanvasDefinitions.MediaCanvas
|
||||
export type RuntimeFactory = artplayerProxyCanvasDefinitions.RuntimeFactory
|
||||
}
|
||||
export = artplayerProxyCanvas
|
||||
export as namespace artplayerProxyCanvas;
|
||||
+212
-76
@@ -1,79 +1,215 @@
|
||||
interface Option {
|
||||
/**
|
||||
* Timeout for loading media in milliseconds
|
||||
* @default 0
|
||||
*/
|
||||
loadTimeout?: number
|
||||
|
||||
/**
|
||||
* Interval for timeupdate events in milliseconds
|
||||
* @default 250
|
||||
*/
|
||||
timeupdateInterval?: number
|
||||
|
||||
/**
|
||||
* Audio-video synchronization tolerance in seconds
|
||||
* @default 0.12
|
||||
*/
|
||||
avSyncTolerance?: number
|
||||
|
||||
/**
|
||||
* Whether to drop late video frames
|
||||
* @default false
|
||||
*/
|
||||
dropLateFrames?: boolean
|
||||
|
||||
/**
|
||||
* Poster image URL
|
||||
*/
|
||||
poster?: string
|
||||
|
||||
/**
|
||||
* Media source (URL, Blob, or ReadableStream)
|
||||
*/
|
||||
source?: string | Blob | ReadableStream<Uint8Array>
|
||||
|
||||
/**
|
||||
* Check if server supports range requests before loading
|
||||
* @default false
|
||||
*/
|
||||
preflightRange?: boolean
|
||||
|
||||
/**
|
||||
* Initial volume (0-1)
|
||||
* @default 0.7
|
||||
*/
|
||||
volume?: number
|
||||
|
||||
/**
|
||||
* Initial muted state
|
||||
* @default false
|
||||
*/
|
||||
muted?: boolean
|
||||
|
||||
/**
|
||||
* Autoplay
|
||||
* @default false
|
||||
*/
|
||||
autoplay?: boolean
|
||||
|
||||
/**
|
||||
* Loop playback
|
||||
* @default false
|
||||
*/
|
||||
loop?: boolean
|
||||
|
||||
/**
|
||||
* Cross-origin setting
|
||||
*/
|
||||
crossOrigin?: string
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerProxyMediabunnyDefinitions {
|
||||
export interface Option {
|
||||
m3u8?: {
|
||||
quality?: {
|
||||
control?: boolean
|
||||
setting?: boolean
|
||||
title?: string
|
||||
auto?: string
|
||||
getName?: (level: {
|
||||
id: number
|
||||
index: number
|
||||
name: null | string
|
||||
height: number
|
||||
bitrate: number
|
||||
}) => string
|
||||
}
|
||||
audio?: {
|
||||
control?: boolean
|
||||
setting?: boolean
|
||||
title?: string
|
||||
auto?: string
|
||||
getName?: (track: {
|
||||
id: number
|
||||
index: number
|
||||
name: null | string
|
||||
lang: string
|
||||
language: string
|
||||
bitrate: number
|
||||
}) => string
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Timeout for loading media in milliseconds
|
||||
* @default 0
|
||||
*/
|
||||
loadTimeout?: number
|
||||
/**
|
||||
* Interval for timeupdate events in milliseconds
|
||||
* @default 250
|
||||
*/
|
||||
timeupdateInterval?: number
|
||||
/**
|
||||
* Audio-video synchronization tolerance in seconds
|
||||
* @default 0.12
|
||||
*/
|
||||
avSyncTolerance?: number
|
||||
/**
|
||||
* Whether to drop late video frames
|
||||
* @default false
|
||||
*/
|
||||
dropLateFrames?: boolean
|
||||
/**
|
||||
* Poster image URL
|
||||
*/
|
||||
poster?: string
|
||||
/**
|
||||
* Media source (URL, Blob, or ReadableStream)
|
||||
*/
|
||||
source?: string | Blob | ReadableStream<Uint8Array>
|
||||
/**
|
||||
* Check if server supports range requests before loading
|
||||
* @default false
|
||||
*/
|
||||
preflightRange?: boolean
|
||||
/**
|
||||
* Initial volume (0-1)
|
||||
* @default 0.7
|
||||
*/
|
||||
volume?: number
|
||||
/**
|
||||
* Initial muted state
|
||||
* @default false
|
||||
*/
|
||||
muted?: boolean
|
||||
/**
|
||||
* Autoplay
|
||||
* @default false
|
||||
*/
|
||||
autoplay?: boolean
|
||||
/**
|
||||
* Loop playback
|
||||
* @default false
|
||||
*/
|
||||
loop?: boolean
|
||||
/**
|
||||
* Cross-origin setting
|
||||
*/
|
||||
crossOrigin?: string
|
||||
}
|
||||
export type Result = HTMLCanvasElement
|
||||
export interface HlsLevel {
|
||||
id: number
|
||||
index: number
|
||||
name: string | null
|
||||
height: number
|
||||
bitrate: number
|
||||
/** SDK object; narrow with the SDK version used by your application. */
|
||||
track: unknown
|
||||
}
|
||||
export interface HlsAudio {
|
||||
id: number
|
||||
index: number
|
||||
name: string | null
|
||||
lang: string
|
||||
language: string
|
||||
bitrate: number
|
||||
/** SDK object; narrow with the SDK version used by your application. */
|
||||
track: unknown
|
||||
}
|
||||
export interface HlsState {
|
||||
levels: HlsLevel[]
|
||||
audios: HlsAudio[]
|
||||
currentLevel: HlsLevel | null
|
||||
currentAudio: HlsAudio | null
|
||||
videoMode: 'auto' | 'manual'
|
||||
audioMode: 'auto' | 'manual'
|
||||
}
|
||||
/** Historical RAF estimates, not decoded-frame or network timing measurements. */
|
||||
export interface SyntheticFrameMetadata {
|
||||
/** Historical media time in seconds, unlike the native video API. */
|
||||
presentationTime: number
|
||||
expectedDisplayTime: number
|
||||
width: number
|
||||
height: number
|
||||
mediaTime: number
|
||||
presentedFrames: number
|
||||
processingDuration: number
|
||||
captureTime: number
|
||||
receiveTime: number
|
||||
rtpTimestamp: number
|
||||
}
|
||||
export type SyntheticFrameCallback = (now: number, metadata: SyntheticFrameMetadata) => void
|
||||
export type MediaListener = (event: Event & {
|
||||
detail: unknown
|
||||
}) => unknown
|
||||
/** Opt-in media surface of art.mediabunny; decoder internals are not part of this view. */
|
||||
export interface MediaBunnyShim {
|
||||
canvas: HTMLCanvasElement
|
||||
/** Runtime also accepts SDK sources; the default Option keeps its historical input union. */
|
||||
src: unknown
|
||||
readonly currentSrc: unknown
|
||||
currentTime: number
|
||||
readonly duration: number
|
||||
/** Synthetic full-duration/current-time ranges, not measured network buffers. */
|
||||
readonly buffered: TimeRanges
|
||||
readonly played: TimeRanges
|
||||
readonly seekable: TimeRanges
|
||||
readonly paused: boolean
|
||||
readonly playing: boolean
|
||||
readonly ended: boolean
|
||||
readonly seeking: boolean
|
||||
readonly readyState: number
|
||||
readonly networkState: number
|
||||
readonly error: {
|
||||
code: number
|
||||
message: string
|
||||
} | null
|
||||
volume: number
|
||||
muted: boolean
|
||||
playbackRate: number
|
||||
readonly videoWidth: number
|
||||
readonly videoHeight: number
|
||||
poster: string
|
||||
/** The following setters are inert; use Option for autoplay/loop/crossOrigin. */
|
||||
autoplay: boolean
|
||||
loop: boolean
|
||||
controls: boolean
|
||||
playsInline: boolean
|
||||
crossOrigin: string
|
||||
preload: string
|
||||
defaultMuted: boolean
|
||||
defaultPlaybackRate: number
|
||||
play: () => Promise<void>
|
||||
pause: () => void
|
||||
load: () => void
|
||||
/** Always returns "maybe"; it does not probe codec/browser support. */
|
||||
canPlayType: (type: string) => 'maybe'
|
||||
getM3u8State: () => Promise<HlsState | null>
|
||||
switchM3u8Quality: (value: unknown) => Promise<void>
|
||||
switchM3u8Audio: (value: unknown) => Promise<void>
|
||||
createTimeRanges: (start: number, end: number) => TimeRanges
|
||||
requestVideoFrameCallback: (callback: SyntheticFrameCallback) => number
|
||||
cancelVideoFrameCallback: (id: number) => void
|
||||
addEventListener: (type: string, listener: MediaListener) => void
|
||||
removeEventListener: (type: string, listener: MediaListener) => void
|
||||
getBoundingClientRect: () => DOMRect
|
||||
setAttribute: (name: string, value: unknown) => void
|
||||
destroy: () => void
|
||||
}
|
||||
/** Native Canvas methods win collisions, including DOM event and attribute methods. */
|
||||
export type MediaBunnyCanvas = HTMLCanvasElement & Omit<MediaBunnyShim, keyof HTMLCanvasElement>
|
||||
/** The alias is installed by the proxy and removed on player destruction. */
|
||||
export type MediaBunnyPlayer = Artplayer & {
|
||||
mediabunny?: MediaBunnyShim
|
||||
}
|
||||
export const artplayerProxyMediabunny: (option?: Option) => (art: Artplayer) => Result
|
||||
}
|
||||
declare const artplayerProxyMediabunny: typeof artplayerProxyMediabunnyDefinitions.artplayerProxyMediabunny
|
||||
declare namespace artplayerProxyMediabunny {
|
||||
export type Option = artplayerProxyMediabunnyDefinitions.Option
|
||||
export type Result = artplayerProxyMediabunnyDefinitions.Result
|
||||
export type HlsLevel = artplayerProxyMediabunnyDefinitions.HlsLevel
|
||||
export type HlsAudio = artplayerProxyMediabunnyDefinitions.HlsAudio
|
||||
export type HlsState = artplayerProxyMediabunnyDefinitions.HlsState
|
||||
export type SyntheticFrameMetadata = artplayerProxyMediabunnyDefinitions.SyntheticFrameMetadata
|
||||
export type SyntheticFrameCallback = artplayerProxyMediabunnyDefinitions.SyntheticFrameCallback
|
||||
export type MediaListener = artplayerProxyMediabunnyDefinitions.MediaListener
|
||||
export type MediaBunnyShim = artplayerProxyMediabunnyDefinitions.MediaBunnyShim
|
||||
export type MediaBunnyCanvas = artplayerProxyMediabunnyDefinitions.MediaBunnyCanvas
|
||||
export type MediaBunnyPlayer = artplayerProxyMediabunnyDefinitions.MediaBunnyPlayer
|
||||
}
|
||||
|
||||
type Result = HTMLCanvasElement
|
||||
|
||||
declare const artplayerProxyMediabunny: (option?: Option) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerProxyMediabunny
|
||||
|
||||
export = artplayerProxyMediabunny
|
||||
export as namespace artplayerProxyMediabunny;
|
||||
+107
-30
@@ -1,32 +1,109 @@
|
||||
interface Message {
|
||||
type: string
|
||||
data: any
|
||||
id?: number
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace ArtplayerToolIframeDefinitions {
|
||||
export interface Option {
|
||||
iframe: HTMLIFrameElement
|
||||
url: string
|
||||
}
|
||||
/** Historical open envelope. data remains required in the default class API. */
|
||||
export interface Message<T = any> {
|
||||
type: string
|
||||
data: T
|
||||
id?: number
|
||||
}
|
||||
export interface Callbacks {
|
||||
resove: (...args: any[]) => any
|
||||
reject: (...args: any[]) => any
|
||||
}
|
||||
/** Public notifications omit the request id and all private session metadata. */
|
||||
export interface Notification<T = unknown> {
|
||||
type: string
|
||||
data: T
|
||||
}
|
||||
export type MessageCallback = (this: ArtplayerToolIframe, message: Notification) => void
|
||||
/** Actual outgoing calls allow an omitted data field. Custom message types remain valid. */
|
||||
export interface OutboundMessage<T = unknown> {
|
||||
type: string
|
||||
data?: T
|
||||
id?: number
|
||||
}
|
||||
/** Known built-in envelopes; use Message/OutboundMessage for application protocols. */
|
||||
export type ProtocolMessage<T = unknown> = {
|
||||
type: 'inject'
|
||||
data?: undefined
|
||||
id?: number
|
||||
} | {
|
||||
type: 'commit'
|
||||
data: string
|
||||
id: number
|
||||
} | {
|
||||
type: 'response'
|
||||
data: T
|
||||
id: number
|
||||
} | {
|
||||
type: 'error'
|
||||
data: unknown
|
||||
id: number
|
||||
}
|
||||
export type Resolve<T> = (value: T | PromiseLike<T>) => void
|
||||
export type ResolverCallback<T> = (resolve: Resolve<T>) => void
|
||||
/** Opt-in view. Response T is supplied by the application's protocol, not validated at runtime. */
|
||||
export interface RuntimeInstance extends Omit<ArtplayerToolIframe, 'messageCallback' | 'postMessage' | 'message'> {
|
||||
messageCallback: MessageCallback | null
|
||||
postMessage: <T = unknown>(message: OutboundMessage) => Promise<T>
|
||||
message: (callback: MessageCallback) => void
|
||||
}
|
||||
/** For the existing serialized resolve(...) protocol; callback bodies must use that exact name. */
|
||||
export interface ResolverInstance extends Omit<RuntimeInstance, 'commit'> {
|
||||
commit: <T>(callback: ResolverCallback<T>) => Promise<T>
|
||||
}
|
||||
/** Opt-in static async/optional-data view. There is no runtime self-default property. */
|
||||
export interface RuntimeConstructor {
|
||||
new (option: Option): RuntimeInstance
|
||||
readonly prototype: RuntimeInstance
|
||||
readonly iframe: boolean
|
||||
postMessage: (message: OutboundMessage) => void
|
||||
onMessage: (event: MessageEvent<OutboundMessage>) => Promise<void>
|
||||
inject: () => void
|
||||
}
|
||||
export class ArtplayerToolIframe {
|
||||
constructor(option: Option)
|
||||
static iframe: boolean
|
||||
static postMessage(message: Message): void
|
||||
static onMessage(event: MessageEvent & {
|
||||
data: Message
|
||||
}): void
|
||||
static inject(): void
|
||||
readonly promises: Record<number, Callbacks>
|
||||
readonly injected: boolean
|
||||
readonly destroyed: boolean
|
||||
readonly $iframe: HTMLIFrameElement
|
||||
readonly url: string
|
||||
readonly messageCallback: (...args: any[]) => any
|
||||
onMessage(event: MessageEvent & {
|
||||
data: Message
|
||||
}): void
|
||||
postMessage(message: Message): Promise<any>
|
||||
commit<T extends (...args: any[]) => any>(callback: T): Promise<ReturnType<T>>
|
||||
message(callback: (...args: any[]) => any): void
|
||||
destroy(): void
|
||||
}
|
||||
}
|
||||
|
||||
declare class ArtplayerToolIframe {
|
||||
constructor(option: { iframe: HTMLIFrameElement, url: string })
|
||||
|
||||
static iframe: boolean
|
||||
static postMessage(message: Message): void
|
||||
static onMessage(event: MessageEvent & { data: Message }): void
|
||||
static inject(): void
|
||||
|
||||
readonly promises: Record<number, { resove: (...args: any[]) => any, reject: (...args: any[]) => any }>
|
||||
readonly injected: boolean
|
||||
readonly destroyed: boolean
|
||||
readonly $iframe: HTMLIFrameElement
|
||||
readonly url: string
|
||||
readonly messageCallback: (...args: any[]) => any
|
||||
|
||||
onMessage(event: MessageEvent & { data: Message }): void
|
||||
postMessage(message: Message): Promise<any>
|
||||
commit<T extends (...args: any[]) => any>(callback: T): Promise<ReturnType<T>>
|
||||
message(callback: (...args: any[]) => any): void
|
||||
destroy(): void
|
||||
declare const ArtplayerToolIframe: typeof ArtplayerToolIframeDefinitions.ArtplayerToolIframe
|
||||
type ArtplayerToolIframe = ArtplayerToolIframeDefinitions.ArtplayerToolIframe
|
||||
declare namespace ArtplayerToolIframe {
|
||||
export type Option = ArtplayerToolIframeDefinitions.Option
|
||||
export type Message<T = any> = ArtplayerToolIframeDefinitions.Message<T>
|
||||
export type Callbacks = ArtplayerToolIframeDefinitions.Callbacks
|
||||
export type Notification<T = unknown> = ArtplayerToolIframeDefinitions.Notification<T>
|
||||
export type MessageCallback = ArtplayerToolIframeDefinitions.MessageCallback
|
||||
export type OutboundMessage<T = unknown> = ArtplayerToolIframeDefinitions.OutboundMessage<T>
|
||||
export type ProtocolMessage<T = unknown> = ArtplayerToolIframeDefinitions.ProtocolMessage<T>
|
||||
export type Resolve<T> = ArtplayerToolIframeDefinitions.Resolve<T>
|
||||
export type ResolverCallback<T> = ArtplayerToolIframeDefinitions.ResolverCallback<T>
|
||||
export type RuntimeInstance = ArtplayerToolIframeDefinitions.RuntimeInstance
|
||||
export type ResolverInstance = ArtplayerToolIframeDefinitions.ResolverInstance
|
||||
export type RuntimeConstructor = ArtplayerToolIframeDefinitions.RuntimeConstructor
|
||||
}
|
||||
|
||||
export default ArtplayerToolIframe
|
||||
|
||||
export = artplayerToolIframe
|
||||
export as namespace artplayerToolIframe;
|
||||
export = ArtplayerToolIframe
|
||||
export as namespace ArtplayerToolIframe;
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/** Extract PNG thumbnail sheets from a locally selected video file. */
|
||||
declare class ArtplayerToolThumbnail {
|
||||
constructor(option?: ArtplayerToolThumbnail.Option)
|
||||
static readonly DEFAULTS: ArtplayerToolThumbnail.DefaultOptions
|
||||
static ondragover(event: DragEvent): void
|
||||
static creatVideo(): HTMLVideoElement
|
||||
processing: boolean
|
||||
option: ArtplayerToolThumbnail.ResolvedOption
|
||||
video: HTMLVideoElement
|
||||
duration: number
|
||||
density: number | undefined
|
||||
file: File | undefined
|
||||
videoUrl: string | undefined
|
||||
thumbnailUrl: string | undefined
|
||||
e?: ArtplayerToolThumbnail.EventRegistry
|
||||
setup(option?: ArtplayerToolThumbnail.Option): this
|
||||
inputChange(event: Event): void
|
||||
ondrop(event: DragEvent): void
|
||||
loadVideo(file?: File | null): void
|
||||
/** Ready-metadata preflight may throw synchronously. Cancellation rejects with AbortError. */
|
||||
start(): Promise<void>
|
||||
creatScreenshotDate(): ArtplayerToolThumbnail.ScreenshotPoint[]
|
||||
creatCanvas(): HTMLCanvasElement
|
||||
download(): this
|
||||
errorHandle(condition: unknown, message: string): void
|
||||
destroy(): void
|
||||
on<Name extends PropertyKey, Custom extends unknown[], Context>(name: Name, callback: (this: Context, ...args: ArtplayerToolThumbnail.EventArgs<Name, Custom>) => unknown, ctx?: Context): this
|
||||
once<Name extends PropertyKey, Custom extends unknown[], Context>(name: Name, callback: (this: Context, ...args: ArtplayerToolThumbnail.EventArgs<Name, Custom>) => unknown, ctx?: Context): this
|
||||
emit<Name extends PropertyKey, Custom extends unknown[]>(name: Name, ...args: ArtplayerToolThumbnail.EventArgs<Name, Custom>): this
|
||||
off<Name extends PropertyKey, Custom extends unknown[]>(name: Name, callback?: ArtplayerToolThumbnail.Listener<ArtplayerToolThumbnail.EventArgs<Name, Custom>>): this
|
||||
}
|
||||
declare namespace ArtplayerToolThumbnail {
|
||||
interface SheetOptions {
|
||||
number: number
|
||||
width: number
|
||||
height: number
|
||||
column: number
|
||||
begin: number
|
||||
end: number
|
||||
}
|
||||
type Compatibility = 'published-3.5' | 'workspace-4.4'
|
||||
interface DefaultOptions extends SheetOptions {
|
||||
delay: number
|
||||
}
|
||||
/** fileInput must be a file input or an Element wrapper when constructing. */
|
||||
interface Option extends Partial<SheetOptions> {
|
||||
fileInput?: Element
|
||||
compatibility?: Compatibility
|
||||
/** Published mode delay in milliseconds, clamped to 10-1000. */
|
||||
delay?: number
|
||||
[name: string]: unknown
|
||||
}
|
||||
interface ResolvedOption extends SheetOptions {
|
||||
fileInput: HTMLInputElement
|
||||
compatibility?: Compatibility
|
||||
delay?: number
|
||||
[name: string]: unknown
|
||||
}
|
||||
interface ScreenshotPoint {
|
||||
time: number
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
interface Events {
|
||||
file: [
|
||||
file: File,
|
||||
]
|
||||
video: [
|
||||
video: HTMLVideoElement,
|
||||
]
|
||||
canvas: [
|
||||
canvas: HTMLCanvasElement,
|
||||
]
|
||||
update: [
|
||||
url: string,
|
||||
progress: number,
|
||||
]
|
||||
done: [
|
||||
]
|
||||
download: [
|
||||
name: string,
|
||||
]
|
||||
/** Built-in failures are strings; user callbacks may throw any message value. */
|
||||
error: [
|
||||
message: unknown,
|
||||
]
|
||||
destroy: [
|
||||
]
|
||||
}
|
||||
type EventArgs<Name extends PropertyKey, Custom extends unknown[] = unknown[]> = Name extends keyof Events ? [
|
||||
...Events[Name],
|
||||
] : Custom
|
||||
type Listener<Args extends unknown[]> = ((...args: Args) => unknown) & {
|
||||
_?: (...args: Args) => unknown
|
||||
}
|
||||
/** Heterogeneous listener storage; dispatch through emit to retain event argument checks. */
|
||||
type EventRegistry = Partial<Record<PropertyKey, {
|
||||
fn: Listener<never[]>
|
||||
ctx: unknown
|
||||
}[]>>
|
||||
}
|
||||
export = ArtplayerToolThumbnail
|
||||
export as namespace ArtplayerToolThumbnail;
|
||||
Vendored
+1365
-1284
File diff suppressed because it is too large.
Load diff
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-ads.js v2.1.0
|
||||
* artplayer-plugin-ads.js v3.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(e,l){"object"===typeof exports&&"undefined"!==typeof module?module.exports=l():"function"==typeof define&&define.amd?(t.artplayerPluginAds=l(),define(function(){return t.artplayerPluginAds})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAds=l()}(this,function(){"use strict";function e(l){return n=>{!function(l){const{version:n,utils:{errorHandle:i}}=l.constructor,a=n.split(".").map(Number);i(a[0]+a[1]/100>=5,`Artplayer.js@${n} is not compatible the artplayerPluginAds@${e.version}. Please update it to version Artplayer.js@5.x.x`)}(n);const{template:{$player:i},icons:{volume:a,volumeClose:t,fullscreenOn:r,fullscreenOff:o,loading:d},constructor:{validator:s,utils:{query:p,append:u,setStyle:c}}}=n;l=s({html:"",video:"",url:"",playDuration:5,totalDuration:10,muted:!1,i18n:{close:"\u5173\u95ed\u5e7f\u544a",countdown:"%s\u79d2",detail:"\u67e5\u770b\u8be6\u60c5",canBeClosed:"%s\u79d2\u540e\u53ef\u5173\u95ed\u5e7f\u544a"},...l},{html:"?string",video:"?string",url:"?string",playDuration:"number",totalDuration:"number",muted:"?boolean",i18n:{close:"string",countdown:"string",detail:"string",canBeClosed:"string"}});let y=null,g=null,f=null,m=null,v=null,x=null,h=0,b=null,w=!1,$=!1,k=!1;function D(e,l){return l.replace("%s",e)}function A(){w=!0,n.play(),l.video&&y.pause(),c(n.template.$ads,"display","none"),n.emit("artplayerPluginAds:skip",l)}function C(){w||(b=setTimeout(()=>{h+=1;const e=l.playDuration-h;e>=1?f.innerHTML=D(e,l.i18n.canBeClosed):(f.innerHTML=l.i18n.close,k||(k=!0)),m.innerHTML=D(l.totalDuration-h,l.i18n.countdown),h>=l.totalDuration?A():C()},1e3))}function P(){w||clearTimeout(b)}function T(){$||($=!0,function(){n.template.$ads=u(i,'<div class="artplayer-plugin-ads"></div>'),y=u(n.template.$ads,l.video?`<video class="artplayer-plugin-ads-video" src="${l.video}" loop playsInline></video>`:`<div class="artplayer-plugin-ads-html">${l.html}</div>`),x=u(n.template.$ads,'<div class="artplayer-plugin-ads-loading"></div>'),u(x,d),g=u(n.template.$ads,`<div class="artplayer-plugin-ads-timer">\n <div class="artplayer-plugin-ads-close">${l.playDuration<=0?l.i18n.close:D(l.playDuration,l.i18n.canBeClosed)}</div>\n <div class="artplayer-plugin-ads-countdown">${D(l.totalDuration,l.i18n.countdown)}</div>\n </div>`),f=p(".artplayer-plugin-ads-close",g),m=p(".artplayer-plugin-ads-countdown",g),l.playDuration>=l.totalDuration&&c(f,"display","none"),n.proxy(f,"click",()=>{k&&A()}),v=u(n.template.$ads,`<div class="artplayer-plugin-ads-control">\n <div class="artplayer-plugin-ads-detail">${l.i18n.detail}</div>\n <div class="artplayer-plugin-ads-muted"></div>\n <div class="artplayer-plugin-ads-fullscreen"></div>\n </div>`);const e=p(".artplayer-plugin-ads-detail",v),s=p(".artplayer-plugin-ads-muted",v),h=p(".artplayer-plugin-ads-fullscreen",v);if(l.url?n.proxy(e,"click",()=>{window.open(l.url),n.emit("artplayerPluginAds:click",l)}):c(e,"display","none"),l.video){const e=u(s,a),i=u(s,t);c(i,"display","none"),l.muted&&(y.muted=!0,c(e,"display","none"),c(i,"display","inline-flex")),n.proxy(s,"click",()=>{y.muted=!y.muted,y.muted?(c(e,"display","none"),c(i,"display","inline-flex")):(c(e,"display","inline-flex"),c(i,"display","none"))})}else c(s,"display","none");const b=u(h,r),w=u(h,o);c(w,"display","none"),n.proxy(h,"click",()=>{n.fullscreen=!n.fullscreen,n.fullscreen?(c(b,"display","inline-flex"),c(w,"display","none")):(c(b,"display","none"),c(w,"display","inline-flex"))}),n.proxy(y,"click",()=>{l.url&&window.open(l.url),n.emit("artplayerPluginAds:click",l)})}(),n.pause(),l.video?(n.proxy(y,"error",A),n.proxy(y,"loadedmetadata",()=>{C(),y.play(),c(g,"display","flex"),c(v,"display","flex"),c(x,"display","none")})):(C(),c(g,"display","flex"),c(v,"display","flex"),c(x,"display","none")),n.on("document:visibilitychange",()=>{document.hidden?P():C()}))}return n.on("ready",()=>{n.once("play",T),n.once("video:playing",T)}),{name:"artplayerPluginAds",skip:A,pause:P,play:C}}}if("undefined"!==typeof document&&!document.getElementById("artplayer-plugin-ads")){const e=document.createElement("style");e.id="artplayer-plugin-ads",e.textContent=".artplayer-plugin-ads{position:absolute;z-index:150;inset:0;width:100%;height:100%;overflow:hidden;font-size:13px;line-height:1;color:#fff;background-color:#000}.artplayer-plugin-ads .artplayer-plugin-ads-html{display:flex;align-items:center;justify-content:center;width:100%;height:100%}.artplayer-plugin-ads .artplayer-plugin-ads-video{width:100%;height:100%}.artplayer-plugin-ads .artplayer-plugin-ads-timer{display:none;position:absolute;top:10px;right:10px}.artplayer-plugin-ads .artplayer-plugin-ads-timer>div{display:flex;align-items:center;background-color:#00000080;border-radius:15px;margin-left:5px;padding:5px 10px;cursor:pointer}.artplayer-plugin-ads .artplayer-plugin-ads-control{display:none;position:absolute;bottom:10px;right:10px}.artplLine truncated
|
||||
!function(e,n){"object"===typeof exports&&"undefined"!==typeof module?module.exports=n():"function"==typeof define&&define.amd?(e.artplayerPluginAds=n(),define(function(){return e.artplayerPluginAds})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAds=n()}(this,function(){"use strict";function e(e){console.warn("Artplayer Ads:",e)}function n(n){const t=[];let i=!1;function l(e,n){if(!i){t.push(n);try{e()}finally{i&&n()}}}return{on(e,t){const a=()=>{i||t()};l(()=>{n.on(e,a)},()=>{n.off(e,a)})},dom(e,n,t){const a=()=>{i||t()};l(()=>e.addEventListener(n,a),()=>e.removeEventListener(n,a))},dispose(){if(!i){i=!0;for(const i of t.splice(0).reverse())try{i()}catch(n){e(n)}}}}}const t=(e,n)=>n.replace("%s",String(e));function i(i,l,a,o){const r=n(i),s=n(i),d=i.template;let u,p,c="waiting",y=!1,f=!1,g=!1;const v=function(e,n,t){let i,l=0,a=!1,o=!1,r=!1;function s(){a&&o&&!r&&void 0===i&&(i=setTimeout(()=>{i=void 0,!r&&o&&(l+=1,n(l),r||(l>=e()?t():s()))},1e3))}function d(){o=!1,void 0!==i&&clearTimeout(i),i=void 0}return{start(){a||r||(a=!0,o=!0,s())},play(){a&&!r&&(o=!0,s())},pause:d,stop(){r=!0,d()}}}(()=>l.totalDuration,e=>p?.render(e),w),m=()=>"active"===c&&!i.isDestroy,h=()=>"destroyed"===c||i.isDestroy;function x(n){try{n?.pause()}catch(t){e(t)}}function b(n,t,i){try{Promise.resolve(n()).then(()=>{m()||i?.()},t).catch(e)}catch(l){t(l)}}function w(){if("ended"!==c&&"destroyed"!==c&&!i.isDestroy){if(c="ended",v.stop(),r.dispose(),y){if(b(()=>i.play(),n=>{"destroyed"!==c&&e(n)}),h())return;if(x(p?.video),h())return;p?.hide()}h()||i.emit("artplayerPluginAds:skip",l)}}function D(){const n=p?.video;if(x(n),n)try{n.removeAttribute("src"),n.load()}catch(t){e(t)}try{u?.remove()}catch(t){e(t)}finally{u&&d.$ads===u&&delete d.$ads}}function k(){"destroyed"!==c&&(c="destroyed",v.stop(),r.dispose(),s.dispose(),D())}function O(){if("waiting"===c&&!i.isDestroy){c="active",y=!0;try{if(p=function(e,n,i,l,a){const{append:o,query:r,setStyle:s}=l,d=o(e,'<div class="artplayer-plugin-ads"></div>');a(d);const u=o(d,i.video?'<video class="artplayer-plugin-ads-video" loop playsInline></video>':`<div class="artplayer-plugin-ads-html">${i.html}</div>`),p=i.video?u:null,c=o(d,'<div class="artplayer-plugin-ads-loading"></div>');o(c,n.loading);const y=o(d,'<div class="artplayer-plugin-ads-timer">\n <div class="artplayer-plugin-ads-close"></div>\n <div class="artplayer-plugin-ads-countdown"></div>\n </div>'),f=r(".artplayer-plugin-ads-close",y),g=r(".artplayer-plugin-ads-countdown",y),v=o(d,`<div class="artplayer-plugin-ads-control">\n <div class="artplayer-plugin-ads-detail">${i.i18n.detail}</div>\n <div class="artplayer-plugin-ads-muted"></div>\n <div class="artplayer-plugin-ads-fullscreen"></div>\n </div>`),m=r(".artplayer-plugin-ads-detail",v),h=r(".artplayer-plugin-ads-muted",v),x=r(".artplayer-plugin-ads-fullscreen",v);let b=i.playDuration<=0;function w(){s(n.volume,"display",p?.muted?"none":"inline-flex"),s(n.volumeClose,"display",p?.muted?"inline-flex":"none")}function D(e){const n=i.playDuration-e;b=0===e?i.playDuration<=0:n<1||Number.isNaN(n),f.innerHTML=b?i.i18n.close:t(n,i.i18n.canBeClosed),g.innerHTML=t(i.totalDuration-e,i.i18n.countdown)}return i.playDuration>=i.totalDuration&&s(f,"display","none"),i.url||s(m,"display","none"),p?(o(h,n.volume),o(h,n.volumeClose),p.muted=Boolean(i.muted),w()):s(h,"display","none"),o(x,n.fullscreenOn),o(x,n.fullscreenOff),D(0),{root:d,video:p,render:D,ready(){s(y,"display","flex"),s(v,"display","flex"),s(c,"display","none")},hide(){s(d,"display","none")},fullscreen(e){s(n.fullscreenOn,"display",e?"none":"inline-flex"),s(n.fullscreenOff,"display",e?"inline-flex":"none")},bind(e,n){e.dom(f,"click",()=>{b&&n.skip()}),e.dom(u,"click",n.click),i.url&&e.dom(m,"click",n.click),p&&e.dom(h,"click",()=>{p.muted=!p.muted,w()}),e.dom(x,"click",n.fullscreen)}}}(d.$player,a,l,o,e=>{u=e,d.$ads=e}),!m())return void D();if(i.pause(),!m())return;const n=p,s=u.ownerDocument;n.fullscreen(i.fullscreen),n.bind(r,{skip:w,click(){l.url&&(s.defaultView||window).open(l.url),m()&&i.emit("artplayerPluginAds:click",l)},fullscreen(){i.fullscreen=!i.fullscreen,m()&&n.fullscreen(i.fullscreen)}}),r.on("fullscreen",()=>n.fullscreen(i.fullscreen));const c=()=>s.hidden?v.pause():v.play();r.dom(s,"visibilitychange",c),r.on("document:visibilitychange",c);const y=()=>{if(m()&&!g){if(g=!0,v.start(),s.hidden&&v.pause(),n.video){const t=n.video;b(()=>t.play(),n=>{m()&&(e(n),w())},()=>x(t))}m()&&n.ready()}};n.video?(r.dom(n.video,"error",w),r.dom(n.video,"loadedmetadata",y),n.video.src=l.video):y()}catch(n){throw k(),n}}}try{s.on("destroy",k),r.on("ready",()=>{f||"waiting"!==c||(f=!0,r.on("play",O),r.on("video:playing",O))}),i.isDestroy&&k()}catch(A){throw k(),A}return{name:"artplayerPluginAds",skip:w,pause:v.pause,play:v.play}}function l(e){return n=>{const t=n.constructor;if("function"!==typeof t.validator||!["append","query","setStyle"].every(e=>"function"===typeof Reflect.get(t.utils||{},e)))thLine truncated
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-ads.js v2.1.0
|
||||
* artplayer-plugin-ads.js v3.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(e,l){"object"===typeof exports&&"undefined"!==typeof module?module.exports=l():"function"==typeof define&&define.amd?(t.artplayerPluginAds=l(),define(function(){return t.artplayerPluginAds})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAds=l()}(this,function(){"use strict";var e=Object.defineProperty,l=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,a=Object.prototype.propertyIsEnumerable,i=(l,n,a)=>n in l?e(l,n,{enumerable:!0,configurable:!0,writable:!0,value:a}):l[n]=a;function t(e){return r=>{!function(e){const{version:l,utils:{errorHandle:n}}=e.constructor,a=l.split(".").map(Number);n(a[0]+a[1]/100>=5,`Artplayer.js@${l} is not compatible the artplayerPluginAds@${t.version}. Please update it to version Artplayer.js@5.x.x`)}(r);const{template:{$player:o},icons:{volume:d,volumeClose:p,fullscreenOn:s,fullscreenOff:u,loading:c},constructor:{validator:y,utils:{query:g,append:f,setStyle:m}}}=r;e=y(((e,t)=>{for(var r in t||(t={}))n.call(t,r)&&i(e,r,t[r]);if(l)for(var r of l(t))a.call(t,r)&&i(e,r,t[r]);return e})({html:"",video:"",url:"",playDuration:5,totalDuration:10,muted:!1,i18n:{close:"\u5173\u95ed\u5e7f\u544a",countdown:"%s\u79d2",detail:"\u67e5\u770b\u8be6\u60c5",canBeClosed:"%s\u79d2\u540e\u53ef\u5173\u95ed\u5e7f\u544a"}},e),{html:"?string",video:"?string",url:"?string",playDuration:"number",totalDuration:"number",muted:"?boolean",i18n:{close:"string",countdown:"string",detail:"string",canBeClosed:"string"}});let v=null,x=null,h=null,b=null,w=null,$=null,k=0,D=null,P=!1,j=!1,A=!1;function O(e,l){return l.replace("%s",e)}function C(){P=!0,r.play(),e.video&&v.pause(),m(r.template.$ads,"display","none"),r.emit("artplayerPluginAds:skip",e)}function T(){P||(D=setTimeout(()=>{k+=1;const l=e.playDuration-k;l>=1?h.innerHTML=O(l,e.i18n.canBeClosed):(h.innerHTML=e.i18n.close,A||(A=!0)),b.innerHTML=O(e.totalDuration-k,e.i18n.countdown),k>=e.totalDuration?C():T()},1e3))}function B(){P||clearTimeout(D)}function H(){j||(j=!0,function(){r.template.$ads=f(o,'<div class="artplayer-plugin-ads"></div>'),v=f(r.template.$ads,e.video?`<video class="artplayer-plugin-ads-video" src="${e.video}" loop playsInline></video>`:`<div class="artplayer-plugin-ads-html">${e.html}</div>`),$=f(r.template.$ads,'<div class="artplayer-plugin-ads-loading"></div>'),f($,c),x=f(r.template.$ads,`<div class="artplayer-plugin-ads-timer">\n <div class="artplayer-plugin-ads-close">${e.playDuration<=0?e.i18n.close:O(e.playDuration,e.i18n.canBeClosed)}</div>\n <div class="artplayer-plugin-ads-countdown">${O(e.totalDuration,e.i18n.countdown)}</div>\n </div>`),h=g(".artplayer-plugin-ads-close",x),b=g(".artplayer-plugin-ads-countdown",x),e.playDuration>=e.totalDuration&&m(h,"display","none"),r.proxy(h,"click",()=>{A&&C()}),w=f(r.template.$ads,`<div class="artplayer-plugin-ads-control">\n <div class="artplayer-plugin-ads-detail">${e.i18n.detail}</div>\n <div class="artplayer-plugin-ads-muted"></div>\n <div class="artplayer-plugin-ads-fullscreen"></div>\n </div>`);const l=g(".artplayer-plugin-ads-detail",w),n=g(".artplayer-plugin-ads-muted",w),a=g(".artplayer-plugin-ads-fullscreen",w);if(e.url?r.proxy(l,"click",()=>{window.open(e.url),r.emit("artplayerPluginAds:click",e)}):m(l,"display","none"),e.video){const l=f(n,d),a=f(n,p);m(a,"display","none"),e.muted&&(v.muted=!0,m(l,"display","none"),m(a,"display","inline-flex")),r.proxy(n,"click",()=>{v.muted=!v.muted,v.muted?(m(l,"display","none"),m(a,"display","inline-flex")):(m(l,"display","inline-flex"),m(a,"display","none"))})}else m(n,"display","none");const i=f(a,s),t=f(a,u);m(t,"display","none"),r.proxy(a,"click",()=>{r.fullscreen=!r.fullscreen,r.fullscreen?(m(i,"display","inline-flex"),m(t,"display","none")):(m(i,"display","none"),m(t,"display","inline-flex"))}),r.proxy(v,"click",()=>{e.url&&window.open(e.url),r.emit("artplayerPluginAds:click",e)})}(),r.pause(),e.video?(r.proxy(v,"error",C),r.proxy(v,"loadedmetadata",()=>{T(),v.play(),m(x,"display","flex"),m(w,"display","flex"),m($,"display","none")})):(T(),m(x,"display","flex"),m(w,"display","flex"),m($,"display","none")),r.on("document:visibilitychange",()=>{document.hidden?B():T()}))}return r.on("ready",()=>{r.once("play",H),r.once("video:playing",H)}),{name:"artplayerPluginAds",skip:C,pause:B,play:T}}}if("undefined"!==typeof document&&!document.getElementById("artplayer-plugin-ads")){const e=document.createElement("style");e.id="artplayer-plugin-ads",e.textContent=".artplayer-plugin-ads{position:absolute;z-index:150;inset:0;width:100%;height:100%;overflow:hidden;font-size:13px;line-height:1;color:#fff;background-color:#000}.artplayer-plugin-ads .artplayer-plugin-ads-html{display:flex;align-items:center;justify-content:center;width:100%;height:100%}.artplayer-plugin-ads .artplayer-plugin-ads-video{width:100%;height:100%}.artplayer-plugin-ads .artplayer-plugin-ads-timer{display:noneLine truncated
|
||||
!function(e,n){"object"===typeof exports&&"undefined"!==typeof module?module.exports=n():"function"==typeof define&&define.amd?(e.artplayerPluginAds=n(),define(function(){return e.artplayerPluginAds})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAds=n()}(this,function(){"use strict";var e=Object.defineProperty,n=Object.getOwnPropertySymbols,t=Object.prototype.hasOwnProperty,l=Object.prototype.propertyIsEnumerable,i=(n,t,l)=>t in n?e(n,t,{enumerable:!0,configurable:!0,writable:!0,value:l}):n[t]=l;function r(e,r){return r(((e,r)=>{for(var o in r||(r={}))t.call(r,o)&&i(e,o,r[o]);if(n)for(var o of n(r))l.call(r,o)&&i(e,o,r[o]);return e})({html:"",video:"",url:"",playDuration:5,totalDuration:10,muted:!1,i18n:{close:"\u5173\u95ed\u5e7f\u544a",countdown:"%s\u79d2",detail:"\u67e5\u770b\u8be6\u60c5",canBeClosed:"%s\u79d2\u540e\u53ef\u5173\u95ed\u5e7f\u544a"}},e),{html:"?string",video:"?string",url:"?string",playDuration:"number",totalDuration:"number",muted:"?boolean",i18n:{close:"string",countdown:"string",detail:"string",canBeClosed:"string"}})}function o(e){console.warn("Artplayer Ads:",e)}function a(e){const n=[];let t=!1;function l(e,l){if(!t){n.push(l);try{e()}finally{t&&l()}}}return{on(n,i){const r=()=>{t||i()};l(()=>{e.on(n,r)},()=>{e.off(n,r)})},dom(e,n,i){const r=()=>{t||i()};l(()=>e.addEventListener(n,r),()=>e.removeEventListener(n,r))},dispose(){if(!t){t=!0;for(const t of n.splice(0).reverse())try{t()}catch(e){o(e)}}}}}const s=(e,n)=>n.replace("%s",String(e));function d(e,n,t,l){const i=a(e),r=a(e),d=e.template;let u,p,c="waiting",y=!1,f=!1,g=!1;const v=function(e,n,t){let l,i=0,r=!1,o=!1,a=!1;function s(){r&&o&&!a&&void 0===l&&(l=setTimeout(()=>{l=void 0,!a&&o&&(i+=1,n(i),a||(i>=e()?t():s()))},1e3))}function d(){o=!1,void 0!==l&&clearTimeout(l),l=void 0}return{start(){r||a||(r=!0,o=!0,s())},play(){r&&!a&&(o=!0,s())},pause:d,stop(){a=!0,d()}}}(()=>n.totalDuration,e=>null==p?void 0:p.render(e),w),m=()=>"active"===c&&!e.isDestroy,h=()=>"destroyed"===c||e.isDestroy;function b(e){try{null==e||e.pause()}catch(n){o(n)}}function x(e,n,t){try{Promise.resolve(e()).then(()=>{m()||null==t||t()},n).catch(o)}catch(l){n(l)}}function w(){if("ended"!==c&&"destroyed"!==c&&!e.isDestroy){if(c="ended",v.stop(),i.dispose(),y){if(x(()=>e.play(),e=>{"destroyed"!==c&&o(e)}),h())return;if(b(null==p?void 0:p.video),h())return;null==p||p.hide()}h()||e.emit("artplayerPluginAds:skip",n)}}function D(){const e=null==p?void 0:p.video;if(b(e),e)try{e.removeAttribute("src"),e.load()}catch(n){o(n)}try{null==u||u.remove()}catch(n){o(n)}finally{u&&d.$ads===u&&delete d.$ads}}function k(){"destroyed"!==c&&(c="destroyed",v.stop(),i.dispose(),r.dispose(),D())}function O(){if("waiting"===c&&!e.isDestroy){c="active",y=!0;try{if(p=function(e,n,t,l,i){const{append:r,query:o,setStyle:a}=l,d=r(e,'<div class="artplayer-plugin-ads"></div>');i(d);const u=r(d,t.video?'<video class="artplayer-plugin-ads-video" loop playsInline></video>':`<div class="artplayer-plugin-ads-html">${t.html}</div>`),p=t.video?u:null,c=r(d,'<div class="artplayer-plugin-ads-loading"></div>');r(c,n.loading);const y=r(d,'<div class="artplayer-plugin-ads-timer">\n <div class="artplayer-plugin-ads-close"></div>\n <div class="artplayer-plugin-ads-countdown"></div>\n </div>'),f=o(".artplayer-plugin-ads-close",y),g=o(".artplayer-plugin-ads-countdown",y),v=r(d,`<div class="artplayer-plugin-ads-control">\n <div class="artplayer-plugin-ads-detail">${t.i18n.detail}</div>\n <div class="artplayer-plugin-ads-muted"></div>\n <div class="artplayer-plugin-ads-fullscreen"></div>\n </div>`),m=o(".artplayer-plugin-ads-detail",v),h=o(".artplayer-plugin-ads-muted",v),b=o(".artplayer-plugin-ads-fullscreen",v);let x=t.playDuration<=0;function w(){a(n.volume,"display",(null==p?void 0:p.muted)?"none":"inline-flex"),a(n.volumeClose,"display",(null==p?void 0:p.muted)?"inline-flex":"none")}function D(e){const n=t.playDuration-e;x=0===e?t.playDuration<=0:n<1||Number.isNaN(n),f.innerHTML=x?t.i18n.close:s(n,t.i18n.canBeClosed),g.innerHTML=s(t.totalDuration-e,t.i18n.countdown)}return t.playDuration>=t.totalDuration&&a(f,"display","none"),t.url||a(m,"display","none"),p?(r(h,n.volume),r(h,n.volumeClose),p.muted=Boolean(t.muted),w()):a(h,"display","none"),r(b,n.fullscreenOn),r(b,n.fullscreenOff),D(0),{root:d,video:p,render:D,ready(){a(y,"display","flex"),a(v,"display","flex"),a(c,"display","none")},hide(){a(d,"display","none")},fullscreen(e){a(n.fullscreenOn,"display",e?"none":"inline-flex"),a(n.fullscreenOff,"display",e?"inline-flex":"none")},bind(e,n){e.dom(f,"click",()=>{x&&n.skip()}),e.dom(u,"click",n.click),t.url&&e.dom(m,"click",n.click),p&&e.dom(h,"click",()=>{p.muted=!p.muted,w()}),e.dom(b,"click",n.fullscreen)}}}(d.$player,t,n,l,e=>{u=e,d.$ads=e}),!m())return void D();if(e.pause(),!m())return;const r=p,a=u.ownerDocument;r.fullscreen(e.fullscreen),r.bind(i,{skip:w,click(){n.url&&(a.defaultView||window).open(n.url),m()&&e.emit("artplayerPluginAds:click",n)},fullscrLine truncated
|
||||
@@ -1,251 +1,402 @@
|
||||
/*!
|
||||
* artplayer-plugin-ads.js v2.1.0
|
||||
* artplayer-plugin-ads.js v3.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
const style = ".artplayer-plugin-ads {\n position: absolute;\n z-index: 150;\n left: 0;\n top: 0;\n right: 0;\n bottom: 0;\n width: 100%;\n height: 100%;\n overflow: hidden;\n font-size: 13px;\n line-height: 1;\n color: #fff;\n background-color: #000;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-html {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-video {\n width: 100%;\n height: 100%;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-timer {\n display: none;\n position: absolute;\n top: 10px;\n right: 10px;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-timer > div {\n display: flex;\n align-items: center;\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: 15px;\n margin-left: 5px;\n padding: 5px 10px;\n cursor: pointer;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-control {\n display: none;\n position: absolute;\n bottom: 10px;\n right: 10px;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-control > div {\n display: flex;\n align-items: center;\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: 15px;\n margin-left: 5px;\n padding: 5px 10px;\n cursor: pointer;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-control .art-icon svg {\n width: 20px;\n height: 20px;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n left: 0;\n top: 0;\n right: 0;\n bottom: 0;\n width: 100%;\n height: 100%;\n}\n";
|
||||
function checkVersion(art) {
|
||||
const {
|
||||
version,
|
||||
utils: { errorHandle }
|
||||
} = art.constructor;
|
||||
const arr = version.split(".").map(Number);
|
||||
const major = arr[0];
|
||||
const minor = arr[1] / 100;
|
||||
errorHandle(
|
||||
major + minor >= 5,
|
||||
`Artplayer.js@${version} is not compatible the artplayerPluginAds@${artplayerPluginAds.version}. Please update it to version Artplayer.js@5.x.x`
|
||||
);
|
||||
function normalizeOptions(input, validate) {
|
||||
return validate({
|
||||
html: "",
|
||||
video: "",
|
||||
url: "",
|
||||
playDuration: 5,
|
||||
totalDuration: 10,
|
||||
muted: false,
|
||||
i18n: {
|
||||
close: "关闭广告",
|
||||
countdown: "%s秒",
|
||||
detail: "查看详情",
|
||||
canBeClosed: "%s秒后可关闭广告"
|
||||
},
|
||||
...input
|
||||
}, {
|
||||
html: "?string",
|
||||
video: "?string",
|
||||
url: "?string",
|
||||
playDuration: "number",
|
||||
totalDuration: "number",
|
||||
muted: "?boolean",
|
||||
i18n: { close: "string", countdown: "string", detail: "string", canBeClosed: "string" }
|
||||
});
|
||||
}
|
||||
function artplayerPluginAds(option) {
|
||||
return (art) => {
|
||||
checkVersion(art);
|
||||
const {
|
||||
template: { $player },
|
||||
icons: { volume, volumeClose, fullscreenOn, fullscreenOff, loading },
|
||||
constructor: {
|
||||
validator,
|
||||
utils: { query, append, setStyle }
|
||||
}
|
||||
} = art;
|
||||
option = validator(
|
||||
{
|
||||
html: "",
|
||||
video: "",
|
||||
url: "",
|
||||
playDuration: 5,
|
||||
totalDuration: 10,
|
||||
muted: false,
|
||||
i18n: {
|
||||
close: "关闭广告",
|
||||
countdown: "%s秒",
|
||||
detail: "查看详情",
|
||||
canBeClosed: "%s秒后可关闭广告"
|
||||
},
|
||||
...option
|
||||
},
|
||||
{
|
||||
html: "?string",
|
||||
video: "?string",
|
||||
url: "?string",
|
||||
playDuration: "number",
|
||||
totalDuration: "number",
|
||||
muted: "?boolean",
|
||||
i18n: {
|
||||
close: "string",
|
||||
countdown: "string",
|
||||
detail: "string",
|
||||
canBeClosed: "string"
|
||||
}
|
||||
}
|
||||
);
|
||||
let $ads = null;
|
||||
let $timer = null;
|
||||
let $close = null;
|
||||
let $countdown = null;
|
||||
let $control = null;
|
||||
let $loading = null;
|
||||
let time = 0;
|
||||
let timer = null;
|
||||
let isEnd = false;
|
||||
let isInit = false;
|
||||
let isCanClose = false;
|
||||
function getI18n(val, str) {
|
||||
return str.replace("%s", val);
|
||||
}
|
||||
function skip() {
|
||||
isEnd = true;
|
||||
art.play();
|
||||
if (option.video)
|
||||
$ads.pause();
|
||||
setStyle(art.template.$ads, "display", "none");
|
||||
art.emit("artplayerPluginAds:skip", option);
|
||||
}
|
||||
function play() {
|
||||
if (isEnd)
|
||||
function createCountdown(total, render, complete) {
|
||||
let elapsed = 0;
|
||||
let ready = false;
|
||||
let running = false;
|
||||
let closed = false;
|
||||
let timer;
|
||||
function schedule() {
|
||||
if (!ready || !running || closed || timer !== void 0)
|
||||
return;
|
||||
timer = setTimeout(() => {
|
||||
timer = void 0;
|
||||
if (closed || !running)
|
||||
return;
|
||||
timer = setTimeout(() => {
|
||||
time += 1;
|
||||
const playDuration = option.playDuration - time;
|
||||
if (playDuration >= 1) {
|
||||
$close.innerHTML = getI18n(playDuration, option.i18n.canBeClosed);
|
||||
} else {
|
||||
$close.innerHTML = option.i18n.close;
|
||||
if (!isCanClose) {
|
||||
isCanClose = true;
|
||||
}
|
||||
}
|
||||
$countdown.innerHTML = getI18n(option.totalDuration - time, option.i18n.countdown);
|
||||
if (time >= option.totalDuration) {
|
||||
skip();
|
||||
} else {
|
||||
play();
|
||||
}
|
||||
}, 1e3);
|
||||
}
|
||||
function pause() {
|
||||
if (isEnd)
|
||||
elapsed += 1;
|
||||
render(elapsed);
|
||||
if (closed)
|
||||
return;
|
||||
if (elapsed >= total())
|
||||
complete();
|
||||
else
|
||||
schedule();
|
||||
}, 1e3);
|
||||
}
|
||||
function pause() {
|
||||
running = false;
|
||||
if (timer !== void 0)
|
||||
clearTimeout(timer);
|
||||
}
|
||||
function show() {
|
||||
art.template.$ads = append($player, '<div class="artplayer-plugin-ads"></div>');
|
||||
$ads = append(
|
||||
art.template.$ads,
|
||||
option.video ? `<video class="artplayer-plugin-ads-video" src="${option.video}" loop playsInline></video>` : `<div class="artplayer-plugin-ads-html">${option.html}</div>`
|
||||
);
|
||||
$loading = append(art.template.$ads, '<div class="artplayer-plugin-ads-loading"></div>');
|
||||
append($loading, loading);
|
||||
$timer = append(
|
||||
art.template.$ads,
|
||||
`<div class="artplayer-plugin-ads-timer">
|
||||
<div class="artplayer-plugin-ads-close">${option.playDuration <= 0 ? option.i18n.close : getI18n(option.playDuration, option.i18n.canBeClosed)}</div>
|
||||
<div class="artplayer-plugin-ads-countdown">${getI18n(
|
||||
option.totalDuration,
|
||||
option.i18n.countdown
|
||||
)}</div>
|
||||
</div>`
|
||||
);
|
||||
$close = query(".artplayer-plugin-ads-close", $timer);
|
||||
$countdown = query(".artplayer-plugin-ads-countdown", $timer);
|
||||
if (option.playDuration >= option.totalDuration) {
|
||||
setStyle($close, "display", "none");
|
||||
}
|
||||
art.proxy($close, "click", () => {
|
||||
if (isCanClose) {
|
||||
skip();
|
||||
}
|
||||
});
|
||||
$control = append(
|
||||
art.template.$ads,
|
||||
`<div class="artplayer-plugin-ads-control">
|
||||
<div class="artplayer-plugin-ads-detail">${option.i18n.detail}</div>
|
||||
<div class="artplayer-plugin-ads-muted"></div>
|
||||
<div class="artplayer-plugin-ads-fullscreen"></div>
|
||||
</div>`
|
||||
);
|
||||
const $detail = query(".artplayer-plugin-ads-detail", $control);
|
||||
const $muted = query(".artplayer-plugin-ads-muted", $control);
|
||||
const $fullscreen = query(".artplayer-plugin-ads-fullscreen", $control);
|
||||
if (option.url) {
|
||||
art.proxy($detail, "click", () => {
|
||||
window.open(option.url);
|
||||
art.emit("artplayerPluginAds:click", option);
|
||||
});
|
||||
} else {
|
||||
setStyle($detail, "display", "none");
|
||||
}
|
||||
if (option.video) {
|
||||
const $volume = append($muted, volume);
|
||||
const $volumeClose = append($muted, volumeClose);
|
||||
setStyle($volumeClose, "display", "none");
|
||||
if (option.muted) {
|
||||
$ads.muted = true;
|
||||
setStyle($volume, "display", "none");
|
||||
setStyle($volumeClose, "display", "inline-flex");
|
||||
}
|
||||
art.proxy($muted, "click", () => {
|
||||
$ads.muted = !$ads.muted;
|
||||
if ($ads.muted) {
|
||||
setStyle($volume, "display", "none");
|
||||
setStyle($volumeClose, "display", "inline-flex");
|
||||
} else {
|
||||
setStyle($volume, "display", "inline-flex");
|
||||
setStyle($volumeClose, "display", "none");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
setStyle($muted, "display", "none");
|
||||
}
|
||||
const $fullscreenOn = append($fullscreen, fullscreenOn);
|
||||
const $fullscreenOff = append($fullscreen, fullscreenOff);
|
||||
setStyle($fullscreenOff, "display", "none");
|
||||
art.proxy($fullscreen, "click", () => {
|
||||
art.fullscreen = !art.fullscreen;
|
||||
if (art.fullscreen) {
|
||||
setStyle($fullscreenOn, "display", "inline-flex");
|
||||
setStyle($fullscreenOff, "display", "none");
|
||||
} else {
|
||||
setStyle($fullscreenOn, "display", "none");
|
||||
setStyle($fullscreenOff, "display", "inline-flex");
|
||||
}
|
||||
});
|
||||
art.proxy($ads, "click", () => {
|
||||
if (option.url)
|
||||
window.open(option.url);
|
||||
art.emit("artplayerPluginAds:click", option);
|
||||
});
|
||||
}
|
||||
function init() {
|
||||
if (isInit)
|
||||
timer = void 0;
|
||||
}
|
||||
return {
|
||||
start() {
|
||||
if (ready || closed)
|
||||
return;
|
||||
isInit = true;
|
||||
show();
|
||||
art.pause();
|
||||
if (option.video) {
|
||||
art.proxy($ads, "error", skip);
|
||||
art.proxy($ads, "loadedmetadata", () => {
|
||||
play();
|
||||
$ads.play();
|
||||
setStyle($timer, "display", "flex");
|
||||
setStyle($control, "display", "flex");
|
||||
setStyle($loading, "display", "none");
|
||||
});
|
||||
} else {
|
||||
play();
|
||||
setStyle($timer, "display", "flex");
|
||||
setStyle($control, "display", "flex");
|
||||
setStyle($loading, "display", "none");
|
||||
}
|
||||
art.on("document:visibilitychange", () => {
|
||||
if (document.hidden) {
|
||||
pause();
|
||||
} else {
|
||||
play();
|
||||
}
|
||||
});
|
||||
ready = true;
|
||||
running = true;
|
||||
schedule();
|
||||
},
|
||||
play() {
|
||||
if (!ready || closed)
|
||||
return;
|
||||
running = true;
|
||||
schedule();
|
||||
},
|
||||
pause,
|
||||
stop() {
|
||||
closed = true;
|
||||
pause();
|
||||
}
|
||||
art.on("ready", () => {
|
||||
art.once("play", init);
|
||||
art.once("video:playing", init);
|
||||
});
|
||||
return {
|
||||
name: "artplayerPluginAds",
|
||||
skip,
|
||||
pause,
|
||||
play
|
||||
};
|
||||
};
|
||||
}
|
||||
if (typeof document !== "undefined") {
|
||||
if (!document.getElementById("artplayer-plugin-ads")) {
|
||||
const $style = document.createElement("style");
|
||||
$style.id = "artplayer-plugin-ads";
|
||||
$style.textContent = style;
|
||||
document.head.appendChild($style);
|
||||
function report(error) {
|
||||
console.warn("Artplayer Ads:", error);
|
||||
}
|
||||
function createResources(host) {
|
||||
const cleaners = [];
|
||||
let closed = false;
|
||||
function install(add, remove) {
|
||||
if (closed)
|
||||
return;
|
||||
cleaners.push(remove);
|
||||
try {
|
||||
add();
|
||||
} finally {
|
||||
if (closed)
|
||||
remove();
|
||||
}
|
||||
}
|
||||
return {
|
||||
on(name, callback) {
|
||||
const listener = () => {
|
||||
if (!closed)
|
||||
callback();
|
||||
};
|
||||
install(() => {
|
||||
host.on(name, listener);
|
||||
}, () => {
|
||||
host.off(name, listener);
|
||||
});
|
||||
},
|
||||
dom(target, name, callback) {
|
||||
const listener = () => {
|
||||
if (!closed)
|
||||
callback();
|
||||
};
|
||||
install(() => target.addEventListener(name, listener), () => target.removeEventListener(name, listener));
|
||||
},
|
||||
dispose() {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
for (const clean of cleaners.splice(0).reverse()) {
|
||||
try {
|
||||
clean();
|
||||
} catch (error) {
|
||||
report(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
const translate = (value, text) => text.replace("%s", String(value));
|
||||
function createView(parent, icons, option, utils, own) {
|
||||
const { append, query, setStyle } = utils;
|
||||
const root = append(parent, '<div class="artplayer-plugin-ads"></div>');
|
||||
own(root);
|
||||
const content = append(root, option.video ? '<video class="artplayer-plugin-ads-video" loop playsInline></video>' : `<div class="artplayer-plugin-ads-html">${option.html}</div>`);
|
||||
const video = option.video ? content : null;
|
||||
const loading = append(root, '<div class="artplayer-plugin-ads-loading"></div>');
|
||||
append(loading, icons.loading);
|
||||
const timer = append(root, `<div class="artplayer-plugin-ads-timer">
|
||||
<div class="artplayer-plugin-ads-close"></div>
|
||||
<div class="artplayer-plugin-ads-countdown"></div>
|
||||
</div>`);
|
||||
const close = query(".artplayer-plugin-ads-close", timer);
|
||||
const countdown = query(".artplayer-plugin-ads-countdown", timer);
|
||||
const control = append(root, `<div class="artplayer-plugin-ads-control">
|
||||
<div class="artplayer-plugin-ads-detail">${option.i18n.detail}</div>
|
||||
<div class="artplayer-plugin-ads-muted"></div>
|
||||
<div class="artplayer-plugin-ads-fullscreen"></div>
|
||||
</div>`);
|
||||
const detail = query(".artplayer-plugin-ads-detail", control);
|
||||
const muted = query(".artplayer-plugin-ads-muted", control);
|
||||
const fullscreen = query(".artplayer-plugin-ads-fullscreen", control);
|
||||
let canClose = option.playDuration <= 0;
|
||||
if (option.playDuration >= option.totalDuration)
|
||||
setStyle(close, "display", "none");
|
||||
if (!option.url)
|
||||
setStyle(detail, "display", "none");
|
||||
if (video) {
|
||||
append(muted, icons.volume);
|
||||
append(muted, icons.volumeClose);
|
||||
video.muted = Boolean(option.muted);
|
||||
syncMuted();
|
||||
} else {
|
||||
setStyle(muted, "display", "none");
|
||||
}
|
||||
append(fullscreen, icons.fullscreenOn);
|
||||
append(fullscreen, icons.fullscreenOff);
|
||||
function syncMuted() {
|
||||
setStyle(icons.volume, "display", video?.muted ? "none" : "inline-flex");
|
||||
setStyle(icons.volumeClose, "display", video?.muted ? "inline-flex" : "none");
|
||||
}
|
||||
function render(elapsed) {
|
||||
const remaining = option.playDuration - elapsed;
|
||||
canClose = elapsed === 0 ? option.playDuration <= 0 : remaining < 1 || Number.isNaN(remaining);
|
||||
close.innerHTML = canClose ? option.i18n.close : translate(remaining, option.i18n.canBeClosed);
|
||||
countdown.innerHTML = translate(option.totalDuration - elapsed, option.i18n.countdown);
|
||||
}
|
||||
render(0);
|
||||
return {
|
||||
root,
|
||||
video,
|
||||
render,
|
||||
ready() {
|
||||
setStyle(timer, "display", "flex");
|
||||
setStyle(control, "display", "flex");
|
||||
setStyle(loading, "display", "none");
|
||||
},
|
||||
hide() {
|
||||
setStyle(root, "display", "none");
|
||||
},
|
||||
fullscreen(active) {
|
||||
setStyle(icons.fullscreenOn, "display", active ? "none" : "inline-flex");
|
||||
setStyle(icons.fullscreenOff, "display", active ? "inline-flex" : "none");
|
||||
},
|
||||
bind(events, callbacks) {
|
||||
events.dom(close, "click", () => {
|
||||
if (canClose)
|
||||
callbacks.skip();
|
||||
});
|
||||
events.dom(content, "click", callbacks.click);
|
||||
if (option.url)
|
||||
events.dom(detail, "click", callbacks.click);
|
||||
if (video) {
|
||||
events.dom(muted, "click", () => {
|
||||
video.muted = !video.muted;
|
||||
syncMuted();
|
||||
});
|
||||
}
|
||||
events.dom(fullscreen, "click", callbacks.fullscreen);
|
||||
}
|
||||
};
|
||||
}
|
||||
function createSession(art, option, icons, utils) {
|
||||
const events = createResources(art);
|
||||
const lifetime = createResources(art);
|
||||
const template = art.template;
|
||||
let state = "waiting";
|
||||
let initialized = false;
|
||||
let armed = false;
|
||||
let mediaReady = false;
|
||||
let root;
|
||||
let view;
|
||||
const clock = createCountdown(() => option.totalDuration, (time) => view?.render(time), skip);
|
||||
const active = () => state === "active" && !art.isDestroy;
|
||||
const destroyed = () => state === "destroyed" || art.isDestroy;
|
||||
function pauseVideo(video) {
|
||||
try {
|
||||
video?.pause();
|
||||
} catch (error) {
|
||||
report(error);
|
||||
}
|
||||
}
|
||||
function requestPlay(start, rejected, late) {
|
||||
try {
|
||||
Promise.resolve(start()).then(() => {
|
||||
if (!active())
|
||||
late?.();
|
||||
}, rejected).catch(report);
|
||||
} catch (error) {
|
||||
rejected(error);
|
||||
}
|
||||
}
|
||||
function skip() {
|
||||
if (state === "ended" || state === "destroyed" || art.isDestroy)
|
||||
return;
|
||||
state = "ended";
|
||||
clock.stop();
|
||||
events.dispose();
|
||||
if (initialized) {
|
||||
requestPlay(() => art.play(), (error) => {
|
||||
if (state !== "destroyed")
|
||||
report(error);
|
||||
});
|
||||
if (destroyed())
|
||||
return;
|
||||
pauseVideo(view?.video);
|
||||
if (destroyed())
|
||||
return;
|
||||
view?.hide();
|
||||
}
|
||||
if (!destroyed())
|
||||
art.emit("artplayerPluginAds:skip", option);
|
||||
}
|
||||
function disposeView() {
|
||||
const video = view?.video;
|
||||
pauseVideo(video);
|
||||
if (video) {
|
||||
try {
|
||||
video.removeAttribute("src");
|
||||
video.load();
|
||||
} catch (error) {
|
||||
report(error);
|
||||
}
|
||||
}
|
||||
try {
|
||||
root?.remove();
|
||||
} catch (error) {
|
||||
report(error);
|
||||
} finally {
|
||||
if (root && template.$ads === root)
|
||||
delete template.$ads;
|
||||
}
|
||||
}
|
||||
function destroy() {
|
||||
if (state === "destroyed")
|
||||
return;
|
||||
state = "destroyed";
|
||||
clock.stop();
|
||||
events.dispose();
|
||||
lifetime.dispose();
|
||||
disposeView();
|
||||
}
|
||||
function init() {
|
||||
if (state !== "waiting" || art.isDestroy)
|
||||
return;
|
||||
state = "active";
|
||||
initialized = true;
|
||||
try {
|
||||
view = createView(template.$player, icons, option, utils, (node) => {
|
||||
root = node;
|
||||
template.$ads = node;
|
||||
});
|
||||
if (!active()) {
|
||||
disposeView();
|
||||
return;
|
||||
}
|
||||
art.pause();
|
||||
if (!active())
|
||||
return;
|
||||
const current = view;
|
||||
const document2 = root.ownerDocument;
|
||||
current.fullscreen(art.fullscreen);
|
||||
current.bind(events, {
|
||||
skip,
|
||||
click() {
|
||||
if (option.url)
|
||||
(document2.defaultView || window).open(option.url);
|
||||
if (active())
|
||||
art.emit("artplayerPluginAds:click", option);
|
||||
},
|
||||
fullscreen() {
|
||||
art.fullscreen = !art.fullscreen;
|
||||
if (active())
|
||||
current.fullscreen(art.fullscreen);
|
||||
}
|
||||
});
|
||||
events.on("fullscreen", () => current.fullscreen(art.fullscreen));
|
||||
const visibility = () => document2.hidden ? clock.pause() : clock.play();
|
||||
events.dom(document2, "visibilitychange", visibility);
|
||||
events.on("document:visibilitychange", visibility);
|
||||
const ready = () => {
|
||||
if (!active() || mediaReady)
|
||||
return;
|
||||
mediaReady = true;
|
||||
clock.start();
|
||||
if (document2.hidden)
|
||||
clock.pause();
|
||||
if (current.video) {
|
||||
const video = current.video;
|
||||
requestPlay(() => video.play(), (error) => {
|
||||
if (active()) {
|
||||
report(error);
|
||||
skip();
|
||||
}
|
||||
}, () => pauseVideo(video));
|
||||
}
|
||||
if (active())
|
||||
current.ready();
|
||||
};
|
||||
if (current.video) {
|
||||
events.dom(current.video, "error", skip);
|
||||
events.dom(current.video, "loadedmetadata", ready);
|
||||
current.video.src = option.video;
|
||||
} else {
|
||||
ready();
|
||||
}
|
||||
} catch (error) {
|
||||
destroy();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
try {
|
||||
lifetime.on("destroy", destroy);
|
||||
events.on("ready", () => {
|
||||
if (armed || state !== "waiting")
|
||||
return;
|
||||
armed = true;
|
||||
events.on("play", init);
|
||||
events.on("video:playing", init);
|
||||
});
|
||||
if (art.isDestroy)
|
||||
destroy();
|
||||
} catch (error) {
|
||||
destroy();
|
||||
throw error;
|
||||
}
|
||||
return { name: "artplayerPluginAds", skip, pause: clock.pause, play: clock.play };
|
||||
}
|
||||
const style = ".artplayer-plugin-ads {\n position: absolute;\n z-index: 150;\n left: 0;\n top: 0;\n right: 0;\n bottom: 0;\n width: 100%;\n height: 100%;\n overflow: hidden;\n font-size: 13px;\n line-height: 1;\n color: #fff;\n background-color: #000;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-html {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-video {\n width: 100%;\n height: 100%;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-timer {\n display: none;\n position: absolute;\n top: 10px;\n right: 10px;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-timer > div {\n display: flex;\n align-items: center;\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: 15px;\n margin-left: 5px;\n padding: 5px 10px;\n cursor: pointer;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-control {\n display: none;\n position: absolute;\n bottom: 10px;\n right: 10px;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-control > div {\n display: flex;\n align-items: center;\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: 15px;\n margin-left: 5px;\n padding: 5px 10px;\n cursor: pointer;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-control .art-icon svg {\n width: 20px;\n height: 20px;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n left: 0;\n top: 0;\n right: 0;\n bottom: 0;\n width: 100%;\n height: 100%;\n}\n";
|
||||
function artplayerPluginAds(input) {
|
||||
return (art) => {
|
||||
const constructor = art.constructor;
|
||||
if (typeof constructor.validator !== "function" || !["append", "query", "setStyle"].every((name) => typeof Reflect.get(constructor.utils || {}, name) === "function")) {
|
||||
throw new Error("Artplayer Ads requires the core validator and DOM utilities");
|
||||
}
|
||||
const option = normalizeOptions(input, constructor.validator);
|
||||
const { volume, volumeClose, fullscreenOn, fullscreenOff, loading } = art.icons;
|
||||
return createSession(art, option, { volume, volumeClose, fullscreenOn, fullscreenOff, loading }, constructor.utils);
|
||||
};
|
||||
}
|
||||
const index = Object.assign(artplayerPluginAds, { default: artplayerPluginAds });
|
||||
if (typeof document !== "undefined" && !document.getElementById("artplayer-plugin-ads")) {
|
||||
const element = document.createElement("style");
|
||||
element.id = "artplayer-plugin-ads";
|
||||
element.textContent = style;
|
||||
document.head.appendChild(element);
|
||||
}
|
||||
export {
|
||||
artplayerPluginAds as default
|
||||
index as default
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-ambilight.js v1.1.0
|
||||
* artplayer-plugin-ambilight.js v2.0.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.artplayerPluginAmbilight=t(),define(function(){return t.artplayerPluginAmbilight})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAmbilight=t()}(this,function(){"use strict";return function(e={}){return t=>{const{$video:n}=t.template,{createElement:r,addClass:i,setStyles:o}=t.constructor.utils,{blur:a="50px",opacity:l=.5,frequency:u=10,duration:f=.3}=e,s=r("div"),d=((c=s).innerHTML=Array.from({length:9}).fill("<div></div>").join(""),Array.from(c.children));var c,m,p,g;!function(e,t){i(e,"artplayer-plugin-ambilight"),t.parentNode.insertBefore(e,t),o(e,{position:"absolute",top:0,left:0,zIndex:9,inset:0,display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gridTemplateRows:"1fr 1fr 1fr"})}(s,n),m=a,p=l,g=f,d.forEach(e=>{o(e,{opacity:p,filter:`blur(${m})`,transition:`background-color ${g}s ease`})});const y=function(e,n,i){const o=r("canvas"),a=o.getContext("2d");o.width=3,o.height=3;let l=0;return function r(){const o=performance.now();if(o-l<1e3/i||!t.playing)return void(h=requestAnimationFrame(r));l=o;const u=e.videoWidth/3,f=e.videoHeight/3,s=[[0,0],[u,0],[2*u,0],[0,f],[u,f],[2*u,f],[0,2*f],[u,2*f],[2*u,2*f]].map(([t,n])=>function(t,n,r,i){a.drawImage(e,t,n,r,i,0,0,1,1);const[o,l,u]=a.getImageData(0,0,1,1).data;return`rgb(${o}, ${l}, ${u})`}(t,n,u,f));n.forEach((e,t)=>{e.style.backgroundColor=s[t]}),h=requestAnimationFrame(r)}}(n,d,u);let h=null;function b(){h||y()}function v(){h&&(cancelAnimationFrame(h),h=null)}return t.on("ready",b),t.on("destroy",v),{name:"artplayerPluginAmbilight",start:b,stop:v}}}});
|
||||
!function(t,n){"object"===typeof exports&&"undefined"!==typeof module?module.exports=n():"function"==typeof define&&define.amd?(t.artplayerPluginAmbilight=n(),define(function(){return t.artplayerPluginAmbilight})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginAmbilight=n()}(this,function(){"use strict";function t(t,n,e){let r="stopped",i=null,o=0,l=!1,u=0;function c(){const s=o,f=()=>"running"===r&&s===o;l=!0;try{const r=performance.now();if(r-u<1e3/t||!n()||!f())return;u=r,e(f)}finally{l=!1,"running"===r&&null===i&&function(){const t=o;try{i=requestAnimationFrame(()=>{"running"===r&&t===o&&(i=null,c())})}catch(n){throw r="stopped",o++,n}}()}}return{start:function(){"stopped"===r&&(r="running",o++,l||c())},stop:function(){if("destroyed"===r)return;r="stopped",o++;const t=i;i=null,null!==t&&cancelAnimationFrame(t)},destroy:function(){if("destroyed"===r)return;r="destroyed",o++;const t=i;i=null,null!==t&&cancelAnimationFrame(t)}}}function n(n={}){return e=>{let r=e,i=e.isDestroy,o=null,l=null,u=null;const c=[],s={name:"artplayerPluginAmbilight",start(){i||u?.start()},stop(){i||u?.stop()}};if(i)return r=null,s;function f(){const t=[u?.destroy,l?.destroy,o?.destroy];u=null,l=null,o=null;const n=[];for(const r of t)try{r?.()}catch(e){n.push(e)}if(n.length)throw n[0]}function a(){if(i)return;i=!0;const t=r;r=null;const n=[];for(const[r,i]of c.splice(0))try{t?.off(r,i)}catch(e){n.push(e)}try{f()}catch(e){n.push(e)}if(n.length)throw n[0]}function d(t,n){c.push([t,n]),r?.on(t,n)}try{if(d("destroy",a),i)return s;const{$video:c}=e.template,h=e.constructor.utils,{blur:y="50px",opacity:p=.5,frequency:g=10,duration:m=.3}=n;if(i)return s;if(o=function(t){const n=t.createElement("div");n.innerHTML=Array.from({length:9}).fill("<div></div>").join("");const e=Array.from(n.children);return{mount:function(r,i,o){if(o()&&(t.addClass(n,"artplayer-plugin-ambilight"),o()&&(r.parentNode.insertBefore(n,r),o()))){t.setStyles(n,{position:"absolute",top:0,left:0,zIndex:9,inset:0,display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gridTemplateRows:"1fr 1fr 1fr"});for(const n of e){if(!o())return;t.setStyles(n,{opacity:i.opacity,filter:`blur(${i.blur})`,transition:`background-color ${i.duration}s ease`})}}},render:function(t,n){for(let r=0;r<t.length;r++){if(!n())return;const i=e[r],o=t[r];i&&void 0!==o&&(i.style.backgroundColor=o)}},destroy:function(){try{n.parentNode?.removeChild(n)}finally{e.length=0}}}}(h),i||o.mount(c,{blur:y,opacity:p,duration:m},()=>!i),i)return f(),s;const b=h.createElement("canvas");if(i)return b.width=0,b.height=0,s;if(l=function(t,n,e){let r;try{r=t.getContext("2d"),t.width=3,t.height=3}catch(l){throw t.width=0,t.height=0,l}let i=!1,o=!1;return{read:function(l){if(i||!l())return null;const u="CANVAS"===n.nodeName,c=u?n.width:n.videoWidth,s=u?n.height:n.videoHeight;if(!Number.isFinite(c)||!Number.isFinite(s)||c<=0||s<=0)return null;const f=c/3,a=s/3,d=[];try{if(o){const n=e();if(i||!l())return n.width=0,n.height=0,null;if(r=null,r=(t=n).getContext("2d"),i||!l())return t.width=0,t.height=0,null;t.width=3,t.height=3,o=!1}if(!r)return null;for(let t=0;t<3;t++)for(let e=0;e<3;e++){if(i||!l())return null;if(r.drawImage(n,e*f,t*a,f,a,0,0,1,1),i||!l())return null;const[o,u,c]=r.getImageData(0,0,1,1).data;d.push(`rgb(${o}, ${u}, ${c})`)}return d}catch{return i||(o=!0,t.width=0,t.height=0),null}},destroy:function(){i||(i=!0,t.width=0,t.height=0)}}}(b,c,()=>h.createElement("canvas")),i)return f(),s;u=t(g,()=>Boolean(r?.playing),t=>{const n=l?.read(t);n&&t()&&o?.render(n,t)}),d("ready",s.start),i&&f()}catch(h){try{a()}catch{}try{f()}catch{}throw h}return s}}return Object.assign(n,{default:n})});
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-ambilight.js v1.1.0
|
||||
* artplayer-plugin-ambilight.js v2.0.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.artplayerPluginAmbilight=t(),define(function(){return t.artplayerPluginAmbilight})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAmbilight=t()}(this,function(){"use strict";return function(e={}){return t=>{const{$video:n}=t.template,{createElement:r,addClass:i,setStyles:o}=t.constructor.utils,{blur:a="50px",opacity:l=.5,frequency:u=10,duration:f=.3}=e,s=r("div"),d=((c=s).innerHTML=Array.from({length:9}).fill("<div></div>").join(""),Array.from(c.children));var c,m,p,g;!function(e,t){i(e,"artplayer-plugin-ambilight"),t.parentNode.insertBefore(e,t),o(e,{position:"absolute",top:0,left:0,zIndex:9,inset:0,display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gridTemplateRows:"1fr 1fr 1fr"})}(s,n),m=a,p=l,g=f,d.forEach(e=>{o(e,{opacity:p,filter:`blur(${m})`,transition:`background-color ${g}s ease`})});const y=function(e,n,i){const o=r("canvas"),a=o.getContext("2d");o.width=3,o.height=3;let l=0;return function r(){const o=performance.now();if(o-l<1e3/i||!t.playing)return void(h=requestAnimationFrame(r));l=o;const u=e.videoWidth/3,f=e.videoHeight/3,s=[[0,0],[u,0],[2*u,0],[0,f],[u,f],[2*u,f],[0,2*f],[u,2*f],[2*u,2*f]].map(([t,n])=>function(t,n,r,i){a.drawImage(e,t,n,r,i,0,0,1,1);const[o,l,u]=a.getImageData(0,0,1,1).data;return`rgb(${o}, ${l}, ${u})`}(t,n,u,f));n.forEach((e,t)=>{e.style.backgroundColor=s[t]}),h=requestAnimationFrame(r)}}(n,d,u);let h=null;function b(){h||y()}function v(){h&&(cancelAnimationFrame(h),h=null)}return t.on("ready",b),t.on("destroy",v),{name:"artplayerPluginAmbilight",start:b,stop:v}}}});
|
||||
!function(t,n){"object"===typeof exports&&"undefined"!==typeof module?module.exports=n():"function"==typeof define&&define.amd?(t.artplayerPluginAmbilight=n(),define(function(){return t.artplayerPluginAmbilight})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginAmbilight=n()}(this,function(){"use strict";function t(t,n,e){let r="stopped",i=null,o=0,l=!1,u=0;function c(){const s=o,f=()=>"running"===r&&s===o;l=!0;try{const r=performance.now();if(r-u<1e3/t||!n()||!f())return;u=r,e(f)}finally{l=!1,"running"===r&&null===i&&function(){const t=o;try{i=requestAnimationFrame(()=>{"running"===r&&t===o&&(i=null,c())})}catch(n){throw r="stopped",o++,n}}()}}return{start:function(){"stopped"===r&&(r="running",o++,l||c())},stop:function(){if("destroyed"===r)return;r="stopped",o++;const t=i;i=null,null!==t&&cancelAnimationFrame(t)},destroy:function(){if("destroyed"===r)return;r="destroyed",o++;const t=i;i=null,null!==t&&cancelAnimationFrame(t)}}}function n(n={}){return e=>{let r=e,i=e.isDestroy,o=null,l=null,u=null;const c=[],s={name:"artplayerPluginAmbilight",start(){i||null==u||u.start()},stop(){i||null==u||u.stop()}};if(i)return r=null,s;function f(){const t=[null==u?void 0:u.destroy,null==l?void 0:l.destroy,null==o?void 0:o.destroy];u=null,l=null,o=null;const n=[];for(const r of t)try{null==r||r()}catch(e){n.push(e)}if(n.length)throw n[0]}function a(){if(i)return;i=!0;const t=r;r=null;const n=[];for(const[r,i]of c.splice(0))try{null==t||t.off(r,i)}catch(e){n.push(e)}try{f()}catch(e){n.push(e)}if(n.length)throw n[0]}function d(t,n){c.push([t,n]),null==r||r.on(t,n)}try{if(d("destroy",a),i)return s;const{$video:c}=e.template,h=e.constructor.utils,{blur:y="50px",opacity:p=.5,frequency:g=10,duration:m=.3}=n;if(i)return s;if(o=function(t){const n=t.createElement("div");n.innerHTML=Array.from({length:9}).fill("<div></div>").join("");const e=Array.from(n.children);return{mount:function(r,i,o){if(o()&&(t.addClass(n,"artplayer-plugin-ambilight"),o()&&(r.parentNode.insertBefore(n,r),o()))){t.setStyles(n,{position:"absolute",top:0,left:0,zIndex:9,inset:0,display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gridTemplateRows:"1fr 1fr 1fr"});for(const n of e){if(!o())return;t.setStyles(n,{opacity:i.opacity,filter:`blur(${i.blur})`,transition:`background-color ${i.duration}s ease`})}}},render:function(t,n){for(let r=0;r<t.length;r++){if(!n())return;const i=e[r],o=t[r];i&&void 0!==o&&(i.style.backgroundColor=o)}},destroy:function(){var t;try{null==(t=n.parentNode)||t.removeChild(n)}finally{e.length=0}}}}(h),i||o.mount(c,{blur:y,opacity:p,duration:m},()=>!i),i)return f(),s;const b=h.createElement("canvas");if(i)return b.width=0,b.height=0,s;if(l=function(t,n,e){let r;try{r=t.getContext("2d"),t.width=3,t.height=3}catch(l){throw t.width=0,t.height=0,l}let i=!1,o=!1;return{read:function(l){if(i||!l())return null;const u="CANVAS"===n.nodeName,c=u?n.width:n.videoWidth,s=u?n.height:n.videoHeight;if(!Number.isFinite(c)||!Number.isFinite(s)||c<=0||s<=0)return null;const f=c/3,a=s/3,d=[];try{if(o){const n=e();if(i||!l())return n.width=0,n.height=0,null;if(r=null,r=(t=n).getContext("2d"),i||!l())return t.width=0,t.height=0,null;t.width=3,t.height=3,o=!1}if(!r)return null;for(let t=0;t<3;t++)for(let e=0;e<3;e++){if(i||!l())return null;if(r.drawImage(n,e*f,t*a,f,a,0,0,1,1),i||!l())return null;const[o,u,c]=r.getImageData(0,0,1,1).data;d.push(`rgb(${o}, ${u}, ${c})`)}return d}catch(h){return i||(o=!0,t.width=0,t.height=0),null}},destroy:function(){i||(i=!0,t.width=0,t.height=0)}}}(b,c,()=>h.createElement("canvas")),i)return f(),s;u=t(g,()=>Boolean(null==r?void 0:r.playing),t=>{const n=null==l?void 0:l.read(t);n&&t()&&(null==o||o.render(n,t))}),d("ready",s.start),i&&f()}catch(h){try{a()}catch(y){}try{f()}catch(y){}throw h}return s}}return Object.assign(n,{default:n})});
|
||||
@@ -1,104 +1,309 @@
|
||||
/*!
|
||||
* artplayer-plugin-ambilight.js v1.1.0
|
||||
* artplayer-plugin-ambilight.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
function isCanvas(source) {
|
||||
return source.nodeName === "CANVAS";
|
||||
}
|
||||
function createColorSampler(canvas, video, createCanvas) {
|
||||
let context;
|
||||
try {
|
||||
context = canvas.getContext("2d");
|
||||
canvas.width = 3;
|
||||
canvas.height = 3;
|
||||
} catch (error) {
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
throw error;
|
||||
}
|
||||
let destroyed = false;
|
||||
let replaceCanvas = false;
|
||||
function read(active) {
|
||||
if (destroyed || !active())
|
||||
return null;
|
||||
const canvasOutput = isCanvas(video);
|
||||
const width = canvasOutput ? video.width : video.videoWidth;
|
||||
const height = canvasOutput ? video.height : video.videoHeight;
|
||||
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0)
|
||||
return null;
|
||||
const w = width / 3;
|
||||
const h = height / 3;
|
||||
const colors = [];
|
||||
try {
|
||||
if (replaceCanvas) {
|
||||
const replacement = createCanvas();
|
||||
if (destroyed || !active()) {
|
||||
replacement.width = 0;
|
||||
replacement.height = 0;
|
||||
return null;
|
||||
}
|
||||
canvas = replacement;
|
||||
context = null;
|
||||
context = canvas.getContext("2d");
|
||||
if (destroyed || !active()) {
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
return null;
|
||||
}
|
||||
canvas.width = 3;
|
||||
canvas.height = 3;
|
||||
replaceCanvas = false;
|
||||
}
|
||||
if (!context)
|
||||
return null;
|
||||
for (let row = 0; row < 3; row++) {
|
||||
for (let column = 0; column < 3; column++) {
|
||||
if (destroyed || !active())
|
||||
return null;
|
||||
context.drawImage(video, column * w, row * h, w, h, 0, 0, 1, 1);
|
||||
if (destroyed || !active())
|
||||
return null;
|
||||
const [r, g, b] = context.getImageData(0, 0, 1, 1).data;
|
||||
colors.push(`rgb(${r}, ${g}, ${b})`);
|
||||
}
|
||||
}
|
||||
return colors;
|
||||
} catch {
|
||||
if (!destroyed) {
|
||||
replaceCanvas = true;
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function destroy() {
|
||||
if (destroyed)
|
||||
return;
|
||||
destroyed = true;
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
}
|
||||
return { read, destroy };
|
||||
}
|
||||
function createFrameLoop(frequency, playing, update) {
|
||||
let state = "stopped";
|
||||
let pending = null;
|
||||
let generation = 0;
|
||||
let inFrame = false;
|
||||
let lastUpdateTime = 0;
|
||||
function schedule() {
|
||||
const current = generation;
|
||||
try {
|
||||
pending = requestAnimationFrame(() => {
|
||||
if (state !== "running" || current !== generation)
|
||||
return;
|
||||
pending = null;
|
||||
tick();
|
||||
});
|
||||
} catch (error) {
|
||||
state = "stopped";
|
||||
generation++;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
function tick() {
|
||||
const current = generation;
|
||||
const active = () => state === "running" && current === generation;
|
||||
inFrame = true;
|
||||
try {
|
||||
const now = performance.now();
|
||||
if (now - lastUpdateTime < 1e3 / frequency || !playing() || !active())
|
||||
return;
|
||||
lastUpdateTime = now;
|
||||
update(active);
|
||||
} finally {
|
||||
inFrame = false;
|
||||
if (state === "running" && pending === null)
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
function start() {
|
||||
if (state !== "stopped")
|
||||
return;
|
||||
state = "running";
|
||||
generation++;
|
||||
if (!inFrame)
|
||||
tick();
|
||||
}
|
||||
function stop() {
|
||||
if (state === "destroyed")
|
||||
return;
|
||||
state = "stopped";
|
||||
generation++;
|
||||
const frame = pending;
|
||||
pending = null;
|
||||
if (frame !== null)
|
||||
cancelAnimationFrame(frame);
|
||||
}
|
||||
function destroy() {
|
||||
if (state === "destroyed")
|
||||
return;
|
||||
state = "destroyed";
|
||||
generation++;
|
||||
const frame = pending;
|
||||
pending = null;
|
||||
if (frame !== null)
|
||||
cancelAnimationFrame(frame);
|
||||
}
|
||||
return { start, stop, destroy };
|
||||
}
|
||||
function createAmbilightView(utils) {
|
||||
const element = utils.createElement("div");
|
||||
element.innerHTML = Array.from({ length: 9 }).fill("<div></div>").join("");
|
||||
const items = Array.from(element.children);
|
||||
function mount(video, option, active) {
|
||||
if (!active())
|
||||
return;
|
||||
utils.addClass(element, "artplayer-plugin-ambilight");
|
||||
if (!active())
|
||||
return;
|
||||
video.parentNode.insertBefore(element, video);
|
||||
if (!active())
|
||||
return;
|
||||
utils.setStyles(element, { position: "absolute", top: 0, left: 0, zIndex: 9, inset: 0, display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gridTemplateRows: "1fr 1fr 1fr" });
|
||||
for (const item of items) {
|
||||
if (!active())
|
||||
return;
|
||||
utils.setStyles(item, { opacity: option.opacity, filter: `blur(${option.blur})`, transition: `background-color ${option.duration}s ease` });
|
||||
}
|
||||
}
|
||||
function render(colors, active) {
|
||||
for (let index2 = 0; index2 < colors.length; index2++) {
|
||||
if (!active())
|
||||
return;
|
||||
const item = items[index2];
|
||||
const color = colors[index2];
|
||||
if (item && color !== void 0)
|
||||
item.style.backgroundColor = color;
|
||||
}
|
||||
}
|
||||
function destroy() {
|
||||
try {
|
||||
element.parentNode?.removeChild(element);
|
||||
} finally {
|
||||
items.length = 0;
|
||||
}
|
||||
}
|
||||
return { mount, render, destroy };
|
||||
}
|
||||
function artplayerPluginAmbilight(option = {}) {
|
||||
return (art) => {
|
||||
const { $video } = art.template;
|
||||
const { createElement, addClass, setStyles } = art.constructor.utils;
|
||||
const { blur = "50px", opacity = 0.5, frequency = 10, duration = 0.3 } = option;
|
||||
const $ambilight = createElement("div");
|
||||
const gridItems = createGridItems($ambilight);
|
||||
setupAmbilight($ambilight, $video);
|
||||
setupGridItems(gridItems, blur, opacity, duration);
|
||||
const updateColors = createColorUpdater($video, gridItems, frequency);
|
||||
let animationFrameId = null;
|
||||
function start() {
|
||||
if (!animationFrameId) {
|
||||
updateColors();
|
||||
}
|
||||
}
|
||||
function stop() {
|
||||
if (animationFrameId) {
|
||||
cancelAnimationFrame(animationFrameId);
|
||||
animationFrameId = null;
|
||||
}
|
||||
}
|
||||
art.on("ready", start);
|
||||
art.on("destroy", stop);
|
||||
return {
|
||||
let host = art;
|
||||
let closed = art.isDestroy;
|
||||
let view = null;
|
||||
let sampler = null;
|
||||
let loop = null;
|
||||
const subscriptions = [];
|
||||
const result = {
|
||||
name: "artplayerPluginAmbilight",
|
||||
start,
|
||||
stop
|
||||
};
|
||||
function createGridItems($ambilight2) {
|
||||
$ambilight2.innerHTML = Array.from({ length: 9 }).fill("<div></div>").join("");
|
||||
return Array.from($ambilight2.children);
|
||||
}
|
||||
function setupAmbilight($ambilight2, $video2) {
|
||||
addClass($ambilight2, "artplayer-plugin-ambilight");
|
||||
$video2.parentNode.insertBefore($ambilight2, $video2);
|
||||
setStyles($ambilight2, {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 9,
|
||||
inset: 0,
|
||||
display: "grid",
|
||||
gridTemplateColumns: "1fr 1fr 1fr",
|
||||
gridTemplateRows: "1fr 1fr 1fr"
|
||||
});
|
||||
}
|
||||
function setupGridItems(gridItems2, blur2, opacity2, duration2) {
|
||||
gridItems2.forEach(($item) => {
|
||||
setStyles($item, {
|
||||
opacity: opacity2,
|
||||
filter: `blur(${blur2})`,
|
||||
transition: `background-color ${duration2}s ease`
|
||||
});
|
||||
});
|
||||
}
|
||||
function createColorUpdater($video2, gridItems2, frequency2) {
|
||||
const canvas = createElement("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
canvas.width = 3;
|
||||
canvas.height = 3;
|
||||
function getAverageColor(x, y, w, h) {
|
||||
ctx.drawImage($video2, x, y, w, h, 0, 0, 1, 1);
|
||||
const [r, g, b] = ctx.getImageData(0, 0, 1, 1).data;
|
||||
return `rgb(${r}, ${g}, ${b})`;
|
||||
start() {
|
||||
if (!closed)
|
||||
loop?.start();
|
||||
},
|
||||
stop() {
|
||||
if (!closed)
|
||||
loop?.stop();
|
||||
}
|
||||
let lastUpdateTime = 0;
|
||||
return function updateColors2() {
|
||||
const now = performance.now();
|
||||
if (now - lastUpdateTime < 1e3 / frequency2 || !art.playing) {
|
||||
animationFrameId = requestAnimationFrame(updateColors2);
|
||||
return;
|
||||
}
|
||||
lastUpdateTime = now;
|
||||
const w = $video2.videoWidth / 3;
|
||||
const h = $video2.videoHeight / 3;
|
||||
const colors = [
|
||||
[0, 0],
|
||||
[w, 0],
|
||||
[2 * w, 0],
|
||||
[0, h],
|
||||
[w, h],
|
||||
[2 * w, h],
|
||||
[0, 2 * h],
|
||||
[w, 2 * h],
|
||||
[2 * w, 2 * h]
|
||||
].map(([x, y]) => getAverageColor(x, y, w, h));
|
||||
gridItems2.forEach(($item, index) => {
|
||||
$item.style.backgroundColor = colors[index];
|
||||
});
|
||||
animationFrameId = requestAnimationFrame(updateColors2);
|
||||
};
|
||||
};
|
||||
if (closed) {
|
||||
host = null;
|
||||
return result;
|
||||
}
|
||||
function releaseResources() {
|
||||
const releases = [loop?.destroy, sampler?.destroy, view?.destroy];
|
||||
loop = null;
|
||||
sampler = null;
|
||||
view = null;
|
||||
const failures = [];
|
||||
for (const release of releases) {
|
||||
try {
|
||||
release?.();
|
||||
} catch (error) {
|
||||
failures.push(error);
|
||||
}
|
||||
}
|
||||
if (failures.length)
|
||||
throw failures[0];
|
||||
}
|
||||
function destroy() {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
const current = host;
|
||||
host = null;
|
||||
const failures = [];
|
||||
for (const [event, callback] of subscriptions.splice(0)) {
|
||||
try {
|
||||
current?.off(event, callback);
|
||||
} catch (error) {
|
||||
failures.push(error);
|
||||
}
|
||||
}
|
||||
try {
|
||||
releaseResources();
|
||||
} catch (error) {
|
||||
failures.push(error);
|
||||
}
|
||||
if (failures.length)
|
||||
throw failures[0];
|
||||
}
|
||||
function listen(event, callback) {
|
||||
subscriptions.push([event, callback]);
|
||||
host?.on(event, callback);
|
||||
}
|
||||
try {
|
||||
listen("destroy", destroy);
|
||||
if (closed)
|
||||
return result;
|
||||
const { $video } = art.template;
|
||||
const utils = art.constructor.utils;
|
||||
const { blur = "50px", opacity = 0.5, frequency = 10, duration = 0.3 } = option;
|
||||
if (closed)
|
||||
return result;
|
||||
view = createAmbilightView(utils);
|
||||
if (!closed)
|
||||
view.mount($video, { blur, opacity, duration }, () => !closed);
|
||||
if (closed) {
|
||||
releaseResources();
|
||||
return result;
|
||||
}
|
||||
const canvas = utils.createElement("canvas");
|
||||
if (closed) {
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
return result;
|
||||
}
|
||||
sampler = createColorSampler(canvas, $video, () => utils.createElement("canvas"));
|
||||
if (closed) {
|
||||
releaseResources();
|
||||
return result;
|
||||
}
|
||||
loop = createFrameLoop(frequency, () => Boolean(host?.playing), (valid) => {
|
||||
const colors = sampler?.read(valid);
|
||||
if (colors && valid())
|
||||
view?.render(colors, valid);
|
||||
});
|
||||
listen("ready", result.start);
|
||||
if (closed)
|
||||
releaseResources();
|
||||
} catch (error) {
|
||||
try {
|
||||
destroy();
|
||||
} catch {
|
||||
}
|
||||
try {
|
||||
releaseResources();
|
||||
} catch {
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
const index = Object.assign(artplayerPluginAmbilight, { default: artplayerPluginAmbilight });
|
||||
export {
|
||||
artplayerPluginAmbilight as default
|
||||
index as default
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-asr.js v2.1.0
|
||||
* artplayer-plugin-asr.js v3.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginAsr=e(),define(function(){return t.artplayerPluginAsr})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginAsr=e()}(this,function(){"use strict";if("undefined"!==typeof document&&!document.getElementById("artplayer-plugin-asr")){const t=document.createElement("style");t.id="artplayer-plugin-asr",t.textContent=".art-video-player .art-layer-asr{pointer-events:none!important;position:absolute;z-index:150;inset:0;display:flex;flex-direction:column;justify-content:end;padding:0 2%;font-size:1rem;gap:var(--art-subtitle-gap);padding-bottom:var(--art-subtitle-bottom);transition:padding-bottom var(--art-transition-duration) ease;text-shadow:var(--art-subtitle-border) 1px 0 1px,var(--art-subtitle-border) 0 1px 1px,var(--art-subtitle-border) -1px 0 1px,var(--art-subtitle-border) 0 -1px 1px,var(--art-subtitle-border) 1px 1px 1px,var(--art-subtitle-border) -1px -1px 1px,var(--art-subtitle-border) 1px -1px 1px,var(--art-subtitle-border) -1px 1px 1px}.art-video-player.art-control-show .art-layer-asr{padding-bottom:calc(var(--art-control-height) + var(--art-subtitle-bottom))}",document.head.appendChild(t)}return function(t={}){const{length:e=3,interval:n=100,sampleRate:r=16e3,autoHideTimeout:a=1e4,onAudioChunk:o=()=>null}=t;return t=>{let i=!1,l=null,s=null,u=null,c=null,d=[],p=null,f=!1,y=null,m=null,g=null;const h=t.layers.add({name:"asr",html:""});function w(){h.style.display="none"}function b(t){var n;"string"===typeof t&&(clearTimeout(y),y=setTimeout(w,a),h.style.display="",h.innerHTML=(n=t,n.split(/(?<=[\u3001\u3002\uff01\uff1f!?.])\s*/u).map(t=>t.trim()).filter(Boolean).slice(-e)).map(t=>`<div class="art-asr-line">${t}</div>`).join(""))}async function v(){if(!s&&t.video)try{return s=l.createMediaElementSource(t.video),s}catch(e){console.warn("[artplayerPluginAsr] Direct connection failed:",e)}try{if(m||(m=await async function(t){try{return t.captureStream?t.captureStream():t.mozCaptureStream?t.mozCaptureStream():(console.warn("[artplayerPluginAsr] captureStream not supported"),null)}catch(e){return console.warn("[artplayerPluginAsr] Error capturing stream:",e),null}}(t.video)),m)return g=l.createMediaStreamSource(m),g}catch(e){console.warn("[artplayerPluginAsr] MediaStream fallback failed:",e)}return null}async function x(){i&&(i=!1,clearInterval(p),p=null,u&&(u.disconnect(),u.port.onmessage=null,u=null),c&&(c.disconnect(),c=null),d=[])}async function A(){await x(),g&&(g.disconnect(),g=null),s&&(s.disconnect(),s=null),m&&(m.getTracks().forEach(t=>t.stop()),m=null),l&&(await l.close(),l=null),f=!1}return t.on("video:volumechange",()=>{c&&(c.gain.value=t.volume)}),t.on("play",async function(){if(!i)try{await async function(){return l||(l=new(window.AudioContext||window.webkitAudioContext)({sampleRate:r}),"suspended"===l.state&&await l.resume(),l)}();const t=await v();if(!t)throw new Error("Could not establish audio source");if(!f){const t=(()=>{const t=new Blob(["\n class RecorderProcessor extends AudioWorkletProcessor {\n process(inputs) {\n const input = inputs[0];\n if (input && input[0]) {\n this.port.postMessage(input[0]);\n }\n return true;\n }\n }\n registerProcessor('recorder-processor', RecorderProcessor);\n "],{type:"application/javascript"});return URL.createObjectURL(t)})();await l.audioWorklet.addModule(t),URL.revokeObjectURL(t),f=!0}c=l.createGain(),c.gain.value=1,u=new AudioWorkletNode(l,"recorder-processor"),u.port.onmessage=t=>{d.push(new Float32Array(t.data))},t.connect(u),t.connect(c),c.connect(l.destination);const e=r*(n/1e3);p=setInterval(async()=>{if(0===d.length)return;let t=new Float32Array(0);for(;t.length<e&&d.length;){const e=d.shift(),n=new Float32Array(t.length+e.length);n.set(t,0),n.set(e,t.length),t=n}if(t.length<e)return;const n=function(t){const e=t.length,n=new ArrayBuffer(2*e),r=new DataView(n);for(let a=0;a<e;a++){const e=Math.max(-1,Math.min(1,t[a]));r.setInt16(2*a,e<0?32768*e:32767*e,!0)}return n}(t.slice(0,e)),a=function(t,e){const n=t.byteLength,r=new ArrayBuffer(44+n),a=new DataView(r),o=(t,e)=>{for(let n=0;n<e.length;n++)a.setUint8(t+n,e.charCodeAt(n))};return o(0,"RIFF"),a.setUint32(4,36+n,!0),o(8,"WAVE"),o(12,"fmt "),a.setUint32(16,16,!0),a.setUint16(20,1,!0),a.setUint16(22,1,!0),a.setUint32(24,e,!0),a.setUint32(28,2*e,!0),a.setUint16(32,2,!0),a.setUint16(34,16,!0),o(36,"data"),a.setUint32(40,n,!0),new Uint8Array(r).set(new Uint8Array(t),44),r}(n,r);b(await o({pcm:n,wav:a}))},n),i=!0}catch(t){console.error("[artplayerPluginAsr] Initialization failed:",t),await x()}}),t.on("pause",x),t.on("destroy",A),{name:"artplayerPluginAsr",stop:A,hide:w,append:b}}}});
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginAsr=e(),define(function(){return t.artplayerPluginAsr})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginAsr=e()}(this,function(){"use strict";class t{constructor(t,e,i=!1){this.video=t,this.sampleRate=e,this.captureOnly=i,this.closed=!1,this.direct=!1,this.workletLoaded=!1}assertOpen(){if(this.closed)throw new Error("Audio capture was closed")}revokeWorklet(){void 0!==this.blobUrl&&(URL.revokeObjectURL(this.blobUrl),this.blobUrl=void 0)}async initialize(){this.assertOpen();const t=window,e=window.AudioContext||t.webkitAudioContext;if(!e)throw new Error("AudioContext is not supported");const i=this.context??(this.context=new e({sampleRate:this.sampleRate}));if("suspended"===i.state&&await i.resume(),this.assertOpen(),!this.workletLoaded){this.blobUrl=URL.createObjectURL(new Blob(["\nclass RecorderProcessor extends AudioWorkletProcessor {\n process(inputs) {\n const input = inputs[0];\n if (input && input[0]) {\n this.port.postMessage(input[0]);\n }\n return true;\n }\n}\nregisterProcessor('recorder-processor', RecorderProcessor);\n"],{type:"application/javascript"}));try{await i.audioWorklet.addModule(this.blobUrl),this.workletLoaded=!0}finally{this.revokeWorklet()}}if(this.assertOpen(),!this.source){if(!this.captureOnly)try{this.source=i.createMediaElementSource(this.video),this.direct=!0}catch(s){console.warn("[artplayerPluginAsr] Direct connection failed:",s)}if(!this.source){const t=this.video.captureStream||this.video.mozCaptureStream;if(!t)throw new Error("Could not establish audio source");this.stream=t.call(this.video),this.source=i.createMediaStreamSource(this.stream)}}}prepare(){return this.preparation??(this.preparation=this.initialize().catch(t=>{throw this.preparation=void 0,t})),this.preparation}get ownsMediaConnection(){return this.direct}idle(){const t=this.gain;this.disconnect(),this.direct&&this.context&&this.source&&(this.gain=t||this.context.createGain(),t||(this.gain.gain.value=1),this.source.connect(this.gain),this.gain.connect(this.context.destination))}connect(t){this.assertOpen();const e=this.context,i=this.source;if(!e||!i)throw new Error("Audio capture is not prepared");const s=this.gain;this.disconnect();const r=this.gain=s||e.createGain();s||(r.gain.value=this.direct?1:0);const n=this.recorder=new AudioWorkletNode(e,"recorder-processor");n.port.onmessage=e=>{this.closed||this.recorder!==n||t(e.data)},i.connect(n),this.direct?i.connect(r):n.connect(r),r.connect(e.destination)}disconnect(){this.recorder&&(this.recorder.port.onmessage=null,this.recorder.disconnect(),this.recorder=void 0),this.gain?.disconnect(),this.gain=void 0,this.source?.disconnect()}async close(){if(this.closed)return;this.closed=!0,this.disconnect(),this.revokeWorklet(),this.stream?.getTracks().forEach(t=>t.stop()),this.stream=void 0;const t=this.context;this.context=void 0,this.source=void 0,t&&"closed"!==t.state&&await t.close()}}class e{constructor(){this.offset=0,this.size=0}get length(){return this.size}push(t){if(0===t.length)return;const e={samples:new Float32Array(t)};this.tail?this.tail.next=e:this.head=e,this.tail=e,this.size+=t.length}take(t){if(!Number.isSafeInteger(t)||t<=0)throw new RangeError("Sample count must be a positive safe integer");if(t>this.size)return null;const e=new Float32Array(t);let i=0;for(;this.head&&i<t;){const s=this.head.samples,r=Math.min(s.length-this.offset,t-i);e.set(s.subarray(this.offset,this.offset+r),i),i+=r,this.offset+=r,this.offset===s.length&&(this.head=this.head.next,this.offset=0)}return this.head||(this.tail=void 0),this.size-=t,e}clear(){this.head=void 0,this.tail=void 0,this.offset=0,this.size=0}}class i{constructor(t,i,s){this.video=t,this.options=i,this.append=s,this.queue=new e,this.closing=Promise.resolve(),this.running=!1,this.terminal=!1,this.epoch=0}reset(){this.epoch++,this.pending=void 0,this.queue.clear()}pause(){this.reset(),this.running=!1,clearInterval(this.timer),this.timer=void 0,this.starting=void 0,this.graph?.idle()}restart(){const t=this.running||Boolean(this.starting);if(this.pause(),this.graph&&!this.graph.ownsMediaConnection){const e=this.stop(),i=this.epoch;return e.then(()=>t&&!this.terminal&&this.epoch===i?this.start():void 0)}return t?this.start():Promise.resolve()}start(){if(this.terminal||this.running)return Promise.resolve();if(this.starting)return this.starting;const e=this.epoch,i=()=>!this.terminal&&this.epoch===e,s=(async()=>{if(await this.closing,!i())return;const{sampleRate:e,interval:s}=this.options,r=Math.floor(e*s/1e3);if(!Number.isSafeInteger(r)||r<1||!Number.isFinite(s)||s<=0)throw new Error("Audio chunk length must be positive and finite");const n=this.graph??(this.graph=new t(this.video,e,this.options.captureOnly));await n.prepare(),i()?(n.connect(t=>{if(this.running&&this.graph===n)return this.queue.length+tLine truncated
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-asr.js v2.1.0
|
||||
* artplayer-plugin-asr.js v3.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginAsr=e(),define(function(){return t.artplayerPluginAsr})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginAsr=e()}(this,function(){"use strict";var t=(t,e,n)=>new Promise((r,o)=>{var a=t=>{try{l(n.next(t))}catch(e){o(e)}},i=t=>{try{l(n.throw(t))}catch(e){o(e)}},l=t=>t.done?r(t.value):Promise.resolve(t.value).then(a,i);l((n=n.apply(t,e)).next())});if("undefined"!==typeof document&&!document.getElementById("artplayer-plugin-asr")){const t=document.createElement("style");t.id="artplayer-plugin-asr",t.textContent=".art-video-player .art-layer-asr{pointer-events:none!important;position:absolute;z-index:150;inset:0;display:flex;flex-direction:column;justify-content:end;padding:0 2%;font-size:1rem;gap:var(--art-subtitle-gap);padding-bottom:var(--art-subtitle-bottom);transition:padding-bottom var(--art-transition-duration) ease;text-shadow:var(--art-subtitle-border) 1px 0 1px,var(--art-subtitle-border) 0 1px 1px,var(--art-subtitle-border) -1px 0 1px,var(--art-subtitle-border) 0 -1px 1px,var(--art-subtitle-border) 1px 1px 1px,var(--art-subtitle-border) -1px -1px 1px,var(--art-subtitle-border) 1px -1px 1px,var(--art-subtitle-border) -1px 1px 1px}.art-video-player.art-control-show .art-layer-asr{padding-bottom:calc(var(--art-control-height) + var(--art-subtitle-bottom))}",document.head.appendChild(t)}return function(e={}){const{length:n=3,interval:r=100,sampleRate:o=16e3,autoHideTimeout:a=1e4,onAudioChunk:i=()=>null}=e;return e=>{let l=!1,s=null,u=null,c=null,d=null,p=[],f=null,y=!1,m=null,h=null,g=null;const v=e.layers.add({name:"asr",html:""});function b(){v.style.display="none"}function x(t){var e;"string"===typeof t&&(clearTimeout(m),m=setTimeout(b,a),v.style.display="",v.innerHTML=(e=t,e.split(new RegExp("(?<=[\u3001\u3002\uff01\uff1f!?.])\\s*","u")).map(t=>t.trim()).filter(Boolean).slice(-n)).map(t=>`<div class="art-asr-line">${t}</div>`).join(""))}function w(){return t(this,null,function*(){if(!u&&e.video)try{return u=s.createMediaElementSource(e.video),u}catch(n){console.warn("[artplayerPluginAsr] Direct connection failed:",n)}try{if(h||(h=yield function(e){return t(this,null,function*(){try{return e.captureStream?e.captureStream():e.mozCaptureStream?e.mozCaptureStream():(console.warn("[artplayerPluginAsr] captureStream not supported"),null)}catch(n){return console.warn("[artplayerPluginAsr] Error capturing stream:",n),null}})}(e.video)),h)return g=s.createMediaStreamSource(h),g}catch(n){console.warn("[artplayerPluginAsr] MediaStream fallback failed:",n)}return null})}function A(){return t(this,null,function*(){l&&(l=!1,clearInterval(f),f=null,c&&(c.disconnect(),c.port.onmessage=null,c=null),d&&(d.disconnect(),d=null),p=[])})}function U(){return t(this,null,function*(){yield A(),g&&(g.disconnect(),g=null),u&&(u.disconnect(),u=null),h&&(h.getTracks().forEach(t=>t.stop()),h=null),s&&(yield s.close(),s=null),y=!1})}return e.on("video:volumechange",()=>{d&&(d.gain.value=e.volume)}),e.on("play",function(){return t(this,null,function*(){if(!l)try{yield function(){return t(this,null,function*(){return s||(s=new(window.AudioContext||window.webkitAudioContext)({sampleRate:o}),"suspended"===s.state&&(yield s.resume()),s)})}();const e=yield w();if(!e)throw new Error("Could not establish audio source");if(!y){const t=(()=>{const t=new Blob(["\n class RecorderProcessor extends AudioWorkletProcessor {\n process(inputs) {\n const input = inputs[0];\n if (input && input[0]) {\n this.port.postMessage(input[0]);\n }\n return true;\n }\n }\n registerProcessor('recorder-processor', RecorderProcessor);\n "],{type:"application/javascript"});return URL.createObjectURL(t)})();yield s.audioWorklet.addModule(t),URL.revokeObjectURL(t),y=!0}d=s.createGain(),d.gain.value=1,c=new AudioWorkletNode(s,"recorder-processor"),c.port.onmessage=t=>{p.push(new Float32Array(t.data))},e.connect(c),e.connect(d),d.connect(s.destination);const n=o*(r/1e3);f=setInterval(()=>t(null,null,function*(){if(0===p.length)return;let t=new Float32Array(0);for(;t.length<n&&p.length;){const e=p.shift(),n=new Float32Array(t.length+e.length);n.set(t,0),n.set(e,t.length),t=n}if(t.length<n)return;const e=function(t){const e=t.length,n=new ArrayBuffer(2*e),r=new DataView(n);for(let o=0;o<e;o++){const e=Math.max(-1,Math.min(1,t[o]));r.setInt16(2*o,e<0?32768*e:32767*e,!0)}return n}(t.slice(0,n)),r=function(t,e){const n=t.byteLength,r=new ArrayBuffer(44+n),o=new DataView(r),a=(t,e)=>{for(let n=0;n<e.length;n++)o.setUint8(t+n,e.charCodeAt(n))};return a(0,"RIFF"),o.setUint32(4,36+n,!0),a(8,"WAVE"),a(12,"fmt "),o.setUint32(16,16,!0),o.setUint16(20,1,!0),o.setUint16(22,1,!0),o.setUint32(24,e,!0),o.setUint32(28,2*e,!0),o.setUint16(32,2,!0),o.setUintLine truncated
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginAsr=e(),define(function(){return t.artplayerPluginAsr})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginAsr=e()}(this,function(){"use strict";var t=(t,e,i)=>new Promise((s,n)=>{var r=t=>{try{a(i.next(t))}catch(e){n(e)}},o=t=>{try{a(i.throw(t))}catch(e){n(e)}},a=t=>t.done?s(t.value):Promise.resolve(t.value).then(r,o);a((i=i.apply(t,e)).next())});class e{constructor(t,e,i=!1){this.video=t,this.sampleRate=e,this.captureOnly=i,this.closed=!1,this.direct=!1,this.workletLoaded=!1}assertOpen(){if(this.closed)throw new Error("Audio capture was closed")}revokeWorklet(){void 0!==this.blobUrl&&(URL.revokeObjectURL(this.blobUrl),this.blobUrl=void 0)}initialize(){return t(this,null,function*(){var t;this.assertOpen();const e=window,i=window.AudioContext||e.webkitAudioContext;if(!i)throw new Error("AudioContext is not supported");const s=null!=(t=this.context)?t:this.context=new i({sampleRate:this.sampleRate});if("suspended"===s.state&&(yield s.resume()),this.assertOpen(),!this.workletLoaded){this.blobUrl=URL.createObjectURL(new Blob(["\nclass RecorderProcessor extends AudioWorkletProcessor {\n process(inputs) {\n const input = inputs[0];\n if (input && input[0]) {\n this.port.postMessage(input[0]);\n }\n return true;\n }\n}\nregisterProcessor('recorder-processor', RecorderProcessor);\n"],{type:"application/javascript"}));try{yield s.audioWorklet.addModule(this.blobUrl),this.workletLoaded=!0}finally{this.revokeWorklet()}}if(this.assertOpen(),!this.source){if(!this.captureOnly)try{this.source=s.createMediaElementSource(this.video),this.direct=!0}catch(n){console.warn("[artplayerPluginAsr] Direct connection failed:",n)}if(!this.source){const t=this.video.captureStream||this.video.mozCaptureStream;if(!t)throw new Error("Could not establish audio source");this.stream=t.call(this.video),this.source=s.createMediaStreamSource(this.stream)}}})}prepare(){return null!=this.preparation||(this.preparation=this.initialize().catch(t=>{throw this.preparation=void 0,t})),this.preparation}get ownsMediaConnection(){return this.direct}idle(){const t=this.gain;this.disconnect(),this.direct&&this.context&&this.source&&(this.gain=t||this.context.createGain(),t||(this.gain.gain.value=1),this.source.connect(this.gain),this.gain.connect(this.context.destination))}connect(t){this.assertOpen();const e=this.context,i=this.source;if(!e||!i)throw new Error("Audio capture is not prepared");const s=this.gain;this.disconnect();const n=this.gain=s||e.createGain();s||(n.gain.value=this.direct?1:0);const r=this.recorder=new AudioWorkletNode(e,"recorder-processor");r.port.onmessage=e=>{this.closed||this.recorder!==r||t(e.data)},i.connect(r),this.direct?i.connect(n):r.connect(n),n.connect(e.destination)}disconnect(){var t,e;this.recorder&&(this.recorder.port.onmessage=null,this.recorder.disconnect(),this.recorder=void 0),null==(t=this.gain)||t.disconnect(),this.gain=void 0,null==(e=this.source)||e.disconnect()}close(){return t(this,null,function*(){var t;if(this.closed)return;this.closed=!0,this.disconnect(),this.revokeWorklet(),null==(t=this.stream)||t.getTracks().forEach(t=>t.stop()),this.stream=void 0;const e=this.context;this.context=void 0,this.source=void 0,e&&"closed"!==e.state&&(yield e.close())})}}class i{constructor(){this.offset=0,this.size=0}get length(){return this.size}push(t){if(0===t.length)return;const e={samples:new Float32Array(t)};this.tail?this.tail.next=e:this.head=e,this.tail=e,this.size+=t.length}take(t){if(!Number.isSafeInteger(t)||t<=0)throw new RangeError("Sample count must be a positive safe integer");if(t>this.size)return null;const e=new Float32Array(t);let i=0;for(;this.head&&i<t;){const s=this.head.samples,n=Math.min(s.length-this.offset,t-i);e.set(s.subarray(this.offset,this.offset+n),i),i+=n,this.offset+=n,this.offset===s.length&&(this.head=this.head.next,this.offset=0)}return this.head||(this.tail=void 0),this.size-=t,e}clear(){this.head=void 0,this.tail=void 0,this.offset=0,this.size=0}}class s{constructor(t,e,s){this.video=t,this.options=e,this.append=s,this.queue=new i,this.closing=Promise.resolve(),this.running=!1,this.terminal=!1,this.epoch=0}reset(){this.epoch++,this.pending=void 0,this.queue.clear()}pause(){var t;this.reset(),this.running=!1,clearInterval(this.timer),this.timer=void 0,this.starting=void 0,null==(t=this.graph)||t.idle()}restart(){const t=this.running||Boolean(this.starting);if(this.pause(),this.graph&&!this.graph.ownsMediaConnection){const e=this.stop(),i=this.epoch;return e.then(()=>t&&!this.terminal&&this.epoch===i?this.start():void 0)}return t?this.start():Promise.resolve()}start(){if(this.terminal||this.running)return Promise.resolve();if(this.starting)return this.starting;const i=this.epoch,s=()=>!this.terminal&&this.epoch===i,n=(()=>t(this,null,function*(){var t;if(yield this.closing,!Line truncated
|
||||
@@ -1,251 +1,402 @@
|
||||
/*!
|
||||
* artplayer-plugin-asr.js v2.1.0
|
||||
* artplayer-plugin-asr.js v3.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
const style = ".art-video-player .art-layer-asr {\n pointer-events: none !important;\n position: absolute;\n z-index: 150;\n inset: 0px;\n display: flex;\n flex-direction: column;\n justify-content: end;\n padding: 0 2%;\n font-size: 1rem;\n gap: var(--art-subtitle-gap);\n padding-bottom: var(--art-subtitle-bottom);\n transition: padding-bottom var(--art-transition-duration) ease;\n text-shadow: var(--art-subtitle-border) 1px 0 1px, var(--art-subtitle-border) 0 1px 1px, var(--art-subtitle-border) -1px 0 1px, var(--art-subtitle-border) 0 -1px 1px, var(--art-subtitle-border) 1px 1px 1px, var(--art-subtitle-border) -1px -1px 1px, var(--art-subtitle-border) 1px -1px 1px, var(--art-subtitle-border) -1px 1px 1px;\n}\n.art-video-player.art-control-show .art-layer-asr {\n padding-bottom: calc(var(--art-control-height) + var(--art-subtitle-bottom));\n}\n";
|
||||
function artplayerPluginAsr(option = {}) {
|
||||
const {
|
||||
length = 3,
|
||||
interval = 100,
|
||||
sampleRate = 16e3,
|
||||
autoHideTimeout = 1e4,
|
||||
onAudioChunk = () => null
|
||||
} = option;
|
||||
return (art) => {
|
||||
let started = false;
|
||||
let audioCtx = null;
|
||||
let sourceNode = null;
|
||||
let recorderNode = null;
|
||||
let gainNode = null;
|
||||
let bufferChunks = [];
|
||||
let timer = null;
|
||||
let workletLoaded = false;
|
||||
let hideTimer = null;
|
||||
let mediaStream = null;
|
||||
let mediaStreamSource = null;
|
||||
const $asr = art.layers.add({
|
||||
name: "asr",
|
||||
html: ""
|
||||
});
|
||||
function splitByPunctuation(text) {
|
||||
return text.split(/(?<=[、。!?!?.])\s*/u).map((s) => s.trim()).filter(Boolean).slice(-length);
|
||||
}
|
||||
function hide() {
|
||||
$asr.style.display = "none";
|
||||
}
|
||||
function append(subtitle) {
|
||||
if (typeof subtitle !== "string")
|
||||
return;
|
||||
clearTimeout(hideTimer);
|
||||
hideTimer = setTimeout(hide, autoHideTimeout);
|
||||
$asr.style.display = "";
|
||||
$asr.innerHTML = splitByPunctuation(subtitle).map((line) => `<div class="art-asr-line">${line}</div>`).join("");
|
||||
}
|
||||
const recorderProcessorCode = `
|
||||
class RecorderProcessor extends AudioWorkletProcessor {
|
||||
process(inputs) {
|
||||
const input = inputs[0];
|
||||
if (input && input[0]) {
|
||||
this.port.postMessage(input[0]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
registerProcessor('recorder-processor', RecorderProcessor);
|
||||
`;
|
||||
const createWorkletBlobUrl = () => {
|
||||
const blob = new Blob([recorderProcessorCode], { type: "application/javascript" });
|
||||
return URL.createObjectURL(blob);
|
||||
};
|
||||
function floatTo16BitPCM(float32Array) {
|
||||
const len = float32Array.length;
|
||||
const buffer = new ArrayBuffer(len * 2);
|
||||
const view = new DataView(buffer);
|
||||
for (let i = 0; i < len; i++) {
|
||||
const s = Math.max(-1, Math.min(1, float32Array[i]));
|
||||
view.setInt16(i * 2, s < 0 ? s * 32768 : s * 32767, true);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
function pcmToWav(pcmBuffer, sampleRate2) {
|
||||
const pcmLength = pcmBuffer.byteLength;
|
||||
const wavBuffer = new ArrayBuffer(44 + pcmLength);
|
||||
const view = new DataView(wavBuffer);
|
||||
const writeString = (offset, str) => {
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
view.setUint8(offset + i, str.charCodeAt(i));
|
||||
const recorderProcessorCode = `
|
||||
class RecorderProcessor extends AudioWorkletProcessor {
|
||||
process(inputs) {
|
||||
const input = inputs[0];
|
||||
if (input && input[0]) {
|
||||
this.port.postMessage(input[0]);
|
||||
}
|
||||
};
|
||||
writeString(0, "RIFF");
|
||||
view.setUint32(4, 36 + pcmLength, true);
|
||||
writeString(8, "WAVE");
|
||||
writeString(12, "fmt ");
|
||||
view.setUint32(16, 16, true);
|
||||
view.setUint16(20, 1, true);
|
||||
view.setUint16(22, 1, true);
|
||||
view.setUint32(24, sampleRate2, true);
|
||||
view.setUint32(28, sampleRate2 * 2, true);
|
||||
view.setUint16(32, 2, true);
|
||||
view.setUint16(34, 16, true);
|
||||
writeString(36, "data");
|
||||
view.setUint32(40, pcmLength, true);
|
||||
new Uint8Array(wavBuffer).set(new Uint8Array(pcmBuffer), 44);
|
||||
return wavBuffer;
|
||||
return true;
|
||||
}
|
||||
async function setupAudioContext() {
|
||||
if (audioCtx)
|
||||
return audioCtx;
|
||||
audioCtx = new (window.AudioContext || window.webkitAudioContext)({ sampleRate });
|
||||
if (audioCtx.state === "suspended")
|
||||
await audioCtx.resume();
|
||||
return audioCtx;
|
||||
}
|
||||
registerProcessor('recorder-processor', RecorderProcessor);
|
||||
`;
|
||||
class AudioGraph {
|
||||
constructor(video, sampleRate, captureOnly = false) {
|
||||
this.video = video;
|
||||
this.sampleRate = sampleRate;
|
||||
this.captureOnly = captureOnly;
|
||||
this.closed = false;
|
||||
this.direct = false;
|
||||
this.workletLoaded = false;
|
||||
}
|
||||
assertOpen() {
|
||||
if (this.closed)
|
||||
throw new Error("Audio capture was closed");
|
||||
}
|
||||
revokeWorklet() {
|
||||
if (this.blobUrl !== void 0) {
|
||||
URL.revokeObjectURL(this.blobUrl);
|
||||
this.blobUrl = void 0;
|
||||
}
|
||||
async function setupAudioSource() {
|
||||
if (!sourceNode && art.video) {
|
||||
}
|
||||
async initialize() {
|
||||
this.assertOpen();
|
||||
const platform = window;
|
||||
const Context = window.AudioContext || platform.webkitAudioContext;
|
||||
if (!Context)
|
||||
throw new Error("AudioContext is not supported");
|
||||
const context = this.context ?? (this.context = new Context({ sampleRate: this.sampleRate }));
|
||||
if (context.state === "suspended")
|
||||
await context.resume();
|
||||
this.assertOpen();
|
||||
if (!this.workletLoaded) {
|
||||
this.blobUrl = URL.createObjectURL(new Blob([recorderProcessorCode], { type: "application/javascript" }));
|
||||
try {
|
||||
await context.audioWorklet.addModule(this.blobUrl);
|
||||
this.workletLoaded = true;
|
||||
} finally {
|
||||
this.revokeWorklet();
|
||||
}
|
||||
}
|
||||
this.assertOpen();
|
||||
if (!this.source) {
|
||||
if (!this.captureOnly) {
|
||||
try {
|
||||
sourceNode = audioCtx.createMediaElementSource(art.video);
|
||||
return sourceNode;
|
||||
} catch (err) {
|
||||
console.warn("[artplayerPluginAsr] Direct connection failed:", err);
|
||||
this.source = context.createMediaElementSource(this.video);
|
||||
this.direct = true;
|
||||
} catch (error) {
|
||||
console.warn("[artplayerPluginAsr] Direct connection failed:", error);
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (!mediaStream) {
|
||||
mediaStream = await captureAudioFromVideo(art.video);
|
||||
}
|
||||
if (mediaStream) {
|
||||
mediaStreamSource = audioCtx.createMediaStreamSource(mediaStream);
|
||||
return mediaStreamSource;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn("[artplayerPluginAsr] MediaStream fallback failed:", err);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
async function captureAudioFromVideo(videoElement) {
|
||||
try {
|
||||
if (videoElement.captureStream)
|
||||
return videoElement.captureStream();
|
||||
if (videoElement.mozCaptureStream)
|
||||
return videoElement.mozCaptureStream();
|
||||
console.warn("[artplayerPluginAsr] captureStream not supported");
|
||||
return null;
|
||||
} catch (err) {
|
||||
console.warn("[artplayerPluginAsr] Error capturing stream:", err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
async function startCapture() {
|
||||
if (started)
|
||||
return;
|
||||
try {
|
||||
await setupAudioContext();
|
||||
const audioSource = await setupAudioSource();
|
||||
if (!audioSource)
|
||||
if (!this.source) {
|
||||
const capture = this.video.captureStream || this.video.mozCaptureStream;
|
||||
if (!capture)
|
||||
throw new Error("Could not establish audio source");
|
||||
if (!workletLoaded) {
|
||||
const blobUrl = createWorkletBlobUrl();
|
||||
await audioCtx.audioWorklet.addModule(blobUrl);
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
workletLoaded = true;
|
||||
}
|
||||
gainNode = audioCtx.createGain();
|
||||
gainNode.gain.value = 1;
|
||||
recorderNode = new AudioWorkletNode(audioCtx, "recorder-processor");
|
||||
recorderNode.port.onmessage = (event) => {
|
||||
bufferChunks.push(new Float32Array(event.data));
|
||||
};
|
||||
audioSource.connect(recorderNode);
|
||||
audioSource.connect(gainNode);
|
||||
gainNode.connect(audioCtx.destination);
|
||||
const CHUNK_SAMPLES = sampleRate * (interval / 1e3);
|
||||
timer = setInterval(async () => {
|
||||
if (bufferChunks.length === 0)
|
||||
return;
|
||||
let accumulated = new Float32Array(0);
|
||||
while (accumulated.length < CHUNK_SAMPLES && bufferChunks.length) {
|
||||
const next = bufferChunks.shift();
|
||||
const tmp = new Float32Array(accumulated.length + next.length);
|
||||
tmp.set(accumulated, 0);
|
||||
tmp.set(next, accumulated.length);
|
||||
accumulated = tmp;
|
||||
}
|
||||
if (accumulated.length < CHUNK_SAMPLES)
|
||||
return;
|
||||
const chunkToSend = accumulated.slice(0, CHUNK_SAMPLES);
|
||||
const pcm = floatTo16BitPCM(chunkToSend);
|
||||
const wav = pcmToWav(pcm, sampleRate);
|
||||
const subtitle = await onAudioChunk({ pcm, wav });
|
||||
append(subtitle);
|
||||
}, interval);
|
||||
started = true;
|
||||
} catch (err) {
|
||||
console.error("[artplayerPluginAsr] Initialization failed:", err);
|
||||
await stopCapture();
|
||||
this.stream = capture.call(this.video);
|
||||
this.source = context.createMediaStreamSource(this.stream);
|
||||
}
|
||||
}
|
||||
async function stopCapture() {
|
||||
if (!started)
|
||||
return;
|
||||
started = false;
|
||||
clearInterval(timer);
|
||||
timer = null;
|
||||
if (recorderNode) {
|
||||
recorderNode.disconnect();
|
||||
recorderNode.port.onmessage = null;
|
||||
recorderNode = null;
|
||||
}
|
||||
if (gainNode) {
|
||||
gainNode.disconnect();
|
||||
gainNode = null;
|
||||
}
|
||||
bufferChunks = [];
|
||||
}
|
||||
prepare() {
|
||||
this.preparation ?? (this.preparation = this.initialize().catch((error) => {
|
||||
this.preparation = void 0;
|
||||
throw error;
|
||||
}));
|
||||
return this.preparation;
|
||||
}
|
||||
get ownsMediaConnection() {
|
||||
return this.direct;
|
||||
}
|
||||
idle() {
|
||||
const gain = this.gain;
|
||||
this.disconnect();
|
||||
if (this.direct && this.context && this.source) {
|
||||
this.gain = gain || this.context.createGain();
|
||||
if (!gain)
|
||||
this.gain.gain.value = 1;
|
||||
this.source.connect(this.gain);
|
||||
this.gain.connect(this.context.destination);
|
||||
}
|
||||
async function destroy() {
|
||||
await stopCapture();
|
||||
if (mediaStreamSource) {
|
||||
mediaStreamSource.disconnect();
|
||||
mediaStreamSource = null;
|
||||
}
|
||||
if (sourceNode) {
|
||||
sourceNode.disconnect();
|
||||
sourceNode = null;
|
||||
}
|
||||
if (mediaStream) {
|
||||
mediaStream.getTracks().forEach((track) => track.stop());
|
||||
mediaStream = null;
|
||||
}
|
||||
if (audioCtx) {
|
||||
await audioCtx.close();
|
||||
audioCtx = null;
|
||||
}
|
||||
workletLoaded = false;
|
||||
}
|
||||
art.on("video:volumechange", () => {
|
||||
if (gainNode) {
|
||||
gainNode.gain.value = art.volume;
|
||||
}
|
||||
});
|
||||
art.on("play", startCapture);
|
||||
art.on("pause", stopCapture);
|
||||
art.on("destroy", destroy);
|
||||
return {
|
||||
name: "artplayerPluginAsr",
|
||||
stop: destroy,
|
||||
hide,
|
||||
append
|
||||
}
|
||||
connect(receive) {
|
||||
this.assertOpen();
|
||||
const context = this.context;
|
||||
const source = this.source;
|
||||
if (!context || !source)
|
||||
throw new Error("Audio capture is not prepared");
|
||||
const previousGain = this.gain;
|
||||
this.disconnect();
|
||||
const gain = this.gain = previousGain || context.createGain();
|
||||
if (!previousGain)
|
||||
gain.gain.value = this.direct ? 1 : 0;
|
||||
const recorder = this.recorder = new AudioWorkletNode(context, "recorder-processor");
|
||||
recorder.port.onmessage = (event) => {
|
||||
if (!this.closed && this.recorder === recorder)
|
||||
receive(event.data);
|
||||
};
|
||||
source.connect(recorder);
|
||||
if (this.direct)
|
||||
source.connect(gain);
|
||||
else recorder.connect(gain);
|
||||
gain.connect(context.destination);
|
||||
}
|
||||
disconnect() {
|
||||
if (this.recorder) {
|
||||
this.recorder.port.onmessage = null;
|
||||
this.recorder.disconnect();
|
||||
this.recorder = void 0;
|
||||
}
|
||||
this.gain?.disconnect();
|
||||
this.gain = void 0;
|
||||
this.source?.disconnect();
|
||||
}
|
||||
async close() {
|
||||
if (this.closed)
|
||||
return;
|
||||
this.closed = true;
|
||||
this.disconnect();
|
||||
this.revokeWorklet();
|
||||
this.stream?.getTracks().forEach((track) => track.stop());
|
||||
this.stream = void 0;
|
||||
const context = this.context;
|
||||
this.context = void 0;
|
||||
this.source = void 0;
|
||||
if (context && context.state !== "closed")
|
||||
await context.close();
|
||||
}
|
||||
}
|
||||
function encodeAudio(samples, sampleRate) {
|
||||
const pcm = new ArrayBuffer(samples.length * 2);
|
||||
const pcmView = new DataView(pcm);
|
||||
for (let index = 0; index < samples.length; index++) {
|
||||
const value = Math.max(-1, Math.min(1, samples[index]));
|
||||
pcmView.setInt16(index * 2, value < 0 ? value * 32768 : value * 32767, true);
|
||||
}
|
||||
const wav = new ArrayBuffer(44 + pcm.byteLength);
|
||||
const header = new DataView(wav);
|
||||
function writeString(offset, value) {
|
||||
for (let index = 0; index < value.length; index++)
|
||||
header.setUint8(offset + index, value.charCodeAt(index));
|
||||
}
|
||||
writeString(0, "RIFF");
|
||||
header.setUint32(4, 36 + pcm.byteLength, true);
|
||||
writeString(8, "WAVE");
|
||||
writeString(12, "fmt ");
|
||||
header.setUint32(16, 16, true);
|
||||
header.setUint16(20, 1, true);
|
||||
header.setUint16(22, 1, true);
|
||||
header.setUint32(24, sampleRate, true);
|
||||
header.setUint32(28, sampleRate * 2, true);
|
||||
header.setUint16(32, 2, true);
|
||||
header.setUint16(34, 16, true);
|
||||
writeString(36, "data");
|
||||
header.setUint32(40, pcm.byteLength, true);
|
||||
new Uint8Array(wav).set(new Uint8Array(pcm), 44);
|
||||
return { pcm, wav };
|
||||
}
|
||||
class SampleQueue {
|
||||
constructor() {
|
||||
this.offset = 0;
|
||||
this.size = 0;
|
||||
}
|
||||
get length() {
|
||||
return this.size;
|
||||
}
|
||||
push(input) {
|
||||
if (input.length === 0)
|
||||
return;
|
||||
const block = { samples: new Float32Array(input) };
|
||||
if (this.tail)
|
||||
this.tail.next = block;
|
||||
else
|
||||
this.head = block;
|
||||
this.tail = block;
|
||||
this.size += input.length;
|
||||
}
|
||||
take(count) {
|
||||
if (!Number.isSafeInteger(count) || count <= 0)
|
||||
throw new RangeError("Sample count must be a positive safe integer");
|
||||
if (count > this.size)
|
||||
return null;
|
||||
const output = new Float32Array(count);
|
||||
let written = 0;
|
||||
while (this.head && written < count) {
|
||||
const samples = this.head.samples;
|
||||
const amount = Math.min(samples.length - this.offset, count - written);
|
||||
output.set(samples.subarray(this.offset, this.offset + amount), written);
|
||||
written += amount;
|
||||
this.offset += amount;
|
||||
if (this.offset === samples.length) {
|
||||
this.head = this.head.next;
|
||||
this.offset = 0;
|
||||
}
|
||||
}
|
||||
if (!this.head)
|
||||
this.tail = void 0;
|
||||
this.size -= count;
|
||||
return output;
|
||||
}
|
||||
clear() {
|
||||
this.head = void 0;
|
||||
this.tail = void 0;
|
||||
this.offset = 0;
|
||||
this.size = 0;
|
||||
}
|
||||
}
|
||||
class Capture {
|
||||
constructor(video, options, append) {
|
||||
this.video = video;
|
||||
this.options = options;
|
||||
this.append = append;
|
||||
this.queue = new SampleQueue();
|
||||
this.closing = Promise.resolve();
|
||||
this.running = false;
|
||||
this.terminal = false;
|
||||
this.epoch = 0;
|
||||
}
|
||||
reset() {
|
||||
this.epoch++;
|
||||
this.pending = void 0;
|
||||
this.queue.clear();
|
||||
}
|
||||
pause() {
|
||||
this.reset();
|
||||
this.running = false;
|
||||
clearInterval(this.timer);
|
||||
this.timer = void 0;
|
||||
this.starting = void 0;
|
||||
this.graph?.idle();
|
||||
}
|
||||
restart() {
|
||||
const active = this.running || Boolean(this.starting);
|
||||
this.pause();
|
||||
if (this.graph && !this.graph.ownsMediaConnection) {
|
||||
const stopping = this.stop();
|
||||
const epoch = this.epoch;
|
||||
return stopping.then(() => active && !this.terminal && this.epoch === epoch ? this.start() : void 0);
|
||||
}
|
||||
return active ? this.start() : Promise.resolve();
|
||||
}
|
||||
start() {
|
||||
if (this.terminal || this.running)
|
||||
return Promise.resolve();
|
||||
if (this.starting)
|
||||
return this.starting;
|
||||
const epoch = this.epoch;
|
||||
const current = () => !this.terminal && this.epoch === epoch;
|
||||
const operation = (async () => {
|
||||
await this.closing;
|
||||
if (!current())
|
||||
return;
|
||||
const { sampleRate, interval } = this.options;
|
||||
const count = Math.floor(sampleRate * interval / 1e3);
|
||||
if (!Number.isSafeInteger(count) || count < 1 || !Number.isFinite(interval) || interval <= 0)
|
||||
throw new Error("Audio chunk length must be positive and finite");
|
||||
const graph = this.graph ?? (this.graph = new AudioGraph(this.video, sampleRate, this.options.captureOnly));
|
||||
await graph.prepare();
|
||||
if (!current()) {
|
||||
if (!this.running && this.graph === graph)
|
||||
graph.idle();
|
||||
return;
|
||||
}
|
||||
graph.connect((samples) => {
|
||||
if (!this.running || this.graph !== graph)
|
||||
return;
|
||||
if (this.queue.length + samples.length > Math.max(sampleRate * 60, count * 2)) {
|
||||
console.error("[artplayerPluginAsr] Audio callback backlog exceeded its capture limit");
|
||||
this.pause();
|
||||
return;
|
||||
}
|
||||
this.queue.push(samples);
|
||||
});
|
||||
this.running = true;
|
||||
this.timer = setInterval(() => this.tick(count), interval);
|
||||
})().catch(async (error) => {
|
||||
if (current()) {
|
||||
console.error("[artplayerPluginAsr] Initialization failed:", error);
|
||||
await this.stop();
|
||||
}
|
||||
}).finally(() => {
|
||||
if (this.starting === operation)
|
||||
this.starting = void 0;
|
||||
});
|
||||
this.starting = operation;
|
||||
return operation;
|
||||
}
|
||||
async tick(count) {
|
||||
if (!this.running || this.pending)
|
||||
return;
|
||||
const samples = this.queue.take(count);
|
||||
if (!samples)
|
||||
return;
|
||||
const epoch = this.epoch;
|
||||
const pending = this.pending = {};
|
||||
try {
|
||||
const text = await this.options.onAudioChunk(encodeAudio(samples, this.options.sampleRate));
|
||||
if (this.running && !this.terminal && this.epoch === epoch)
|
||||
this.append(text);
|
||||
} catch (error) {
|
||||
if (this.epoch === epoch && !this.terminal)
|
||||
console.error("[artplayerPluginAsr] Audio callback failed:", error);
|
||||
} finally {
|
||||
if (this.pending === pending)
|
||||
this.pending = void 0;
|
||||
}
|
||||
}
|
||||
stop(terminal = false) {
|
||||
this.terminal || (this.terminal = terminal);
|
||||
this.pause();
|
||||
const graph = this.graph;
|
||||
if (terminal || !graph?.ownsMediaConnection) {
|
||||
this.graph = void 0;
|
||||
this.closing = Promise.all([this.closing, graph?.close()]).then(() => void 0);
|
||||
}
|
||||
return this.closing;
|
||||
}
|
||||
}
|
||||
const style = ".art-video-player .art-layer-asr {\n pointer-events: none !important;\n position: absolute;\n z-index: 150;\n inset: 0px;\n display: flex;\n flex-direction: column;\n justify-content: end;\n padding: 0 2%;\n font-size: 1rem;\n gap: var(--art-subtitle-gap);\n padding-bottom: var(--art-subtitle-bottom);\n transition: padding-bottom var(--art-transition-duration) ease;\n text-shadow: var(--art-subtitle-border) 1px 0 1px, var(--art-subtitle-border) 0 1px 1px, var(--art-subtitle-border) -1px 0 1px, var(--art-subtitle-border) 0 -1px 1px, var(--art-subtitle-border) 1px 1px 1px, var(--art-subtitle-border) -1px -1px 1px, var(--art-subtitle-border) 1px -1px 1px, var(--art-subtitle-border) -1px 1px 1px;\n}\n.art-video-player.art-control-show .art-layer-asr {\n padding-bottom: calc(var(--art-control-height) + var(--art-subtitle-bottom));\n}\n";
|
||||
function createSubtitles(layer, length, autoHideTimeout) {
|
||||
let timer;
|
||||
let destroyed = false;
|
||||
function cancelTimer() {
|
||||
clearTimeout(timer);
|
||||
timer = void 0;
|
||||
}
|
||||
function hide() {
|
||||
if (!destroyed)
|
||||
layer.style.display = "none";
|
||||
}
|
||||
function append(subtitle) {
|
||||
if (destroyed || typeof subtitle !== "string")
|
||||
return;
|
||||
cancelTimer();
|
||||
timer = setTimeout(hide, autoHideTimeout);
|
||||
layer.style.display = "";
|
||||
layer.innerHTML = subtitle.split(/(?<=[、。!?!?.])\s*/u).map((line) => line.trim()).filter(Boolean).slice(-length).map((line) => `<div class="art-asr-line">${line}</div>`).join("");
|
||||
}
|
||||
return {
|
||||
append,
|
||||
hide,
|
||||
destroy() {
|
||||
destroyed = true;
|
||||
cancelTimer();
|
||||
}
|
||||
};
|
||||
}
|
||||
if (typeof document !== "undefined") {
|
||||
if (!document.getElementById("artplayer-plugin-asr")) {
|
||||
const $style = document.createElement("style");
|
||||
$style.id = "artplayer-plugin-asr";
|
||||
$style.textContent = style;
|
||||
document.head.appendChild($style);
|
||||
}
|
||||
function artplayerPluginAsr(option = {}) {
|
||||
const { length = 3, interval = 100, sampleRate = 16e3, autoHideTimeout = 1e4, onAudioChunk = () => null, audioInput } = option;
|
||||
if (audioInput !== void 0 && audioInput.type !== "capture")
|
||||
throw new TypeError("Unsupported ASR audio input");
|
||||
const captureOnly = audioInput?.type === "capture";
|
||||
return (art) => {
|
||||
const layer = art.layers.add({ name: "asr", html: "" });
|
||||
if (!layer)
|
||||
throw new Error("Could not create ASR subtitle layer");
|
||||
const subtitles = createSubtitles(layer, length, autoHideTimeout);
|
||||
const capture = new Capture(art.video, { interval, sampleRate, onAudioChunk, captureOnly }, subtitles.append);
|
||||
const play = () => capture.start();
|
||||
const pause = () => capture.pause();
|
||||
const restart = () => capture.restart();
|
||||
const stop = () => capture.stop();
|
||||
const destroy = () => {
|
||||
subtitles.destroy();
|
||||
art.off("play", play);
|
||||
art.off("pause", pause);
|
||||
art.off("restart", restart);
|
||||
art.off("video:error", stop);
|
||||
art.off("destroy", destroy);
|
||||
return capture.stop(true);
|
||||
};
|
||||
art.on("play", play);
|
||||
art.on("pause", pause);
|
||||
art.on("restart", restart);
|
||||
art.on("video:error", stop);
|
||||
art.on("destroy", destroy);
|
||||
return { name: "artplayerPluginAsr", stop, hide: subtitles.hide, append: subtitles.append };
|
||||
};
|
||||
}
|
||||
Object.defineProperty(artplayerPluginAsr, "default", { value: artplayerPluginAsr });
|
||||
if (typeof document !== "undefined" && !document.getElementById("artplayer-plugin-asr")) {
|
||||
const styleElement = document.createElement("style");
|
||||
styleElement.id = "artplayer-plugin-asr";
|
||||
styleElement.textContent = style;
|
||||
document.head.appendChild(styleElement);
|
||||
}
|
||||
export {
|
||||
artplayerPluginAsr as default
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-audio-track.js v1.1.0
|
||||
* artplayer-plugin-audio-track.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(e,o){"object"===typeof exports&&"undefined"!==typeof module?module.exports=o():"function"==typeof define&&define.amd?(t.artplayerPluginAudioTrack=o(),define(function(){return t.artplayerPluginAudioTrack})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAudioTrack=o()}(this,function(){"use strict";return function(e){return o=>{let{url:n,offset:a=0,sync:t=.3}=e;const u=new Audio;function i(){if(!o.video||!n)return;const e=o.currentTime+a;Math.abs(u.currentTime-e)>t&&(u.currentTime=e)}return u.preload="auto",n&&(u.src=n),o.on("play",()=>{n&&(i(),u.play().catch(e=>{console.warn(e)}))}),o.on("pause",()=>{u.pause()}),o.on("seek",()=>{i()}),o.on("video:timeupdate",()=>{o.playing&&i()}),o.on("video:ratechange",()=>{u.playbackRate=o.video.playbackRate}),o.on("video:volumechange",()=>{u.volume=o.volume,u.muted=o.muted}),o.on("video:waiting",()=>{u.pause()}),o.on("video:playing",()=>{n&&o.playing&&u.play().catch(e=>{console.warn(e)})}),o.on("destroy",()=>{u.pause(),u.src="",u.load()}),u.volume=o.volume,u.muted=o.muted,u.playbackRate=o.video?.playbackRate||1,{name:"artplayerPluginAudioTrack",audio:u,update:function(e){e.url&&e.url!==n&&(n=e.url,u.src=n,o.playing&&u.play().catch(e=>console.warn(e))),void 0!==e.offset&&(a=e.offset),void 0!==e.sync&&(t=e.sync)}}}}});
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAudioTrack=t(),define(function(){return e.artplayerPluginAudioTrack})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAudioTrack=t()}(this,function(){"use strict";return function(e){return t=>{const o=function(e){let{url:t,offset:o=0,sync:n=.3}=e;const a=new Audio;let i=!1;function u(){!i&&t&&a.play().catch(e=>{i||console.warn(e)})}function c(){if(i)return;i=!0;const e=[];for(const o of[()=>a.pause(),()=>a.removeAttribute("src"),()=>a.load()])try{o()}catch(t){e.push(t)}if(e.length)throw e[0]}try{a.preload="auto",t&&(a.src=t)}catch(r){try{c()}catch{}throw r}return{audio:a,play:u,pause:function(){i||a.pause()},destroy:c,sync(e){if(i||!t)return;const u=e+o;Math.abs(a.currentTime-u)>n&&(a.currentTime=u)},update(e,c){i||(e.url&&e.url!==t&&(t=e.url,a.src=t,c&&u()),void 0!==e.offset&&(o=e.offset),void 0!==e.sync&&(n=e.sync))}}}(e),{audio:n}=o,a=[];let i=!0;function u(){t.video&&o.sync(t.currentTime)}function c(){const e=t.video;return!!e&&("playing"in e&&"boolean"===typeof e.playing?e.playing:t.playing||!1===e.paused&&!e.ended&&e.readyState>2)}function r(e,o){const n=()=>{i&&o()};a.push([e,n]),t.on(e,n)}function d(){if(!i)return;i=!1;const e=[];for(const[o,i]of a.splice(0))try{t.off(o,i)}catch(n){e.push(n)}try{o.destroy()}catch(n){e.push(n)}if(e.length)throw e[0]}try{r("play",()=>{u(),o.play()});for(const e of["pause","video:pause","video:ended","video:waiting","video:emptied","video:seeking"])r(e,o.pause);r("seek",u),r("video:seeked",()=>{u(),c()&&o.play()}),r("video:timeupdate",()=>{t.playing&&u()}),r("video:ratechange",()=>{n.playbackRate=t.video.playbackRate}),r("video:volumechange",()=>{n.volume=t.volume,n.muted=t.muted}),r("video:playing",()=>{c()&&(u(),o.play())}),r("video:canplay",()=>{n.paused&&c()&&(u(),o.play())}),r("destroy",d),n.volume=t.volume,n.muted=t.muted,n.playbackRate=t.video?.playbackRate||1}catch(s){try{d()}catch{}throw s}return{name:"artplayerPluginAudioTrack",audio:n,update(e){i&&o.update(e,t.playing)}}}}});
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-audio-track.js v1.1.0
|
||||
* artplayer-plugin-audio-track.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(e,o){"object"===typeof exports&&"undefined"!==typeof module?module.exports=o():"function"==typeof define&&define.amd?(t.artplayerPluginAudioTrack=o(),define(function(){return t.artplayerPluginAudioTrack})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAudioTrack=o()}(this,function(){"use strict";return function(e){return o=>{var n;let{url:a,offset:t=0,sync:u=.3}=e;const i=new Audio;function l(){if(!o.video||!a)return;const e=o.currentTime+t;Math.abs(i.currentTime-e)>u&&(i.currentTime=e)}return i.preload="auto",a&&(i.src=a),o.on("play",()=>{a&&(l(),i.play().catch(e=>{console.warn(e)}))}),o.on("pause",()=>{i.pause()}),o.on("seek",()=>{l()}),o.on("video:timeupdate",()=>{o.playing&&l()}),o.on("video:ratechange",()=>{i.playbackRate=o.video.playbackRate}),o.on("video:volumechange",()=>{i.volume=o.volume,i.muted=o.muted}),o.on("video:waiting",()=>{i.pause()}),o.on("video:playing",()=>{a&&o.playing&&i.play().catch(e=>{console.warn(e)})}),o.on("destroy",()=>{i.pause(),i.src="",i.load()}),i.volume=o.volume,i.muted=o.muted,i.playbackRate=(null==(n=o.video)?void 0:n.playbackRate)||1,{name:"artplayerPluginAudioTrack",audio:i,update:function(e){e.url&&e.url!==a&&(a=e.url,i.src=a,o.playing&&i.play().catch(e=>console.warn(e))),void 0!==e.offset&&(t=e.offset),void 0!==e.sync&&(u=e.sync)}}}}});
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAudioTrack=t(),define(function(){return e.artplayerPluginAudioTrack})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAudioTrack=t()}(this,function(){"use strict";return function(e){return t=>{var o;const n=function(e){let{url:t,offset:o=0,sync:n=.3}=e;const a=new Audio;let i=!1;function u(){!i&&t&&a.play().catch(e=>{i||console.warn(e)})}function c(){if(i)return;i=!0;const e=[];for(const o of[()=>a.pause(),()=>a.removeAttribute("src"),()=>a.load()])try{o()}catch(t){e.push(t)}if(e.length)throw e[0]}try{a.preload="auto",t&&(a.src=t)}catch(r){try{c()}catch(d){}throw r}return{audio:a,play:u,pause:function(){i||a.pause()},destroy:c,sync(e){if(i||!t)return;const u=e+o;Math.abs(a.currentTime-u)>n&&(a.currentTime=u)},update(e,c){i||(e.url&&e.url!==t&&(t=e.url,a.src=t,c&&u()),void 0!==e.offset&&(o=e.offset),void 0!==e.sync&&(n=e.sync))}}}(e),{audio:a}=n,i=[];let u=!0;function c(){t.video&&n.sync(t.currentTime)}function r(){const e=t.video;return!!e&&("playing"in e&&"boolean"===typeof e.playing?e.playing:t.playing||!1===e.paused&&!e.ended&&e.readyState>2)}function d(e,o){const n=()=>{u&&o()};i.push([e,n]),t.on(e,n)}function l(){if(!u)return;u=!1;const e=[];for(const[n,a]of i.splice(0))try{t.off(n,a)}catch(o){e.push(o)}try{n.destroy()}catch(o){e.push(o)}if(e.length)throw e[0]}try{d("play",()=>{c(),n.play()});for(const e of["pause","video:pause","video:ended","video:waiting","video:emptied","video:seeking"])d(e,n.pause);d("seek",c),d("video:seeked",()=>{c(),r()&&n.play()}),d("video:timeupdate",()=>{t.playing&&c()}),d("video:ratechange",()=>{a.playbackRate=t.video.playbackRate}),d("video:volumechange",()=>{a.volume=t.volume,a.muted=t.muted}),d("video:playing",()=>{r()&&(c(),n.play())}),d("video:canplay",()=>{a.paused&&r()&&(c(),n.play())}),d("destroy",l),a.volume=t.volume,a.muted=t.muted,a.playbackRate=(null==(o=t.video)?void 0:o.playbackRate)||1}catch(s){try{l()}catch(p){}throw s}return{name:"artplayerPluginAudioTrack",audio:a,update(e){u&&n.update(e,t.playing)}}}}});
|
||||
@@ -1,89 +1,179 @@
|
||||
/*!
|
||||
* artplayer-plugin-audio-track.js v1.1.0
|
||||
* artplayer-plugin-audio-track.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
function artplayerPluginAudioTrack(option) {
|
||||
return (art) => {
|
||||
let { url, offset = 0, sync = 0.3 } = option;
|
||||
const audio = new Audio();
|
||||
function createAudioTrack(option) {
|
||||
let { url, offset = 0, sync = 0.3 } = option;
|
||||
const audio = new Audio();
|
||||
let closed = false;
|
||||
function play() {
|
||||
if (closed || !url)
|
||||
return;
|
||||
audio.play().catch((error) => {
|
||||
if (!closed)
|
||||
console.warn(error);
|
||||
});
|
||||
}
|
||||
function pause() {
|
||||
if (!closed)
|
||||
audio.pause();
|
||||
}
|
||||
function destroy() {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
const failures = [];
|
||||
for (const release of [() => audio.pause(), () => audio.removeAttribute("src"), () => audio.load()]) {
|
||||
try {
|
||||
release();
|
||||
} catch (error) {
|
||||
failures.push(error);
|
||||
}
|
||||
}
|
||||
if (failures.length)
|
||||
throw failures[0];
|
||||
}
|
||||
try {
|
||||
audio.preload = "auto";
|
||||
if (url) {
|
||||
if (url)
|
||||
audio.src = url;
|
||||
} catch (error) {
|
||||
try {
|
||||
destroy();
|
||||
} catch {
|
||||
}
|
||||
function syncAudio() {
|
||||
if (!art.video || !url)
|
||||
throw error;
|
||||
}
|
||||
return {
|
||||
audio,
|
||||
play,
|
||||
pause,
|
||||
destroy,
|
||||
sync(time) {
|
||||
if (closed || !url)
|
||||
return;
|
||||
const videoTime = art.currentTime;
|
||||
const targetTime = videoTime + offset;
|
||||
if (Math.abs(audio.currentTime - targetTime) > sync) {
|
||||
audio.currentTime = targetTime;
|
||||
}
|
||||
}
|
||||
art.on("play", () => {
|
||||
if (!url)
|
||||
const target = time + offset;
|
||||
if (Math.abs(audio.currentTime - target) > sync)
|
||||
audio.currentTime = target;
|
||||
},
|
||||
update(newOption, playing) {
|
||||
if (closed)
|
||||
return;
|
||||
syncAudio();
|
||||
audio.play().catch((err) => {
|
||||
console.warn(err);
|
||||
});
|
||||
});
|
||||
art.on("pause", () => {
|
||||
audio.pause();
|
||||
});
|
||||
art.on("seek", () => {
|
||||
syncAudio();
|
||||
});
|
||||
art.on("video:timeupdate", () => {
|
||||
if (art.playing) {
|
||||
syncAudio();
|
||||
}
|
||||
});
|
||||
art.on("video:ratechange", () => {
|
||||
audio.playbackRate = art.video.playbackRate;
|
||||
});
|
||||
art.on("video:volumechange", () => {
|
||||
audio.volume = art.volume;
|
||||
audio.muted = art.muted;
|
||||
});
|
||||
art.on("video:waiting", () => {
|
||||
audio.pause();
|
||||
});
|
||||
art.on("video:playing", () => {
|
||||
if (url && art.playing) {
|
||||
audio.play().catch((err) => {
|
||||
console.warn(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
art.on("destroy", () => {
|
||||
audio.pause();
|
||||
audio.src = "";
|
||||
audio.load();
|
||||
});
|
||||
function update(newOption) {
|
||||
if (newOption.url && newOption.url !== url) {
|
||||
url = newOption.url;
|
||||
audio.src = url;
|
||||
if (art.playing) {
|
||||
audio.play().catch((err) => console.warn(err));
|
||||
if (playing)
|
||||
play();
|
||||
}
|
||||
if (newOption.offset !== void 0)
|
||||
offset = newOption.offset;
|
||||
if (newOption.sync !== void 0)
|
||||
sync = newOption.sync;
|
||||
}
|
||||
};
|
||||
}
|
||||
function artplayerPluginAudioTrack(option) {
|
||||
return (art) => {
|
||||
const track = createAudioTrack(option);
|
||||
const { audio } = track;
|
||||
const subscriptions = [];
|
||||
let active = true;
|
||||
function syncAudio() {
|
||||
if (art.video)
|
||||
track.sync(art.currentTime);
|
||||
}
|
||||
function canResumeAudio() {
|
||||
const video = art.video;
|
||||
if (!video)
|
||||
return false;
|
||||
if ("playing" in video && typeof video.playing === "boolean")
|
||||
return video.playing;
|
||||
return art.playing || video.paused === false && !video.ended && video.readyState > 2;
|
||||
}
|
||||
function listen(event, callback) {
|
||||
const listener = () => {
|
||||
if (active)
|
||||
callback();
|
||||
};
|
||||
subscriptions.push([event, listener]);
|
||||
art.on(event, listener);
|
||||
}
|
||||
function destroy() {
|
||||
if (!active)
|
||||
return;
|
||||
active = false;
|
||||
const failures = [];
|
||||
for (const [event, listener] of subscriptions.splice(0)) {
|
||||
try {
|
||||
art.off(event, listener);
|
||||
} catch (error) {
|
||||
failures.push(error);
|
||||
}
|
||||
}
|
||||
if (newOption.offset !== void 0) {
|
||||
offset = newOption.offset;
|
||||
}
|
||||
if (newOption.sync !== void 0) {
|
||||
sync = newOption.sync;
|
||||
try {
|
||||
track.destroy();
|
||||
} catch (error) {
|
||||
failures.push(error);
|
||||
}
|
||||
if (failures.length)
|
||||
throw failures[0];
|
||||
}
|
||||
try {
|
||||
listen("play", () => {
|
||||
syncAudio();
|
||||
track.play();
|
||||
});
|
||||
for (const event of ["pause", "video:pause", "video:ended", "video:waiting", "video:emptied", "video:seeking"])
|
||||
listen(event, track.pause);
|
||||
listen("seek", syncAudio);
|
||||
listen("video:seeked", () => {
|
||||
syncAudio();
|
||||
if (canResumeAudio())
|
||||
track.play();
|
||||
});
|
||||
listen("video:timeupdate", () => {
|
||||
if (art.playing)
|
||||
syncAudio();
|
||||
});
|
||||
listen("video:ratechange", () => {
|
||||
audio.playbackRate = art.video.playbackRate;
|
||||
});
|
||||
listen("video:volumechange", () => {
|
||||
audio.volume = art.volume;
|
||||
audio.muted = art.muted;
|
||||
});
|
||||
listen("video:playing", () => {
|
||||
if (canResumeAudio()) {
|
||||
syncAudio();
|
||||
track.play();
|
||||
}
|
||||
});
|
||||
listen("video:canplay", () => {
|
||||
if (audio.paused && canResumeAudio()) {
|
||||
syncAudio();
|
||||
track.play();
|
||||
}
|
||||
});
|
||||
listen("destroy", destroy);
|
||||
audio.volume = art.volume;
|
||||
audio.muted = art.muted;
|
||||
audio.playbackRate = art.video?.playbackRate || 1;
|
||||
} catch (error) {
|
||||
try {
|
||||
destroy();
|
||||
} catch {
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
audio.volume = art.volume;
|
||||
audio.muted = art.muted;
|
||||
audio.playbackRate = art.video?.playbackRate || 1;
|
||||
return {
|
||||
name: "artplayerPluginAudioTrack",
|
||||
audio,
|
||||
update
|
||||
update(newOption) {
|
||||
if (active)
|
||||
track.update(newOption, art.playing);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-auto-thumbnail.js v1.1.0
|
||||
* artplayer-plugin-auto-thumbnail.js v2.0.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.artplayerPluginAutoThumbnail=t(),define(function(){return t.artplayerPluginAutoThumbnail})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAutoThumbnail=t()}(this,function(){"use strict";return function(e){return async t=>(t.on("video:loadedmetadata",()=>{const n=e.url||t.option.url,o=e.width||160,i=e.number||100,u=e.scale||1;!function({url:e,width:t,number:n},o){const i=document.createElement("video");i.crossOrigin="anonymous",i.src=e,i.onloadedmetadata=()=>{const e=i.duration,u=document.createElement("canvas"),a=u.getContext("2d"),l=Math.floor(t*i.videoHeight/i.videoWidth);u.width=10*t,u.height=l*Math.ceil(n/10);let r=null;!function d(c){u.toBlob(e=>{URL.revokeObjectURL(r),r=URL.createObjectURL(e),o({url:r,height:l})},"image/jpeg"),c>=n||(i.currentTime=e*c/n,i.onseeked=()=>{a.drawImage(i,c%10*t,Math.floor(c/10)*l,t,l),d(c+1)})}(0)}}({url:n,width:o,number:i},e=>{t.thumbnails={...e,column:10,number:i,width:o,scale:u}})}),{name:"artplayerPluginAutoThumbnail"})}});
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAutoThumbnail=t(),define(function(){return e.artplayerPluginAutoThumbnail})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAutoThumbnail=t()}(this,function(){"use strict";function e(e){let t,n=!1;for(const r of e)try{r()}catch(i){n||(n=!0,t=i)}return{failed:n,failure:t}}function t(t,n){const i="function"===typeof n.requestVideoFrameCallback&&"function"===typeof n.cancelVideoFrameCallback;let r;function o(){const t=r;r=void 0;const i=e([()=>{n.onloadeddata=null},()=>{n.onseeked=null},()=>{t&&null!==t.timer&&clearTimeout(t.timer)},()=>{t&&null!==t.frame&&n.cancelVideoFrameCallback(t.frame)}]);if(i.failed)throw i.failure}return t.own(o),(e,a)=>{if(o(),!t.active())return;const u={frame:null,timer:null,sought:!1,presented:!i,retries:0,sequence:0,started:!1};r=u;const d=()=>t.active()&&r===u,l=t.guard(()=>{d()&&u.sought&&u.presented&&(o(),t.active()&&a())}),c=()=>{u.sought=!1,(()=>{if(!i)return;const e=++u.sequence;u.presented=!1;const r=u.frame;if(u.frame=null,null!==r&&n.cancelVideoFrameCallback(r),!d())return;let o=!1;const a=n.requestVideoFrameCallback(t.guard(()=>{d()&&e===u.sequence&&!o&&(o=!0,u.frame=null,u.presented=!0,l())}));d()&&e===u.sequence&&!o?u.frame=a:n.cancelVideoFrameCallback(a)})(),d()&&(n.currentTime=e)},s=t.guard(()=>{d()&&!u.started&&(u.started=!0,n.onloadeddata=null,n.onseeked=t.guard(()=>{if(!d()||n.seeking)return;const t=n.currentTime;if(d())if(!Number.isFinite(t)||Math.abs(t-e)>.05){if(++u.retries>3)throw new Error("Auto-thumbnail seek did not reach the requested time");c()}else u.sought=!0,l()}),c())});if(u.timer=setTimeout(t.guard(()=>{if(d())throw new Error("Auto-thumbnail frame readiness timed out")}),3e4),!d())return void clearTimeout(u.timer);const f=!i||n.readyState>=2;d()&&(f?s():n.onloadeddata=s)}}function n(e,n){const i=function(e){const t=document.createElement("video");e.own(()=>t.remove()),e.own(()=>t.load()),e.own(()=>t.removeAttribute("src")),e.own(()=>t.pause());for(const n of["onloadedmetadata","onloadeddata","onseeked","onerror"])e.own(()=>{t[n]=null});return e.active()?(t.crossOrigin="anonymous",t.muted=!0,t.playsInline=!0,t.tabIndex=-1,t.setAttribute("aria-hidden","true"),t.style.cssText="position:fixed;left:0;top:0;visibility:hidden;pointer-events:none;display:block;width:auto;height:auto;max-width:none;max-height:none",document.documentElement.appendChild(t),e.active()||t.remove(),t):t}(e);if(!e.active())return;let r=null;const o=()=>{const e=r;r=null,null!==e&&clearTimeout(e)};e.own(o),i.onerror=e.guard(()=>{throw i.error||new Error("Auto-thumbnail media failed to load")}),i.onloadedmetadata=e.guard(()=>{o(),i.onloadedmetadata=null;const r=i.duration,a=i.videoHeight,u=i.videoWidth,{height:d,canvasWidth:l,canvasHeight:c}=function(e,t){if(!Number.isFinite(t.duration)||t.duration<=0||!Number.isFinite(t.videoWidth)||t.videoWidth<=0||!Number.isFinite(t.videoHeight)||t.videoHeight<=0)throw new TypeError("Auto-thumbnail requires finite media duration and dimensions");const n=Math.floor(e.width*t.videoHeight/t.videoWidth),i=Math.trunc(10*e.width),r=Math.trunc(n*Math.ceil(e.number/10));if(![n,i,r].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:n,canvasWidth:i,canvasHeight:r}}(n,{duration:r,videoHeight:a,videoWidth:u});if(!e.active())return;i.width=u,i.height=a,i.style.width=`${u}px`,i.style.height=`${a}px`;const s=document.createElement("canvas");if(e.own(()=>{s.height=0}),e.own(()=>{s.width=0}),!e.active())return;if(s.width=l,!e.active())return;if(s.height=c,!e.active())return;const f=s.getContext("2d");if(!f)throw new Error("Auto-thumbnail canvas context is unavailable");if(!e.active())return;const m=t(e,i),h=function(e,t){let n;function i(){const e=n;n=void 0,e&&null!==e.timer&&clearTimeout(e.timer)}return e.own(i),r=>{if(!e.active())return;if(n)throw new Error("Auto-thumbnail encoding is already pending");const o={timer:null};n=o;const a=()=>e.active()&&n===o;o.timer=setTimeout(e.guard(()=>{if(a())throw new Error("Auto-thumbnail encoding timed out")}),3e4),a()?t.toBlob(e.guard(t=>{a()&&(i(),e.active()&&r(t))}),"image/jpeg"):clearTimeout(o.timer)}}(e,s);let v=0;const b=e.guard(()=>{v>=n.number?e.dispose():m(r*v/n.number,e.guard(()=>{f.drawImage(i,v%10*n.width,Math.floor(v/10)*d,n.width,d),e.active()&&h(t=>{e.publish(t,{height:d,column:10,number:n.number,width:n.width,scale:n.scale}),e.active()&&(v+=1,b())})}))});b()}),e.active()&&(r=setTimeout(e.guard(()=>{if(null!==r)throw new Error("Auto-thumbnail metadata timed out")}),3e4),e.active()?i.src=n.url:o())}function i(t){return async i=>{if(i.isDestroy)return{name:"artplayerPluginAutoThumbnail"};const r=e=>console.warn("ArtPlayer auto-thumbnail failed:",e),o=function(t,n){let i,r,o=!1;const a=new Set;function u(e){void 0!==e&&a.delete(e)&&URL.revokeObjectURL(e)}functiLine truncated
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-auto-thumbnail.js v1.1.0
|
||||
* artplayer-plugin-auto-thumbnail.js v2.0.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.artplayerPluginAutoThumbnail=t(),define(function(){return t.artplayerPluginAutoThumbnail})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAutoThumbnail=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.defineProperties,n=Object.getOwnPropertyDescriptors,r=Object.getOwnPropertySymbols,o=Object.prototype.hasOwnProperty,a=Object.prototype.propertyIsEnumerable,i=(t,n,r)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[n]=r;return function(e){return l=>{return u=null,c=null,d=function*(){return l.on("video:loadedmetadata",()=>{const u=e.url||l.option.url,c=e.width||160,d=e.number||100,s=e.scale||1;!function({url:e,width:t,number:n},r){const o=document.createElement("video");o.crossOrigin="anonymous",o.src=e,o.onloadedmetadata=()=>{const e=o.duration,a=document.createElement("canvas"),i=a.getContext("2d"),l=Math.floor(t*o.videoHeight/o.videoWidth);a.width=10*t,a.height=l*Math.ceil(n/10);let u=null;!function c(d){a.toBlob(e=>{URL.revokeObjectURL(u),u=URL.createObjectURL(e),r({url:u,height:l})},"image/jpeg"),d>=n||(o.currentTime=e*d/n,o.onseeked=()=>{i.drawImage(o,d%10*t,Math.floor(d/10)*l,t,l),c(d+1)})}(0)}}({url:u,width:c,number:d},e=>{var u;l.thumbnails=(u=((e,t)=>{for(var n in t||(t={}))o.call(t,n)&&i(e,n,t[n]);if(r)for(var n of r(t))a.call(t,n)&&i(e,n,t[n]);return e})({},e),t(u,n({column:10,number:d,width:c,scale:s})))})}),{name:"artplayerPluginAutoThumbnail"}},new Promise((e,t)=>{var n=e=>{try{o(d.next(e))}catch(n){t(n)}},r=e=>{try{o(d.throw(e))}catch(n){t(n)}},o=t=>t.done?e(t.value):Promise.resolve(t.value).then(n,r);o((d=d.apply(u,c)).next())});var u,c,d}}});
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAutoThumbnail=t(),define(function(){return e.artplayerPluginAutoThumbnail})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAutoThumbnail=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable,i=(t,n,r)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[n]=r;function o(e){let t,n=!1;for(const i of e)try{i()}catch(r){n||(n=!0,t=r)}return{failed:n,failure:t}}function a(e,a){let u,l,d=!1;const c=new Set;function s(e){void 0!==e&&c.delete(e)&&URL.revokeObjectURL(e)}function f(){const e=u;u=void 0,null==e||e.dispose()}return{start:function(){if(d)return;const f=u,m=[];let h=!1;const v={active:()=>!d&&!h&&u===v,own(e){if(h){const t=o([e]);t.failed&&a(t.failure)}else m.push(e)},dispose(){if(h)return;h=!0,u===v&&(u=void 0);const e=o(m.splice(0).reverse());e.failed&&a(e.failure)},fail(e){v.active()&&(v.dispose(),a(e))},guard:e=>(...t)=>{if(v.active())try{return e(...t)}catch(n){v.fail(n)}},publish(u,d){if(!v.active())return;if(!u)throw new Error("Auto-thumbnail encoding returned no Blob");const f=URL.createObjectURL(u);if(c.add(f),!v.active())return void s(f);const m=l;l=f;try{e(((e,o)=>{for(var a in o||(o={}))n.call(o,a)&&i(e,a,o[a]);if(t)for(var a of t(o))r.call(o,a)&&i(e,a,o[a]);return e})({url:f},d))}catch(h){l===f&&(l=void 0!==m&&c.has(m)?m:void 0);const e=o([()=>s(f)]);throw e.failed&&a(e.failure),h}s(m)}};return u=v,null==f||f.dispose(),v},cancel:f,destroy:function(){if(d)return;d=!0;const e=o([f,...[...c].map(e=>()=>s(e))]);l=void 0,e.failed&&a(e.failure)},get closed(){return d}}}function u(e,t){const n="function"===typeof t.requestVideoFrameCallback&&"function"===typeof t.cancelVideoFrameCallback;let r;function i(){const e=r;r=void 0;const n=o([()=>{t.onloadeddata=null},()=>{t.onseeked=null},()=>{e&&null!==e.timer&&clearTimeout(e.timer)},()=>{e&&null!==e.frame&&t.cancelVideoFrameCallback(e.frame)}]);if(n.failed)throw n.failure}return e.own(i),(o,a)=>{if(i(),!e.active())return;const u={frame:null,timer:null,sought:!1,presented:!n,retries:0,sequence:0,started:!1};r=u;const l=()=>e.active()&&r===u,d=e.guard(()=>{l()&&u.sought&&u.presented&&(i(),e.active()&&a())}),c=()=>{u.sought=!1,(()=>{if(!n)return;const r=++u.sequence;u.presented=!1;const i=u.frame;if(u.frame=null,null!==i&&t.cancelVideoFrameCallback(i),!l())return;let o=!1;const a=t.requestVideoFrameCallback(e.guard(()=>{l()&&r===u.sequence&&!o&&(o=!0,u.frame=null,u.presented=!0,d())}));l()&&r===u.sequence&&!o?u.frame=a:t.cancelVideoFrameCallback(a)})(),l()&&(t.currentTime=o)},s=e.guard(()=>{l()&&!u.started&&(u.started=!0,t.onloadeddata=null,t.onseeked=e.guard(()=>{if(!l()||t.seeking)return;const e=t.currentTime;if(l())if(!Number.isFinite(e)||Math.abs(e-o)>.05){if(++u.retries>3)throw new Error("Auto-thumbnail seek did not reach the requested time");c()}else u.sought=!0,d()}),c())});if(u.timer=setTimeout(e.guard(()=>{if(l())throw new Error("Auto-thumbnail frame readiness timed out")}),3e4),!l())return void clearTimeout(u.timer);const f=!n||t.readyState>=2;l()&&(f?s():t.onloadeddata=s)}}function l(e,t){const n=function(e){const t=document.createElement("video");e.own(()=>t.remove()),e.own(()=>t.load()),e.own(()=>t.removeAttribute("src")),e.own(()=>t.pause());for(const n of["onloadedmetadata","onloadeddata","onseeked","onerror"])e.own(()=>{t[n]=null});return e.active()?(t.crossOrigin="anonymous",t.muted=!0,t.playsInline=!0,t.tabIndex=-1,t.setAttribute("aria-hidden","true"),t.style.cssText="position:fixed;left:0;top:0;visibility:hidden;pointer-events:none;display:block;width:auto;height:auto;max-width:none;max-height:none",document.documentElement.appendChild(t),e.active()||t.remove(),t):t}(e);if(!e.active())return;let r=null;const i=()=>{const e=r;r=null,null!==e&&clearTimeout(e)};e.own(i),n.onerror=e.guard(()=>{throw n.error||new Error("Auto-thumbnail media failed to load")}),n.onloadedmetadata=e.guard(()=>{i(),n.onloadedmetadata=null;const r=n.duration,o=n.videoHeight,a=n.videoWidth,{height:l,canvasWidth:d,canvasHeight:c}=function(e,t){if(!Number.isFinite(t.duration)||t.duration<=0||!Number.isFinite(t.videoWidth)||t.videoWidth<=0||!Number.isFinite(t.videoHeight)||t.videoHeight<=0)throw new TypeError("Auto-thumbnail requires finite media duration and dimensions");const n=Math.floor(e.width*t.videoHeight/t.videoWidth),r=Math.trunc(10*e.width),i=Math.trunc(n*Math.ceil(e.number/10));if(![n,r,i].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:n,canvasWidth:r,canvasHeight:i}}(t,{duration:r,videoHeight:o,videoWidth:a});if(!e.active())return;n.width=a,n.height=o,n.style.width=`${a}px`,n.style.height=`${o}px`;const s=document.createElement("canvas");if(e.own(()=>{s.height=0}),e.own(()=Line truncated
|
||||
@@ -1,63 +1,448 @@
|
||||
/*!
|
||||
* artplayer-plugin-auto-thumbnail.js v1.1.0
|
||||
* artplayer-plugin-auto-thumbnail.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
function create({ url, width, number }, callback) {
|
||||
const video = document.createElement("video");
|
||||
video.crossOrigin = "anonymous";
|
||||
video.src = url;
|
||||
video.onloadedmetadata = () => {
|
||||
const duration = video.duration;
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
const height = Math.floor(width * video.videoHeight / video.videoWidth);
|
||||
canvas.width = width * 10;
|
||||
canvas.height = height * Math.ceil(number / 10);
|
||||
let blobUrl = null;
|
||||
function seekAndDraw(index) {
|
||||
canvas.toBlob((blob) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
blobUrl = URL.createObjectURL(blob);
|
||||
callback({
|
||||
url: blobUrl,
|
||||
height
|
||||
});
|
||||
}, "image/jpeg");
|
||||
if (index >= number)
|
||||
return;
|
||||
video.currentTime = duration * index / number;
|
||||
video.onseeked = () => {
|
||||
ctx.drawImage(video, index % 10 * width, Math.floor(index / 10) * height, width, height);
|
||||
seekAndDraw(index + 1);
|
||||
};
|
||||
function createEncoder(job, canvas) {
|
||||
let pending;
|
||||
function clear() {
|
||||
const previous = pending;
|
||||
pending = void 0;
|
||||
if (previous && previous.timer !== null)
|
||||
clearTimeout(previous.timer);
|
||||
}
|
||||
job.own(clear);
|
||||
return (publish) => {
|
||||
if (!job.active())
|
||||
return;
|
||||
if (pending)
|
||||
throw new Error("Auto-thumbnail encoding is already pending");
|
||||
const current = { timer: null };
|
||||
pending = current;
|
||||
const active = () => job.active() && pending === current;
|
||||
current.timer = setTimeout(job.guard(() => {
|
||||
if (active())
|
||||
throw new Error("Auto-thumbnail encoding timed out");
|
||||
}), 3e4);
|
||||
if (!active()) {
|
||||
clearTimeout(current.timer);
|
||||
return;
|
||||
}
|
||||
seekAndDraw(0);
|
||||
canvas.toBlob(job.guard((blob) => {
|
||||
if (!active())
|
||||
return;
|
||||
clear();
|
||||
if (job.active())
|
||||
publish(blob);
|
||||
}), "image/jpeg");
|
||||
};
|
||||
}
|
||||
function cleanupAll(actions) {
|
||||
let failure;
|
||||
let failed = false;
|
||||
for (const action of actions) {
|
||||
try {
|
||||
action();
|
||||
} catch (error) {
|
||||
if (!failed) {
|
||||
failed = true;
|
||||
failure = error;
|
||||
}
|
||||
}
|
||||
}
|
||||
return { failed, failure };
|
||||
}
|
||||
function createSession(publish, report) {
|
||||
let closed = false;
|
||||
let current;
|
||||
let lastUrl;
|
||||
const urls = /* @__PURE__ */ new Set();
|
||||
function release(url) {
|
||||
if (url !== void 0 && urls.delete(url))
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
function cancel() {
|
||||
const previous = current;
|
||||
current = void 0;
|
||||
previous?.dispose();
|
||||
}
|
||||
function destroy() {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
const result = cleanupAll([cancel, ...[...urls].map((url) => () => release(url))]);
|
||||
lastUrl = void 0;
|
||||
if (result.failed)
|
||||
report(result.failure);
|
||||
}
|
||||
function start() {
|
||||
if (closed)
|
||||
return;
|
||||
const previous = current;
|
||||
const actions = [];
|
||||
let disposed = false;
|
||||
const job = {
|
||||
active: () => !closed && !disposed && current === job,
|
||||
own(action) {
|
||||
if (disposed) {
|
||||
const result = cleanupAll([action]);
|
||||
if (result.failed)
|
||||
report(result.failure);
|
||||
} else {
|
||||
actions.push(action);
|
||||
}
|
||||
},
|
||||
dispose() {
|
||||
if (disposed)
|
||||
return;
|
||||
disposed = true;
|
||||
if (current === job)
|
||||
current = void 0;
|
||||
const result = cleanupAll(actions.splice(0).reverse());
|
||||
if (result.failed)
|
||||
report(result.failure);
|
||||
},
|
||||
fail(error) {
|
||||
if (!job.active())
|
||||
return;
|
||||
job.dispose();
|
||||
report(error);
|
||||
},
|
||||
guard(callback) {
|
||||
return (...args) => {
|
||||
if (!job.active())
|
||||
return;
|
||||
try {
|
||||
return callback(...args);
|
||||
} catch (error) {
|
||||
job.fail(error);
|
||||
}
|
||||
};
|
||||
},
|
||||
publish(blob, config) {
|
||||
if (!job.active())
|
||||
return;
|
||||
if (!blob)
|
||||
throw new Error("Auto-thumbnail encoding returned no Blob");
|
||||
const url = URL.createObjectURL(blob);
|
||||
urls.add(url);
|
||||
if (!job.active()) {
|
||||
release(url);
|
||||
return;
|
||||
}
|
||||
const previousUrl = lastUrl;
|
||||
lastUrl = url;
|
||||
try {
|
||||
publish({ url, ...config });
|
||||
} catch (error) {
|
||||
if (lastUrl === url)
|
||||
lastUrl = previousUrl !== void 0 && urls.has(previousUrl) ? previousUrl : void 0;
|
||||
const result = cleanupAll([() => release(url)]);
|
||||
if (result.failed)
|
||||
report(result.failure);
|
||||
throw error;
|
||||
}
|
||||
release(previousUrl);
|
||||
}
|
||||
};
|
||||
current = job;
|
||||
previous?.dispose();
|
||||
return job;
|
||||
}
|
||||
return {
|
||||
start,
|
||||
cancel,
|
||||
destroy,
|
||||
get closed() {
|
||||
return closed;
|
||||
}
|
||||
};
|
||||
}
|
||||
function createFrameReader(job, video) {
|
||||
const presentedFrames = typeof video.requestVideoFrameCallback === "function" && typeof video.cancelVideoFrameCallback === "function";
|
||||
let pending;
|
||||
function clear() {
|
||||
const previous = pending;
|
||||
pending = void 0;
|
||||
const result = cleanupAll([
|
||||
() => {
|
||||
video.onloadeddata = null;
|
||||
},
|
||||
() => {
|
||||
video.onseeked = null;
|
||||
},
|
||||
() => {
|
||||
if (previous && previous.timer !== null)
|
||||
clearTimeout(previous.timer);
|
||||
},
|
||||
() => {
|
||||
if (previous && previous.frame !== null)
|
||||
video.cancelVideoFrameCallback(previous.frame);
|
||||
}
|
||||
]);
|
||||
if (result.failed)
|
||||
throw result.failure;
|
||||
}
|
||||
job.own(clear);
|
||||
return (target, draw) => {
|
||||
clear();
|
||||
if (!job.active())
|
||||
return;
|
||||
const current = { frame: null, timer: null, sought: false, presented: !presentedFrames, retries: 0, sequence: 0, started: false };
|
||||
pending = current;
|
||||
const active = () => job.active() && pending === current;
|
||||
const finish = job.guard(() => {
|
||||
if (!active() || !current.sought || !current.presented)
|
||||
return;
|
||||
clear();
|
||||
if (job.active())
|
||||
draw();
|
||||
});
|
||||
const requestFrame = () => {
|
||||
if (!presentedFrames)
|
||||
return;
|
||||
const sequence = ++current.sequence;
|
||||
current.presented = false;
|
||||
const previous = current.frame;
|
||||
current.frame = null;
|
||||
if (previous !== null)
|
||||
video.cancelVideoFrameCallback(previous);
|
||||
if (!active())
|
||||
return;
|
||||
let delivered = false;
|
||||
const id = video.requestVideoFrameCallback(job.guard(() => {
|
||||
if (!active() || sequence !== current.sequence || delivered)
|
||||
return;
|
||||
delivered = true;
|
||||
current.frame = null;
|
||||
current.presented = true;
|
||||
finish();
|
||||
}));
|
||||
if (active() && sequence === current.sequence && !delivered)
|
||||
current.frame = id;
|
||||
else
|
||||
video.cancelVideoFrameCallback(id);
|
||||
};
|
||||
const seek = () => {
|
||||
current.sought = false;
|
||||
requestFrame();
|
||||
if (active())
|
||||
video.currentTime = target;
|
||||
};
|
||||
const begin = job.guard(() => {
|
||||
if (!active() || current.started)
|
||||
return;
|
||||
current.started = true;
|
||||
video.onloadeddata = null;
|
||||
video.onseeked = job.guard(() => {
|
||||
if (!active() || video.seeking)
|
||||
return;
|
||||
const time = video.currentTime;
|
||||
if (!active())
|
||||
return;
|
||||
if (!Number.isFinite(time) || Math.abs(time - target) > 0.05) {
|
||||
if (++current.retries > 3)
|
||||
throw new Error("Auto-thumbnail seek did not reach the requested time");
|
||||
seek();
|
||||
return;
|
||||
}
|
||||
current.sought = true;
|
||||
finish();
|
||||
});
|
||||
seek();
|
||||
});
|
||||
current.timer = setTimeout(job.guard(() => {
|
||||
if (active())
|
||||
throw new Error("Auto-thumbnail frame readiness timed out");
|
||||
}), 3e4);
|
||||
if (!active()) {
|
||||
clearTimeout(current.timer);
|
||||
return;
|
||||
}
|
||||
const ready = !presentedFrames || video.readyState >= 2;
|
||||
if (!active())
|
||||
return;
|
||||
if (!ready)
|
||||
video.onloadeddata = begin;
|
||||
else
|
||||
begin();
|
||||
};
|
||||
}
|
||||
function readOptions(option, getFallbackUrl) {
|
||||
const config = {
|
||||
url: option.url || getFallbackUrl(),
|
||||
width: option.width || 160,
|
||||
number: option.number || 100,
|
||||
scale: option.scale || 1
|
||||
};
|
||||
if (!Number.isFinite(Number(config.width)) || config.width <= 0 || !Number.isFinite(Number(config.number)) || config.number <= 0)
|
||||
throw new TypeError("Auto-thumbnail width and number must be finite positive numbers");
|
||||
return config;
|
||||
}
|
||||
function sheetSize(config, video) {
|
||||
if (!Number.isFinite(video.duration) || video.duration <= 0 || !Number.isFinite(video.videoWidth) || video.videoWidth <= 0 || !Number.isFinite(video.videoHeight) || video.videoHeight <= 0)
|
||||
throw new TypeError("Auto-thumbnail requires finite media duration and dimensions");
|
||||
const height = Math.floor(config.width * video.videoHeight / video.videoWidth);
|
||||
const canvasWidth = Math.trunc(config.width * 10);
|
||||
const canvasHeight = Math.trunc(height * Math.ceil(config.number / 10));
|
||||
if (![height, canvasWidth, canvasHeight].every((value) => Number.isSafeInteger(value) && value > 0 && value <= 4294967295))
|
||||
throw new RangeError("Auto-thumbnail canvas dimensions are invalid");
|
||||
return { height, canvasWidth, canvasHeight };
|
||||
}
|
||||
function createVideo(job) {
|
||||
const video = document.createElement("video");
|
||||
job.own(() => video.remove());
|
||||
job.own(() => video.load());
|
||||
job.own(() => video.removeAttribute("src"));
|
||||
job.own(() => video.pause());
|
||||
for (const property of ["onloadedmetadata", "onloadeddata", "onseeked", "onerror"])
|
||||
job.own(() => {
|
||||
video[property] = null;
|
||||
});
|
||||
if (!job.active())
|
||||
return video;
|
||||
video.crossOrigin = "anonymous";
|
||||
video.muted = true;
|
||||
video.playsInline = true;
|
||||
video.tabIndex = -1;
|
||||
video.setAttribute("aria-hidden", "true");
|
||||
video.style.cssText = "position:fixed;left:0;top:0;visibility:hidden;pointer-events:none;display:block;width:auto;height:auto;max-width:none;max-height:none";
|
||||
document.documentElement.appendChild(video);
|
||||
if (!job.active())
|
||||
video.remove();
|
||||
return video;
|
||||
}
|
||||
function extract(job, config) {
|
||||
const video = createVideo(job);
|
||||
if (!job.active())
|
||||
return;
|
||||
let metadataTimer = null;
|
||||
const clearMetadataTimer = () => {
|
||||
const previous = metadataTimer;
|
||||
metadataTimer = null;
|
||||
if (previous !== null)
|
||||
clearTimeout(previous);
|
||||
};
|
||||
job.own(clearMetadataTimer);
|
||||
video.onerror = job.guard(() => {
|
||||
throw video.error || new Error("Auto-thumbnail media failed to load");
|
||||
});
|
||||
video.onloadedmetadata = job.guard(() => {
|
||||
clearMetadataTimer();
|
||||
video.onloadedmetadata = null;
|
||||
const duration = video.duration;
|
||||
const videoHeight = video.videoHeight;
|
||||
const videoWidth = video.videoWidth;
|
||||
const { height, canvasWidth, canvasHeight } = sheetSize(config, {
|
||||
duration,
|
||||
videoHeight,
|
||||
videoWidth
|
||||
});
|
||||
if (!job.active())
|
||||
return;
|
||||
video.width = videoWidth;
|
||||
video.height = videoHeight;
|
||||
video.style.width = `${videoWidth}px`;
|
||||
video.style.height = `${videoHeight}px`;
|
||||
const canvas = document.createElement("canvas");
|
||||
job.own(() => {
|
||||
canvas.height = 0;
|
||||
});
|
||||
job.own(() => {
|
||||
canvas.width = 0;
|
||||
});
|
||||
if (!job.active())
|
||||
return;
|
||||
canvas.width = canvasWidth;
|
||||
if (!job.active())
|
||||
return;
|
||||
canvas.height = canvasHeight;
|
||||
if (!job.active())
|
||||
return;
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx)
|
||||
throw new Error("Auto-thumbnail canvas context is unavailable");
|
||||
if (!job.active())
|
||||
return;
|
||||
const readFrame = createFrameReader(job, video);
|
||||
const encode = createEncoder(job, canvas);
|
||||
let index = 0;
|
||||
const seek = job.guard(() => {
|
||||
if (index >= config.number) {
|
||||
job.dispose();
|
||||
return;
|
||||
}
|
||||
readFrame(duration * index / config.number, job.guard(() => {
|
||||
ctx.drawImage(video, index % 10 * config.width, Math.floor(index / 10) * height, config.width, height);
|
||||
if (!job.active())
|
||||
return;
|
||||
encode((blob) => {
|
||||
job.publish(blob, { height, column: 10, number: config.number, width: config.width, scale: config.scale });
|
||||
if (job.active()) {
|
||||
index += 1;
|
||||
seek();
|
||||
}
|
||||
});
|
||||
}));
|
||||
});
|
||||
seek();
|
||||
});
|
||||
if (!job.active())
|
||||
return;
|
||||
metadataTimer = setTimeout(job.guard(() => {
|
||||
if (metadataTimer !== null)
|
||||
throw new Error("Auto-thumbnail metadata timed out");
|
||||
}), 3e4);
|
||||
if (!job.active()) {
|
||||
clearMetadataTimer();
|
||||
return;
|
||||
}
|
||||
video.src = config.url;
|
||||
}
|
||||
function artplayerPluginAutoThumbnail(option) {
|
||||
return async (art) => {
|
||||
art.on("video:loadedmetadata", () => {
|
||||
const url = option.url || art.option.url;
|
||||
const width = option.width || 160;
|
||||
const number = option.number || 100;
|
||||
const scale = option.scale || 1;
|
||||
create({ url, width, number }, (config) => {
|
||||
art.thumbnails = {
|
||||
...config,
|
||||
column: 10,
|
||||
number,
|
||||
width,
|
||||
scale
|
||||
};
|
||||
});
|
||||
});
|
||||
return {
|
||||
name: "artplayerPluginAutoThumbnail"
|
||||
if (art.isDestroy)
|
||||
return { name: "artplayerPluginAutoThumbnail" };
|
||||
const report = (error) => console.warn("ArtPlayer auto-thumbnail failed:", error);
|
||||
const session = createSession((config) => {
|
||||
art.thumbnails = config;
|
||||
}, report);
|
||||
const subscriptions = [];
|
||||
const onMetadata = () => {
|
||||
const job = session.start();
|
||||
if (job) {
|
||||
job.guard(() => {
|
||||
const config = readOptions(option, () => art.option.url);
|
||||
if (job.active())
|
||||
extract(job, config);
|
||||
})();
|
||||
}
|
||||
};
|
||||
const onDestroy = () => {
|
||||
const actions = subscriptions.splice(0);
|
||||
const result = cleanupAll([session.destroy, ...actions]);
|
||||
if (result.failed)
|
||||
report(result.failure);
|
||||
};
|
||||
try {
|
||||
const events = [["destroy", onDestroy], ["restart", session.cancel], ["video:loadedmetadata", onMetadata]];
|
||||
for (const [name, callback] of events) {
|
||||
if (session.closed)
|
||||
break;
|
||||
subscriptions.push(() => art.off(name, callback));
|
||||
art.on(name, callback);
|
||||
if (session.closed)
|
||||
art.off(name, callback);
|
||||
}
|
||||
} catch (error) {
|
||||
onDestroy();
|
||||
throw error;
|
||||
}
|
||||
return { name: "artplayerPluginAutoThumbnail" };
|
||||
};
|
||||
}
|
||||
artplayerPluginAutoThumbnail.default = artplayerPluginAutoThumbnail;
|
||||
export {
|
||||
artplayerPluginAutoThumbnail as default
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-chapter.js v1.1.0
|
||||
* artplayer-plugin-chapter.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginChapter=e(),define(function(){return t.artplayerPluginChapter})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginChapter=e()}(this,function(){"use strict";if("undefined"!==typeof document){const t="artplayer-plugin-chapter";let e=document.getElementById(t);e||(e=document.createElement("style"),e.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(e)}):(document.head||document.documentElement).appendChild(e)),e.textContent=".artplayer-plugin-chapter .art-control-progress-inner{height:100%!important;background-color:transparent!important}.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-hover,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-loaded,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-played{display:none!important}.artplayer-plugin-chapter .art-control-thumbnails{bottom:calc(var(--art-bottom-gap) + 64px)!important}.artplayer-plugin-chapter .art-chapters{position:absolute;z-index:0;inset:0;display:flex;align-items:center;gap:4px;height:100%;transform:scaleY(1.25)}.artplayer-plugin-chapter .art-chapters .art-chapter{display:flex;align-items:center;height:100%}.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner{position:relative;cursor:pointer;width:100%;height:50%;border-radius:10px;overflow:hidden;transition:height var(--art-transition-duration) ease;background-color:var(--art-progress-color)}.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner{height:100%}.artplayer-plugin-chapter .art-chapter-title{transform-origin:bottom center;transform:scale(.5);opacity:0;position:absolute;z-index:70;top:-50px;left:0;padding:3px 5px;line-height:1;font-size:14px;border-radius:var(--art-border-radius);white-space:nowrap;background-color:var(--art-tip-background);transition:transform var(--art-transition-duration) ease,opacity var(--art-transition-duration) ease}.artplayer-plugin-chapter.art-progress-hover .art-chapter-title{transform:scale(1);opacity:1}"}return function(t={}){return e=>{const{$player:r}=e.template,{setStyle:a,append:n,clamp:o,query:i,addClass:p,removeClass:s}=e.constructor.utils;let d=[];const l=e.query(".art-control-progress-inner"),c=n(l,'<div class="art-chapters"></div>'),h=n(l,'<div class="art-chapter-title"></div>');function u({$chapter:t,width:e}){const r=t.dataset.title.trim();if(r){h.textContent=r;const t=h.clientWidth;e<=t/2?a(h,"left",0):e>l.clientWidth-t/2?a(h,"left",l.clientWidth-t+"px"):a(h,"left",e-t/2+"px")}}function g(t=[]){if(d=[],c.textContent="",s(r,"artplayer-plugin-chapter"),Array.isArray(t)&&t.length&&e.duration){t=t.sort((t,e)=>t.start-e.start);for(let r=0;r<t.length;r++){const a=t[r],n=t[r+1];if(a.end===1/0&&(a.end=e.duration),"number"!==typeof a.start||"number"!==typeof a.end||"string"!==typeof a.title)throw new TypeError("Illegal chapter data type");if(a.start<0||a.end>e.duration||a.start>=a.end)throw new Error("Illegal chapter time point");if(n&&a.end>n.start)throw new Error("Illegal chapter time point")}t[0].start>0&&t.unshift({start:0,end:t[0].start,title:""}),t[t.length-1].end<e.duration&&t.push({start:t[t.length-1].end,end:e.duration,title:""});for(let e=0;e<t.length-1;e++)t[e].end!==t[e+1].start&&t.splice(e+1,0,{start:t[e].end,end:t[e+1].start,title:""});d=t.map(t=>{const r=n(c,'\n <div class="art-chapter">\n <div class="art-chapter-inner">\n <div class="art-progress-hover"></div>\n <div class="art-progress-loaded"></div>\n <div class="art-progress-played"></div>\n </div>\n </div>\n '),a=o(t.start,0,e.duration),p=o(t.end,0,e.duration),s=p-a,d=s/e.duration;return r.dataset.start=a,r.dataset.end=p,r.dataset.duration=s,r.dataset.title=t.title.trim(),r.style.width=100*d+"%",{$chapter:r,$hover:i(".art-progress-hover",r),$loaded:i(".art-progress-loaded",r),$played:i(".art-progress-played",r)}}),p(r,"artplayer-plugin-chapter"),e.emit("setBar","loaded",e.loaded||0)}}return e.on("setBar",(t,r)=>{if(d.length)for(let n=0;n<d.length;n++){const{$chapter:o,$loaded:i,$played:p,$hover:s}=d[n],l={hover:s,loaded:i,played:p}[t];if(!l)return;const h=c.clientWidth*r,g=e.duration*r,y=Number.parseFloat(o.dataset.duration),f=Number.parseFloat(o.dataset.start),m=Number.parseFloat(o.dataset.end);if(g<f&&a(l,"width",0),g>m&&a(l,"width","100%"),g>=f&&g<=m){a(l,"width",100*((g-f)/y)+"%"),"hover"===t&&h>0&&u({$chapter:o,width:h})}}}),e.once("video:loadedmetadata",()=>g(t.chapters)),{name:"artplayerPluginChapter",update:({chapters:t})=>g(t)}}}});
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginChapter=e(),define(function(){return t.artplayerPluginChapter})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginChapter=e()}(this,function(){"use strict";return function(){if("undefined"===typeof document)return;const t="artplayer-plugin-chapter",e=()=>{let e=document.getElementById(t);e||(e=document.createElement("style"),e.id=t,(document.head||document.documentElement).appendChild(e)),e.textContent=".artplayer-plugin-chapter .art-control-progress-inner{height:100%!important;background-color:transparent!important}.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-hover,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-loaded,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-played{display:none!important}.artplayer-plugin-chapter .art-control-thumbnails{bottom:calc(var(--art-bottom-gap) + 64px)!important}.artplayer-plugin-chapter .art-chapters{position:absolute;z-index:0;inset:0;display:flex;align-items:center;gap:4px;height:100%;transform:scaleY(1.25)}.artplayer-plugin-chapter .art-chapters .art-chapter{display:flex;align-items:center;height:100%}.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner{position:relative;cursor:pointer;width:100%;height:50%;border-radius:10px;overflow:hidden;transition:height var(--art-transition-duration) ease;background-color:var(--art-progress-color)}.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner{height:100%}.artplayer-plugin-chapter .art-chapter-title{transform-origin:bottom center;transform:scale(.5);opacity:0;position:absolute;z-index:70;top:-50px;left:0;padding:3px 5px;line-height:1;font-size:14px;border-radius:var(--art-border-radius);white-space:nowrap;box-sizing:border-box;max-width:100%;overflow:hidden;text-overflow:ellipsis;background-color:var(--art-tip-background);transition:transform var(--art-transition-duration) ease,opacity var(--art-transition-duration) ease}.artplayer-plugin-chapter.art-progress-hover .art-chapter-title{transform:scale(1);opacity:1}"};document.getElementById(t)||"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e,{once:!0})}(),function(t={}){return e=>{const r=e.template.$player,a=e.query(".art-control-progress-inner");if(!a)throw new Error("Missing ArtPlayer progress container");const n="artplayer-plugin-chapter";let o=function(t){const e=(e,r)=>{const a=t.ownerDocument.createElement("div");return a.className=r,e.appendChild(a),a},r=e(t,"art-chapters"),a=e(t,"art-chapter-title");let n=[];function o(){a.textContent="",a.style.left="0px",a.style.visibility="hidden"}function i(){n=[],r.textContent="",o()}return o(),{clear:i,render:function(t,a){n=t.map(t=>{const n=e(r,"art-chapter"),o=e(n,"art-chapter-inner"),i=t.end-t.start;return n.dataset.start=String(t.start),n.dataset.end=String(t.end),n.dataset.duration=String(i),n.dataset.title=t.title.trim(),n.style.width=i/a*100+"%",{start:t.start,end:t.end,title:t.title.trim(),bars:{hover:e(o,"art-progress-hover"),loaded:e(o,"art-progress-loaded"),played:e(o,"art-progress-played")}}})},setBar:function(e,i,s){if("hover"!==e&&"loaded"!==e&&"played"!==e)return;if(!Number.isFinite(i))return;const l=s*i;let d;for(const t of n)t.bars[e].style.width=l<t.start?"0px":l>t.end?"100%":(l-t.start)/(t.end-t.start)*100+"%",l>=t.start&&l<=t.end&&(d=t);if("hover"!==e)return;o();const p=r.clientWidth*i;d?.title&&p>0&&(a.textContent=d.title,a.style.visibility="visible",a.style.left=`${Math.max(0,Math.min(p-a.clientWidth/2,t.clientWidth-a.clientWidth))}px`)},destroy:function(){i(),r.remove(),a.remove()}}}(a);function i(t){if(!o||e.isDestroy)return;o.clear(),r.classList.remove(n);const a=function(t=[],e){if(!Array.isArray(t)||!t.length||!Number.isFinite(e)||e<=0)return[];t.sort((t,e)=>t.start-e.start);for(const[n,o]of t.entries()){if(!o||"number"!==typeof o.start||"number"!==typeof o.end||"string"!==typeof o.title)throw new TypeError("Illegal chapter data type");o.end===1/0&&(o.end=e);const r=t[n+1];if(!Number.isFinite(o.start)||!Number.isFinite(o.end)||o.start<0||o.end>e||o.start>=o.end||r&&o.end>r.start)throw new Error("Illegal chapter time point")}const r=t[0],a=t[t.length-1];r&&r.start>0&&t.unshift({start:0,end:r.start,title:""}),a&&a.end<e&&t.push({start:a.end,end:e,title:""});for(let n=0;n<t.length-1;n++){const e=t[n],r=t[n+1];e&&r&&e.end!==r.start&&t.splice(n+1,0,{start:e.end,end:r.start,title:""})}return t}(t,e.duration);a.length&&(o.render(a,e.duration),r.classList.add(n),e.emit("setBar","loaded",e.loaded||0))}function s(t,r){e.isDestroy||o?.setBar(t,r,e.duration)}function l(){i(t.chapters)}return e.on("setBar",s),e.once("video:loadedmetadata",l),e.on("destroy",function t(){e.off("setBar",s),e.off("video:loadedmetadata",l),e.off("destroy",t),o?.destroy(),o=void 0,r.classList.remove(n)}),{name:"artplayerPluginChapteLine truncated
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-chapter.js v1.1.0
|
||||
* artplayer-plugin-chapter.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginChapter=e(),define(function(){return t.artplayerPluginChapter})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginChapter=e()}(this,function(){"use strict";if("undefined"!==typeof document){const t="artplayer-plugin-chapter";let e=document.getElementById(t);e||(e=document.createElement("style"),e.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(e)}):(document.head||document.documentElement).appendChild(e)),e.textContent=".artplayer-plugin-chapter .art-control-progress-inner{height:100%!important;background-color:transparent!important}.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-hover,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-loaded,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-played{display:none!important}.artplayer-plugin-chapter .art-control-thumbnails{bottom:calc(var(--art-bottom-gap) + 64px)!important}.artplayer-plugin-chapter .art-chapters{position:absolute;z-index:0;inset:0;display:flex;align-items:center;gap:4px;height:100%;transform:scaleY(1.25)}.artplayer-plugin-chapter .art-chapters .art-chapter{display:flex;align-items:center;height:100%}.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner{position:relative;cursor:pointer;width:100%;height:50%;border-radius:10px;overflow:hidden;transition:height var(--art-transition-duration) ease;background-color:var(--art-progress-color)}.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner{height:100%}.artplayer-plugin-chapter .art-chapter-title{transform-origin:bottom center;transform:scale(.5);opacity:0;position:absolute;z-index:70;top:-50px;left:0;padding:3px 5px;line-height:1;font-size:14px;border-radius:var(--art-border-radius);white-space:nowrap;background-color:var(--art-tip-background);transition:transform var(--art-transition-duration) ease,opacity var(--art-transition-duration) ease}.artplayer-plugin-chapter.art-progress-hover .art-chapter-title{transform:scale(1);opacity:1}"}return function(t={}){return e=>{const{$player:r}=e.template,{setStyle:a,append:n,clamp:o,query:i,addClass:p,removeClass:s}=e.constructor.utils;let d=[];const l=e.query(".art-control-progress-inner"),c=n(l,'<div class="art-chapters"></div>'),h=n(l,'<div class="art-chapter-title"></div>');function u({$chapter:t,width:e}){const r=t.dataset.title.trim();if(r){h.textContent=r;const t=h.clientWidth;e<=t/2?a(h,"left",0):e>l.clientWidth-t/2?a(h,"left",l.clientWidth-t+"px"):a(h,"left",e-t/2+"px")}}function g(t=[]){if(d=[],c.textContent="",s(r,"artplayer-plugin-chapter"),Array.isArray(t)&&t.length&&e.duration){t=t.sort((t,e)=>t.start-e.start);for(let r=0;r<t.length;r++){const a=t[r],n=t[r+1];if(a.end===1/0&&(a.end=e.duration),"number"!==typeof a.start||"number"!==typeof a.end||"string"!==typeof a.title)throw new TypeError("Illegal chapter data type");if(a.start<0||a.end>e.duration||a.start>=a.end)throw new Error("Illegal chapter time point");if(n&&a.end>n.start)throw new Error("Illegal chapter time point")}t[0].start>0&&t.unshift({start:0,end:t[0].start,title:""}),t[t.length-1].end<e.duration&&t.push({start:t[t.length-1].end,end:e.duration,title:""});for(let e=0;e<t.length-1;e++)t[e].end!==t[e+1].start&&t.splice(e+1,0,{start:t[e].end,end:t[e+1].start,title:""});d=t.map(t=>{const r=n(c,'\n <div class="art-chapter">\n <div class="art-chapter-inner">\n <div class="art-progress-hover"></div>\n <div class="art-progress-loaded"></div>\n <div class="art-progress-played"></div>\n </div>\n </div>\n '),a=o(t.start,0,e.duration),p=o(t.end,0,e.duration),s=p-a,d=s/e.duration;return r.dataset.start=a,r.dataset.end=p,r.dataset.duration=s,r.dataset.title=t.title.trim(),r.style.width=100*d+"%",{$chapter:r,$hover:i(".art-progress-hover",r),$loaded:i(".art-progress-loaded",r),$played:i(".art-progress-played",r)}}),p(r,"artplayer-plugin-chapter"),e.emit("setBar","loaded",e.loaded||0)}}return e.on("setBar",(t,r)=>{if(d.length)for(let n=0;n<d.length;n++){const{$chapter:o,$loaded:i,$played:p,$hover:s}=d[n],l={hover:s,loaded:i,played:p}[t];if(!l)return;const h=c.clientWidth*r,g=e.duration*r,y=Number.parseFloat(o.dataset.duration),f=Number.parseFloat(o.dataset.start),m=Number.parseFloat(o.dataset.end);if(g<f&&a(l,"width",0),g>m&&a(l,"width","100%"),g>=f&&g<=m){a(l,"width",100*((g-f)/y)+"%"),"hover"===t&&h>0&&u({$chapter:o,width:h})}}}),e.once("video:loadedmetadata",()=>g(t.chapters)),{name:"artplayerPluginChapter",update:({chapters:t})=>g(t)}}}});
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginChapter=e(),define(function(){return t.artplayerPluginChapter})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginChapter=e()}(this,function(){"use strict";return function(){if("undefined"===typeof document)return;const t="artplayer-plugin-chapter",e=()=>{let e=document.getElementById(t);e||(e=document.createElement("style"),e.id=t,(document.head||document.documentElement).appendChild(e)),e.textContent=".artplayer-plugin-chapter .art-control-progress-inner{height:100%!important;background-color:transparent!important}.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-hover,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-loaded,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-played{display:none!important}.artplayer-plugin-chapter .art-control-thumbnails{bottom:calc(var(--art-bottom-gap) + 64px)!important}.artplayer-plugin-chapter .art-chapters{position:absolute;z-index:0;inset:0;display:flex;align-items:center;gap:4px;height:100%;transform:scaleY(1.25)}.artplayer-plugin-chapter .art-chapters .art-chapter{display:flex;align-items:center;height:100%}.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner{position:relative;cursor:pointer;width:100%;height:50%;border-radius:10px;overflow:hidden;transition:height var(--art-transition-duration) ease;background-color:var(--art-progress-color)}.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner{height:100%}.artplayer-plugin-chapter .art-chapter-title{transform-origin:bottom center;transform:scale(.5);opacity:0;position:absolute;z-index:70;top:-50px;left:0;padding:3px 5px;line-height:1;font-size:14px;border-radius:var(--art-border-radius);white-space:nowrap;box-sizing:border-box;max-width:100%;overflow:hidden;text-overflow:ellipsis;background-color:var(--art-tip-background);transition:transform var(--art-transition-duration) ease,opacity var(--art-transition-duration) ease}.artplayer-plugin-chapter.art-progress-hover .art-chapter-title{transform:scale(1);opacity:1}"};document.getElementById(t)||"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e,{once:!0})}(),function(t={}){return e=>{const r=e.template.$player,a=e.query(".art-control-progress-inner");if(!a)throw new Error("Missing ArtPlayer progress container");const n="artplayer-plugin-chapter";let o=function(t){const e=(e,r)=>{const a=t.ownerDocument.createElement("div");return a.className=r,e.appendChild(a),a},r=e(t,"art-chapters"),a=e(t,"art-chapter-title");let n=[];function o(){a.textContent="",a.style.left="0px",a.style.visibility="hidden"}function i(){n=[],r.textContent="",o()}return o(),{clear:i,render:function(t,a){n=t.map(t=>{const n=e(r,"art-chapter"),o=e(n,"art-chapter-inner"),i=t.end-t.start;return n.dataset.start=String(t.start),n.dataset.end=String(t.end),n.dataset.duration=String(i),n.dataset.title=t.title.trim(),n.style.width=i/a*100+"%",{start:t.start,end:t.end,title:t.title.trim(),bars:{hover:e(o,"art-progress-hover"),loaded:e(o,"art-progress-loaded"),played:e(o,"art-progress-played")}}})},setBar:function(e,i,s){if("hover"!==e&&"loaded"!==e&&"played"!==e)return;if(!Number.isFinite(i))return;const l=s*i;let d;for(const t of n)t.bars[e].style.width=l<t.start?"0px":l>t.end?"100%":(l-t.start)/(t.end-t.start)*100+"%",l>=t.start&&l<=t.end&&(d=t);if("hover"!==e)return;o();const p=r.clientWidth*i;(null==d?void 0:d.title)&&p>0&&(a.textContent=d.title,a.style.visibility="visible",a.style.left=`${Math.max(0,Math.min(p-a.clientWidth/2,t.clientWidth-a.clientWidth))}px`)},destroy:function(){i(),r.remove(),a.remove()}}}(a);function i(t){if(!o||e.isDestroy)return;o.clear(),r.classList.remove(n);const a=function(t=[],e){if(!Array.isArray(t)||!t.length||!Number.isFinite(e)||e<=0)return[];t.sort((t,e)=>t.start-e.start);for(const[n,o]of t.entries()){if(!o||"number"!==typeof o.start||"number"!==typeof o.end||"string"!==typeof o.title)throw new TypeError("Illegal chapter data type");o.end===1/0&&(o.end=e);const r=t[n+1];if(!Number.isFinite(o.start)||!Number.isFinite(o.end)||o.start<0||o.end>e||o.start>=o.end||r&&o.end>r.start)throw new Error("Illegal chapter time point")}const r=t[0],a=t[t.length-1];r&&r.start>0&&t.unshift({start:0,end:r.start,title:""}),a&&a.end<e&&t.push({start:a.end,end:e,title:""});for(let n=0;n<t.length-1;n++){const e=t[n],r=t[n+1];e&&r&&e.end!==r.start&&t.splice(n+1,0,{start:e.end,end:r.start,title:""})}return t}(t,e.duration);a.length&&(o.render(a,e.duration),r.classList.add(n),e.emit("setBar","loaded",e.loaded||0))}function s(t,r){e.isDestroy||null==o||o.setBar(t,r,e.duration)}function l(){i(t.chapters)}return e.on("setBar",s),e.once("video:loadedmetadata",l),e.on("destroy",function t(){e.off("setBar",s),e.off("video:loadedmetadata",l),e.off("destroy",t),null==o||o.destroy(),o=void 0,r.classList.remove(nLine truncated
|
||||
@@ -1,159 +1,171 @@
|
||||
/*!
|
||||
* artplayer-plugin-chapter.js v1.1.0
|
||||
* artplayer-plugin-chapter.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
const style = ".artplayer-plugin-chapter .art-control-progress-inner {\n height: 100% !important;\n background-color: transparent !important;\n}\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-hover,\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-loaded,\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-played {\n display: none !important;\n}\n.artplayer-plugin-chapter .art-control-thumbnails {\n bottom: calc(var(--art-bottom-gap) + 64px) !important;\n}\n.artplayer-plugin-chapter .art-chapters {\n position: absolute;\n z-index: 0;\n inset: 0;\n display: flex;\n align-items: center;\n gap: 4px;\n height: 100%;\n transform: scaleY(1.25);\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter {\n display: flex;\n align-items: center;\n height: 100%;\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner {\n position: relative;\n cursor: pointer;\n width: 100%;\n height: 50%;\n border-radius: 10px;\n overflow: hidden;\n transition: height var(--art-transition-duration) ease;\n background-color: var(--art-progress-color);\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner {\n height: 100%;\n}\n.artplayer-plugin-chapter .art-chapter-title {\n transform-origin: bottom center;\n transform: scale(0.5);\n opacity: 0;\n position: absolute;\n z-index: 70;\n top: -50px;\n left: 0;\n padding: 3px 5px;\n line-height: 1;\n font-size: 14px;\n border-radius: var(--art-border-radius);\n white-space: nowrap;\n background-color: var(--art-tip-background);\n transition: transform var(--art-transition-duration) ease, opacity var(--art-transition-duration) ease;\n}\n.artplayer-plugin-chapter.art-progress-hover .art-chapter-title {\n transform: scale(1);\n opacity: 1;\n}\n";
|
||||
function artplayerPluginChapter(option = {}) {
|
||||
return (art) => {
|
||||
const { $player } = art.template;
|
||||
const { setStyle, append, clamp, query, addClass, removeClass } = art.constructor.utils;
|
||||
const html = `
|
||||
<div class="art-chapter">
|
||||
<div class="art-chapter-inner">
|
||||
<div class="art-progress-hover"></div>
|
||||
<div class="art-progress-loaded"></div>
|
||||
<div class="art-progress-played"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
let $chapters = [];
|
||||
const $inner = art.query(".art-control-progress-inner");
|
||||
const $control = append($inner, '<div class="art-chapters"></div>');
|
||||
const $title = append($inner, '<div class="art-chapter-title"></div>');
|
||||
function showTitle({ $chapter, width }) {
|
||||
const title = $chapter.dataset.title.trim();
|
||||
if (title) {
|
||||
$title.textContent = title;
|
||||
const titleWidth = $title.clientWidth;
|
||||
if (width <= titleWidth / 2) {
|
||||
setStyle($title, "left", 0);
|
||||
} else if (width > $inner.clientWidth - titleWidth / 2) {
|
||||
setStyle($title, "left", `${$inner.clientWidth - titleWidth}px`);
|
||||
} else {
|
||||
setStyle($title, "left", `${width - titleWidth / 2}px`);
|
||||
}
|
||||
}
|
||||
}
|
||||
function update(chapters = []) {
|
||||
$chapters = [];
|
||||
$control.textContent = "";
|
||||
removeClass($player, "artplayer-plugin-chapter");
|
||||
if (!Array.isArray(chapters))
|
||||
return;
|
||||
if (!chapters.length)
|
||||
return;
|
||||
if (!art.duration)
|
||||
return;
|
||||
chapters = chapters.sort((a, b) => a.start - b.start);
|
||||
for (let i = 0; i < chapters.length; i++) {
|
||||
const chapter = chapters[i];
|
||||
const nextChapter = chapters[i + 1];
|
||||
if (chapter.end === Infinity) {
|
||||
chapter.end = art.duration;
|
||||
}
|
||||
if (typeof chapter.start !== "number" || typeof chapter.end !== "number" || typeof chapter.title !== "string") {
|
||||
throw new TypeError("Illegal chapter data type");
|
||||
}
|
||||
if (chapter.start < 0 || chapter.end > art.duration || chapter.start >= chapter.end) {
|
||||
throw new Error("Illegal chapter time point");
|
||||
}
|
||||
if (nextChapter && chapter.end > nextChapter.start) {
|
||||
throw new Error("Illegal chapter time point");
|
||||
}
|
||||
}
|
||||
if (chapters[0].start > 0) {
|
||||
chapters.unshift({ start: 0, end: chapters[0].start, title: "" });
|
||||
}
|
||||
if (chapters[chapters.length - 1].end < art.duration) {
|
||||
chapters.push({ start: chapters[chapters.length - 1].end, end: art.duration, title: "" });
|
||||
}
|
||||
for (let i = 0; i < chapters.length - 1; i++) {
|
||||
if (chapters[i].end !== chapters[i + 1].start) {
|
||||
chapters.splice(i + 1, 0, {
|
||||
start: chapters[i].end,
|
||||
end: chapters[i + 1].start,
|
||||
title: ""
|
||||
});
|
||||
}
|
||||
}
|
||||
$chapters = chapters.map((chapter) => {
|
||||
const $chapter = append($control, html);
|
||||
const start = clamp(chapter.start, 0, art.duration);
|
||||
const end = clamp(chapter.end, 0, art.duration);
|
||||
const duration = end - start;
|
||||
const percentage = duration / art.duration;
|
||||
$chapter.dataset.start = start;
|
||||
$chapter.dataset.end = end;
|
||||
$chapter.dataset.duration = duration;
|
||||
$chapter.dataset.title = chapter.title.trim();
|
||||
$chapter.style.width = `${percentage * 100}%`;
|
||||
return {
|
||||
$chapter,
|
||||
$hover: query(".art-progress-hover", $chapter),
|
||||
$loaded: query(".art-progress-loaded", $chapter),
|
||||
$played: query(".art-progress-played", $chapter)
|
||||
};
|
||||
});
|
||||
addClass($player, "artplayer-plugin-chapter");
|
||||
art.emit("setBar", "loaded", art.loaded || 0);
|
||||
}
|
||||
art.on("setBar", (type, percentage) => {
|
||||
if (!$chapters.length)
|
||||
return;
|
||||
for (let i = 0; i < $chapters.length; i++) {
|
||||
const { $chapter, $loaded, $played, $hover } = $chapters[i];
|
||||
const $target = {
|
||||
hover: $hover,
|
||||
loaded: $loaded,
|
||||
played: $played
|
||||
}[type];
|
||||
if (!$target)
|
||||
return;
|
||||
const width = $control.clientWidth * percentage;
|
||||
const currentTime = art.duration * percentage;
|
||||
const duration = Number.parseFloat($chapter.dataset.duration);
|
||||
const start = Number.parseFloat($chapter.dataset.start);
|
||||
const end = Number.parseFloat($chapter.dataset.end);
|
||||
if (currentTime < start) {
|
||||
setStyle($target, "width", 0);
|
||||
}
|
||||
if (currentTime > end) {
|
||||
setStyle($target, "width", "100%");
|
||||
}
|
||||
if (currentTime >= start && currentTime <= end) {
|
||||
const percentage2 = (currentTime - start) / duration;
|
||||
setStyle($target, "width", `${percentage2 * 100}%`);
|
||||
if (type === "hover" && width > 0) {
|
||||
showTitle({ $chapter, width });
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
art.once("video:loadedmetadata", () => update(option.chapters));
|
||||
return {
|
||||
name: "artplayerPluginChapter",
|
||||
update: ({ chapters }) => update(chapters)
|
||||
};
|
||||
};
|
||||
}
|
||||
if (typeof document !== "undefined") {
|
||||
const id = "artplayer-plugin-chapter";
|
||||
let $style = document.getElementById(id);
|
||||
if (!$style) {
|
||||
$style = document.createElement("style");
|
||||
$style.id = id;
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
document.head.appendChild($style);
|
||||
});
|
||||
} else {
|
||||
(document.head || document.documentElement).appendChild($style);
|
||||
function normalizeChapters(chapters = [], duration) {
|
||||
if (!Array.isArray(chapters) || !chapters.length || !Number.isFinite(duration) || duration <= 0)
|
||||
return [];
|
||||
chapters.sort((a, b) => a.start - b.start);
|
||||
for (const [index, chapter] of chapters.entries()) {
|
||||
if (!chapter || typeof chapter.start !== "number" || typeof chapter.end !== "number" || typeof chapter.title !== "string")
|
||||
throw new TypeError("Illegal chapter data type");
|
||||
if (chapter.end === Infinity)
|
||||
chapter.end = duration;
|
||||
const next = chapters[index + 1];
|
||||
if (!Number.isFinite(chapter.start) || !Number.isFinite(chapter.end) || chapter.start < 0 || chapter.end > duration || chapter.start >= chapter.end || next && chapter.end > next.start) {
|
||||
throw new Error("Illegal chapter time point");
|
||||
}
|
||||
}
|
||||
$style.textContent = style;
|
||||
const first = chapters[0];
|
||||
const last = chapters[chapters.length - 1];
|
||||
if (first && first.start > 0)
|
||||
chapters.unshift({ start: 0, end: first.start, title: "" });
|
||||
if (last && last.end < duration)
|
||||
chapters.push({ start: last.end, end: duration, title: "" });
|
||||
for (let index = 0; index < chapters.length - 1; index++) {
|
||||
const current = chapters[index];
|
||||
const next = chapters[index + 1];
|
||||
if (current && next && current.end !== next.start)
|
||||
chapters.splice(index + 1, 0, { start: current.end, end: next.start, title: "" });
|
||||
}
|
||||
return chapters;
|
||||
}
|
||||
function createProgress(inner) {
|
||||
const create = (parent, className) => {
|
||||
const element = inner.ownerDocument.createElement("div");
|
||||
element.className = className;
|
||||
parent.appendChild(element);
|
||||
return element;
|
||||
};
|
||||
const control = create(inner, "art-chapters");
|
||||
const title = create(inner, "art-chapter-title");
|
||||
let segments = [];
|
||||
function clearTitle() {
|
||||
title.textContent = "";
|
||||
title.style.left = "0px";
|
||||
title.style.visibility = "hidden";
|
||||
}
|
||||
function clear() {
|
||||
segments = [];
|
||||
control.textContent = "";
|
||||
clearTitle();
|
||||
}
|
||||
function render(chapters, duration) {
|
||||
segments = chapters.map((chapter) => {
|
||||
const element = create(control, "art-chapter");
|
||||
const body = create(element, "art-chapter-inner");
|
||||
const length = chapter.end - chapter.start;
|
||||
element.dataset.start = String(chapter.start);
|
||||
element.dataset.end = String(chapter.end);
|
||||
element.dataset.duration = String(length);
|
||||
element.dataset.title = chapter.title.trim();
|
||||
element.style.width = `${length / duration * 100}%`;
|
||||
return {
|
||||
start: chapter.start,
|
||||
end: chapter.end,
|
||||
title: chapter.title.trim(),
|
||||
bars: {
|
||||
hover: create(body, "art-progress-hover"),
|
||||
loaded: create(body, "art-progress-loaded"),
|
||||
played: create(body, "art-progress-played")
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
function setBar(type, percentage, duration) {
|
||||
if (type !== "hover" && type !== "loaded" && type !== "played")
|
||||
return;
|
||||
if (!Number.isFinite(percentage))
|
||||
return;
|
||||
const currentTime = duration * percentage;
|
||||
let hovered;
|
||||
for (const segment of segments) {
|
||||
const target = segment.bars[type];
|
||||
target.style.width = currentTime < segment.start ? "0px" : currentTime > segment.end ? "100%" : `${(currentTime - segment.start) / (segment.end - segment.start) * 100}%`;
|
||||
if (currentTime >= segment.start && currentTime <= segment.end)
|
||||
hovered = segment;
|
||||
}
|
||||
if (type !== "hover")
|
||||
return;
|
||||
clearTitle();
|
||||
const width = control.clientWidth * percentage;
|
||||
if (hovered?.title && width > 0) {
|
||||
title.textContent = hovered.title;
|
||||
title.style.visibility = "visible";
|
||||
title.style.left = `${Math.max(0, Math.min(width - title.clientWidth / 2, inner.clientWidth - title.clientWidth))}px`;
|
||||
}
|
||||
}
|
||||
function destroy() {
|
||||
clear();
|
||||
control.remove();
|
||||
title.remove();
|
||||
}
|
||||
clearTitle();
|
||||
return { clear, render, setBar, destroy };
|
||||
}
|
||||
const style = ".artplayer-plugin-chapter .art-control-progress-inner {\n height: 100% !important;\n background-color: transparent !important;\n}\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-hover,\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-loaded,\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-played {\n display: none !important;\n}\n.artplayer-plugin-chapter .art-control-thumbnails {\n bottom: calc(var(--art-bottom-gap) + 64px) !important;\n}\n.artplayer-plugin-chapter .art-chapters {\n position: absolute;\n z-index: 0;\n inset: 0;\n display: flex;\n align-items: center;\n gap: 4px;\n height: 100%;\n transform: scaleY(1.25);\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter {\n display: flex;\n align-items: center;\n height: 100%;\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner {\n position: relative;\n cursor: pointer;\n width: 100%;\n height: 50%;\n border-radius: 10px;\n overflow: hidden;\n transition: height var(--art-transition-duration) ease;\n background-color: var(--art-progress-color);\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner {\n height: 100%;\n}\n.artplayer-plugin-chapter .art-chapter-title {\n transform-origin: bottom center;\n transform: scale(0.5);\n opacity: 0;\n position: absolute;\n z-index: 70;\n top: -50px;\n left: 0;\n padding: 3px 5px;\n line-height: 1;\n font-size: 14px;\n border-radius: var(--art-border-radius);\n white-space: nowrap;\n box-sizing: border-box;\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n background-color: var(--art-tip-background);\n transition: transform var(--art-transition-duration) ease, opacity var(--art-transition-duration) ease;\n}\n.artplayer-plugin-chapter.art-progress-hover .art-chapter-title {\n transform: scale(1);\n opacity: 1;\n}\n";
|
||||
function installStyle() {
|
||||
if (typeof document === "undefined")
|
||||
return;
|
||||
const id = "artplayer-plugin-chapter";
|
||||
const install = () => {
|
||||
let element = document.getElementById(id);
|
||||
if (!element) {
|
||||
element = document.createElement("style");
|
||||
element.id = id;
|
||||
(document.head || document.documentElement).appendChild(element);
|
||||
}
|
||||
element.textContent = style;
|
||||
};
|
||||
if (document.getElementById(id) || document.readyState !== "loading")
|
||||
install();
|
||||
else
|
||||
document.addEventListener("DOMContentLoaded", install, { once: true });
|
||||
}
|
||||
function artplayerPluginChapter(option = {}) {
|
||||
return (art) => {
|
||||
const player = art.template.$player;
|
||||
const inner = art.query(".art-control-progress-inner");
|
||||
if (!inner)
|
||||
throw new Error("Missing ArtPlayer progress container");
|
||||
const className = "artplayer-plugin-chapter";
|
||||
let progress = createProgress(inner);
|
||||
function update(chapters) {
|
||||
if (!progress || art.isDestroy)
|
||||
return;
|
||||
progress.clear();
|
||||
player.classList.remove(className);
|
||||
const normalized = normalizeChapters(chapters, art.duration);
|
||||
if (!normalized.length)
|
||||
return;
|
||||
progress.render(normalized, art.duration);
|
||||
player.classList.add(className);
|
||||
art.emit("setBar", "loaded", art.loaded || 0);
|
||||
}
|
||||
function setBar(type, percentage) {
|
||||
if (!art.isDestroy)
|
||||
progress?.setBar(type, percentage, art.duration);
|
||||
}
|
||||
function initialize() {
|
||||
update(option.chapters);
|
||||
}
|
||||
function destroy() {
|
||||
art.off("setBar", setBar);
|
||||
art.off("video:loadedmetadata", initialize);
|
||||
art.off("destroy", destroy);
|
||||
progress?.destroy();
|
||||
progress = void 0;
|
||||
player.classList.remove(className);
|
||||
}
|
||||
art.on("setBar", setBar);
|
||||
art.once("video:loadedmetadata", initialize);
|
||||
art.on("destroy", destroy);
|
||||
return { name: "artplayerPluginChapter", update: ({ chapters }) => update(chapters) };
|
||||
};
|
||||
}
|
||||
installStyle();
|
||||
export {
|
||||
artplayerPluginChapter as default
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-chromecast.js v1.1.0
|
||||
* artplayer-plugin-chromecast.js v2.0.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.artplayerPluginChromecast=t(),define(function(){return t.artplayerPluginChromecast})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginChromecast=t()}(this,function(){"use strict";return function(e){let t=!1,o=null,n=null;const a=e=>{const t=document.querySelector(".art-icon-cast");if(t)switch(e){case"connected":t.style.color="red";break;case"connecting":case"disconnecting":t.style.color="orange";break;default:t.style.color="white"}},c=()=>new Promise((c,s)=>{var i;window.__onGCastApiAvailable=i=>{if(i){const s=window.cast.framework.CastContext.getInstance();s.setOptions({receiverApplicationId:window.chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID,autoJoinPolicy:window.chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED}),s.addEventListener(window.cast.framework.CastContextEventType.SESSION_STATE_CHANGED,t=>{const c=window.cast.framework.SessionState;switch(n=t.sessionState,o=t.session,t.sessionState){case c.NO_SESSION:e.onStateChange?.("disconnected"),a("disconnected");break;case c.SESSION_STARTING:e.onStateChange?.("connecting"),a("connecting");break;case c.SESSION_STARTED:e.onStateChange?.("connected"),a("connected");break;case c.SESSION_ENDING:e.onStateChange?.("disconnecting"),a("disconnecting");break;case c.SESSION_RESUMED:e.onStateChange?.("connected"),a("connected")}}),s.addEventListener(window.cast.framework.CastContextEventType.CAST_STATE_CHANGED,t=>{const o=window.cast.framework.CastState;switch(t.castState){case o.NO_DEVICES_AVAILABLE:e.onCastAvailable?.(!1);break;case o.NOT_CONNECTED:case o.CONNECTING:case o.CONNECTED:e.onCastAvailable?.(!0)}}),t=!0,c()}else s(new Error("Cast API is not available"))},window.chrome&&window.chrome.cast||(i=e.sdk||"https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1",new Promise((e,t)=>{const o=document.createElement("script");o.src=i,o.onload=e,o.onerror=t,document.body.appendChild(o)})).catch(s)}),s=(t,o)=>{const n=e.url||t.option.url,a=new window.chrome.cast.media.MediaInfo(n,e.mimeType||function(e){return{mp4:"video/mp4",webm:"video/webm",ogg:"video/ogg",ogv:"video/ogg",mp3:"audio/mp3",wav:"audio/wav",flv:"video/x-flv",mov:"video/quicktime",avi:"video/x-msvideo",wmv:"video/x-ms-wmv",mpd:"application/dash+xml",m3u8:"application/x-mpegURL"}[e.split("?")[0].split("#")[0].split(".").pop().toLowerCase()]||"application/octet-stream"}(n)),c=new window.chrome.cast.media.LoadRequest(a);o.loadMedia(c).then(()=>{t.notice.show="Casting started",e.onCastStart?.()}).catch(o=>{throw t.notice.show="Error casting media",e.onError?.(o),o})};return async a=>(a.controls.add({name:"chromecast",position:"right",tooltip:"Chromecast",html:`<i class="art-icon art-icon-cast">${e.icon||'<svg height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M512 96H64v99c-13-2-26.4-3-40-3H0V96C0 60.7 28.7 32 64 32H512c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H288V456c0-13.6-1-27-3-40H512V96zM24 224c128.1 0 232 103.9 232 232c0 13.3-10.7 24-24 24s-24-10.7-24-24c0-101.6-82.4-184-184-184c-13.3 0-24-10.7-24-24s10.7-24 24-24zm8 192a32 32 0 1 1 0 64 32 32 0 1 1 0-64zM0 344c0-13.3 10.7-24 24-24c75.1 0 136 60.9 136 136c0 13.3-10.7 24-24 24s-24-10.7-24-24c0-48.6-39.4-88-88-88c-13.3 0-24-10.7-24-24z"/></svg>'}</i>`,click:async()=>{if(!t)try{await c()}catch(i){throw a.notice.show="Failed to initialize Cast API",e.onError?.(i),i}const n=window.cast.framework.CastContext.getInstance();if(o)s(a,o);else try{const e=await n.requestSession();s(a,e)}catch(i){throw a.notice.show="Error connecting to cast session",e.onError?.(i),i}}}),{name:"artplayerPluginChromecast",getCastState:()=>n,isCasting:()=>null!==o})}});
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginChromecast=t(),define(function(){return e.artplayerPluginChromecast})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginChromecast=t()}(this,function(){"use strict";const e={mp4:"video/mp4",webm:"video/webm",ogg:"video/ogg",ogv:"video/ogg",mp3:"audio/mp3",wav:"audio/wav",flv:"video/x-flv",mov:"video/quicktime",avi:"video/x-msvideo",wmv:"video/x-ms-wmv",mpd:"application/dash+xml",m3u8:"application/x-mpegURL"};function t(t,o,n,i){const r=n.url||i,s=r.split("?")[0].split("#")[0].split(".").pop().toLowerCase(),a=new t.media.MediaInfo(r,n.mimeType||e[s]||"application/octet-stream");return o.loadMedia(new t.media.LoadRequest(a))}const o=new WeakMap,n=new WeakSet;function i(e){const t=e.cast?.framework,o=e.chrome?.cast;if("function"===typeof t?.CastContext?.getInstance&&t.CastContextEventType&&t.SessionState&&t.CastState&&"function"===typeof o?.media?.MediaInfo&&"function"===typeof o.media.LoadRequest&&o.AutoJoinPolicy)return{framework:t,media:o.media,autoJoinPolicy:o.AutoJoinPolicy.ORIGIN_SCOPED}}function r(e,t){let o;const n=new Promise((n,i)=>{o={ready:t,resolve:n,reject:i},e.subscribers.add(o)});let i=!1;return{promise:n,release:()=>{i||(i=!0,e.subscribers.delete(o),o.reject(new Error("Cast initialization cancelled")),e.subscribers.size||e.cancel())}}}function s(e,s){let a,c,l,d,u,f,m=!1,v=null,S=null,p=0,E=!1;const w=new Promise(e=>{f=()=>e(void 0)});let C;const h=()=>!m&&!e.isDestroy,y=e=>{if(s.onStateChange?.(e),!h())return;const t=C?.querySelector(".art-icon-cast");t&&(t.style.color="connected"===e?"red":"connecting"===e||"disconnecting"===e?"orange":"white")},g=e=>{if(!h()||!a)return;S=e.sessionState;const t=a.framework.SessionState;S===t.NO_SESSION||S===t.SESSION_ENDED||S===t.SESSION_START_FAILED?((S!==t.NO_SESSION||E)&&(p++,u?.()),v=null,y("disconnected")):((S===t.SESSION_ENDING||v&&e.session&&e.session!==v)&&(p++,u?.()),v=e.session||null,S===t.SESSION_STARTING?y("connecting"):S===t.SESSION_ENDING?y("disconnecting"):S!==t.SESSION_STARTED&&S!==t.SESSION_RESUMED||y("connected"))},A=e=>{if(!h()||!a)return;const t=a.framework.CastState;e.castState===t.NO_DEVICES_AVAILABLE?s.onCastAvailable?.(!1):e.castState!==t.NOT_CONNECTED&&e.castState!==t.CONNECTING&&e.castState!==t.CONNECTED||s.onCastAvailable?.(!0)},_=()=>{const e=c,t=a;if(c=void 0,a=void 0,e&&t){const n=t.framework.CastContextEventType,i=[];try{e.removeEventListener(n.SESSION_STATE_CHANGED,g)}catch(o){i.push(o)}try{e.removeEventListener(n.CAST_STATE_CHANGED,A)}catch(o){i.push(o)}if(i.length)throw i[0]}},N=()=>{if(m)return;m=!0,f();const t=d;d=void 0;const o=[];for(const i of[t,_,()=>e.off("destroy",N)])try{i?.()}catch(n){o.push(n)}if(v=null,C=void 0,o.length)throw o[0]};async function I(){const l=p,f=()=>h()&&p===l;let m;const S=new Promise(e=>{m=()=>e(void 0)});u=m;let C="Failed to initialize Cast API";try{if(!a||!c){const e=function(e,t){const n=window,s=i(n);if(s)return{promise:new Promise((e,o)=>{try{t(s),e(s)}catch(n){o(n)}}),release:()=>{}};const a=o.get(n);if(a)return r(a,t);const c={subscribers:new Set,cancel:()=>v(void 0,new Error("Cast initialization cancelled"))};o.set(n,c);const l=r(c,t),d=n.__onGCastApiAvailable;let u,f,m=!1;function v(e,t){if(!m){m=!0,void 0!==f&&n.clearTimeout(f),o.delete(n),n.__onGCastApiAvailable===S&&(n.__onGCastApiAvailable=d),u&&(u.onload=null,u.onerror=null,e||u.remove());for(const o of c.subscribers)try{e?(o.ready(e),o.resolve(e)):o.reject(t)}catch(i){o.reject(i)}c.subscribers.clear()}}function S(e,t){try{d?.call(n,e,t)}finally{v(e?i(n):void 0,new Error("Cast API is not available"))}}n.__onGCastApiAvailable=S;try{f=n.setTimeout(()=>v(void 0,new Error("Timed out initializing Cast API")),3e4),u=document.createElement("script"),u.src=e||"https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1",u.onerror=e=>v(void 0,e),u.onload=()=>{const e=i(n);e&&v(e)},document.body.appendChild(u)}catch(p){v(void 0,p)}return l}(s.sdk,e=>{if(!f())return;if(a=e,c=function(e){const t=e.framework.CastContext.getInstance();return n.has(t)||(t.setOptions({receiverApplicationId:e.media.DEFAULT_MEDIA_RECEIVER_APP_ID,autoJoinPolicy:e.autoJoinPolicy}),n.add(t)),t}(a),!f())return;const t=a.framework.CastContextEventType;try{c.addEventListener(t.SESSION_STATE_CHANGED,g),h()&&c.addEventListener(t.CAST_STATE_CHANGED,A)}catch(o){try{_()}catch{}throw o}});d=e.release,await Promise.race([e.promise,w,S]),e.release(),d=void 0}if(!f()||!c||!a)return;C="Error connecting to cast session",E=!0;let l=c.getCurrentSession();if(!f())return;if(!l){if(await Promise.race([c.requestSession(),w,S]),!f())return;l=c.getCurrentSession()}if(!f())return;if(!l)throw new Error("No active Cast session");v=l,C="Error casting media",await Promise.race([t(a,l,s,e.option.url),w,S]),f()&&(e.notice.show="Casting started",s.onCastStart?.())}catch(y){if(f())throw e.notice.show=C,s.onError?.(y),y}Line truncated
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-chromecast.js v1.1.0
|
||||
* artplayer-plugin-chromecast.js v2.0.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.artplayerPluginChromecast=t(),define(function(){return t.artplayerPluginChromecast})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginChromecast=t()}(this,function(){"use strict";var e=(e,t,n)=>new Promise((o,a)=>{var c=e=>{try{i(n.next(e))}catch(t){a(t)}},s=e=>{try{i(n.throw(e))}catch(t){a(t)}},i=e=>e.done?o(e.value):Promise.resolve(e.value).then(c,s);i((n=n.apply(e,t)).next())});return function(t){let n=!1,o=null,a=null;const c=e=>{const t=document.querySelector(".art-icon-cast");if(t)switch(e){case"connected":t.style.color="red";break;case"connecting":case"disconnecting":t.style.color="orange";break;default:t.style.color="white"}},s=()=>new Promise((e,s)=>{var i;window.__onGCastApiAvailable=i=>{if(i){const s=window.cast.framework.CastContext.getInstance();s.setOptions({receiverApplicationId:window.chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID,autoJoinPolicy:window.chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED}),s.addEventListener(window.cast.framework.CastContextEventType.SESSION_STATE_CHANGED,e=>{var n,s,i,l,r;const d=window.cast.framework.SessionState;switch(a=e.sessionState,o=e.session,e.sessionState){case d.NO_SESSION:null==(n=t.onStateChange)||n.call(t,"disconnected"),c("disconnected");break;case d.SESSION_STARTING:null==(s=t.onStateChange)||s.call(t,"connecting"),c("connecting");break;case d.SESSION_STARTED:null==(i=t.onStateChange)||i.call(t,"connected"),c("connected");break;case d.SESSION_ENDING:null==(l=t.onStateChange)||l.call(t,"disconnecting"),c("disconnecting");break;case d.SESSION_RESUMED:null==(r=t.onStateChange)||r.call(t,"connected"),c("connected")}}),s.addEventListener(window.cast.framework.CastContextEventType.CAST_STATE_CHANGED,e=>{var n,o,a;const c=window.cast.framework.CastState;switch(e.castState){case c.NO_DEVICES_AVAILABLE:null==(n=t.onCastAvailable)||n.call(t,!1);break;case c.NOT_CONNECTED:null==(o=t.onCastAvailable)||o.call(t,!0);break;case c.CONNECTING:case c.CONNECTED:null==(a=t.onCastAvailable)||a.call(t,!0)}}),n=!0,e()}else s(new Error("Cast API is not available"))},window.chrome&&window.chrome.cast||(i=t.sdk||"https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1",new Promise((e,t)=>{const n=document.createElement("script");n.src=i,n.onload=e,n.onerror=t,document.body.appendChild(n)})).catch(s)}),i=(e,n)=>{const o=t.url||e.option.url,a=new window.chrome.cast.media.MediaInfo(o,t.mimeType||function(e){return{mp4:"video/mp4",webm:"video/webm",ogg:"video/ogg",ogv:"video/ogg",mp3:"audio/mp3",wav:"audio/wav",flv:"video/x-flv",mov:"video/quicktime",avi:"video/x-msvideo",wmv:"video/x-ms-wmv",mpd:"application/dash+xml",m3u8:"application/x-mpegURL"}[e.split("?")[0].split("#")[0].split(".").pop().toLowerCase()]||"application/octet-stream"}(o)),c=new window.chrome.cast.media.LoadRequest(a);n.loadMedia(c).then(()=>{var n;e.notice.show="Casting started",null==(n=t.onCastStart)||n.call(t)}).catch(n=>{var o;throw e.notice.show="Error casting media",null==(o=t.onError)||o.call(t,n),n})};return c=>e(null,null,function*(){return c.controls.add({name:"chromecast",position:"right",tooltip:"Chromecast",html:`<i class="art-icon art-icon-cast">${t.icon||'<svg height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M512 96H64v99c-13-2-26.4-3-40-3H0V96C0 60.7 28.7 32 64 32H512c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H288V456c0-13.6-1-27-3-40H512V96zM24 224c128.1 0 232 103.9 232 232c0 13.3-10.7 24-24 24s-24-10.7-24-24c0-101.6-82.4-184-184-184c-13.3 0-24-10.7-24-24s10.7-24 24-24zm8 192a32 32 0 1 1 0 64 32 32 0 1 1 0-64zM0 344c0-13.3 10.7-24 24-24c75.1 0 136 60.9 136 136c0 13.3-10.7 24-24 24s-24-10.7-24-24c0-48.6-39.4-88-88-88c-13.3 0-24-10.7-24-24z"/></svg>'}</i>`,click:()=>e(null,null,function*(){var e,a;if(!n)try{yield s()}catch(r){throw c.notice.show="Failed to initialize Cast API",null==(e=t.onError)||e.call(t,r),r}const l=window.cast.framework.CastContext.getInstance();if(o)i(c,o);else try{const e=yield l.requestSession();i(c,e)}catch(r){throw c.notice.show="Error connecting to cast session",null==(a=t.onError)||a.call(t,r),r}})}),{name:"artplayerPluginChromecast",getCastState:()=>a,isCasting:()=>null!==o}})}});
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginChromecast=t(),define(function(){return e.artplayerPluginChromecast})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginChromecast=t()}(this,function(){"use strict";var e=(e,t,o)=>new Promise((n,i)=>{var r=e=>{try{a(o.next(e))}catch(t){i(t)}},s=e=>{try{a(o.throw(e))}catch(t){i(t)}},a=e=>e.done?n(e.value):Promise.resolve(e.value).then(r,s);a((o=o.apply(e,t)).next())});const t={mp4:"video/mp4",webm:"video/webm",ogg:"video/ogg",ogv:"video/ogg",mp3:"audio/mp3",wav:"audio/wav",flv:"video/x-flv",mov:"video/quicktime",avi:"video/x-msvideo",wmv:"video/x-ms-wmv",mpd:"application/dash+xml",m3u8:"application/x-mpegURL"};function o(e,o,n,i){const r=n.url||i,s=r.split("?")[0].split("#")[0].split(".").pop().toLowerCase(),a=new e.media.MediaInfo(r,n.mimeType||t[s]||"application/octet-stream");return o.loadMedia(new e.media.LoadRequest(a))}const n=new WeakMap,i=new WeakSet;function r(e){var t,o,n,i;const r=null==(t=e.cast)?void 0:t.framework,s=null==(o=e.chrome)?void 0:o.cast;if("function"===typeof(null==(n=null==r?void 0:r.CastContext)?void 0:n.getInstance)&&r.CastContextEventType&&r.SessionState&&r.CastState&&"function"===typeof(null==(i=null==s?void 0:s.media)?void 0:i.MediaInfo)&&"function"===typeof s.media.LoadRequest&&s.AutoJoinPolicy)return{framework:r,media:s.media,autoJoinPolicy:s.AutoJoinPolicy.ORIGIN_SCOPED}}function s(e,t){let o;const n=new Promise((n,i)=>{o={ready:t,resolve:n,reject:i},e.subscribers.add(o)});let i=!1;return{promise:n,release:()=>{i||(i=!0,e.subscribers.delete(o),o.reject(new Error("Cast initialization cancelled")),e.subscribers.size||e.cancel())}}}function a(t,a){let l,c,u,d,v,f,m=!1,S=null,p=null,E=0,C=!1;const w=new Promise(e=>{f=()=>e(void 0)});let h;const y=()=>!m&&!t.isDestroy,g=e=>{var t;if(null==(t=a.onStateChange)||t.call(a,e),!y())return;const o=null==h?void 0:h.querySelector(".art-icon-cast");o&&(o.style.color="connected"===e?"red":"connecting"===e||"disconnecting"===e?"orange":"white")},A=e=>{if(!y()||!l)return;p=e.sessionState;const t=l.framework.SessionState;p===t.NO_SESSION||p===t.SESSION_ENDED||p===t.SESSION_START_FAILED?((p!==t.NO_SESSION||C)&&(E++,null==v||v()),S=null,g("disconnected")):((p===t.SESSION_ENDING||S&&e.session&&e.session!==S)&&(E++,null==v||v()),S=e.session||null,p===t.SESSION_STARTING?g("connecting"):p===t.SESSION_ENDING?g("disconnecting"):p!==t.SESSION_STARTED&&p!==t.SESSION_RESUMED||g("connected"))},_=e=>{var t,o;if(!y()||!l)return;const n=l.framework.CastState;e.castState===n.NO_DEVICES_AVAILABLE?null==(t=a.onCastAvailable)||t.call(a,!1):e.castState!==n.NOT_CONNECTED&&e.castState!==n.CONNECTING&&e.castState!==n.CONNECTED||null==(o=a.onCastAvailable)||o.call(a,!0)},N=()=>{const e=c,t=l;if(c=void 0,l=void 0,e&&t){const n=t.framework.CastContextEventType,i=[];try{e.removeEventListener(n.SESSION_STATE_CHANGED,A)}catch(o){i.push(o)}try{e.removeEventListener(n.CAST_STATE_CHANGED,_)}catch(o){i.push(o)}if(i.length)throw i[0]}},I=()=>{if(m)return;m=!0,f();const e=d;d=void 0;const o=[];for(const i of[e,N,()=>t.off("destroy",I)])try{null==i||i()}catch(n){o.push(n)}if(S=null,h=void 0,o.length)throw o[0]};function T(){return e(this,null,function*(){var e,u;const f=E,m=()=>y()&&E===f;let p;const h=new Promise(e=>{p=()=>e(void 0)});v=p;let g="Failed to initialize Cast API";try{if(!l||!c){const e=function(e,t){const o=window,i=r(o);if(i)return{promise:new Promise((e,o)=>{try{t(i),e(i)}catch(n){o(n)}}),release:()=>{}};const a=n.get(o);if(a)return s(a,t);const l={subscribers:new Set,cancel:()=>m(void 0,new Error("Cast initialization cancelled"))};n.set(o,l);const c=s(l,t),u=o.__onGCastApiAvailable;let d,v,f=!1;function m(e,t){if(!f){f=!0,void 0!==v&&o.clearTimeout(v),n.delete(o),o.__onGCastApiAvailable===S&&(o.__onGCastApiAvailable=u),d&&(d.onload=null,d.onerror=null,e||d.remove());for(const o of l.subscribers)try{e?(o.ready(e),o.resolve(e)):o.reject(t)}catch(i){o.reject(i)}l.subscribers.clear()}}function S(e,t){try{null==u||u.call(o,e,t)}finally{m(e?r(o):void 0,new Error("Cast API is not available"))}}o.__onGCastApiAvailable=S;try{v=o.setTimeout(()=>m(void 0,new Error("Timed out initializing Cast API")),3e4),d=document.createElement("script"),d.src=e||"https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1",d.onerror=e=>m(void 0,e),d.onload=()=>{const e=r(o);e&&m(e)},document.body.appendChild(d)}catch(p){m(void 0,p)}return c}(a.sdk,e=>{if(!m())return;if(l=e,c=function(e){const t=e.framework.CastContext.getInstance();return i.has(t)||(t.setOptions({receiverApplicationId:e.media.DEFAULT_MEDIA_RECEIVER_APP_ID,autoJoinPolicy:e.autoJoinPolicy}),i.add(t)),t}(l),!m())return;const t=l.framework.CastContextEventType;try{c.addEventListener(t.SESSION_STATE_CHANGED,A),y()&&c.addEventListener(t.CAST_STATE_CHANGED,_)}catch(o){try{N()}catch(n){}throw o}});d=e.release,yield Promise.race([e.promise,w,h]),e.relLine truncated
|
||||
@@ -1,176 +1,362 @@
|
||||
/*!
|
||||
* artplayer-plugin-chromecast.js v1.1.0
|
||||
* artplayer-plugin-chromecast.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
function loadScript(src) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const script = document.createElement("script");
|
||||
script.src = src;
|
||||
script.onload = resolve;
|
||||
script.onerror = reject;
|
||||
document.body.appendChild(script);
|
||||
});
|
||||
}
|
||||
function getMimeType(url) {
|
||||
const icon = '<svg height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7V4h17v14h-8M3 11a10 10 0 0 1 10 10M3 16a5 5 0 0 1 5 5"/><circle cx="3" cy="21" r="1" fill="currentColor" stroke="none"/></svg>\r\n';
|
||||
const mimeTypes = {
|
||||
mp4: "video/mp4",
|
||||
webm: "video/webm",
|
||||
ogg: "video/ogg",
|
||||
ogv: "video/ogg",
|
||||
mp3: "audio/mp3",
|
||||
wav: "audio/wav",
|
||||
flv: "video/x-flv",
|
||||
mov: "video/quicktime",
|
||||
avi: "video/x-msvideo",
|
||||
wmv: "video/x-ms-wmv",
|
||||
mpd: "application/dash+xml",
|
||||
m3u8: "application/x-mpegURL"
|
||||
};
|
||||
function loadMedia(sdk, session, option, currentUrl) {
|
||||
const url = option.url || currentUrl;
|
||||
const extension = url.split("?")[0].split("#")[0].split(".").pop().toLowerCase();
|
||||
const mimeTypes = {
|
||||
mp4: "video/mp4",
|
||||
webm: "video/webm",
|
||||
ogg: "video/ogg",
|
||||
ogv: "video/ogg",
|
||||
mp3: "audio/mp3",
|
||||
wav: "audio/wav",
|
||||
flv: "video/x-flv",
|
||||
mov: "video/quicktime",
|
||||
avi: "video/x-msvideo",
|
||||
wmv: "video/x-ms-wmv",
|
||||
mpd: "application/dash+xml",
|
||||
m3u8: "application/x-mpegURL"
|
||||
};
|
||||
return mimeTypes[extension] || "application/octet-stream";
|
||||
const info = new sdk.media.MediaInfo(url, option.mimeType || mimeTypes[extension] || "application/octet-stream");
|
||||
return session.loadMedia(new sdk.media.LoadRequest(info));
|
||||
}
|
||||
function artplayerPluginChromecast(option) {
|
||||
const DEFAULT_ICON = `<svg height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M512 96H64v99c-13-2-26.4-3-40-3H0V96C0 60.7 28.7 32 64 32H512c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H288V456c0-13.6-1-27-3-40H512V96zM24 224c128.1 0 232 103.9 232 232c0 13.3-10.7 24-24 24s-24-10.7-24-24c0-101.6-82.4-184-184-184c-13.3 0-24-10.7-24-24s10.7-24 24-24zm8 192a32 32 0 1 1 0 64 32 32 0 1 1 0-64zM0 344c0-13.3 10.7-24 24-24c75.1 0 136 60.9 136 136c0 13.3-10.7 24-24 24s-24-10.7-24-24c0-48.6-39.4-88-88-88c-13.3 0-24-10.7-24-24z"/></svg>`;
|
||||
const DEFAULT_SDK = "https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1";
|
||||
let isCastInitialized = false;
|
||||
let castSession = null;
|
||||
let castState = null;
|
||||
const updateCastButton = (state) => {
|
||||
const button = document.querySelector(".art-icon-cast");
|
||||
if (button) {
|
||||
switch (state) {
|
||||
case "connected":
|
||||
button.style.color = "red";
|
||||
break;
|
||||
case "connecting":
|
||||
case "disconnecting":
|
||||
button.style.color = "orange";
|
||||
break;
|
||||
case "disconnected":
|
||||
default:
|
||||
button.style.color = "white";
|
||||
break;
|
||||
const DEFAULT_SDK = "https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1";
|
||||
const pending = /* @__PURE__ */ new WeakMap();
|
||||
const configured = /* @__PURE__ */ new WeakSet();
|
||||
function ready(host) {
|
||||
const framework = host.cast?.framework;
|
||||
const api = host.chrome?.cast;
|
||||
if (typeof framework?.CastContext?.getInstance === "function" && framework.CastContextEventType && framework.SessionState && framework.CastState && typeof api?.media?.MediaInfo === "function" && typeof api.media.LoadRequest === "function" && api.AutoJoinPolicy) {
|
||||
return { framework, media: api.media, autoJoinPolicy: api.AutoJoinPolicy.ORIGIN_SCOPED };
|
||||
}
|
||||
}
|
||||
function configure(sdk) {
|
||||
const context = sdk.framework.CastContext.getInstance();
|
||||
if (!configured.has(context)) {
|
||||
context.setOptions({ receiverApplicationId: sdk.media.DEFAULT_MEDIA_RECEIVER_APP_ID, autoJoinPolicy: sdk.autoJoinPolicy });
|
||||
configured.add(context);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
function lease(loading, onReady) {
|
||||
let subscriber;
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
subscriber = { ready: onReady, resolve, reject };
|
||||
loading.subscribers.add(subscriber);
|
||||
});
|
||||
let released = false;
|
||||
return { promise, release: () => {
|
||||
if (released)
|
||||
return;
|
||||
released = true;
|
||||
loading.subscribers.delete(subscriber);
|
||||
subscriber.reject(new Error("Cast initialization cancelled"));
|
||||
if (!loading.subscribers.size)
|
||||
loading.cancel();
|
||||
} };
|
||||
}
|
||||
function loadSdk(src, onReady) {
|
||||
const host = window;
|
||||
const loaded = ready(host);
|
||||
if (loaded) {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
try {
|
||||
onReady(loaded);
|
||||
resolve(loaded);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
return { promise, release: () => {
|
||||
} };
|
||||
}
|
||||
const existing = pending.get(host);
|
||||
if (existing)
|
||||
return lease(existing, onReady);
|
||||
const loading = { subscribers: /* @__PURE__ */ new Set(), cancel: () => finish(void 0, new Error("Cast initialization cancelled")) };
|
||||
pending.set(host, loading);
|
||||
const subscription = lease(loading, onReady);
|
||||
const previous = host.__onGCastApiAvailable;
|
||||
let script;
|
||||
let timer;
|
||||
let settled = false;
|
||||
function finish(sdk, error) {
|
||||
if (settled)
|
||||
return;
|
||||
settled = true;
|
||||
if (timer !== void 0)
|
||||
host.clearTimeout(timer);
|
||||
pending.delete(host);
|
||||
if (host.__onGCastApiAvailable === available)
|
||||
host.__onGCastApiAvailable = previous;
|
||||
if (script) {
|
||||
script.onload = null;
|
||||
script.onerror = null;
|
||||
if (!sdk)
|
||||
script.remove();
|
||||
}
|
||||
for (const subscriber of loading.subscribers) {
|
||||
try {
|
||||
if (sdk) {
|
||||
subscriber.ready(sdk);
|
||||
subscriber.resolve(sdk);
|
||||
} else {
|
||||
subscriber.reject(error);
|
||||
}
|
||||
} catch (error2) {
|
||||
subscriber.reject(error2);
|
||||
}
|
||||
}
|
||||
};
|
||||
const initializeCastApi = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.__onGCastApiAvailable = (isAvailable) => {
|
||||
if (isAvailable) {
|
||||
const context = window.cast.framework.CastContext.getInstance();
|
||||
context.setOptions({
|
||||
receiverApplicationId: window.chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID,
|
||||
autoJoinPolicy: window.chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED
|
||||
});
|
||||
context.addEventListener(
|
||||
window.cast.framework.CastContextEventType.SESSION_STATE_CHANGED,
|
||||
(event) => {
|
||||
const SessionState = window.cast.framework.SessionState;
|
||||
castState = event.sessionState;
|
||||
castSession = event.session;
|
||||
switch (event.sessionState) {
|
||||
case SessionState.NO_SESSION:
|
||||
option.onStateChange?.("disconnected");
|
||||
updateCastButton("disconnected");
|
||||
break;
|
||||
case SessionState.SESSION_STARTING:
|
||||
option.onStateChange?.("connecting");
|
||||
updateCastButton("connecting");
|
||||
break;
|
||||
case SessionState.SESSION_STARTED:
|
||||
option.onStateChange?.("connected");
|
||||
updateCastButton("connected");
|
||||
break;
|
||||
case SessionState.SESSION_ENDING:
|
||||
option.onStateChange?.("disconnecting");
|
||||
updateCastButton("disconnecting");
|
||||
break;
|
||||
case SessionState.SESSION_RESUMED:
|
||||
option.onStateChange?.("connected");
|
||||
updateCastButton("connected");
|
||||
break;
|
||||
}
|
||||
}
|
||||
);
|
||||
context.addEventListener(window.cast.framework.CastContextEventType.CAST_STATE_CHANGED, (event) => {
|
||||
const CastState = window.cast.framework.CastState;
|
||||
switch (event.castState) {
|
||||
case CastState.NO_DEVICES_AVAILABLE:
|
||||
option.onCastAvailable?.(false);
|
||||
break;
|
||||
case CastState.NOT_CONNECTED:
|
||||
option.onCastAvailable?.(true);
|
||||
break;
|
||||
case CastState.CONNECTING:
|
||||
case CastState.CONNECTED:
|
||||
option.onCastAvailable?.(true);
|
||||
break;
|
||||
}
|
||||
});
|
||||
isCastInitialized = true;
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error("Cast API is not available"));
|
||||
}
|
||||
};
|
||||
if (!window.chrome || !window.chrome.cast) {
|
||||
loadScript(option.sdk || DEFAULT_SDK).catch(reject);
|
||||
}
|
||||
});
|
||||
};
|
||||
const castVideo = (art, session) => {
|
||||
const url = option.url || art.option.url;
|
||||
const mediaInfo = new window.chrome.cast.media.MediaInfo(url, option.mimeType || getMimeType(url));
|
||||
const request = new window.chrome.cast.media.LoadRequest(mediaInfo);
|
||||
session.loadMedia(request).then(() => {
|
||||
art.notice.show = "Casting started";
|
||||
option.onCastStart?.();
|
||||
}).catch((error) => {
|
||||
art.notice.show = "Error casting media";
|
||||
option.onError?.(error);
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
return async (art) => {
|
||||
art.controls.add({
|
||||
name: "chromecast",
|
||||
position: "right",
|
||||
tooltip: "Chromecast",
|
||||
html: `<i class="art-icon art-icon-cast">${option.icon || DEFAULT_ICON}</i>`,
|
||||
click: async () => {
|
||||
if (!isCastInitialized) {
|
||||
try {
|
||||
await initializeCastApi();
|
||||
} catch (error) {
|
||||
art.notice.show = "Failed to initialize Cast API";
|
||||
option.onError?.(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
const context = window.cast.framework.CastContext.getInstance();
|
||||
if (castSession) {
|
||||
castVideo(art, castSession);
|
||||
} else {
|
||||
try {
|
||||
const session = await context.requestSession();
|
||||
castVideo(art, session);
|
||||
} catch (error) {
|
||||
art.notice.show = "Error connecting to cast session";
|
||||
option.onError?.(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return {
|
||||
name: "artplayerPluginChromecast",
|
||||
getCastState: () => castState,
|
||||
isCasting: () => castSession !== null
|
||||
loading.subscribers.clear();
|
||||
}
|
||||
function available(value, errorInfo) {
|
||||
try {
|
||||
previous?.call(host, value, errorInfo);
|
||||
} finally {
|
||||
const sdk = value ? ready(host) : void 0;
|
||||
finish(sdk, new Error("Cast API is not available"));
|
||||
}
|
||||
}
|
||||
host.__onGCastApiAvailable = available;
|
||||
try {
|
||||
timer = host.setTimeout(() => finish(void 0, new Error("Timed out initializing Cast API")), 3e4);
|
||||
script = document.createElement("script");
|
||||
script.src = src || DEFAULT_SDK;
|
||||
script.onerror = (error) => finish(void 0, error);
|
||||
script.onload = () => {
|
||||
const sdk = ready(host);
|
||||
if (sdk)
|
||||
finish(sdk);
|
||||
};
|
||||
};
|
||||
document.body.appendChild(script);
|
||||
} catch (error) {
|
||||
finish(void 0, error);
|
||||
}
|
||||
return subscription;
|
||||
}
|
||||
function createController(art, option) {
|
||||
let disposed = false;
|
||||
let sdk;
|
||||
let context;
|
||||
let session = null;
|
||||
let state = null;
|
||||
let activeClick;
|
||||
let releaseLoader;
|
||||
let generation = 0;
|
||||
let operationStarted = false;
|
||||
let cancelOperation;
|
||||
let cancel;
|
||||
const cancelled = new Promise((resolve) => {
|
||||
cancel = () => resolve(void 0);
|
||||
});
|
||||
let element;
|
||||
const active = () => !disposed && !art.isDestroy;
|
||||
const update = (value) => {
|
||||
option.onStateChange?.(value);
|
||||
if (!active())
|
||||
return;
|
||||
const button = element?.querySelector(".art-icon-cast");
|
||||
if (button)
|
||||
button.style.color = value === "connected" ? "red" : value === "connecting" || value === "disconnecting" ? "orange" : "white";
|
||||
};
|
||||
const onSession = (event) => {
|
||||
if (!active() || !sdk)
|
||||
return;
|
||||
state = event.sessionState;
|
||||
const states = sdk.framework.SessionState;
|
||||
if (state === states.NO_SESSION || state === states.SESSION_ENDED || state === states.SESSION_START_FAILED) {
|
||||
if (state !== states.NO_SESSION || operationStarted) {
|
||||
generation++;
|
||||
cancelOperation?.();
|
||||
}
|
||||
session = null;
|
||||
update("disconnected");
|
||||
} else {
|
||||
if (state === states.SESSION_ENDING || session && event.session && event.session !== session) {
|
||||
generation++;
|
||||
cancelOperation?.();
|
||||
}
|
||||
session = event.session || null;
|
||||
if (state === states.SESSION_STARTING)
|
||||
update("connecting");
|
||||
else if (state === states.SESSION_ENDING)
|
||||
update("disconnecting");
|
||||
else if (state === states.SESSION_STARTED || state === states.SESSION_RESUMED)
|
||||
update("connected");
|
||||
}
|
||||
};
|
||||
const onAvailability = (event) => {
|
||||
if (!active() || !sdk)
|
||||
return;
|
||||
const states = sdk.framework.CastState;
|
||||
if (event.castState === states.NO_DEVICES_AVAILABLE)
|
||||
option.onCastAvailable?.(false);
|
||||
else if (event.castState === states.NOT_CONNECTED || event.castState === states.CONNECTING || event.castState === states.CONNECTED)
|
||||
option.onCastAvailable?.(true);
|
||||
};
|
||||
const detach = () => {
|
||||
const ownedContext = context;
|
||||
const ownedSdk = sdk;
|
||||
context = void 0;
|
||||
sdk = void 0;
|
||||
if (ownedContext && ownedSdk) {
|
||||
const events = ownedSdk.framework.CastContextEventType;
|
||||
const errors = [];
|
||||
try {
|
||||
ownedContext.removeEventListener(events.SESSION_STATE_CHANGED, onSession);
|
||||
} catch (error) {
|
||||
errors.push(error);
|
||||
}
|
||||
try {
|
||||
ownedContext.removeEventListener(events.CAST_STATE_CHANGED, onAvailability);
|
||||
} catch (error) {
|
||||
errors.push(error);
|
||||
}
|
||||
if (errors.length)
|
||||
throw errors[0];
|
||||
}
|
||||
};
|
||||
const destroy = () => {
|
||||
if (disposed)
|
||||
return;
|
||||
disposed = true;
|
||||
cancel();
|
||||
const release = releaseLoader;
|
||||
releaseLoader = void 0;
|
||||
const errors = [];
|
||||
for (const cleanup of [release, detach, () => art.off("destroy", destroy)]) {
|
||||
try {
|
||||
cleanup?.();
|
||||
} catch (error) {
|
||||
errors.push(error);
|
||||
}
|
||||
}
|
||||
session = null;
|
||||
element = void 0;
|
||||
if (errors.length)
|
||||
throw errors[0];
|
||||
};
|
||||
async function cast() {
|
||||
const epoch = generation;
|
||||
const currentOperation = () => active() && generation === epoch;
|
||||
let stop;
|
||||
const superseded = new Promise((resolve) => {
|
||||
stop = () => resolve(void 0);
|
||||
});
|
||||
cancelOperation = stop;
|
||||
let failureNotice = "Failed to initialize Cast API";
|
||||
try {
|
||||
if (!sdk || !context) {
|
||||
const loading = loadSdk(option.sdk, (available) => {
|
||||
if (!currentOperation())
|
||||
return;
|
||||
sdk = available;
|
||||
context = configure(sdk);
|
||||
if (!currentOperation())
|
||||
return;
|
||||
const events = sdk.framework.CastContextEventType;
|
||||
try {
|
||||
context.addEventListener(events.SESSION_STATE_CHANGED, onSession);
|
||||
if (active())
|
||||
context.addEventListener(events.CAST_STATE_CHANGED, onAvailability);
|
||||
} catch (error) {
|
||||
try {
|
||||
detach();
|
||||
} catch {
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
releaseLoader = loading.release;
|
||||
await Promise.race([loading.promise, cancelled, superseded]);
|
||||
loading.release();
|
||||
releaseLoader = void 0;
|
||||
}
|
||||
if (!currentOperation() || !context || !sdk)
|
||||
return;
|
||||
failureNotice = "Error connecting to cast session";
|
||||
operationStarted = true;
|
||||
let current = context.getCurrentSession();
|
||||
if (!currentOperation())
|
||||
return;
|
||||
if (!current) {
|
||||
await Promise.race([context.requestSession(), cancelled, superseded]);
|
||||
if (!currentOperation())
|
||||
return;
|
||||
current = context.getCurrentSession();
|
||||
}
|
||||
if (!currentOperation())
|
||||
return;
|
||||
if (!current)
|
||||
throw new Error("No active Cast session");
|
||||
session = current;
|
||||
failureNotice = "Error casting media";
|
||||
await Promise.race([loadMedia(sdk, current, option, art.option.url), cancelled, superseded]);
|
||||
if (currentOperation()) {
|
||||
art.notice.show = "Casting started";
|
||||
option.onCastStart?.();
|
||||
}
|
||||
} catch (error) {
|
||||
if (currentOperation()) {
|
||||
art.notice.show = failureNotice;
|
||||
option.onError?.(error);
|
||||
throw error;
|
||||
}
|
||||
} finally {
|
||||
releaseLoader?.();
|
||||
releaseLoader = void 0;
|
||||
if (cancelOperation === stop)
|
||||
cancelOperation = void 0;
|
||||
operationStarted = false;
|
||||
}
|
||||
}
|
||||
const click = () => {
|
||||
if (!active())
|
||||
return Promise.resolve();
|
||||
if (!activeClick) {
|
||||
let resolve;
|
||||
let reject;
|
||||
activeClick = new Promise((yes, no) => {
|
||||
resolve = yes;
|
||||
reject = no;
|
||||
});
|
||||
activeClick.catch(() => {
|
||||
});
|
||||
cast().then(() => {
|
||||
activeClick = void 0;
|
||||
resolve();
|
||||
}, (error) => {
|
||||
activeClick = void 0;
|
||||
reject(error);
|
||||
});
|
||||
}
|
||||
return activeClick;
|
||||
};
|
||||
art.controls.add({
|
||||
name: "chromecast",
|
||||
position: "right",
|
||||
tooltip: "Chromecast",
|
||||
html: `<i class="art-icon art-icon-cast">${option.icon || icon}</i>`,
|
||||
mounted(control) {
|
||||
if (active())
|
||||
element = control;
|
||||
},
|
||||
click
|
||||
});
|
||||
art.on("destroy", destroy);
|
||||
if (art.isDestroy)
|
||||
destroy();
|
||||
return { name: "artplayerPluginChromecast", getCastState: () => state, isCasting: () => session !== null };
|
||||
}
|
||||
function artplayerPluginChromecast(option) {
|
||||
return async (art) => createController(art, option);
|
||||
}
|
||||
Object.defineProperty(artplayerPluginChromecast, "default", { value: artplayerPluginChromecast, writable: true, configurable: true });
|
||||
export {
|
||||
artplayerPluginChromecast as default
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-danmuku-mask.js v1.1.0
|
||||
* artplayer-plugin-danmuku-mask.js v2.0.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.artplayerPluginDanmukuMask=t(),define(function(){return t.artplayerPluginDanmukuMask})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDanmukuMask=t()}(this,function(){"use strict";function e(e,t){for(var n=0;n<t.length;n++){const r=t[n];if("string"!==typeof r&&!Array.isArray(r))for(const t in r)if("default"!==t&&!(t in e)){const n=Object.getOwnPropertyDescriptor(r,t);n&&Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>r[t]})}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}class t{constructor(e,t){this.backend=e,this.dataMover=t,this.data=new WeakMap,this.dataIdsCount=0}get(e){return this.data.has(e)||this.dataMover.moveData(this.backend,e),this.data.get(e)}set(e,t){this.dataIdsCount++,this.data.set(e,t)}has(e){return this.data.has(e)}delete(e){return this.dataIdsCount--,this.data.delete(e)}numDataIds(){return this.dataIdsCount}}class n{refCount(e){return r("refCount")}incRef(e){return r("incRef")}timerAvailable(){return!0}time(e){return r("time")}read(e){return r("read")}readSync(e){return r("readSync")}readToGPU(e,t){return r("readToGPU")}numDataIds(){return r("numDataIds")}disposeData(e,t){return r("disposeData")}write(e,t,n){return r("write")}move(e,t,n,a,s){return r("move")}createTensorFromGPUData(e,t,n){return r("createTensorFromGPUData")}memory(){return r("memory")}floatPrecision(){return r("floatPrecision")}epsilon(){return 32===this.floatPrecision()?1e-7:1e-4}dispose(){return r("dispose")}}function r(e){throw new Error(`'${e}' not yet implemented or not found in the registry. This kernel may not be supported by the tfjs backend you have chosen`)}function a(e,t,n){return Math.max(e,Math.min(t,n))}function s(e){return e%2===0?e:e+1}function o(e,t,n){const r=e[t];e[t]=e[n],e[n]=r}function i(e,t){if(!e)throw new Error("string"===typeof t?t:t())}function u(e,t,n=""){i(d(e,t),()=>n+` Shapes ${e} and ${t} must match`)}function l(e){i(null!=e,()=>"The input to the tensor constructor must be a non-null value.")}function c(e){if(0===e.length)return 1;let t=e[0];for(let n=1;n<e.length;n++)t*=e[n];return t}function d(e,t){if(e===t)return!0;if(null==e||null==t)return!1;if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(e[n]!==t[n])return!1;return!0}function p(e){return e%1===0}function h(e){const t=Math.ceil(Math.sqrt(e));return[t,Math.ceil(e/t)]}function f(e,t){return t<=e.length?e:e+" ".repeat(t-e.length)}function m(e,t=e=>0,n,r){return new Promise((a,s)=>{let o=0;const i=()=>{if(e())return void a();o++;const u=t(o);null!=n&&o>=n?s():null!=r?r(i,u):setTimeout(i,u)};i()})}function g(e,t){let n=1,r=-1;for(let s=0;s<e.length;++s)if(e[s]>=0)n*=e[s];else if(-1===e[s]){if(-1!==r)throw Error(`Shapes can only have 1 implicit size. Found -1 at dim ${r} and dim ${s}`);r=s}else if(e[s]<0)throw Error(`Shapes can not be < 0. Found ${e[s]} at dim ${s}`);if(-1===r){if(t>0&&t!==n)throw Error(`Size(${t}) must match the product of shape ${e}`);return e}if(0===n)throw Error(`Cannot infer the missing size in [${e}] when there are 0 elements`);if(t%n!==0)throw Error(`The implicit shape can't be a fractional number. Got ${t} / ${n}`);const a=e.slice();return a[r]=t/n,a}function y(e,t){const n=t.length;return i((e=null==e?t.map((e,t)=>t):[].concat(e)).every(e=>e>=-n&&e<n),()=>`All values in axis param must be in range [-${n}, ${n}) but got axis ${e}`),i(e.every(e=>p(e)),()=>`All values in axis param must be integers but got axis ${e}`),e.map(e=>e<0?n+e:e)}function b(e,t){const n=[],r=[],a=null!=t&&Array.isArray(t)&&0===t.length,s=null==t||a?null:y(t,e).sort();let o=0;for(let i=0;i<e.length;++i){if(null!=s){if(s[o]===i&&1!==e[i])throw new Error(`Can't squeeze axis ${i} since its dim '${e[i]}' is not 1`);(null==s[o]||s[o]>i)&&1===e[i]&&(n.push(e[i]),r.push(i)),s[o]<=i&&o++}1!==e[i]&&(n.push(e[i]),r.push(i))}return{newShape:n,keptDims:r}}function x(e,t){return v(e,t)}function v(e,t){let n=null;if(null==e||"float32"===e)n=new Float32Array(t);else if("int32"===e)n=new Int32Array(t);else if("bool"===e)n=new Uint8Array(t);else{if("string"!==e)throw new Error(`Unknown data type ${e}`);n=new Array(t)}return n}function w(e,t){return"complex64"!==t&&(("float32"!==t||"complex64"===e)&&(("int32"!==t||"float32"===e||"complex64"===e)&&("bool"!==t||"bool"!==e)))}function k(e){if("float32"===e||"int32"===e)return 4;if("complex64"===e)return 8;if("bool"===e)return 1;throw new Error(`Unknown dtype ${e}`)}function I(e){return"string"===typeof e||e instanceof String}function N(e){return Array.isArray(e)?N(e[0]):e instanceof Float32Array?"float32":e instanceof Int32Array||e instanceof Uint8Array||e instanceof Uint8ClampedArray?"int32":"number"===typeof e?"float32":I(e)?"string":function(e){return"boolean"===typeof e}(e)?"bool":"float32"}function S(e){return!!(e&&e.constructor&&e.call&&e.apply)}function T(e,t){for(let n=t;n<e;++n)if(e%n===0)return nLine truncated
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginDanmukuMask=t(),define(function(){return e.artplayerPluginDanmukuMask})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDanmukuMask=t()}(this,function(){"use strict";function e(e,t){for(var n=0;n<t.length;n++){const r=t[n];if("string"!==typeof r&&!Array.isArray(r))for(const t in r)if("default"!==t&&!(t in e)){const n=Object.getOwnPropertyDescriptor(r,t);n&&Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>r[t]})}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}class t{constructor(e,t){this.backend=e,this.dataMover=t,this.data=new WeakMap,this.dataIdsCount=0}get(e){return this.data.has(e)||this.dataMover.moveData(this.backend,e),this.data.get(e)}set(e,t){this.dataIdsCount++,this.data.set(e,t)}has(e){return this.data.has(e)}delete(e){return this.dataIdsCount--,this.data.delete(e)}numDataIds(){return this.dataIdsCount}}class n{refCount(e){return r("refCount")}incRef(e){return r("incRef")}timerAvailable(){return!0}time(e){return r("time")}read(e){return r("read")}readSync(e){return r("readSync")}readToGPU(e,t){return r("readToGPU")}numDataIds(){return r("numDataIds")}disposeData(e,t){return r("disposeData")}write(e,t,n){return r("write")}move(e,t,n,a,s){return r("move")}createTensorFromGPUData(e,t,n){return r("createTensorFromGPUData")}memory(){return r("memory")}floatPrecision(){return r("floatPrecision")}epsilon(){return 32===this.floatPrecision()?1e-7:1e-4}dispose(){return r("dispose")}}function r(e){throw new Error(`'${e}' not yet implemented or not found in the registry. This kernel may not be supported by the tfjs backend you have chosen`)}function a(e,t,n){return Math.max(e,Math.min(t,n))}function s(e){return e%2===0?e:e+1}function o(e,t,n){const r=e[t];e[t]=e[n],e[n]=r}function i(e,t){if(!e)throw new Error("string"===typeof t?t:t())}function u(e,t,n=""){i(d(e,t),()=>n+` Shapes ${e} and ${t} must match`)}function l(e){i(null!=e,()=>"The input to the tensor constructor must be a non-null value.")}function c(e){if(0===e.length)return 1;let t=e[0];for(let n=1;n<e.length;n++)t*=e[n];return t}function d(e,t){if(e===t)return!0;if(null==e||null==t)return!1;if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(e[n]!==t[n])return!1;return!0}function p(e){return e%1===0}function h(e){const t=Math.ceil(Math.sqrt(e));return[t,Math.ceil(e/t)]}function f(e,t){return t<=e.length?e:e+" ".repeat(t-e.length)}function m(e,t=e=>0,n,r){return new Promise((a,s)=>{let o=0;const i=()=>{if(e())return void a();o++;const u=t(o);null!=n&&o>=n?s():null!=r?r(i,u):setTimeout(i,u)};i()})}function g(e,t){let n=1,r=-1;for(let s=0;s<e.length;++s)if(e[s]>=0)n*=e[s];else if(-1===e[s]){if(-1!==r)throw Error(`Shapes can only have 1 implicit size. Found -1 at dim ${r} and dim ${s}`);r=s}else if(e[s]<0)throw Error(`Shapes can not be < 0. Found ${e[s]} at dim ${s}`);if(-1===r){if(t>0&&t!==n)throw Error(`Size(${t}) must match the product of shape ${e}`);return e}if(0===n)throw Error(`Cannot infer the missing size in [${e}] when there are 0 elements`);if(t%n!==0)throw Error(`The implicit shape can't be a fractional number. Got ${t} / ${n}`);const a=e.slice();return a[r]=t/n,a}function y(e,t){const n=t.length;return i((e=null==e?t.map((e,t)=>t):[].concat(e)).every(e=>e>=-n&&e<n),()=>`All values in axis param must be in range [-${n}, ${n}) but got axis ${e}`),i(e.every(e=>p(e)),()=>`All values in axis param must be integers but got axis ${e}`),e.map(e=>e<0?n+e:e)}function b(e,t){const n=[],r=[],a=null!=t&&Array.isArray(t)&&0===t.length,s=null==t||a?null:y(t,e).sort();let o=0;for(let i=0;i<e.length;++i){if(null!=s){if(s[o]===i&&1!==e[i])throw new Error(`Can't squeeze axis ${i} since its dim '${e[i]}' is not 1`);(null==s[o]||s[o]>i)&&1===e[i]&&(n.push(e[i]),r.push(i)),s[o]<=i&&o++}1!==e[i]&&(n.push(e[i]),r.push(i))}return{newShape:n,keptDims:r}}function x(e,t){return v(e,t)}function v(e,t){let n=null;if(null==e||"float32"===e)n=new Float32Array(t);else if("int32"===e)n=new Int32Array(t);else if("bool"===e)n=new Uint8Array(t);else{if("string"!==e)throw new Error(`Unknown data type ${e}`);n=new Array(t)}return n}function w(e,t){return"complex64"!==t&&(("float32"!==t||"complex64"===e)&&(("int32"!==t||"float32"===e||"complex64"===e)&&("bool"!==t||"bool"!==e)))}function k(e){if("float32"===e||"int32"===e)return 4;if("complex64"===e)return 8;if("bool"===e)return 1;throw new Error(`Unknown dtype ${e}`)}function I(e){return"string"===typeof e||e instanceof String}function N(e){return Array.isArray(e)?N(e[0]):e instanceof Float32Array?"float32":e instanceof Int32Array||e instanceof Uint8Array||e instanceof Uint8ClampedArray?"int32":"number"===typeof e?"float32":I(e)?"string":function(e){return"boolean"===typeof e}(e)?"bool":"float32"}function S(e){return!!(e&&e.constructor&&e.call&&e.apply)}function T(e,t){for(let n=t;n<e;++n)if(e%n===0)return nLine truncated
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-danmuku-mask.js v1.1.0
|
||||
* artplayer-plugin-danmuku-mask.js v2.0.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.artplayerPluginDanmukuMask=t(),define(function(){return t.artplayerPluginDanmukuMask})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDanmukuMask=t()}(this,function(){"use strict";var e=(e,t,n)=>new Promise((r,a)=>{var s=e=>{try{i(n.next(e))}catch(t){a(t)}},o=e=>{try{i(n.throw(e))}catch(t){a(t)}},i=e=>e.done?r(e.value):Promise.resolve(e.value).then(s,o);i((n=n.apply(e,t)).next())});function t(e,t){for(var n=0;n<t.length;n++){const r=t[n];if("string"!==typeof r&&!Array.isArray(r))for(const t in r)if("default"!==t&&!(t in e)){const n=Object.getOwnPropertyDescriptor(r,t);n&&Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>r[t]})}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}class n{constructor(e,t){this.backend=e,this.dataMover=t,this.data=new WeakMap,this.dataIdsCount=0}get(e){return this.data.has(e)||this.dataMover.moveData(this.backend,e),this.data.get(e)}set(e,t){this.dataIdsCount++,this.data.set(e,t)}has(e){return this.data.has(e)}delete(e){return this.dataIdsCount--,this.data.delete(e)}numDataIds(){return this.dataIdsCount}}class r{refCount(e){return a("refCount")}incRef(e){return a("incRef")}timerAvailable(){return!0}time(e){return a("time")}read(e){return a("read")}readSync(e){return a("readSync")}readToGPU(e,t){return a("readToGPU")}numDataIds(){return a("numDataIds")}disposeData(e,t){return a("disposeData")}write(e,t,n){return a("write")}move(e,t,n,r,s){return a("move")}createTensorFromGPUData(e,t,n){return a("createTensorFromGPUData")}memory(){return a("memory")}floatPrecision(){return a("floatPrecision")}epsilon(){return 32===this.floatPrecision()?1e-7:1e-4}dispose(){return a("dispose")}}function a(e){throw new Error(`'${e}' not yet implemented or not found in the registry. This kernel may not be supported by the tfjs backend you have chosen`)}function s(e,t,n){return Math.max(e,Math.min(t,n))}function o(e){return e%2===0?e:e+1}function i(e,t,n){const r=e[t];e[t]=e[n],e[n]=r}function u(e,t){if(!e)throw new Error("string"===typeof t?t:t())}function l(e,t,n=""){u(p(e,t),()=>n+` Shapes ${e} and ${t} must match`)}function c(e){u(null!=e,()=>"The input to the tensor constructor must be a non-null value.")}function d(e){if(0===e.length)return 1;let t=e[0];for(let n=1;n<e.length;n++)t*=e[n];return t}function p(e,t){if(e===t)return!0;if(null==e||null==t)return!1;if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(e[n]!==t[n])return!1;return!0}function h(e){return e%1===0}function f(e){const t=Math.ceil(Math.sqrt(e));return[t,Math.ceil(e/t)]}function m(e,t){return t<=e.length?e:e+" ".repeat(t-e.length)}function g(e,t=e=>0,n,r){return new Promise((a,s)=>{let o=0;const i=()=>{if(e())return void a();o++;const u=t(o);null!=n&&o>=n?s():null!=r?r(i,u):setTimeout(i,u)};i()})}function y(e,t){let n=1,r=-1;for(let s=0;s<e.length;++s)if(e[s]>=0)n*=e[s];else if(-1===e[s]){if(-1!==r)throw Error(`Shapes can only have 1 implicit size. Found -1 at dim ${r} and dim ${s}`);r=s}else if(e[s]<0)throw Error(`Shapes can not be < 0. Found ${e[s]} at dim ${s}`);if(-1===r){if(t>0&&t!==n)throw Error(`Size(${t}) must match the product of shape ${e}`);return e}if(0===n)throw Error(`Cannot infer the missing size in [${e}] when there are 0 elements`);if(t%n!==0)throw Error(`The implicit shape can't be a fractional number. Got ${t} / ${n}`);const a=e.slice();return a[r]=t/n,a}function b(e,t){const n=t.length;return u((e=null==e?t.map((e,t)=>t):[].concat(e)).every(e=>e>=-n&&e<n),()=>`All values in axis param must be in range [-${n}, ${n}) but got axis ${e}`),u(e.every(e=>h(e)),()=>`All values in axis param must be integers but got axis ${e}`),e.map(e=>e<0?n+e:e)}function x(e,t){const n=[],r=[],a=null!=t&&Array.isArray(t)&&0===t.length,s=null==t||a?null:b(t,e).sort();let o=0;for(let i=0;i<e.length;++i){if(null!=s){if(s[o]===i&&1!==e[i])throw new Error(`Can't squeeze axis ${i} since its dim '${e[i]}' is not 1`);(null==s[o]||s[o]>i)&&1===e[i]&&(n.push(e[i]),r.push(i)),s[o]<=i&&o++}1!==e[i]&&(n.push(e[i]),r.push(i))}return{newShape:n,keptDims:r}}function v(e,t){return w(e,t)}function w(e,t){let n=null;if(null==e||"float32"===e)n=new Float32Array(t);else if("int32"===e)n=new Int32Array(t);else if("bool"===e)n=new Uint8Array(t);else{if("string"!==e)throw new Error(`Unknown data type ${e}`);n=new Array(t)}return n}function k(e,t){return"complex64"!==t&&(("float32"!==t||"complex64"===e)&&(("int32"!==t||"float32"===e||"complex64"===e)&&("bool"!==t||"bool"!==e)))}function I(e){if("float32"===e||"int32"===e)return 4;if("complex64"===e)return 8;if("bool"===e)return 1;throw new Error(`Unknown dtype ${e}`)}function N(e){return"string"===typeof e||e instanceof String}function S(e){return Array.isArray(e)?S(e[0]):e instanceof Float32Array?"float32":e instanceof Int32Array||e instanceof Uint8Array||e instanceof Uint8ClampedArray?"int32":"number"===tLine truncated
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginDanmukuMask=t(),define(function(){return e.artplayerPluginDanmukuMask})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDanmukuMask=t()}(this,function(){"use strict";var e=(e,t,n)=>new Promise((r,a)=>{var s=e=>{try{i(n.next(e))}catch(t){a(t)}},o=e=>{try{i(n.throw(e))}catch(t){a(t)}},i=e=>e.done?r(e.value):Promise.resolve(e.value).then(s,o);i((n=n.apply(e,t)).next())});function t(e,t){for(var n=0;n<t.length;n++){const r=t[n];if("string"!==typeof r&&!Array.isArray(r))for(const t in r)if("default"!==t&&!(t in e)){const n=Object.getOwnPropertyDescriptor(r,t);n&&Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>r[t]})}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}class n{constructor(e,t){this.backend=e,this.dataMover=t,this.data=new WeakMap,this.dataIdsCount=0}get(e){return this.data.has(e)||this.dataMover.moveData(this.backend,e),this.data.get(e)}set(e,t){this.dataIdsCount++,this.data.set(e,t)}has(e){return this.data.has(e)}delete(e){return this.dataIdsCount--,this.data.delete(e)}numDataIds(){return this.dataIdsCount}}class r{refCount(e){return a("refCount")}incRef(e){return a("incRef")}timerAvailable(){return!0}time(e){return a("time")}read(e){return a("read")}readSync(e){return a("readSync")}readToGPU(e,t){return a("readToGPU")}numDataIds(){return a("numDataIds")}disposeData(e,t){return a("disposeData")}write(e,t,n){return a("write")}move(e,t,n,r,s){return a("move")}createTensorFromGPUData(e,t,n){return a("createTensorFromGPUData")}memory(){return a("memory")}floatPrecision(){return a("floatPrecision")}epsilon(){return 32===this.floatPrecision()?1e-7:1e-4}dispose(){return a("dispose")}}function a(e){throw new Error(`'${e}' not yet implemented or not found in the registry. This kernel may not be supported by the tfjs backend you have chosen`)}function s(e,t,n){return Math.max(e,Math.min(t,n))}function o(e){return e%2===0?e:e+1}function i(e,t,n){const r=e[t];e[t]=e[n],e[n]=r}function u(e,t){if(!e)throw new Error("string"===typeof t?t:t())}function l(e,t,n=""){u(p(e,t),()=>n+` Shapes ${e} and ${t} must match`)}function c(e){u(null!=e,()=>"The input to the tensor constructor must be a non-null value.")}function d(e){if(0===e.length)return 1;let t=e[0];for(let n=1;n<e.length;n++)t*=e[n];return t}function p(e,t){if(e===t)return!0;if(null==e||null==t)return!1;if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(e[n]!==t[n])return!1;return!0}function h(e){return e%1===0}function f(e){const t=Math.ceil(Math.sqrt(e));return[t,Math.ceil(e/t)]}function m(e,t){return t<=e.length?e:e+" ".repeat(t-e.length)}function g(e,t=e=>0,n,r){return new Promise((a,s)=>{let o=0;const i=()=>{if(e())return void a();o++;const u=t(o);null!=n&&o>=n?s():null!=r?r(i,u):setTimeout(i,u)};i()})}function y(e,t){let n=1,r=-1;for(let s=0;s<e.length;++s)if(e[s]>=0)n*=e[s];else if(-1===e[s]){if(-1!==r)throw Error(`Shapes can only have 1 implicit size. Found -1 at dim ${r} and dim ${s}`);r=s}else if(e[s]<0)throw Error(`Shapes can not be < 0. Found ${e[s]} at dim ${s}`);if(-1===r){if(t>0&&t!==n)throw Error(`Size(${t}) must match the product of shape ${e}`);return e}if(0===n)throw Error(`Cannot infer the missing size in [${e}] when there are 0 elements`);if(t%n!==0)throw Error(`The implicit shape can't be a fractional number. Got ${t} / ${n}`);const a=e.slice();return a[r]=t/n,a}function b(e,t){const n=t.length;return u((e=null==e?t.map((e,t)=>t):[].concat(e)).every(e=>e>=-n&&e<n),()=>`All values in axis param must be in range [-${n}, ${n}) but got axis ${e}`),u(e.every(e=>h(e)),()=>`All values in axis param must be integers but got axis ${e}`),e.map(e=>e<0?n+e:e)}function x(e,t){const n=[],r=[],a=null!=t&&Array.isArray(t)&&0===t.length,s=null==t||a?null:b(t,e).sort();let o=0;for(let i=0;i<e.length;++i){if(null!=s){if(s[o]===i&&1!==e[i])throw new Error(`Can't squeeze axis ${i} since its dim '${e[i]}' is not 1`);(null==s[o]||s[o]>i)&&1===e[i]&&(n.push(e[i]),r.push(i)),s[o]<=i&&o++}1!==e[i]&&(n.push(e[i]),r.push(i))}return{newShape:n,keptDims:r}}function v(e,t){return w(e,t)}function w(e,t){let n=null;if(null==e||"float32"===e)n=new Float32Array(t);else if("int32"===e)n=new Int32Array(t);else if("bool"===e)n=new Uint8Array(t);else{if("string"!==e)throw new Error(`Unknown data type ${e}`);n=new Array(t)}return n}function k(e,t){return"complex64"!==t&&(("float32"!==t||"complex64"===e)&&(("int32"!==t||"float32"===e||"complex64"===e)&&("bool"!==t||"bool"!==e)))}function I(e){if("float32"===e||"int32"===e)return 4;if("complex64"===e)return 8;if("bool"===e)return 1;throw new Error(`Unknown dtype ${e}`)}function N(e){return"string"===typeof e||e instanceof String}function S(e){return Array.isArray(e)?S(e[0]):e instanceof Float32Array?"float32":e instanceof Int32Array||e instanceof Uint8Array||e instanceof Uint8ClampedArray?"int32":"number"===tLine truncated
|
||||
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* artplayer-plugin-danmuku-mask.js v1.1.0
|
||||
* artplayer-plugin-danmuku-mask.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
@@ -23,6 +23,20 @@ function _mergeNamespaces(n, m) {
|
||||
}
|
||||
return Object.freeze(Object.defineProperty(n, Symbol.toStringTag, { value: "Module" }));
|
||||
}
|
||||
function maskConfig(option) {
|
||||
return {
|
||||
solutionPath: option.solutionPath || "https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation",
|
||||
modelSelection: option.modelSelection || 1,
|
||||
smoothSegmentation: option.smoothSegmentation !== void 0 ? option.smoothSegmentation : true,
|
||||
minDetectionConfidence: option.minDetectionConfidence || 0.5,
|
||||
minTrackingConfidence: option.minTrackingConfidence || 0.5,
|
||||
selfieMode: option.selfieMode || false,
|
||||
drawContour: option.drawContour || false,
|
||||
foregroundThreshold: option.foregroundThreshold || 0.5,
|
||||
opacity: option.opacity || 1,
|
||||
maskBlurAmount: option.maskBlurAmount || 3
|
||||
};
|
||||
}
|
||||
const EPSILON_FLOAT32$1 = 1e-7;
|
||||
const EPSILON_FLOAT16$1 = 1e-4;
|
||||
class DataStorage {
|
||||
@@ -49040,129 +49054,278 @@ const kernelConfigs = [
|
||||
for (const kernelConfig of kernelConfigs) {
|
||||
registerKernel(kernelConfig);
|
||||
}
|
||||
function artplayerPluginDanmukuMask(option = {}) {
|
||||
return (art) => {
|
||||
const {
|
||||
template: { $video, $danmuku }
|
||||
} = art;
|
||||
let segmenter = null;
|
||||
let canvas = null;
|
||||
let ctx = null;
|
||||
let animationFrameId = null;
|
||||
let isInitialized = false;
|
||||
const config = {
|
||||
solutionPath: option.solutionPath || "https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation",
|
||||
modelSelection: option.modelSelection || 1,
|
||||
smoothSegmentation: option.smoothSegmentation !== void 0 ? option.smoothSegmentation : true,
|
||||
minDetectionConfidence: option.minDetectionConfidence || 0.5,
|
||||
minTrackingConfidence: option.minTrackingConfidence || 0.5,
|
||||
selfieMode: option.selfieMode || false,
|
||||
drawContour: option.drawContour || false,
|
||||
foregroundThreshold: option.foregroundThreshold || 0.5,
|
||||
opacity: option.opacity || 1,
|
||||
maskBlurAmount: option.maskBlurAmount || 3
|
||||
async function loadSegmenter(config, active) {
|
||||
try {
|
||||
await setBackend("webgl");
|
||||
} catch (error) {
|
||||
if (!active())
|
||||
return null;
|
||||
console.warn("WebGL backend not available, falling back to CPU", error.message);
|
||||
await setBackend("cpu");
|
||||
}
|
||||
if (!active())
|
||||
return null;
|
||||
try {
|
||||
return await ke(Se.MediaPipeSelfieSegmentation, {
|
||||
runtime: "mediapipe",
|
||||
modelType: "general",
|
||||
solutionPath: config.solutionPath,
|
||||
modelSelection: config.modelSelection,
|
||||
smoothSegmentation: config.smoothSegmentation,
|
||||
minDetectionConfidence: config.minDetectionConfidence,
|
||||
minTrackingConfidence: config.minTrackingConfidence,
|
||||
selfieMode: config.selfieMode
|
||||
});
|
||||
} catch (error) {
|
||||
if (active())
|
||||
console.error("Error initializing segmenter:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
async function releaseSegmenter(segmenter) {
|
||||
try {
|
||||
await segmenter.dispose();
|
||||
} catch (error) {
|
||||
console.warn("Failed to dispose danmuku mask segmenter:", error);
|
||||
}
|
||||
}
|
||||
const toBinaryMask = (...args) => Ue(...args);
|
||||
const drawMask = (...args) => Ne(...args);
|
||||
function makeWhiteTransparent(imageData) {
|
||||
const data = imageData.data;
|
||||
for (let i = 0; i < data.length; i += 4) {
|
||||
if (data[i] > 250 && data[i + 1] > 250 && data[i + 2] > 250)
|
||||
data[i + 3] = 0;
|
||||
}
|
||||
return imageData;
|
||||
}
|
||||
function createOutput(layer) {
|
||||
const canvas = document.createElement("canvas");
|
||||
try {
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx)
|
||||
throw new Error("Danmuku mask requires a 2D canvas context");
|
||||
Object.assign(layer.style, {
|
||||
maskMode: "alpha",
|
||||
maskSize: "contain",
|
||||
maskRepeat: "no-repeat",
|
||||
backgroundSize: "contain",
|
||||
backgroundRepeat: "no-repeat"
|
||||
});
|
||||
return { canvas, ctx };
|
||||
} catch (error) {
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async function renderMask(output, video, layer, segmenter, config, active) {
|
||||
const { canvas, ctx } = output;
|
||||
canvas.width = video.videoWidth;
|
||||
canvas.height = video.videoHeight;
|
||||
const segmentation = await segmenter.segmentPeople(video);
|
||||
if (!active() || !segmentation || !segmentation.length)
|
||||
return;
|
||||
const mask = await toBinaryMask(
|
||||
segmentation,
|
||||
{ r: 255, g: 255, b: 255, a: 255 },
|
||||
{ r: 0, g: 0, b: 0, a: 255 },
|
||||
config.drawContour,
|
||||
config.foregroundThreshold
|
||||
);
|
||||
if (!active())
|
||||
return;
|
||||
await drawMask(canvas, video, mask, config.opacity, config.maskBlurAmount);
|
||||
if (!active())
|
||||
return;
|
||||
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
ctx.putImageData(makeWhiteTransparent(imageData), 0, 0);
|
||||
const url = canvas.toDataURL();
|
||||
if (active())
|
||||
layer.style.maskImage = `url(${url})`;
|
||||
}
|
||||
function releaseOutput(output) {
|
||||
if (output) {
|
||||
output.canvas.width = 0;
|
||||
output.canvas.height = 0;
|
||||
}
|
||||
}
|
||||
class MaskController {
|
||||
constructor(art, config, { $video, $danmuku }) {
|
||||
this.art = art;
|
||||
this.config = config;
|
||||
this.video = $video;
|
||||
this.layer = $danmuku;
|
||||
this.closed = art.isDestroy;
|
||||
this.run = null;
|
||||
this.tail = Promise.resolve();
|
||||
this.start = this.start.bind(this);
|
||||
this.stop = this.stop.bind(this);
|
||||
this.destroy = this.destroy.bind(this);
|
||||
this.ready = () => {
|
||||
this.start().catch((error) => console.error("Failed to start danmuku mask:", error));
|
||||
};
|
||||
async function initTensorFlow() {
|
||||
if (!this.closed) {
|
||||
try {
|
||||
await setBackend("webgl");
|
||||
art.on("destroy", this.destroy);
|
||||
if (!this.closed)
|
||||
art.on("ready", this.ready);
|
||||
} catch (error) {
|
||||
console.warn("WebGL backend not available, falling back to CPU", error.message);
|
||||
await setBackend("cpu");
|
||||
}
|
||||
}
|
||||
async function initSegmenter() {
|
||||
await initTensorFlow();
|
||||
const model = Se.MediaPipeSelfieSegmentation;
|
||||
const segmenterConfig = {
|
||||
runtime: "mediapipe",
|
||||
modelType: "general",
|
||||
solutionPath: config.solutionPath,
|
||||
modelSelection: config.modelSelection,
|
||||
smoothSegmentation: config.smoothSegmentation,
|
||||
minDetectionConfidence: config.minDetectionConfidence,
|
||||
minTrackingConfidence: config.minTrackingConfidence,
|
||||
selfieMode: config.selfieMode
|
||||
};
|
||||
try {
|
||||
segmenter = await ke(model, segmenterConfig);
|
||||
isInitialized = true;
|
||||
} catch (error) {
|
||||
console.error("Error initializing segmenter:", error);
|
||||
isInitialized = false;
|
||||
}
|
||||
}
|
||||
function setupDanmukuStyle() {
|
||||
Object.assign($danmuku.style, {
|
||||
maskMode: "alpha",
|
||||
maskSize: "contain",
|
||||
maskRepeat: "no-repeat",
|
||||
backgroundSize: "contain",
|
||||
backgroundRepeat: "no-repeat"
|
||||
});
|
||||
}
|
||||
function createCanvas2() {
|
||||
canvas = document.createElement("canvas");
|
||||
ctx = canvas.getContext("2d");
|
||||
}
|
||||
function makeWhiteTransparent(imageData) {
|
||||
const data = imageData.data;
|
||||
for (let i = 0; i < data.length; i += 4) {
|
||||
if (data[i] > 250 && data[i + 1] > 250 && data[i + 2] > 250) {
|
||||
data[i + 3] = 0;
|
||||
this.closed = true;
|
||||
this.halt();
|
||||
try {
|
||||
art.off("ready", this.ready);
|
||||
} catch {
|
||||
}
|
||||
try {
|
||||
art.off("destroy", this.destroy);
|
||||
} catch {
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
return imageData;
|
||||
}
|
||||
async function segmentBody() {
|
||||
if (!isInitialized || $video.paused || $video.ended) {
|
||||
animationFrameId = requestAnimationFrame(segmentBody);
|
||||
return;
|
||||
}
|
||||
}
|
||||
active(run) {
|
||||
return run === this.run && run.running && !this.closed && !this.art.isDestroy;
|
||||
}
|
||||
release(run) {
|
||||
if (run.releasing)
|
||||
return run.releasing;
|
||||
const segmenter = run.segmenter;
|
||||
run.segmenter = null;
|
||||
const output = run.output;
|
||||
run.output = null;
|
||||
run.releasing = (async () => {
|
||||
await Promise.resolve();
|
||||
try {
|
||||
canvas.width = $video.videoWidth;
|
||||
canvas.height = $video.videoHeight;
|
||||
const segmentation = await segmenter.segmentPeople($video);
|
||||
if (!segmentation || segmentation.length === 0) {
|
||||
animationFrameId = requestAnimationFrame(segmentBody);
|
||||
releaseOutput(output);
|
||||
} finally {
|
||||
if (segmenter)
|
||||
await releaseSegmenter(segmenter);
|
||||
}
|
||||
})();
|
||||
return run.releasing;
|
||||
}
|
||||
schedule(run) {
|
||||
if (!this.active(run) || run.frame !== null || run.busy)
|
||||
return;
|
||||
run.frame = requestAnimationFrame(() => {
|
||||
run.frame = null;
|
||||
this.tick(run);
|
||||
});
|
||||
}
|
||||
tick(run) {
|
||||
if (!this.active(run) || run.busy)
|
||||
return;
|
||||
const video = this.video;
|
||||
if (video.paused || video.ended || !(video.videoWidth > 0 && video.videoHeight > 0)) {
|
||||
this.schedule(run);
|
||||
return;
|
||||
}
|
||||
run.busy = true;
|
||||
const work = (async () => {
|
||||
try {
|
||||
await Promise.resolve();
|
||||
if (this.active(run))
|
||||
await renderMask(run.output, video, this.layer, run.segmenter, this.config, () => this.active(run));
|
||||
} catch (error) {
|
||||
if (this.active(run))
|
||||
console.error("Error in segmentBody:", error);
|
||||
} finally {
|
||||
run.busy = false;
|
||||
if (!this.active(run))
|
||||
await this.release(run);
|
||||
else this.schedule(run);
|
||||
}
|
||||
})();
|
||||
this.tail = work.catch((error) => console.warn("Failed to release danmuku mask resources:", error));
|
||||
}
|
||||
async start() {
|
||||
if (this.closed || this.art.isDestroy)
|
||||
return;
|
||||
if (this.run?.running)
|
||||
return this.run.started;
|
||||
let cancel;
|
||||
const cancelled = new Promise((resolve) => cancel = resolve);
|
||||
const run = { running: true, initializing: true, busy: false, frame: null, segmenter: null, output: null, cancel, started: null };
|
||||
const previous = this.tail;
|
||||
this.run = run;
|
||||
const initialize = (async () => {
|
||||
try {
|
||||
await previous;
|
||||
if (!this.active(run))
|
||||
return;
|
||||
if (!this.video || !this.layer?.style)
|
||||
throw new Error("Danmuku mask requires core video and danmuku template nodes");
|
||||
run.segmenter = await loadSegmenter(this.config, () => this.active(run));
|
||||
if (!this.active(run))
|
||||
return;
|
||||
if (!run.segmenter) {
|
||||
run.running = false;
|
||||
return;
|
||||
}
|
||||
const foregroundColor = { r: 255, g: 255, b: 255, a: 255 };
|
||||
const backgroundColor = { r: 0, g: 0, b: 0, a: 255 };
|
||||
const mask = await Ue(
|
||||
segmentation,
|
||||
foregroundColor,
|
||||
backgroundColor,
|
||||
config.drawContour,
|
||||
config.foregroundThreshold
|
||||
);
|
||||
await Ne(canvas, $video, mask, config.opacity, config.maskBlurAmount);
|
||||
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
ctx.putImageData(makeWhiteTransparent(imageData), 0, 0);
|
||||
$danmuku.style.maskImage = `url(${canvas.toDataURL()})`;
|
||||
run.output = createOutput(this.layer);
|
||||
} catch (error) {
|
||||
console.error("Error in segmentBody:", error);
|
||||
if (this.active(run)) {
|
||||
run.running = false;
|
||||
throw error;
|
||||
}
|
||||
} finally {
|
||||
run.initializing = false;
|
||||
if (!this.active(run))
|
||||
await this.release(run);
|
||||
}
|
||||
animationFrameId = requestAnimationFrame(segmentBody);
|
||||
if (this.active(run))
|
||||
this.tick(run);
|
||||
})();
|
||||
this.tail = initialize.catch(() => {
|
||||
});
|
||||
run.started = Promise.race([initialize, cancelled]);
|
||||
return run.started;
|
||||
}
|
||||
halt() {
|
||||
const run = this.run;
|
||||
if (run) {
|
||||
run.running = false;
|
||||
run.cancel();
|
||||
if (run.frame !== null) {
|
||||
cancelAnimationFrame(run.frame);
|
||||
run.frame = null;
|
||||
}
|
||||
if (!run.initializing && !run.busy)
|
||||
this.tail = this.release(run).catch((error) => console.warn("Failed to release danmuku mask resources:", error));
|
||||
}
|
||||
}
|
||||
stop() {
|
||||
this.halt();
|
||||
if (this.layer?.style)
|
||||
this.layer.style.maskImage = "none";
|
||||
}
|
||||
destroy() {
|
||||
if (this.closed)
|
||||
return;
|
||||
this.closed = true;
|
||||
try {
|
||||
this.stop();
|
||||
} finally {
|
||||
try {
|
||||
this.art.off("ready", this.ready);
|
||||
} finally {
|
||||
this.art.off("destroy", this.destroy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function artplayerPluginDanmukuMask(option = {}) {
|
||||
return (art) => {
|
||||
const { template: { $video, $danmuku } } = art;
|
||||
const controller = new MaskController(art, maskConfig(option), { $video, $danmuku });
|
||||
async function startSegmentation() {
|
||||
if (!isInitialized) {
|
||||
await initSegmenter();
|
||||
}
|
||||
if (!canvas) {
|
||||
createCanvas2();
|
||||
}
|
||||
setupDanmukuStyle();
|
||||
segmentBody();
|
||||
await controller.start();
|
||||
}
|
||||
function stopSegmentation() {
|
||||
$danmuku.style.maskImage = "none";
|
||||
if (animationFrameId) {
|
||||
cancelAnimationFrame(animationFrameId);
|
||||
animationFrameId = null;
|
||||
}
|
||||
controller.stop();
|
||||
}
|
||||
art.on("ready", startSegmentation);
|
||||
art.on("destroy", stopSegmentation);
|
||||
return {
|
||||
name: "artplayerPluginDanmukuMask",
|
||||
start: startSegmentation,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-danmuku.js v5.3.0
|
||||
* artplayer-plugin-danmuku.js v6.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDanmuku=e(),define(function(){return t.artplayerPluginDanmuku})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDanmuku=e()}(this,function(){"use strict";function t(t){switch(t){case 1:case 2:case 3:default:return 0;case 4:return 2;case 5:return 1}}function e(e){if("string"!==typeof e)return[];const i=e.matchAll(/<d[^>]*?p="(?<p>[^"]+)"[^>]*>(?<text>.*?)<\/d>/gs);return Array.from(i).map(e=>{const i=e.groups.p.split(",");if(i.length>=8){return{text:e.groups.text.trim().replaceAll(""",'"').replaceAll("'","'").replaceAll("<","<").replaceAll(">",">").replaceAll("&","&"),time:Number(i[0]),mode:t(Number(i[1])),fontSize:Number(i[2]),color:`#${Number(i[3]).toString(16)}`,timestamp:Number(i[4]),pool:Number(i[5]),userID:i[6],rowID:Number(i[7])}}return null}).filter(Boolean)}function i({data:t}){const{xml:i,id:a}=t;if(!a||!i)return;const n=e(i);globalThis.postMessage({danmus:n,id:a})}function a(){const a=`\n ${t.toString()}\n ${e.toString()}\n onmessage = ${i.toString()}\n `,n=new Blob([a],{type:"application/javascript"});return new Worker(URL.createObjectURL(n))}const n='/*!\n * artplayer-plugin-danmuku.js v5.3.0\n * Github: https://github.com/zhw2590582/ArtPlayer\n * (c) 2017-2026 Harvey Zhao\n * Released under the MIT License.\n */\nfunction t({target:t,visibles:e,clientWidth:i,clientHeight:h,marginBottom:n,marginTop:o,antiOverlap:s}){const r=h-n,p=e.filter(e=>e.mode===t.mode&&e.top<=r).sort((t,e)=>t.top-e.top);if(0===p.length)return 2===t.mode?r-t.height:o;if(p.unshift({type:"top",top:0,left:0,right:0,height:o,width:i,speed:0,distance:i}),p.push({type:"bottom",top:r,left:0,right:0,height:n,width:i,speed:0,distance:i}),2===t.mode)for(let g=p.length-2;g>=0;g-=1){const e=p[g],i=p[g+1],h=e.top+e.height;if(i.top-h>=t.height)return i.top-t.height}else for(let g=1;g<p.length;g+=1){const e=p[g],i=p[g-1],h=i.top+i.height;if(e.top-h>=t.height)return h}const a=[];for(let g=1;g<p.length-1;g+=1){const t=p[g];if(a.length){const e=a[a.length-1];e[0].top===t.top?e.push(t):a.push([t])}else a.push([t])}if(!s){switch(t.mode){case 0:a.sort((t,e)=>{const i=Math.min(...e.map(t=>t.right)),h=Math.min(...t.map(t=>t.right));return i*e.length-h*t.length});break;case 1:case 2:a.sort((t,e)=>{const i=Math.max(...e.map(t=>t.width));return Math.max(...t.map(t=>t.width))*t.length-i*e.length})}return a[0][0].top}switch(t.mode){case 0:{const e=a.find(e=>e.every(e=>{if(i<e.distance)return!1;if(t.speed<e.speed)return!0;return e.right/(t.speed-e.speed)>e.time}));return e&&e[0]?e[0].top:void 0}case 1:case 2:return}}onmessage=e=>{const{data:i}=e;if(!i.id||!i.type)return;const h=(0,{getDanmuTop:t}[i.type])(i);globalThis.postMessage({result:h,id:i.id})};\n',s="undefined"!==typeof self&&self.Blob&&new Blob(["URL.revokeObjectURL(import.meta.url);",n],{type:"text/javascript;charset=utf-8"});function o(t){let e;try{if(e=s&&(self.URL||self.webkitURL).createObjectURL(s),!e)throw"";const i=new Worker(e,{type:"module",name:t?.name});return i.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(e)}),i}catch(i){return new Worker("data:text/javascript;charset=utf-8,"+encodeURIComponent(n),{type:"module",name:t?.name})}}class r{constructor(t,e){const{constructor:i,template:a}=t;this.utils=i.utils,this.validator=i.validator,this.$danmuku=a.$danmuku,this.$player=a.$player,this.art=t,this.queue=[],this.$refs=[],this.isStop=!1,this.isHide=!1,this.timer=null,this.index=0,this.option=r.option,this.states={wait:[],ready:[],emit:[],stop:[]},this.config(e,!0),this.worker=new o,this.start=this.start.bind(this),this.stop=this.stop.bind(this),this.reset=this.reset.bind(this),this.resize=this.resize.bind(this),this.destroy=this.destroy.bind(this),t.on("video:play",this.start),t.on("video:playing",this.start),t.on("video:pause",this.stop),t.on("video:waiting",this.stop),t.on("destroy",this.destroy),t.on("resize",this.resize),this.load()}static get option(){return{danmuku:[],speed:5,margin:[10,"25%"],opacity:1,color:"#FFFFFF",mode:0,modes:[0,1,2],fontSize:25,antiOverlap:!0,synchronousPlayback:!1,mount:void 0,heatmap:!1,width:512,points:[],filter:()=>!0,beforeEmit:()=>!0,beforeVisible:()=>!0,visible:!0,emitter:!0,maxLength:200,lockTime:5,theme:"dark",OPACITY:{},FONT_SIZE:{},MARGIN:{},SPEED:{},COLOR:[]}}static get scheme(){return{danmuku:"array|function|string",speed:"number",margin:"array",opacity:"number",color:"string",mode:"number",modes:"array",fontSize:"number|string",antiOverlap:"boolean",synchronousPlayback:"boolean",mount:"?htmldivelement|string",heatmap:"object|boolean",width:"number",points:"array",filter:"function",beforeEmit:"function",beforeVisible:"function",visible:"boolean",emitter:"boolean",maxLength:"number",lockTime:"number",theme:"string",OPACITY:"object",FONT_SIZE:"object",MARGIN:"object",SPEED:"object",COLOR:"array"}}static get cssLine truncated
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDanmuku=e(),define(function(){return t.artplayerPluginDanmuku})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDanmuku=e()}(this,function(){"use strict";function t(t){return t instanceof Promise||"[object Promise]"===Object.prototype.toString.call(t)}function e(t){switch(t){case 1:case 2:case 3:default:return 0;case 4:return 2;case 5:return 1}}function i(t){if("string"!==typeof t)return[];const i=t.matchAll(/<d[^>]*?p="(?<p>[^"]+)"[^>]*>(?<text>.*?)<\/d>/gs);return Array.from(i).map(t=>{const i=t.groups.p.split(",");if(i.length>=8){return{text:t.groups.text.trim().replaceAll(""",'"').replaceAll("'","'").replaceAll("<","<").replaceAll(">",">").replaceAll("&","&"),time:Number(i[0]),mode:e(Number(i[1])),fontSize:Number(i[2]),color:`#${Number(i[3]).toString(16)}`,timestamp:Number(i[4]),pool:Number(i[5]),userID:i[6],rowID:Number(i[7])}}return null}).filter(Boolean)}function n({data:t}){const{xml:e,id:n}=t,s=i(e);globalThis.postMessage({danmus:s,id:n})}let s=0;function a(t,{signal:a,onCancel:r}={}){return new Promise((o,l)=>{let d,h,c,p=!1;const u=++s,m=()=>g(void 0,function(t){if(void 0!==t?.reason)return t.reason;const e=new Error("Bilibili Danmu loading cancelled");return e.name="AbortError",e}(a));function f(){let t,e=!1;try{if(d){const t=d;d=void 0,t.onmessage=null,t.onerror=null,t.onmessageerror=null,t.terminate()}}catch(i){t=i,e=!0}if(void 0!==h){const n=h;h=void 0;try{URL.revokeObjectURL(n)}catch(i){e||(t=i),e=!0}}if(e)throw t}function g(t,e){if(p)return;p=!0;let i=arguments.length>1;a?.removeEventListener("abort",m),c?.();try{f()}catch(n){i||(e=n),i=!0}i?l(e):o(t)}function y(t,e){if(!p){console.error("Error parsing Bilibili Danmu:",e);try{g(i(t))}catch(n){g(void 0,n)}}}a?.aborted?m():(a?.addEventListener("abort",m),c=r?.(m),p?c?.():async function(){const s=a?await fetch(t,{signal:a}):await fetch(t);if(p)return;const r=await s.text();if(!p)try{const t=`\n ${e.toString()}\n ${i.toString()}\n onmessage = ${n.toString()}\n `;if(h=URL.createObjectURL(new Blob([t],{type:"application/javascript"})),p)return void f();if(d=new Worker(h),p)return void f();d.onmessage=t=>{if(p||t.data?.id!==u)return;const{danmus:e}=t.data;Array.isArray(e)?g(e):g(void 0,new Error("Invalid Bilibili Danmu worker response"))},d.onerror=t=>{t.preventDefault?.(),y(r,t.error||t)},d.onmessageerror=t=>y(r,t.error||t),d.postMessage({xml:r,id:u})}catch(o){y(r,o)}}().catch(t=>g(void 0,t)))})}const r=new WeakMap,o=Symbol("cancelled danmuku input");function l(t){return r.has(t)||r.set(t,{closed:!1,tasks:new Set,emitting:[]}),r.get(t)}function d(t){const e=l(t),i=e.emitting[e.emitting.length-1];return!e.closed&&!t.art.isDestroy&&(!i||i.active())}function h(t){const e=l(t);e.closed=!0;for(const i of[...e.tasks])i.cancel()}function c(t,e,i){const n=t.states[e]||[];for(let s=0;s<n.length;s++)i(n[s]);return n}class p{constructor(t){this.owner=t,this.nodes=new Set}acquire(){const t=this.owner.$refs.pop()||document.createElement("div");return t.style.cssText=this.owner.constructor.cssText,t.dataset.mode="",t.dataset.id="",t.className="",this.nodes.add(t),t}get visibles(){const t=[],{clientWidth:e}=this.owner.$player,i=this.owner.getLeft(this.owner.$player);return this.owner.filter("emit",n=>{const s=n.$ref.offsetTop,a=this.owner.getLeft(n.$ref)-i,r=n.$ref.clientHeight,o=n.$ref.clientWidth,l=a+o,d=e-l,h=l/n.$restTime,c={};c.top=s,c.left=a,c.height=r,c.width=o,c.right=d,c.speed=h,c.distance=l,c.time=n.$restTime,c.mode=n.mode,t.push(c)}),t}left(t){const e=t.getBoundingClientRect();return this.owner.isRotate?e.top:e.left}makeWait(t){this.owner.setState(t,"wait"),t.$ref&&(t.$ref.style.cssText=this.owner.constructor.cssText,t.$ref.style.visibility="hidden",t.$ref.style.marginLeft="0px",t.$ref.style.transform="translateX(0px)",t.$ref.style.transition="transform 0s linear 0s",this.owner.$refs.push(t.$ref),t.$ref=null)}resize(){const{clientWidth:t}=this.owner.$player;this.owner.filter("stop",e=>{if(0===e.mode)e.$ref.style.left=`${t}px`}),this.owner.filter("emit",e=>{switch(e.$lastStartTime=Date.now(),e.mode){case 0:{const i=t+e.$ref.clientWidth;e.$ref.style.left=`${t}px`,e.$ref.style.transform=`translateX(${-i}px)`,e.$ref.style.transition=`transform ${e.$restTime}s linear 0s`;break}}})}continue(){const{clientWidth:t}=this.owner.$player;return this.owner.filter("stop",e=>{switch(this.owner.setState(e,"emit"),e.$lastStartTime=Date.now(),e.mode){case 0:{const i=t+e.$ref.clientWidth;e.$ref.style.transform=`translateX(${-i}px)`,e.$ref.style.transition=`transform ${e.$restTime}s linear 0s`;break}}}),this}suspend(){const{clientWidth:t}=this.owner.$player;return this.owner.filter("emit",e=>{switch(this.owner.setState(e,"stop"),e.mode){case 0:{const i=t-(this.owner.getLeft(e.$ref)-this.owner.getLeft(this.owner.$player));e.$ref.style.transform=`translLine truncated
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-danmuku.js v5.3.0
|
||||
* artplayer-plugin-danmuku.js v6.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDanmuku=e(),define(function(){return t.artplayerPluginDanmuku})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDanmuku=e()}(this,function(){"use strict";var t=Object.defineProperty,e=Object.defineProperties,i=Object.getOwnPropertyDescriptors,a=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,o=Math.pow,r=(e,i,a)=>i in e?t(e,i,{enumerable:!0,configurable:!0,writable:!0,value:a}):e[i]=a,l=(t,e)=>{for(var i in e||(e={}))n.call(e,i)&&r(t,i,e[i]);if(a)for(var i of a(e))s.call(e,i)&&r(t,i,e[i]);return t},d=(t,a)=>e(t,i(a)),p=(t,e,i)=>new Promise((a,n)=>{var s=t=>{try{r(i.next(t))}catch(e){n(e)}},o=t=>{try{r(i.throw(t))}catch(e){n(e)}},r=t=>t.done?a(t.value):Promise.resolve(t.value).then(s,o);r((i=i.apply(t,e)).next())});function h(t){switch(t){case 1:case 2:case 3:default:return 0;case 4:return 2;case 5:return 1}}function u(t){if("string"!==typeof t)return[];const e=new RegExp('<d[^>]*?p="(?<p>[^"]+)"[^>]*>(?<text>.*?)<\\/d>',"gs"),i=t.matchAll(e);return Array.from(i).map(t=>{const e=t.groups.p.split(",");if(e.length>=8){return{text:t.groups.text.trim().replaceAll(""",'"').replaceAll("'","'").replaceAll("<","<").replaceAll(">",">").replaceAll("&","&"),time:Number(e[0]),mode:h(Number(e[1])),fontSize:Number(e[2]),color:`#${Number(e[3]).toString(16)}`,timestamp:Number(e[4]),pool:Number(e[5]),userID:e[6],rowID:Number(e[7])}}return null}).filter(Boolean)}function c({data:t}){const{xml:e,id:i}=t;if(!i||!e)return;const a=u(e);globalThis.postMessage({danmus:a,id:i})}function m(){const t=`\n ${h.toString()}\n ${u.toString()}\n onmessage = ${c.toString()}\n `,e=new Blob([t],{type:"application/javascript"});return new Worker(URL.createObjectURL(e))}const f='/*!\n * artplayer-plugin-danmuku.js v5.3.0\n * Github: https://github.com/zhw2590582/ArtPlayer\n * (c) 2017-2026 Harvey Zhao\n * Released under the MIT License.\n */\nfunction t({target:t,visibles:e,clientWidth:i,clientHeight:h,marginBottom:n,marginTop:o,antiOverlap:s}){const r=h-n,p=e.filter(e=>e.mode===t.mode&&e.top<=r).sort((t,e)=>t.top-e.top);if(0===p.length)return 2===t.mode?r-t.height:o;if(p.unshift({type:"top",top:0,left:0,right:0,height:o,width:i,speed:0,distance:i}),p.push({type:"bottom",top:r,left:0,right:0,height:n,width:i,speed:0,distance:i}),2===t.mode)for(let g=p.length-2;g>=0;g-=1){const e=p[g],i=p[g+1],h=e.top+e.height;if(i.top-h>=t.height)return i.top-t.height}else for(let g=1;g<p.length;g+=1){const e=p[g],i=p[g-1],h=i.top+i.height;if(e.top-h>=t.height)return h}const a=[];for(let g=1;g<p.length-1;g+=1){const t=p[g];if(a.length){const e=a[a.length-1];e[0].top===t.top?e.push(t):a.push([t])}else a.push([t])}if(!s){switch(t.mode){case 0:a.sort((t,e)=>{const i=Math.min(...e.map(t=>t.right)),h=Math.min(...t.map(t=>t.right));return i*e.length-h*t.length});break;case 1:case 2:a.sort((t,e)=>{const i=Math.max(...e.map(t=>t.width));return Math.max(...t.map(t=>t.width))*t.length-i*e.length})}return a[0][0].top}switch(t.mode){case 0:{const e=a.find(e=>e.every(e=>{if(i<e.distance)return!1;if(t.speed<e.speed)return!0;return e.right/(t.speed-e.speed)>e.time}));return e&&e[0]?e[0].top:void 0}case 1:case 2:return}}onmessage=e=>{const{data:i}=e;if(!i.id||!i.type)return;const h=(0,{getDanmuTop:t}[i.type])(i);globalThis.postMessage({result:h,id:i.id})};\n',g="undefined"!==typeof self&&self.Blob&&new Blob(["URL.revokeObjectURL(import.meta.url);",f],{type:"text/javascript;charset=utf-8"});function y(t){let e;try{if(e=g&&(self.URL||self.webkitURL).createObjectURL(g),!e)throw"";const i=new Worker(e,{type:"module",name:null==t?void 0:t.name});return i.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(e)}),i}catch(i){return new Worker("data:text/javascript;charset=utf-8,"+encodeURIComponent(f),{type:"module",name:null==t?void 0:t.name})}}class v{constructor(t,e){const{constructor:i,template:a}=t;this.utils=i.utils,this.validator=i.validator,this.$danmuku=a.$danmuku,this.$player=a.$player,this.art=t,this.queue=[],this.$refs=[],this.isStop=!1,this.isHide=!1,this.timer=null,this.index=0,this.option=v.option,this.states={wait:[],ready:[],emit:[],stop:[]},this.config(e,!0),this.worker=new y,this.start=this.start.bind(this),this.stop=this.stop.bind(this),this.reset=this.reset.bind(this),this.resize=this.resize.bind(this),this.destroy=this.destroy.bind(this),t.on("video:play",this.start),t.on("video:playing",this.start),t.on("video:pause",this.stop),t.on("video:waiting",this.stop),t.on("destroy",this.destroy),t.on("resize",this.resize),this.load()}static get option(){return{danmuku:[],speed:5,margin:[10,"25%"],opacity:1,color:"#FFFFFF",mode:0,modes:[0,1,2],fontSize:25,antiOverlap:!0,synchronousPlayback:!1,mount:void 0,heatmap:!1,width:512,points:[],filter:()=>!0,beforeEmit:()=>!0,beforeVisible:()=>!0,vLine truncated
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDanmuku=e(),define(function(){return t.artplayerPluginDanmuku})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDanmuku=e()}(this,function(){"use strict";var t=Object.defineProperty,e=Object.defineProperties,i=Object.getOwnPropertyDescriptors,n=Object.getOwnPropertySymbols,s=Object.prototype.hasOwnProperty,a=Object.prototype.propertyIsEnumerable,r=Math.pow,o=(e,i,n)=>i in e?t(e,i,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[i]=n,l=(t,e)=>{for(var i in e||(e={}))s.call(e,i)&&o(t,i,e[i]);if(n)for(var i of n(e))a.call(e,i)&&o(t,i,e[i]);return t},d=(t,n)=>e(t,i(n)),h=(t,e,i)=>new Promise((n,s)=>{var a=t=>{try{o(i.next(t))}catch(e){s(e)}},r=t=>{try{o(i.throw(t))}catch(e){s(e)}},o=t=>t.done?n(t.value):Promise.resolve(t.value).then(a,r);o((i=i.apply(t,e)).next())});function c(t){return t instanceof Promise||"[object Promise]"===Object.prototype.toString.call(t)}function p(t){switch(t){case 1:case 2:case 3:default:return 0;case 4:return 2;case 5:return 1}}function u(t){if("string"!==typeof t)return[];const e=new RegExp('<d[^>]*?p="(?<p>[^"]+)"[^>]*>(?<text>.*?)<\\/d>',"gs"),i=t.matchAll(e);return Array.from(i).map(t=>{const e=t.groups.p.split(",");if(e.length>=8){return{text:t.groups.text.trim().replaceAll(""",'"').replaceAll("'","'").replaceAll("<","<").replaceAll(">",">").replaceAll("&","&"),time:Number(e[0]),mode:p(Number(e[1])),fontSize:Number(e[2]),color:`#${Number(e[3]).toString(16)}`,timestamp:Number(e[4]),pool:Number(e[5]),userID:e[6],rowID:Number(e[7])}}return null}).filter(Boolean)}function m({data:t}){const{xml:e,id:i}=t,n=u(e);globalThis.postMessage({danmus:n,id:i})}let f=0;function g(t,{signal:e,onCancel:i}={}){return new Promise((n,s)=>{let a,r,o,l=!1;const d=++f,c=()=>y(void 0,function(t){if(void 0!==(null==t?void 0:t.reason))return t.reason;const e=new Error("Bilibili Danmu loading cancelled");return e.name="AbortError",e}(e));function g(){let t,e=!1;try{if(a){const t=a;a=void 0,t.onmessage=null,t.onerror=null,t.onmessageerror=null,t.terminate()}}catch(i){t=i,e=!0}if(void 0!==r){const n=r;r=void 0;try{URL.revokeObjectURL(n)}catch(i){e||(t=i),e=!0}}if(e)throw t}function y(t,i){if(l)return;l=!0;let a=arguments.length>1;null==e||e.removeEventListener("abort",c),null==o||o();try{g()}catch(r){a||(i=r),a=!0}a?s(i):n(t)}function v(t,e){if(!l){console.error("Error parsing Bilibili Danmu:",e);try{y(u(t))}catch(i){y(void 0,i)}}}(null==e?void 0:e.aborted)?c():(null==e||e.addEventListener("abort",c),o=null==i?void 0:i(c),l?null==o||o():function(){return h(this,null,function*(){const i=e?yield fetch(t,{signal:e}):yield fetch(t);if(l)return;const n=yield i.text();if(!l)try{const t=`\n ${p.toString()}\n ${u.toString()}\n onmessage = ${m.toString()}\n `;if(r=URL.createObjectURL(new Blob([t],{type:"application/javascript"})),l)return void g();if(a=new Worker(r),l)return void g();a.onmessage=t=>{var e;if(l||(null==(e=t.data)?void 0:e.id)!==d)return;const{danmus:i}=t.data;Array.isArray(i)?y(i):y(void 0,new Error("Invalid Bilibili Danmu worker response"))},a.onerror=t=>{var e;null==(e=t.preventDefault)||e.call(t),v(n,t.error||t)},a.onmessageerror=t=>v(n,t.error||t),a.postMessage({xml:n,id:d})}catch(s){v(n,s)}})}().catch(t=>y(void 0,t)))})}const y=new WeakMap,v=Symbol("cancelled danmuku input");function w(t){return y.has(t)||y.set(t,{closed:!1,tasks:new Set,emitting:[]}),y.get(t)}function k(t){const e=w(t),i=e.emitting[e.emitting.length-1];return!e.closed&&!t.art.isDestroy&&(!i||i.active())}function x(t){const e=w(t);e.closed=!0;for(const i of[...e.tasks])i.cancel()}function b(t,e,i){const n=t.states[e]||[];for(let s=0;s<n.length;s++)i(n[s]);return n}class ${constructor(t){this.owner=t,this.nodes=new Set}acquire(){const t=this.owner.$refs.pop()||document.createElement("div");return t.style.cssText=this.owner.constructor.cssText,t.dataset.mode="",t.dataset.id="",t.className="",this.nodes.add(t),t}get visibles(){const t=[],{clientWidth:e}=this.owner.$player,i=this.owner.getLeft(this.owner.$player);return this.owner.filter("emit",n=>{const s=n.$ref.offsetTop,a=this.owner.getLeft(n.$ref)-i,r=n.$ref.clientHeight,o=n.$ref.clientWidth,l=a+o,d=e-l,h=l/n.$restTime,c={};c.top=s,c.left=a,c.height=r,c.width=o,c.right=d,c.speed=h,c.distance=l,c.time=n.$restTime,c.mode=n.mode,t.push(c)}),t}left(t){const e=t.getBoundingClientRect();return this.owner.isRotate?e.top:e.left}makeWait(t){this.owner.setState(t,"wait"),t.$ref&&(t.$ref.style.cssText=this.owner.constructor.cssText,t.$ref.style.visibility="hidden",t.$ref.style.marginLeft="0px",t.$ref.style.transform="translateX(0px)",t.$ref.style.transition="transform 0s linear 0s",this.owner.$refs.push(t.$ref),t.$ref=null)}resize(){const{clientWidth:t}=this.owner.$player;this.owner.filter("stop",e=>{if(0===e.mode)e.$ref.style.left=`${t}px`}),this.owner.filter("emitLine truncated
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-dash-control.js v1.1.0
|
||||
* artplayer-plugin-dash-control.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDashControl=e(),define(function(){return t.artplayerPluginDashControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDashControl=e()}(this,function(){"use strict";function t(t,e){const o=new Map;return t.filter(t=>{const n=t[e];return void 0===n||!o.has(n)&&o.set(n,1)})}return function(e={}){return o=>{const{$video:n}=o.template,{errorHandle:i}=o.constructor.utils;function a(){i(o.dash.getVideoElement()===n,'Cannot find instance of DASH from "art.dash"'),function(n){const i=n.getBitrateInfoListFor("video");if(!i||!i.length)return;const a=e.quality||{},l=a.auto||"Auto",s=a.title||"Quality",r=a.getName||(t=>`${t.height}p`),c=n.getQualityFor("video"),u=n.getSettings().streaming.abr.autoSwitchBitrate.video,d=u?l:r(i[c]),h=t(i.map(t=>({html:r(t),value:t.qualityIndex,default:c===t.qualityIndex&&!u})),"html").sort((t,e)=>e.value-t.value);h.push({html:l,value:"auto",default:u});const g=t=>("auto"===t.value?n.updateSettings({streaming:{abr:{autoSwitchBitrate:{video:!0}}}}):(n.updateSettings({streaming:{abr:{autoSwitchBitrate:{video:!1}}}}),n.setQualityFor("video",t.value)),o.notice.show=`${s}: ${t.html}`,a.control&&o.controls.check(t),a.setting&&o.setting.check(t),t.html);a.control&&o.controls.update({name:"dash-quality",position:"right",html:d,style:{padding:"0 10px"},selector:h,onSelect:g}),a.setting&&o.setting.update({name:"dash-quality",tooltip:d,html:s,icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>',width:200,selector:h,onSelect:g})}(o.dash),function(n){const i=n.getTracksFor("audio");if(!i||!i.length)return;const a=e.audio||{},l=a.auto||"Auto",s=a.title||"Audio",r=a.getName||(t=>t.lang||t.id),c=n.getCurrentTrackFor("audio")||i[0],u=c?r(c):l,d=t(i.map(t=>({html:r(t),value:t,default:c===t})),"html"),h=t=>(n.setCurrentTrack(t.value),o.notice.show=`${s}: ${t.html}`,a.control&&o.controls.check(t),a.setting&&o.setting.check(t),t.html);a.control&&o.controls.update({name:"dash-audio",position:"right",html:u,style:{padding:"0 10px"},selector:d,onSelect:h}),a.setting&&o.setting.update({name:"dash-audio",tooltip:u,html:s,icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>',width:200,selector:d,onSelect:h})}(o.dash)}return o.on("ready",a),o.on("restart",a),{name:"artplayerPluginDashControl",update:a}}}});
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDashControl=e(),define(function(){return t.artplayerPluginDashControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDashControl=e()}(this,function(){"use strict";function t(t,e=()=>!0){let n,r=!1;for(const i of t){if(!e())break;try{i()}catch(o){r||(r=!0,n=o)}}if(r)throw n}function e(t){const e=new Map;return t.filter(t=>{if(void 0===t.html)return!0;const n=e.get(t.html);return n?(t.default&&Object.assign(n,t),!1):(e.set(t.html,t),!0)})}function n(e,n,r){let o;const i=new Map;function s(t,r=i.get(t)){if(!r||i.get(t)!==r)return;i.delete(t);const o=e[t];"controls"===t&&o.cache?.get&&o.cache.get(n)?.option?.onSelect!==r||"setting"===t&&o.find&&o.find(n)?.onSelect!==r||o.remove(n)}function c(){o=void 0,t([...i].map(([t,e])=>()=>s(t,e)))}return{update:function(t,a,l){if(!a)return void c();const u={};o=u;const f=()=>u===o&&l(),d=n=>f()?(a.select(n,f),f()?(e.notice.show=`${a.title}: ${n.html}`,f()&&t.control&&e.controls.check(n),f()&&t.setting&&e.setting.check(n),n.html):n.html):n.html;t.control?(i.set("controls",d),e.controls.update({name:n,position:"right",html:a.html,style:{padding:"0 10px"},selector:a.selector,onSelect:d})):s("controls"),f()&&(t.setting?(i.set("setting",d),e.setting.update({name:n,tooltip:a.html,html:a.title,icon:r,width:200,selector:a.selector,onSelect:d})):s("setting"))},clear:c,captureNavigation:function(t){const r=e.setting,o=r.find?.(n),s=i.get("setting");if(t()&&s&&!0===r.show&&o?.onSelect===s&&o.selector&&r.active===o.selector&&"function"===typeof r.render)return()=>{if(!t()||e.setting!==r||!0!==r.show||!r.option||r.active!==r.option)return;const o=r.find?.(n),s=i.get("setting");t()&&s&&o?.onSelect===s&&o.selector&&r.render?.(o.selector)}}}}function r(e){let n;const r=t=>n===t&&e.active(t.dash),o=t=>t.dash.getSettings().streaming.abr.autoSwitchBitrate.video;function i(){const e=n;e&&(n=void 0,e.epoch++,t(e.callbacks.splice(0).map(([t,n])=>()=>e.off.call(e.dash,t,n))))}function s(t,r){if(n===t){try{i()}catch(o){console.warn("ArtPlayer DASH subscription cleanup failed:",o)}if(!n&&e.active(t.dash))try{e.reset()}catch(o){console.warn("ArtPlayer DASH cleanup failed:",o)}}console.warn("ArtPlayer DASH refresh failed:",r)}function c(t){if(!r(t)||t.suspended||t.queued||t.running)return;t.queued=!0;const n=t.epoch;Promise.resolve().then(()=>{if(r(t)&&t.epoch===n&&!t.suspended){t.queued=!1,t.running=!0;try{t.automatic=o(t),r(t)&&e.refresh()}catch(i){s(t,i)}finally{t.running=!1}}})}return{bind:function(t){const a=n;if(a?.dash===t){const t=o(a);return void(r(a)&&(a.automatic=t,a.suspended=!1))}if(i(),n||!e.active(t)||"function"!==typeof t.on||"function"!==typeof t.off)return;const l={dash:t,off:t.off,callbacks:[],epoch:0,queued:!1,running:!1,suspended:!1,automatic:!1};n=l;const u=t.on;try{l.automatic=o(l);const n=["qualityChangeRequested","qualityChangeRendered","trackChangeRendered","streamUpdated","streamInitialized"].map(t=>[t,()=>{"streamUpdated"!==t&&"streamInitialized"!==t||(l.suspended=!1),c(l)}]),i=function(t,e){const n=t;try{if("function"!==typeof n.getVersion||"4.5.2"!==n.getVersion())return;if("function"!==typeof n.getVideoElement||"function"!==typeof n.getActiveStream||"function"!==typeof n.getDashMetrics)return}catch{return}let r=!1;return()=>{if(!r&&e()){r=!0;try{const t=n.getVideoElement?.();if(!t?.seeking||!Number.isFinite(t.currentTime))return;const r=t.currentTime,o=n.getActiveStream?.(),i=n.getDashMetrics?.(),s=o?.getProcessors?.();if(!Array.isArray(s)||"function"!==typeof i?.getCurrentBufferLevel||"function"!==typeof i.addBufferLevel)return;for(const c of s){if(!e())return;const s=c.getType?.();if("audio"!==s&&"video"!==s)continue;const a=c.getBufferController?.();if("function"!==typeof a?.getRangeAt||"function"!==typeof a.getIsPruningInProgress||"function"!==typeof a.getAllRangesWithSafetyFactor)continue;const l=i.getCurrentBufferLevel(s),u=a.getRangeAt(r),f=null===u||u&&Number.isFinite(u.end)&&u.end<=r;if(!Number.isFinite(l)||l<=0||!f||!1!==a.getIsPruningInProgress())continue;const d=a.getAllRangesWithSafetyFactor(r);if(Array.isArray(d)&&0===d.length){if(!e()||n.getActiveStream?.()!==o||n.getDashMetrics?.()!==i||n.getVideoElement?.()!==t||t.currentTime!==r||!t.seeking||!e())return;i.addBufferLevel(s,new Date,0)}}}catch(t){console.warn("ArtPlayer DASH seek buffer refresh failed:",t)}finally{r=!1}}}}(t,()=>r(l)&&!l.suspended);i&&n.push(["playbackSeeking",i]),n.push(["playbackTimeUpdated",()=>{if(r(l)&&!l.suspended)try{const t=o(l);r(l)&&t!==l.automatic&&(l.automatic=t,c(l))}catch(t){s(l,t)}}]),n.push(["streamTeardownComplete",()=>{if(r(l)){l.epoch++,l.queued=!1,l.suspended=!0;try{e.reset()}catch(t){s(l,t)}}}]);for(const e of n){if(!r(l))break;l.callbacks.push(e),u.call(t,...e)}}catch(f){if(n===l)try{i()}catch(d){console.warn("ArtPlayer DASH subscription cleanup failed:",d)}throw f}},release:i}}return function(oLine truncated
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-dash-control.js v1.1.0
|
||||
* artplayer-plugin-dash-control.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDashControl=e(),define(function(){return t.artplayerPluginDashControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDashControl=e()}(this,function(){"use strict";function t(t,e){const o=new Map;return t.filter(t=>{const n=t[e];return void 0===n||!o.has(n)&&o.set(n,1)})}return function(e={}){return o=>{const{$video:n}=o.template,{errorHandle:i}=o.constructor.utils;function a(){i(o.dash.getVideoElement()===n,'Cannot find instance of DASH from "art.dash"'),function(n){const i=n.getBitrateInfoListFor("video");if(!i||!i.length)return;const a=e.quality||{},l=a.auto||"Auto",s=a.title||"Quality",r=a.getName||(t=>`${t.height}p`),c=n.getQualityFor("video"),u=n.getSettings().streaming.abr.autoSwitchBitrate.video,d=u?l:r(i[c]),h=t(i.map(t=>({html:r(t),value:t.qualityIndex,default:c===t.qualityIndex&&!u})),"html").sort((t,e)=>e.value-t.value);h.push({html:l,value:"auto",default:u});const g=t=>("auto"===t.value?n.updateSettings({streaming:{abr:{autoSwitchBitrate:{video:!0}}}}):(n.updateSettings({streaming:{abr:{autoSwitchBitrate:{video:!1}}}}),n.setQualityFor("video",t.value)),o.notice.show=`${s}: ${t.html}`,a.control&&o.controls.check(t),a.setting&&o.setting.check(t),t.html);a.control&&o.controls.update({name:"dash-quality",position:"right",html:d,style:{padding:"0 10px"},selector:h,onSelect:g}),a.setting&&o.setting.update({name:"dash-quality",tooltip:d,html:s,icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>',width:200,selector:h,onSelect:g})}(o.dash),function(n){const i=n.getTracksFor("audio");if(!i||!i.length)return;const a=e.audio||{},l=a.auto||"Auto",s=a.title||"Audio",r=a.getName||(t=>t.lang||t.id),c=n.getCurrentTrackFor("audio")||i[0],u=c?r(c):l,d=t(i.map(t=>({html:r(t),value:t,default:c===t})),"html"),h=t=>(n.setCurrentTrack(t.value),o.notice.show=`${s}: ${t.html}`,a.control&&o.controls.check(t),a.setting&&o.setting.check(t),t.html);a.control&&o.controls.update({name:"dash-audio",position:"right",html:u,style:{padding:"0 10px"},selector:d,onSelect:h}),a.setting&&o.setting.update({name:"dash-audio",tooltip:u,html:s,icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>',width:200,selector:d,onSelect:h})}(o.dash)}return o.on("ready",a),o.on("restart",a),{name:"artplayerPluginDashControl",update:a}}}});
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginDashControl=t(),define(function(){return e.artplayerPluginDashControl})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDashControl=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,r=(t,n,o)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[n]=o,i=(e,i)=>{for(var l in i||(i={}))n.call(i,l)&&r(e,l,i[l]);if(t)for(var l of t(i))o.call(i,l)&&r(e,l,i[l]);return e};function l(e,t=()=>!0){let n,o=!1;for(const i of e){if(!t())break;try{i()}catch(r){o||(o=!0,n=r)}}if(o)throw n}function c(e){const t=new Map;return e.filter(e=>{if(void 0===e.html)return!0;const n=t.get(e.html);return n?(e.default&&Object.assign(n,e),!1):(t.set(e.html,e),!0)})}function a(e,t,n){let o;const r=new Map;function i(n,o=r.get(n)){var i,l,c,a;if(!o||r.get(n)!==o)return;r.delete(n);const s=e[n];"controls"===n&&(null==(i=s.cache)?void 0:i.get)&&(null==(c=null==(l=s.cache.get(t))?void 0:l.option)?void 0:c.onSelect)!==o||"setting"===n&&s.find&&(null==(a=s.find(t))?void 0:a.onSelect)!==o||s.remove(t)}function c(){o=void 0,l([...r].map(([e,t])=>()=>i(e,t)))}return{update:function(l,a,s){if(!a)return void c();const u={};o=u;const f=()=>u===o&&s(),d=t=>f()?(a.select(t,f),f()?(e.notice.show=`${a.title}: ${t.html}`,f()&&l.control&&e.controls.check(t),f()&&l.setting&&e.setting.check(t),t.html):t.html):t.html;l.control?(r.set("controls",d),e.controls.update({name:t,position:"right",html:a.html,style:{padding:"0 10px"},selector:a.selector,onSelect:d})):i("controls"),f()&&(l.setting?(r.set("setting",d),e.setting.update({name:t,tooltip:a.html,html:a.title,icon:n,width:200,selector:a.selector,onSelect:d})):i("setting"))},clear:c,captureNavigation:function(n){var o;const i=e.setting,l=null==(o=i.find)?void 0:o.call(i,t),c=r.get("setting");if(n()&&c&&!0===i.show&&(null==l?void 0:l.onSelect)===c&&l.selector&&i.active===l.selector&&"function"===typeof i.render)return()=>{var o,l;if(!n()||e.setting!==i||!0!==i.show||!i.option||i.active!==i.option)return;const c=null==(o=i.find)?void 0:o.call(i,t),a=r.get("setting");n()&&a&&(null==c?void 0:c.onSelect)===a&&c.selector&&(null==(l=i.render)||l.call(i,c.selector))}}}}function s(e){let t;const n=n=>t===n&&e.active(n.dash),o=e=>e.dash.getSettings().streaming.abr.autoSwitchBitrate.video;function r(){const e=t;e&&(t=void 0,e.epoch++,l(e.callbacks.splice(0).map(([t,n])=>()=>e.off.call(e.dash,t,n))))}function i(n,o){if(t===n){try{r()}catch(i){console.warn("ArtPlayer DASH subscription cleanup failed:",i)}if(!t&&e.active(n.dash))try{e.reset()}catch(i){console.warn("ArtPlayer DASH cleanup failed:",i)}}console.warn("ArtPlayer DASH refresh failed:",o)}function c(t){if(!n(t)||t.suspended||t.queued||t.running)return;t.queued=!0;const r=t.epoch;Promise.resolve().then(()=>{if(n(t)&&t.epoch===r&&!t.suspended){t.queued=!1,t.running=!0;try{t.automatic=o(t),n(t)&&e.refresh()}catch(l){i(t,l)}finally{t.running=!1}}})}return{bind:function(l){const a=t;if((null==a?void 0:a.dash)===l){const e=o(a);return void(n(a)&&(a.automatic=e,a.suspended=!1))}if(r(),t||!e.active(l)||"function"!==typeof l.on||"function"!==typeof l.off)return;const s={dash:l,off:l.off,callbacks:[],epoch:0,queued:!1,running:!1,suspended:!1,automatic:!1};t=s;const u=l.on;try{s.automatic=o(s);const t=["qualityChangeRequested","qualityChangeRendered","trackChangeRendered","streamUpdated","streamInitialized"].map(e=>[e,()=>{"streamUpdated"!==e&&"streamInitialized"!==e||(s.suspended=!1),c(s)}]),r=function(e,t){const n=e;try{if("function"!==typeof n.getVersion||"4.5.2"!==n.getVersion())return;if("function"!==typeof n.getVideoElement||"function"!==typeof n.getActiveStream||"function"!==typeof n.getDashMetrics)return}catch(r){return}let o=!1;return()=>{var e,r,i,l,c,a,s,u,f;if(!o&&t()){o=!0;try{const o=null==(e=n.getVideoElement)?void 0:e.call(n);if(!(null==o?void 0:o.seeking)||!Number.isFinite(o.currentTime))return;const d=o.currentTime,g=null==(r=n.getActiveStream)?void 0:r.call(n),h=null==(i=n.getDashMetrics)?void 0:i.call(n),p=null==(l=null==g?void 0:g.getProcessors)?void 0:l.call(g);if(!Array.isArray(p)||"function"!==typeof(null==h?void 0:h.getCurrentBufferLevel)||"function"!==typeof h.addBufferLevel)return;for(const e of p){if(!t())return;const r=null==(c=e.getType)?void 0:c.call(e);if("audio"!==r&&"video"!==r)continue;const i=null==(a=e.getBufferController)?void 0:a.call(e);if("function"!==typeof(null==i?void 0:i.getRangeAt)||"function"!==typeof i.getIsPruningInProgress||"function"!==typeof i.getAllRangesWithSafetyFactor)continue;const l=h.getCurrentBufferLevel(r),p=i.getRangeAt(d),v=null===p||p&&Number.isFinite(p.end)&&p.end<=d;if(!Number.isFinite(l)||l<=0||!v||!1!==i.getIsPruningInProgress())continue;const y=i.getAllRangesWithSafetyFactor(d);if(Array.isArray(y)&&0===y.lengLine truncated
|
||||
@@ -1,165 +1,469 @@
|
||||
/*!
|
||||
* artplayer-plugin-dash-control.js v1.1.0
|
||||
* artplayer-plugin-dash-control.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
const $audio = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>';
|
||||
const $quality = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>';
|
||||
function uniqBy(array, property) {
|
||||
const seen = /* @__PURE__ */ new Map();
|
||||
return array.filter((item) => {
|
||||
const key = item[property];
|
||||
if (key === void 0) {
|
||||
return true;
|
||||
function runCleanups(actions, current = () => true) {
|
||||
let failed = false;
|
||||
let failure;
|
||||
for (const action of actions) {
|
||||
if (!current())
|
||||
break;
|
||||
try {
|
||||
action();
|
||||
} catch (error) {
|
||||
if (!failed) {
|
||||
failed = true;
|
||||
failure = error;
|
||||
}
|
||||
}
|
||||
return !seen.has(key) && seen.set(key, 1);
|
||||
}
|
||||
if (failed)
|
||||
throw failure;
|
||||
}
|
||||
function qualityAdapter(dash) {
|
||||
const modern = typeof dash.getRepresentationsByType === "function";
|
||||
return {
|
||||
levels: () => modern ? dash.getRepresentationsByType("video") : dash.getBitrateInfoListFor("video"),
|
||||
current(levels) {
|
||||
if (modern)
|
||||
return dash.getCurrentRepresentationForType("video");
|
||||
const quality = dash.getQualityFor("video");
|
||||
return levels.find((level) => level.qualityIndex === quality);
|
||||
},
|
||||
item(level, index, selected, automatic) {
|
||||
return modern ? { value: index, id: level.id, default: !automatic && selected != null && level.id === selected.id } : { value: level.qualityIndex, default: !automatic && selected != null && level.qualityIndex === selected.qualityIndex };
|
||||
},
|
||||
select(item, valid) {
|
||||
const automatic = item.value === "auto";
|
||||
dash.updateSettings({ streaming: { abr: { autoSwitchBitrate: { video: automatic } } } });
|
||||
if (!automatic && valid()) {
|
||||
if (modern)
|
||||
dash.setRepresentationForTypeById("video", item.id);
|
||||
else
|
||||
dash.setQualityFor("video", item.value);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
function uniqueLabels(items) {
|
||||
const seen = /* @__PURE__ */ new Map();
|
||||
return items.filter((item) => {
|
||||
if (item.html === void 0)
|
||||
return true;
|
||||
const first = seen.get(item.html);
|
||||
if (first) {
|
||||
if (item.default)
|
||||
Object.assign(first, item);
|
||||
return false;
|
||||
}
|
||||
seen.set(item.html, item);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
function qualityModel(dash, config, active) {
|
||||
const adapter = qualityAdapter(dash);
|
||||
const levels = adapter.levels();
|
||||
if (!active() || !levels?.length)
|
||||
return null;
|
||||
const auto = config.auto || "Auto";
|
||||
const getName = config.getName || ((level) => `${level.height}p`);
|
||||
const selected = adapter.current(levels);
|
||||
if (!active())
|
||||
return null;
|
||||
const automatic = dash.getSettings().streaming.abr.autoSwitchBitrate.video;
|
||||
if (!active())
|
||||
return null;
|
||||
const html = !automatic && selected ? getName(selected) : auto;
|
||||
if (!active())
|
||||
return null;
|
||||
const items = [];
|
||||
for (const [index, level] of levels.entries()) {
|
||||
const label = getName(level);
|
||||
if (!active())
|
||||
return null;
|
||||
items.push({ html: label, ...adapter.item(level, index, selected, automatic) });
|
||||
}
|
||||
const selector = uniqueLabels(items).sort((left, right) => right.value - left.value);
|
||||
selector.push({ html: auto, value: "auto", default: automatic });
|
||||
return { html, title: config.title || "Quality", selector, select: adapter.select };
|
||||
}
|
||||
function selectedTrack(tracks, current) {
|
||||
if (tracks.includes(current))
|
||||
return current;
|
||||
if (current.id == null && current.index == null)
|
||||
return void 0;
|
||||
const fields = ["id", "index", "lang"];
|
||||
const matching = tracks.filter((track) => fields.every((key) => current[key] == null || track[key] === current[key]));
|
||||
return matching.length === 1 ? matching[0] : void 0;
|
||||
}
|
||||
function audioModel(dash, config, active) {
|
||||
const tracks = dash.getTracksFor("audio");
|
||||
if (!active() || !tracks?.length)
|
||||
return null;
|
||||
const auto = config.auto || "Auto";
|
||||
const getName = config.getName || ((track) => track.lang || track.id);
|
||||
const current = dash.getCurrentTrackFor("audio") || tracks[0];
|
||||
if (!active())
|
||||
return null;
|
||||
const html = current ? getName(current) : auto;
|
||||
if (!active())
|
||||
return null;
|
||||
const selected = selectedTrack(tracks, current);
|
||||
const items = [];
|
||||
for (const track of tracks) {
|
||||
const label = getName(track);
|
||||
if (!active())
|
||||
return null;
|
||||
items.push({ html: label, value: track, default: track === selected });
|
||||
}
|
||||
const selector = uniqueLabels(items);
|
||||
return { html, title: config.title || "Audio", selector, select: (item) => dash.setCurrentTrack(item.value) };
|
||||
}
|
||||
function createMenu(art, name, icon) {
|
||||
let current;
|
||||
const owned = /* @__PURE__ */ new Map();
|
||||
function remove(surface, callback = owned.get(surface)) {
|
||||
if (!callback || owned.get(surface) !== callback)
|
||||
return;
|
||||
owned.delete(surface);
|
||||
const registry = art[surface];
|
||||
if (surface === "controls" && registry.cache?.get && registry.cache.get(name)?.option?.onSelect !== callback)
|
||||
return;
|
||||
if (surface === "setting" && registry.find && registry.find(name)?.onSelect !== callback)
|
||||
return;
|
||||
registry.remove(name);
|
||||
}
|
||||
function clear() {
|
||||
current = void 0;
|
||||
runCleanups([...owned].map(([surface, callback]) => () => remove(surface, callback)));
|
||||
}
|
||||
function update(config, model, active) {
|
||||
if (!model) {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
const state = {};
|
||||
current = state;
|
||||
const valid = () => state === current && active();
|
||||
const onSelect = (item) => {
|
||||
if (!valid())
|
||||
return item.html;
|
||||
model.select(item, valid);
|
||||
if (!valid())
|
||||
return item.html;
|
||||
art.notice.show = `${model.title}: ${item.html}`;
|
||||
if (valid() && config.control)
|
||||
art.controls.check(item);
|
||||
if (valid() && config.setting)
|
||||
art.setting.check(item);
|
||||
return item.html;
|
||||
};
|
||||
if (config.control) {
|
||||
owned.set("controls", onSelect);
|
||||
art.controls.update({ name, position: "right", html: model.html, style: { padding: "0 10px" }, selector: model.selector, onSelect });
|
||||
} else {
|
||||
remove("controls");
|
||||
}
|
||||
if (!valid())
|
||||
return;
|
||||
if (config.setting) {
|
||||
owned.set("setting", onSelect);
|
||||
art.setting.update({ name, tooltip: model.html, html: model.title, icon, width: 200, selector: model.selector, onSelect });
|
||||
} else {
|
||||
remove("setting");
|
||||
}
|
||||
}
|
||||
function captureNavigation(active) {
|
||||
const setting = art.setting;
|
||||
const item = setting.find?.(name);
|
||||
const callback = owned.get("setting");
|
||||
if (!active() || !callback || setting.show !== true || item?.onSelect !== callback || !item.selector || setting.active !== item.selector || typeof setting.render !== "function")
|
||||
return;
|
||||
return () => {
|
||||
if (!active() || art.setting !== setting || setting.show !== true || !setting.option || setting.active !== setting.option)
|
||||
return;
|
||||
const replacement = setting.find?.(name);
|
||||
const callback2 = owned.get("setting");
|
||||
if (active() && callback2 && replacement?.onSelect === callback2 && replacement.selector)
|
||||
setting.render?.(replacement.selector);
|
||||
};
|
||||
}
|
||||
return { update, clear, captureNavigation };
|
||||
}
|
||||
const $quality = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>';
|
||||
function createSeekRecovery(value, active) {
|
||||
const sdk = value;
|
||||
try {
|
||||
if (typeof sdk.getVersion !== "function" || sdk.getVersion() !== "4.5.2")
|
||||
return;
|
||||
if (typeof sdk.getVideoElement !== "function" || typeof sdk.getActiveStream !== "function" || typeof sdk.getDashMetrics !== "function")
|
||||
return;
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
let running = false;
|
||||
return () => {
|
||||
if (running || !active())
|
||||
return;
|
||||
running = true;
|
||||
try {
|
||||
const video = sdk.getVideoElement?.();
|
||||
if (!video?.seeking || !Number.isFinite(video.currentTime))
|
||||
return;
|
||||
const time = video.currentTime;
|
||||
const stream = sdk.getActiveStream?.();
|
||||
const metrics = sdk.getDashMetrics?.();
|
||||
const processors = stream?.getProcessors?.();
|
||||
if (!Array.isArray(processors) || typeof metrics?.getCurrentBufferLevel !== "function" || typeof metrics.addBufferLevel !== "function")
|
||||
return;
|
||||
for (const processor of processors) {
|
||||
if (!active())
|
||||
return;
|
||||
const type = processor.getType?.();
|
||||
if (type !== "audio" && type !== "video")
|
||||
continue;
|
||||
const buffer = processor.getBufferController?.();
|
||||
if (typeof buffer?.getRangeAt !== "function" || typeof buffer.getIsPruningInProgress !== "function" || typeof buffer.getAllRangesWithSafetyFactor !== "function")
|
||||
continue;
|
||||
const cached = metrics.getCurrentBufferLevel(type);
|
||||
const range = buffer.getRangeAt(time);
|
||||
const empty = range === null || range && Number.isFinite(range.end) && range.end <= time;
|
||||
if (!Number.isFinite(cached) || cached <= 0 || !empty || buffer.getIsPruningInProgress() !== false)
|
||||
continue;
|
||||
const removals = buffer.getAllRangesWithSafetyFactor(time);
|
||||
if (!Array.isArray(removals) || removals.length !== 0)
|
||||
continue;
|
||||
if (!active() || sdk.getActiveStream?.() !== stream || sdk.getDashMetrics?.() !== metrics || sdk.getVideoElement?.() !== video || video.currentTime !== time || !video.seeking || !active())
|
||||
return;
|
||||
metrics.addBufferLevel(type, /* @__PURE__ */ new Date(), 0);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("ArtPlayer DASH seek buffer refresh failed:", error);
|
||||
} finally {
|
||||
running = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
function observeSDK(options) {
|
||||
let binding;
|
||||
const active = (record) => binding === record && options.active(record.dash);
|
||||
const automatic = (record) => record.dash.getSettings().streaming.abr.autoSwitchBitrate.video;
|
||||
function release() {
|
||||
const record = binding;
|
||||
if (!record)
|
||||
return;
|
||||
binding = void 0;
|
||||
record.epoch++;
|
||||
runCleanups(record.callbacks.splice(0).map(([name, callback]) => () => record.off.call(record.dash, name, callback)));
|
||||
}
|
||||
function fail(record, error) {
|
||||
if (binding === record) {
|
||||
try {
|
||||
release();
|
||||
} catch (cleanupError) {
|
||||
console.warn("ArtPlayer DASH subscription cleanup failed:", cleanupError);
|
||||
}
|
||||
if (!binding && options.active(record.dash)) {
|
||||
try {
|
||||
options.reset();
|
||||
} catch (cleanupError) {
|
||||
console.warn("ArtPlayer DASH cleanup failed:", cleanupError);
|
||||
}
|
||||
}
|
||||
}
|
||||
console.warn("ArtPlayer DASH refresh failed:", error);
|
||||
}
|
||||
function schedule(record) {
|
||||
if (!active(record) || record.suspended || record.queued || record.running)
|
||||
return;
|
||||
record.queued = true;
|
||||
const epoch = record.epoch;
|
||||
void Promise.resolve().then(() => {
|
||||
if (!active(record) || record.epoch !== epoch || record.suspended)
|
||||
return;
|
||||
record.queued = false;
|
||||
record.running = true;
|
||||
try {
|
||||
record.automatic = automatic(record);
|
||||
if (active(record))
|
||||
options.refresh();
|
||||
} catch (error) {
|
||||
fail(record, error);
|
||||
} finally {
|
||||
record.running = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
function bind(dash) {
|
||||
const previous = binding;
|
||||
if (previous?.dash === dash) {
|
||||
const value = automatic(previous);
|
||||
if (active(previous)) {
|
||||
previous.automatic = value;
|
||||
previous.suspended = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
release();
|
||||
if (binding || !options.active(dash) || typeof dash.on !== "function" || typeof dash.off !== "function")
|
||||
return;
|
||||
const record = { dash, off: dash.off, callbacks: [], epoch: 0, queued: false, running: false, suspended: false, automatic: false };
|
||||
binding = record;
|
||||
const on = dash.on;
|
||||
try {
|
||||
record.automatic = automatic(record);
|
||||
const changed = ["qualityChangeRequested", "qualityChangeRendered", "trackChangeRendered", "streamUpdated", "streamInitialized"];
|
||||
const entries = changed.map((name) => [name, () => {
|
||||
if (name === "streamUpdated" || name === "streamInitialized")
|
||||
record.suspended = false;
|
||||
schedule(record);
|
||||
}]);
|
||||
const recoverSeek = createSeekRecovery(dash, () => active(record) && !record.suspended);
|
||||
if (recoverSeek)
|
||||
entries.push(["playbackSeeking", recoverSeek]);
|
||||
entries.push(["playbackTimeUpdated", () => {
|
||||
if (!active(record) || record.suspended)
|
||||
return;
|
||||
try {
|
||||
const value = automatic(record);
|
||||
if (active(record) && value !== record.automatic) {
|
||||
record.automatic = value;
|
||||
schedule(record);
|
||||
}
|
||||
} catch (error) {
|
||||
fail(record, error);
|
||||
}
|
||||
}]);
|
||||
entries.push(["streamTeardownComplete", () => {
|
||||
if (!active(record))
|
||||
return;
|
||||
record.epoch++;
|
||||
record.queued = false;
|
||||
record.suspended = true;
|
||||
try {
|
||||
options.reset();
|
||||
} catch (error) {
|
||||
fail(record, error);
|
||||
}
|
||||
}]);
|
||||
for (const entry of entries) {
|
||||
if (!active(record))
|
||||
break;
|
||||
record.callbacks.push(entry);
|
||||
on.call(dash, ...entry);
|
||||
}
|
||||
} catch (error) {
|
||||
if (binding === record) {
|
||||
try {
|
||||
release();
|
||||
} catch (cleanupError) {
|
||||
console.warn("ArtPlayer DASH subscription cleanup failed:", cleanupError);
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
return { bind, release };
|
||||
}
|
||||
function artplayerPluginDashControl(option = {}) {
|
||||
return (art) => {
|
||||
return (player) => {
|
||||
const art = player;
|
||||
const { $video } = art.template;
|
||||
const { errorHandle } = art.constructor.utils;
|
||||
function updateQuality(dash) {
|
||||
const qualities = dash.getBitrateInfoListFor("video");
|
||||
if (!qualities || !qualities.length)
|
||||
return;
|
||||
const config = option.quality || {};
|
||||
const auto = config.auto || "Auto";
|
||||
const title = config.title || "Quality";
|
||||
const getName = config.getName || ((level) => `${level.height}p`);
|
||||
const currentQuality = dash.getQualityFor("video");
|
||||
const currentAuto = dash.getSettings().streaming.abr.autoSwitchBitrate.video;
|
||||
const defaultHtml = currentAuto ? auto : getName(qualities[currentQuality]);
|
||||
const selector = uniqBy(
|
||||
qualities.map((item) => {
|
||||
return {
|
||||
html: getName(item),
|
||||
value: item.qualityIndex,
|
||||
default: currentQuality === item.qualityIndex && !currentAuto
|
||||
};
|
||||
}),
|
||||
"html"
|
||||
).sort((a, b) => b.value - a.value);
|
||||
selector.push({
|
||||
html: auto,
|
||||
value: "auto",
|
||||
default: currentAuto
|
||||
});
|
||||
const onSelect = (item) => {
|
||||
if (item.value === "auto") {
|
||||
dash.updateSettings({
|
||||
streaming: {
|
||||
abr: {
|
||||
autoSwitchBitrate: {
|
||||
video: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
dash.updateSettings({
|
||||
streaming: {
|
||||
abr: {
|
||||
autoSwitchBitrate: {
|
||||
video: false
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
dash.setQualityFor("video", item.value);
|
||||
}
|
||||
art.notice.show = `${title}: ${item.html}`;
|
||||
if (config.control)
|
||||
art.controls.check(item);
|
||||
if (config.setting)
|
||||
art.setting.check(item);
|
||||
return item.html;
|
||||
};
|
||||
if (config.control) {
|
||||
art.controls.update({
|
||||
name: "dash-quality",
|
||||
position: "right",
|
||||
html: defaultHtml,
|
||||
style: { padding: "0 10px" },
|
||||
selector,
|
||||
onSelect
|
||||
});
|
||||
}
|
||||
if (config.setting) {
|
||||
art.setting.update({
|
||||
name: "dash-quality",
|
||||
tooltip: defaultHtml,
|
||||
html: title,
|
||||
icon: $quality,
|
||||
width: 200,
|
||||
selector,
|
||||
onSelect
|
||||
});
|
||||
}
|
||||
}
|
||||
function updateAudio(dash) {
|
||||
const audioTracks = dash.getTracksFor("audio");
|
||||
if (!audioTracks || !audioTracks.length)
|
||||
return;
|
||||
const config = option.audio || {};
|
||||
const auto = config.auto || "Auto";
|
||||
const title = config.title || "Audio";
|
||||
const getName = config.getName || ((track) => track.lang || track.id);
|
||||
const currentTrack = dash.getCurrentTrackFor("audio") || audioTracks[0];
|
||||
const defaultHtml = currentTrack ? getName(currentTrack) : auto;
|
||||
const selector = uniqBy(
|
||||
audioTracks.map((item) => {
|
||||
return {
|
||||
html: getName(item),
|
||||
value: item,
|
||||
default: currentTrack === item
|
||||
};
|
||||
}),
|
||||
"html"
|
||||
);
|
||||
const onSelect = (item) => {
|
||||
dash.setCurrentTrack(item.value);
|
||||
art.notice.show = `${title}: ${item.html}`;
|
||||
if (config.control)
|
||||
art.controls.check(item);
|
||||
if (config.setting)
|
||||
art.setting.check(item);
|
||||
return item.html;
|
||||
};
|
||||
if (config.control) {
|
||||
art.controls.update({
|
||||
name: "dash-audio",
|
||||
position: "right",
|
||||
html: defaultHtml,
|
||||
style: { padding: "0 10px" },
|
||||
selector,
|
||||
onSelect
|
||||
});
|
||||
}
|
||||
if (config.setting) {
|
||||
art.setting.update({
|
||||
name: "dash-audio",
|
||||
tooltip: defaultHtml,
|
||||
html: title,
|
||||
icon: $audio,
|
||||
width: 200,
|
||||
selector,
|
||||
onSelect
|
||||
});
|
||||
let closed = false;
|
||||
let revision = 0;
|
||||
const quality = createMenu(art, "dash-quality", $quality);
|
||||
const audio = createMenu(art, "dash-audio", $audio);
|
||||
const subscriptions = [];
|
||||
const observer = observeSDK({
|
||||
active: (dash) => !closed && !art.isDestroy && art.dash === dash,
|
||||
refresh() {
|
||||
const dash = art.dash;
|
||||
let version = revision;
|
||||
const current = () => !closed && !art.isDestroy && art.dash === dash && revision === version;
|
||||
const restore = quality.captureNavigation(current) || audio.captureNavigation(current);
|
||||
if (!current())
|
||||
return;
|
||||
version++;
|
||||
update();
|
||||
if (current())
|
||||
restore?.();
|
||||
},
|
||||
reset() {
|
||||
const version = ++revision;
|
||||
clear(() => version === revision);
|
||||
}
|
||||
});
|
||||
function clear(current = () => true) {
|
||||
runCleanups([quality.clear, audio.clear], current);
|
||||
}
|
||||
function update() {
|
||||
errorHandle(art.dash.getVideoElement() === $video, 'Cannot find instance of DASH from "art.dash"');
|
||||
updateQuality(art.dash);
|
||||
updateAudio(art.dash);
|
||||
if (closed || art.isDestroy)
|
||||
return;
|
||||
const version = ++revision;
|
||||
const dash = art.dash;
|
||||
const current = () => !closed && !art.isDestroy && version === revision && art.dash === dash;
|
||||
const valid = () => current() && dash.getVideoElement() === $video && current();
|
||||
try {
|
||||
errorHandle(dash.getVideoElement() === $video, 'Cannot find instance of DASH from "art.dash"');
|
||||
if (!current())
|
||||
return;
|
||||
observer.bind(dash);
|
||||
if (!valid())
|
||||
return;
|
||||
const qualityConfig = option.quality || {};
|
||||
const qualities = qualityModel(dash, qualityConfig, valid);
|
||||
if (!valid())
|
||||
return;
|
||||
quality.update(qualityConfig, qualities, valid);
|
||||
if (!valid())
|
||||
return;
|
||||
const audioConfig = option.audio || {};
|
||||
const tracks = audioModel(dash, audioConfig, valid);
|
||||
if (valid())
|
||||
audio.update(audioConfig, tracks, valid);
|
||||
} catch (error) {
|
||||
if (current()) {
|
||||
const cleanupVersion = ++revision;
|
||||
for (const cleanup of [observer.release, () => clear(() => revision === cleanupVersion)]) {
|
||||
try {
|
||||
cleanup();
|
||||
} catch (cleanupError) {
|
||||
console.warn("ArtPlayer DASH cleanup failed:", cleanupError);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
art.on("ready", update);
|
||||
art.on("restart", update);
|
||||
return {
|
||||
name: "artplayerPluginDashControl",
|
||||
update
|
||||
};
|
||||
function destroy() {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
revision++;
|
||||
const actions = [observer.release, clear, ...subscriptions.splice(0).map(([name, callback]) => () => art.off(name, callback))];
|
||||
runCleanups(actions);
|
||||
}
|
||||
try {
|
||||
const entries = [["ready", update], ["restart", update], ["destroy", destroy]];
|
||||
for (const entry of entries) {
|
||||
if (closed)
|
||||
break;
|
||||
subscriptions.push(entry);
|
||||
art.on(...entry);
|
||||
}
|
||||
} catch (error) {
|
||||
try {
|
||||
destroy();
|
||||
} catch (cleanupError) {
|
||||
console.warn("ArtPlayer DASH subscription cleanup failed:", cleanupError);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
return { name: "artplayerPluginDashControl", update };
|
||||
};
|
||||
}
|
||||
export {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-document-pip.js v1.1.0
|
||||
* artplayer-plugin-document-pip.js v2.0.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.artplayerPluginDocumentPip=t(),define(function(){return t.artplayerPluginDocumentPip})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDocumentPip=t()}(this,function(){"use strict";if("undefined"!==typeof document){const e="artplayer-plugin-document-pip";let t=document.getElementById(e);t||(t=document.createElement("style"),t.id=e,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(t)}):(document.head||document.documentElement).appendChild(t)),t.textContent=".artplayer-document-pip.art-video-player{width:100%!important;height:100%!important}"}return function(e={}){const t={width:480,height:270,fallbackToVideoPiP:!0,placeholder:"Playing in Document Picture-in-Picture",...e};return e=>{const n="documentPictureInPicture"in window&&"function"===typeof window.documentPictureInPicture?.requestWindow,{proxy:i,icons:o,i18n:r,template:{$player:d},constructor:{utils:{append:l,tooltip:c,addClass:a,removeClass:p,sleep:u}}}=e,s={win:null,originalParent:null,originalNext:null,currentDoc:null,placeholder:null};async function m(){if(!n&&t.fallbackToVideoPiP)return e.pip=!0,void console.warn("[artplayer-plugin-document-pip] Document Picture-in-Picture is not supported, falling back to Video Picture-in-Picture");if(!s.win)try{const n=await window.documentPictureInPicture.requestWindow({width:t.width,height:t.height});s.win=n,s.currentDoc=n.document,s.placeholder=document.createElement("div"),s.placeholder.className="artplayer-document-pip-placeholder",s.placeholder.style.cssText="display:flex;justify-content:center;align-items:center;width:100%;height:100%;",s.placeholder.textContent=t.placeholder,s.originalParent=d.parentNode,s.originalNext=d.nextSibling,s.originalParent.insertBefore(s.placeholder,s.originalNext);const i=n.document.createElement("div");i.id="__art_dpip_root",n.document.body.appendChild(i),function(e){const t=e.createElement("style");if(t.textContent="\n html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }\n #__art_dpip_root { position:absolute; inset:0; display:flex; }\n #__art_dpip_root > * { width:100% !important; height:100% !important; }\n ",e.head.appendChild(t),!e.querySelector('meta[name="viewport"]')){const t=e.createElement("meta");t.name="viewport",t.content="width=device-width,initial-scale=1",e.head.appendChild(t)}try{document.querySelectorAll('link[rel="stylesheet"]').forEach(t=>{const n=e.createElement("link");n.rel="stylesheet",n.href=t.href,t.media&&(n.media=t.media),t.crossOrigin&&(n.crossOrigin=t.crossOrigin),t.referrerPolicy&&(n.referrerPolicy=t.referrerPolicy),e.head.appendChild(n)})}catch{}try{document.querySelectorAll("style").forEach(t=>{const n=e.createElement("style");n.textContent=t.textContent,e.head.appendChild(n)})}catch{}}(n.document);const o=n.document.adoptNode(d);i.appendChild(o),s.currentDoc=n.document;const r=()=>e.resize?.(),l=()=>h();n.addEventListener("resize",r),n.addEventListener("pagehide",l),n.addEventListener("unload",l),s.cleanup=()=>{n.removeEventListener("resize",r),n.removeEventListener("pagehide",l),n.removeEventListener("unload",l)},a(d,"artplayer-document-pip"),e.events.bindGlobalEvents?.(),e.emit("document-pip",!0),await u(100),e.emit("resize")}catch(i){e.notice.show="Document Picture-in-Picture open failed",console.warn("[artplayer-plugin-document-pip] open failed:",i)}}async function h(){if(s.win)try{s.cleanup?.(),function(){if(!s.placeholder)return;const e=s.placeholder.ownerDocument||document,t=e.adoptNode(d);s.originalParent.insertBefore(t,s.placeholder),s.placeholder.remove(),s.placeholder=null,s.currentDoc=e}(),s.win.close(),s.win=null,p(d,"artplayer-document-pip"),e.events.bindGlobalEvents?.(),e.emit("document-pip",!1),await u(100),e.emit("resize")}catch(t){e.notice.show="Document Picture-in-Picture close failed",console.warn("[artplayer-plugin-document-pip] close failed:",t)}}function f(){s.win?h():m()}return e.controls.add({name:"document-pip",position:"right",index:40,tooltip:e.i18n.get("PIP Mode"),mounted:t=>{l(t,o.pip),i(t,"click",f),e.on("document-pip",e=>{c(t,r.get(e?"Exit PIP Mode":"PIP Mode"))})}}),e.on("destroy",h),{name:"artplayerPluginDocumentPip",get isSupported(){return n},get isActive(){return!!s.win},open:m,close:h,toggle:f}}}});
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginDocumentPip=t(),define(function(){return e.artplayerPluginDocumentPip})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDocumentPip=t()}(this,function(){"use strict";function e(e){const t=[];for(const o of e)try{o()}catch(n){t.push(n)}return t}const t=".artplayer-document-pip.art-video-player{width:100%!important;height:100%!important}";function n(t){let n=!1,o=0,i=null,r=null,c=null;const l=()=>!n&&t.alive(),s=e=>e===o&&l();function u(){o++,r?.finish(),r=null,c?.cancel(),c=null}function a(t){const n=e(t.releases.splice(0));return n.push(...e([()=>t.window.close()])),n}async function d(e){if(!s(e))return;const n=function(){let e;const t=new Promise(t=>{e=t});let n=setTimeout(()=>{n=null,e()},100);return{promise:t,cancel(){null!==n&&clearTimeout(n),n=null,e()}}}();c=n,await n.promise,c===n&&(c=null),s(e)&&t.resize()}async function p(){u();const e=o,n=i;if(i=null,!n)return;const r=a(n);if(n.announced)try{t.activate(!1)}catch(c){r.push(c)}r.length&&l()&&t.report("close",r[0]),s(e)&&await d(e)}return{get active(){return null!==i},get opening(){return null!==r},open:async function(){if(!l()||i)return;if(r)return r.promise;u();const n=o;let c,f;const m=new Promise((e,t)=>{c=e,f=t}),h={promise:m,finish:c};r=h;const y=()=>{r===h&&(r=null),c()},g=o=>{if(s(n)){const n=i;i=null,n&&(a(n),n.announced&&e([()=>t.activate(!1)]));try{t.report("open",o)}catch(r){f(r)}}},v=async o=>{if(!s(n))return void(i?.window!==o&&e([()=>o.close()]));const r={window:o,releases:[],announced:!1};i=r;try{const e=t.project(o.document);if(r.releases.push(e.destroy),e.mount(),!s(n))return void a(r);for(const[i,c]of[["resize",()=>{s(n)&&t.nativeResize()}],["pagehide",()=>{p()}],["unload",()=>{p()}]])if(r.releases.unshift(()=>o.removeEventListener(i,c)),o.addEventListener(i,c),!s(n))return void a(r);r.announced=!0,t.activate(!0),await d(n)}catch(c){g(c)}};try{const e=t.request();Promise.resolve(e).then(v,g).then(y,e=>{s(n)&&f(e),y()})}catch(w){try{g(w)}finally{y()}}return m},close:p,destroy(){n||(n=!0,p().catch(()=>{}))}}}function o(t={}){const o={width:480,height:270,fallbackToVideoPiP:!0,placeholder:"Playing in Document Picture-in-Picture",...t};return t=>{const i=window,r="documentPictureInPicture"in i&&"function"===typeof i.documentPictureInPicture?.requestWindow;let c=t,l=t.template.$player,s=t.isDestroy;const u=t.constructor.utils,a=()=>!s&&!!c&&!c.isDestroy,d=n({alive:a,request:()=>i.documentPictureInPicture.requestWindow({width:o.width,height:o.height}),project:t=>function(t,n,o){const i=t.ownerDocument,r=t.parentNode,c=t.nextSibling;if(!r)throw new Error("Document Picture-in-Picture requires a mounted player");const l=i.createElement("div");l.className="artplayer-document-pip-placeholder",l.style.cssText="display:flex;justify-content:center;align-items:center;width:100%;height:100%;",l.textContent=o??"";const s=n.createElement("div");s.id="__art_dpip_root";const u=[];let a=!1;const d=()=>{const e=l.parentNode===r?l:c?.parentNode===r?c:null;if(t.parentNode!==r||t.nextSibling!==e)try{r.insertBefore(t,e)}catch(n){throw i.body.appendChild(t),n}},p=()=>{const t=e([d,()=>l.remove(),...u.splice(0).map(e=>()=>e.remove()),()=>s.remove()]);if(t.length)throw t[0]};return{mount(){if(!a){if(r.insertBefore(l,c?.parentNode===r?c:null),a||n.body.appendChild(s),a||function(e,t,n,o){const i=e=>{o()&&(n(e),t.head.appendChild(e),o()||e.remove())},r=t.createElement("style");if(r.textContent="\n html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }\n #__art_dpip_root { position:absolute; inset:0; display:flex; }\n #__art_dpip_root > * { width:100% !important; height:100% !important; }\n ",i(r),!t.querySelector('meta[name="viewport"]')){const e=t.createElement("meta");e.name="viewport",e.content="width=device-width,initial-scale=1",i(e)}try{e.querySelectorAll('link[rel="stylesheet"]').forEach(e=>{const n=t.createElement("link");n.rel="stylesheet",n.href=e.href,e.media&&(n.media=e.media),e.crossOrigin&&(n.crossOrigin=e.crossOrigin),e.referrerPolicy&&(n.referrerPolicy=e.referrerPolicy),i(n)})}catch{}try{e.querySelectorAll("style").forEach(e=>{const n=t.createElement("style");n.textContent=e.textContent,i(n)})}catch{}}(i,n,e=>u.push(e),()=>!a),!a){const e=n.adoptNode(t);a||s.appendChild(e)}a&&p()}},destroy(){a||(a=!0,p())}}}(l,t,o.placeholder),activate(e){c&&l&&(e?u.addClass(l,"artplayer-document-pip"):u.removeClass(l,"artplayer-document-pip"),a()&&(c.events.bindGlobalEvents?.(),a()&&c.emit("document-pip",e)))},resize:()=>{a()&&c.emit("resize")},nativeResize:()=>{a()&&c.resize?.()},report(e,t){a()&&(c.notice.show=`Document Picture-in-Picture ${e} failed`,console.warn(`[artplayer-plugin-document-pip] ${e} failed:`,t))}});async function p(){if(a())return!r&&o.fallbackToVideoPiP?(c.pip=!0,void console.warn("[artplayer-plugin-document-pip] Document PiLine truncated
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-document-pip.js v1.1.0
|
||||
* artplayer-plugin-document-pip.js v2.0.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.artplayerPluginDocumentPip=t(),define(function(){return t.artplayerPluginDocumentPip})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDocumentPip=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable,o=(t,n,i)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[n]=i,r=(e,t,n)=>new Promise((i,o)=>{var r=e=>{try{c(n.next(e))}catch(t){o(t)}},l=e=>{try{c(n.throw(e))}catch(t){o(t)}},c=e=>e.done?i(e.value):Promise.resolve(e.value).then(r,l);c((n=n.apply(e,t)).next())});if("undefined"!==typeof document){const e="artplayer-plugin-document-pip";let t=document.getElementById(e);t||(t=document.createElement("style"),t.id=e,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(t)}):(document.head||document.documentElement).appendChild(t)),t.textContent=".artplayer-document-pip.art-video-player{width:100%!important;height:100%!important}"}return function(e={}){const l=((e,r)=>{for(var l in r||(r={}))n.call(r,l)&&o(e,l,r[l]);if(t)for(var l of t(r))i.call(r,l)&&o(e,l,r[l]);return e})({width:480,height:270,fallbackToVideoPiP:!0,placeholder:"Playing in Document Picture-in-Picture"},e);return e=>{var t;const n="documentPictureInPicture"in window&&"function"===typeof(null==(t=window.documentPictureInPicture)?void 0:t.requestWindow),{proxy:i,icons:o,i18n:c,template:{$player:a},constructor:{utils:{append:d,tooltip:p,addClass:u,removeClass:s,sleep:m}}}=e,h={win:null,originalParent:null,originalNext:null,currentDoc:null,placeholder:null};function y(){return r(this,null,function*(){var t,i;if(!n&&l.fallbackToVideoPiP)return e.pip=!0,void console.warn("[artplayer-plugin-document-pip] Document Picture-in-Picture is not supported, falling back to Video Picture-in-Picture");if(!h.win)try{const n=yield window.documentPictureInPicture.requestWindow({width:l.width,height:l.height});h.win=n,h.currentDoc=n.document,h.placeholder=document.createElement("div"),h.placeholder.className="artplayer-document-pip-placeholder",h.placeholder.style.cssText="display:flex;justify-content:center;align-items:center;width:100%;height:100%;",h.placeholder.textContent=l.placeholder,h.originalParent=a.parentNode,h.originalNext=a.nextSibling,h.originalParent.insertBefore(h.placeholder,h.originalNext);const o=n.document.createElement("div");o.id="__art_dpip_root",n.document.body.appendChild(o),function(e){const t=e.createElement("style");if(t.textContent="\n html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }\n #__art_dpip_root { position:absolute; inset:0; display:flex; }\n #__art_dpip_root > * { width:100% !important; height:100% !important; }\n ",e.head.appendChild(t),!e.querySelector('meta[name="viewport"]')){const t=e.createElement("meta");t.name="viewport",t.content="width=device-width,initial-scale=1",e.head.appendChild(t)}try{document.querySelectorAll('link[rel="stylesheet"]').forEach(t=>{const n=e.createElement("link");n.rel="stylesheet",n.href=t.href,t.media&&(n.media=t.media),t.crossOrigin&&(n.crossOrigin=t.crossOrigin),t.referrerPolicy&&(n.referrerPolicy=t.referrerPolicy),e.head.appendChild(n)})}catch(n){}try{document.querySelectorAll("style").forEach(t=>{const n=e.createElement("style");n.textContent=t.textContent,e.head.appendChild(n)})}catch(n){}}(n.document);const r=n.document.adoptNode(a);o.appendChild(r),h.currentDoc=n.document;const c=()=>{var t;return null==(t=e.resize)?void 0:t.call(e)},d=()=>f();n.addEventListener("resize",c),n.addEventListener("pagehide",d),n.addEventListener("unload",d),h.cleanup=()=>{n.removeEventListener("resize",c),n.removeEventListener("pagehide",d),n.removeEventListener("unload",d)},u(a,"artplayer-document-pip"),null==(i=(t=e.events).bindGlobalEvents)||i.call(t),e.emit("document-pip",!0),yield m(100),e.emit("resize")}catch(o){e.notice.show="Document Picture-in-Picture open failed",console.warn("[artplayer-plugin-document-pip] open failed:",o)}})}function f(){return r(this,null,function*(){var t,n,i;if(h.win)try{null==(t=h.cleanup)||t.call(h),function(){if(!h.placeholder)return;const e=h.placeholder.ownerDocument||document,t=e.adoptNode(a);h.originalParent.insertBefore(t,h.placeholder),h.placeholder.remove(),h.placeholder=null,h.currentDoc=e}(),h.win.close(),h.win=null,s(a,"artplayer-document-pip"),null==(i=(n=e.events).bindGlobalEvents)||i.call(n),e.emit("document-pip",!1),yield m(100),e.emit("resize")}catch(o){e.notice.show="Document Picture-in-Picture close failed",console.warn("[artplayer-plugin-document-pip] close failed:",o)}})}function g(){h.win?f():y()}return e.controls.add({name:"document-pip",position:"right",index:40,tooltip:e.i18n.get("PIP Mode"),mounted:t=>{d(t,o.pip),i(t,"click",g),e.on("document-pip",Line truncated
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginDocumentPip=t(),define(function(){return e.artplayerPluginDocumentPip})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDocumentPip=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,r=(t,n,o)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[n]=o,i=(e,t,n)=>new Promise((o,r)=>{var i=e=>{try{c(n.next(e))}catch(t){r(t)}},l=e=>{try{c(n.throw(e))}catch(t){r(t)}},c=e=>e.done?o(e.value):Promise.resolve(e.value).then(i,l);c((n=n.apply(e,t)).next())});function l(e){const t=[];for(const o of e)try{o()}catch(n){t.push(n)}return t}const c=".artplayer-document-pip.art-video-player{width:100%!important;height:100%!important}";function u(e){let t=!1,n=0,o=null,r=null,c=null;const u=()=>!t&&e.alive(),s=e=>e===n&&u();function a(){n++,null==r||r.finish(),r=null,null==c||c.cancel(),c=null}function d(e){const t=l(e.releases.splice(0));return t.push(...l([()=>e.window.close()])),t}function p(t){return i(this,null,function*(){if(!s(t))return;const n=function(){let e;const t=new Promise(t=>{e=t});let n=setTimeout(()=>{n=null,e()},100);return{promise:t,cancel(){null!==n&&clearTimeout(n),n=null,e()}}}();c=n,yield n.promise,c===n&&(c=null),s(t)&&e.resize()})}function f(){return i(this,null,function*(){a();const t=n,r=o;if(o=null,!r)return;const i=d(r);if(r.announced)try{e.activate(!1)}catch(l){i.push(l)}i.length&&u()&&e.report("close",i[0]),s(t)&&(yield p(t))})}return{get active(){return null!==o},get opening(){return null!==r},open:function(){return i(this,null,function*(){if(!u()||o)return;if(r)return r.promise;a();const t=n;let c,m;const h=new Promise((e,t)=>{c=e,m=t}),y={promise:h,finish:c};r=y;const v=()=>{r===y&&(r=null),c()},g=n=>{if(s(t)){const t=o;o=null,t&&(d(t),t.announced&&l([()=>e.activate(!1)]));try{e.report("open",n)}catch(r){m(r)}}},P=n=>i(null,null,function*(){if(!s(t))return void((null==o?void 0:o.window)!==n&&l([()=>n.close()]));const r={window:n,releases:[],announced:!1};o=r;try{const o=e.project(n.document);if(r.releases.push(o.destroy),o.mount(),!s(t))return void d(r);for(const[i,l]of[["resize",()=>{s(t)&&e.nativeResize()}],["pagehide",()=>{f()}],["unload",()=>{f()}]])if(r.releases.unshift(()=>n.removeEventListener(i,l)),n.addEventListener(i,l),!s(t))return void d(r);r.announced=!0,e.activate(!0),yield p(t)}catch(i){g(i)}});try{const n=e.request();Promise.resolve(n).then(P,g).then(v,e=>{s(t)&&m(e),v()})}catch(w){try{g(w)}finally{v()}}return h})},close:f,destroy(){t||(t=!0,f().catch(()=>{}))}}}function s(e={}){const c=((e,i)=>{for(var l in i||(i={}))n.call(i,l)&&r(e,l,i[l]);if(t)for(var l of t(i))o.call(i,l)&&r(e,l,i[l]);return e})({width:480,height:270,fallbackToVideoPiP:!0,placeholder:"Playing in Document Picture-in-Picture"},e);return e=>{var t;const n=window,o="documentPictureInPicture"in n&&"function"===typeof(null==(t=n.documentPictureInPicture)?void 0:t.requestWindow);let r=e,s=e.template.$player,a=e.isDestroy;const d=e.constructor.utils,p=()=>!a&&!!r&&!r.isDestroy,f=u({alive:p,request:()=>n.documentPictureInPicture.requestWindow({width:c.width,height:c.height}),project:e=>function(e,t,n){const o=e.ownerDocument,r=e.parentNode,i=e.nextSibling;if(!r)throw new Error("Document Picture-in-Picture requires a mounted player");const c=o.createElement("div");c.className="artplayer-document-pip-placeholder",c.style.cssText="display:flex;justify-content:center;align-items:center;width:100%;height:100%;",c.textContent=null!=n?n:"";const u=t.createElement("div");u.id="__art_dpip_root";const s=[];let a=!1;const d=()=>{const t=c.parentNode===r?c:(null==i?void 0:i.parentNode)===r?i:null;if(e.parentNode!==r||e.nextSibling!==t)try{r.insertBefore(e,t)}catch(n){throw o.body.appendChild(e),n}},p=()=>{const e=l([d,()=>c.remove(),...s.splice(0).map(e=>()=>e.remove()),()=>u.remove()]);if(e.length)throw e[0]};return{mount(){if(!a){if(r.insertBefore(c,(null==i?void 0:i.parentNode)===r?i:null),a||t.body.appendChild(u),a||function(e,t,n,o){const r=e=>{o()&&(n(e),t.head.appendChild(e),o()||e.remove())},i=t.createElement("style");if(i.textContent="\n html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }\n #__art_dpip_root { position:absolute; inset:0; display:flex; }\n #__art_dpip_root > * { width:100% !important; height:100% !important; }\n ",r(i),!t.querySelector('meta[name="viewport"]')){const e=t.createElement("meta");e.name="viewport",e.content="width=device-width,initial-scale=1",r(e)}try{e.querySelectorAll('link[rel="stylesheet"]').forEach(e=>{const n=t.createElement("link");n.rel="stylesheet",n.href=e.href,e.media&&(n.media=e.media),e.crossOrigin&&(n.crossOrigin=e.crossOrigin),e.referrerPolicy&&(n.referrerPolicy=e.referrerPolicy),r(n)})}catch(l){}try{e.querySelectorAll("styleLine truncated
|
||||
@@ -1,194 +1,481 @@
|
||||
/*!
|
||||
* artplayer-plugin-document-pip.js v1.1.0
|
||||
* artplayer-plugin-document-pip.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
const style = ".artplayer-document-pip.art-video-player {\n width: 100% !important;\n height: 100% !important;\n}\n";
|
||||
function artplayerPluginDocumentPip(userOptions = {}) {
|
||||
const options = {
|
||||
width: 480,
|
||||
height: 270,
|
||||
fallbackToVideoPiP: true,
|
||||
placeholder: `Playing in Document Picture-in-Picture`,
|
||||
...userOptions
|
||||
function releaseAll(releases) {
|
||||
const errors = [];
|
||||
for (const release of releases) {
|
||||
try {
|
||||
release();
|
||||
} catch (error) {
|
||||
errors.push(error);
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
function createDelay() {
|
||||
let finish;
|
||||
const promise = new Promise((resolve) => {
|
||||
finish = resolve;
|
||||
});
|
||||
let timer = setTimeout(() => {
|
||||
timer = null;
|
||||
finish();
|
||||
}, 100);
|
||||
return {
|
||||
promise,
|
||||
cancel() {
|
||||
if (timer !== null)
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
finish();
|
||||
}
|
||||
};
|
||||
return (art) => {
|
||||
const isSupported = "documentPictureInPicture" in window && typeof window.documentPictureInPicture?.requestWindow === "function";
|
||||
const { proxy, icons, i18n, template: { $player }, constructor: { utils: { append, tooltip, addClass, removeClass, sleep } } } = art;
|
||||
const state = {
|
||||
win: null,
|
||||
originalParent: null,
|
||||
originalNext: null,
|
||||
currentDoc: null,
|
||||
placeholder: null
|
||||
};
|
||||
function copyStylesTo(targetDoc) {
|
||||
const base = targetDoc.createElement("style");
|
||||
base.textContent = `
|
||||
html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }
|
||||
#__art_dpip_root { position:absolute; inset:0; display:flex; }
|
||||
#__art_dpip_root > * { width:100% !important; height:100% !important; }
|
||||
`;
|
||||
targetDoc.head.appendChild(base);
|
||||
if (!targetDoc.querySelector('meta[name="viewport"]')) {
|
||||
const meta = targetDoc.createElement("meta");
|
||||
meta.name = "viewport";
|
||||
meta.content = "width=device-width,initial-scale=1";
|
||||
targetDoc.head.appendChild(meta);
|
||||
}
|
||||
}
|
||||
function createControl(art, toggle, alive) {
|
||||
const utils = art.constructor.utils;
|
||||
const releases = [];
|
||||
let closed = false;
|
||||
return {
|
||||
mount() {
|
||||
if (closed || !alive())
|
||||
return;
|
||||
releases.push(() => art.controls.remove("document-pip"));
|
||||
art.controls.add({
|
||||
name: "document-pip",
|
||||
position: "right",
|
||||
index: 40,
|
||||
tooltip: art.i18n.get("PIP Mode"),
|
||||
mounted: (control) => {
|
||||
if (closed || !alive())
|
||||
return;
|
||||
utils.append(control, art.icons.pip);
|
||||
const click = () => {
|
||||
if (alive())
|
||||
toggle();
|
||||
};
|
||||
releases.push(() => control.removeEventListener("click", click));
|
||||
const unbind = art.proxy(control, "click", click);
|
||||
if (closed)
|
||||
unbind();
|
||||
else
|
||||
releases.push(unbind);
|
||||
if (closed || !alive())
|
||||
return;
|
||||
const update = (active) => {
|
||||
if (alive())
|
||||
utils.tooltip(control, art.i18n.get(active ? "Exit PIP Mode" : "PIP Mode"));
|
||||
};
|
||||
releases.push(() => art.off("document-pip", update));
|
||||
art.on("document-pip", update);
|
||||
}
|
||||
});
|
||||
if (closed)
|
||||
art.controls.remove("document-pip");
|
||||
},
|
||||
destroy() {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
const errors = releaseAll(releases.splice(0).reverse());
|
||||
if (errors.length)
|
||||
throw errors[0];
|
||||
}
|
||||
};
|
||||
}
|
||||
const style = ".artplayer-document-pip.art-video-player {\n width: 100% !important;\n height: 100% !important;\n}\n";
|
||||
function installStyle(document2) {
|
||||
const id = "artplayer-plugin-document-pip";
|
||||
const existing = document2.getElementById(id);
|
||||
if (existing) {
|
||||
existing.textContent = style;
|
||||
return;
|
||||
}
|
||||
const element = document2.createElement("style");
|
||||
element.id = id;
|
||||
element.textContent = style;
|
||||
const insert = () => {
|
||||
document2.removeEventListener("DOMContentLoaded", insert);
|
||||
const current = document2.getElementById(id);
|
||||
if (current)
|
||||
current.textContent = style;
|
||||
else
|
||||
(document2.head || document2.documentElement).appendChild(element);
|
||||
};
|
||||
if (document2.readyState === "loading")
|
||||
document2.addEventListener("DOMContentLoaded", insert);
|
||||
else
|
||||
insert();
|
||||
}
|
||||
function copyStyles(source, target, own, alive) {
|
||||
const append = (node) => {
|
||||
if (!alive())
|
||||
return;
|
||||
own(node);
|
||||
target.head.appendChild(node);
|
||||
if (!alive())
|
||||
node.remove();
|
||||
};
|
||||
const base = target.createElement("style");
|
||||
base.textContent = `
|
||||
html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }
|
||||
#__art_dpip_root { position:absolute; inset:0; display:flex; }
|
||||
#__art_dpip_root > * { width:100% !important; height:100% !important; }
|
||||
`;
|
||||
append(base);
|
||||
if (!target.querySelector('meta[name="viewport"]')) {
|
||||
const meta = target.createElement("meta");
|
||||
meta.name = "viewport";
|
||||
meta.content = "width=device-width,initial-scale=1";
|
||||
append(meta);
|
||||
}
|
||||
try {
|
||||
source.querySelectorAll('link[rel="stylesheet"]').forEach((link) => {
|
||||
const clone = target.createElement("link");
|
||||
clone.rel = "stylesheet";
|
||||
clone.href = link.href;
|
||||
if (link.media)
|
||||
clone.media = link.media;
|
||||
if (link.crossOrigin)
|
||||
clone.crossOrigin = link.crossOrigin;
|
||||
if (link.referrerPolicy)
|
||||
clone.referrerPolicy = link.referrerPolicy;
|
||||
append(clone);
|
||||
});
|
||||
} catch {
|
||||
}
|
||||
try {
|
||||
source.querySelectorAll("style").forEach((element) => {
|
||||
const clone = target.createElement("style");
|
||||
clone.textContent = element.textContent;
|
||||
append(clone);
|
||||
});
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
function createProjection(player, target, text) {
|
||||
const source = player.ownerDocument;
|
||||
const parent = player.parentNode;
|
||||
const next = player.nextSibling;
|
||||
if (!parent)
|
||||
throw new Error("Document Picture-in-Picture requires a mounted player");
|
||||
const placeholder = source.createElement("div");
|
||||
placeholder.className = "artplayer-document-pip-placeholder";
|
||||
placeholder.style.cssText = "display:flex;justify-content:center;align-items:center;width:100%;height:100%;";
|
||||
placeholder.textContent = text ?? "";
|
||||
const root = target.createElement("div");
|
||||
root.id = "__art_dpip_root";
|
||||
const nodes = [];
|
||||
let closed = false;
|
||||
const restore = () => {
|
||||
const anchor = placeholder.parentNode === parent ? placeholder : next?.parentNode === parent ? next : null;
|
||||
if (player.parentNode !== parent || player.nextSibling !== anchor) {
|
||||
try {
|
||||
document.querySelectorAll('link[rel="stylesheet"]').forEach((link) => {
|
||||
const clone = targetDoc.createElement("link");
|
||||
clone.rel = "stylesheet";
|
||||
clone.href = link.href;
|
||||
if (link.media)
|
||||
clone.media = link.media;
|
||||
if (link.crossOrigin)
|
||||
clone.crossOrigin = link.crossOrigin;
|
||||
if (link.referrerPolicy)
|
||||
clone.referrerPolicy = link.referrerPolicy;
|
||||
targetDoc.head.appendChild(clone);
|
||||
});
|
||||
} catch {
|
||||
}
|
||||
try {
|
||||
document.querySelectorAll("style").forEach((style2) => {
|
||||
const clone = targetDoc.createElement("style");
|
||||
clone.textContent = style2.textContent;
|
||||
targetDoc.head.appendChild(clone);
|
||||
});
|
||||
} catch {
|
||||
parent.insertBefore(player, anchor);
|
||||
} catch (error) {
|
||||
source.body.appendChild(player);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
const cleanup = () => {
|
||||
const errors = releaseAll([restore, () => placeholder.remove(), ...nodes.splice(0).map((node) => () => node.remove()), () => root.remove()]);
|
||||
if (errors.length)
|
||||
throw errors[0];
|
||||
};
|
||||
return {
|
||||
mount() {
|
||||
if (closed)
|
||||
return;
|
||||
parent.insertBefore(placeholder, next?.parentNode === parent ? next : null);
|
||||
if (!closed)
|
||||
target.body.appendChild(root);
|
||||
if (!closed)
|
||||
copyStyles(source, target, (node) => nodes.push(node), () => !closed);
|
||||
if (!closed) {
|
||||
const adopted = target.adoptNode(player);
|
||||
if (!closed)
|
||||
root.appendChild(adopted);
|
||||
}
|
||||
if (closed)
|
||||
cleanup();
|
||||
},
|
||||
destroy() {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
cleanup();
|
||||
}
|
||||
};
|
||||
}
|
||||
function createWindowSession(hooks) {
|
||||
let destroyed = false;
|
||||
let revision = 0;
|
||||
let session = null;
|
||||
let pending = null;
|
||||
let delay = null;
|
||||
const alive = () => !destroyed && hooks.alive();
|
||||
const valid = (value) => value === revision && alive();
|
||||
function invalidate() {
|
||||
revision++;
|
||||
pending?.finish();
|
||||
pending = null;
|
||||
delay?.cancel();
|
||||
delay = null;
|
||||
}
|
||||
function dispose(current) {
|
||||
const errors = releaseAll(current.releases.splice(0));
|
||||
errors.push(...releaseAll([() => current.window.close()]));
|
||||
return errors;
|
||||
}
|
||||
async function resizeLater(value) {
|
||||
if (!valid(value))
|
||||
return;
|
||||
const current = createDelay();
|
||||
delay = current;
|
||||
await current.promise;
|
||||
if (delay === current)
|
||||
delay = null;
|
||||
if (valid(value))
|
||||
hooks.resize();
|
||||
}
|
||||
async function close() {
|
||||
invalidate();
|
||||
const value = revision;
|
||||
const current = session;
|
||||
session = null;
|
||||
if (!current)
|
||||
return;
|
||||
const errors = dispose(current);
|
||||
if (current.announced) {
|
||||
try {
|
||||
hooks.activate(false);
|
||||
} catch (error) {
|
||||
errors.push(error);
|
||||
}
|
||||
}
|
||||
if (errors.length && alive())
|
||||
hooks.report("close", errors[0]);
|
||||
if (valid(value))
|
||||
await resizeLater(value);
|
||||
}
|
||||
async function open() {
|
||||
if (!alive() || session)
|
||||
return;
|
||||
if (pending)
|
||||
return pending.promise;
|
||||
invalidate();
|
||||
const value = revision;
|
||||
let finish;
|
||||
let reject;
|
||||
const promise = new Promise((resolve, fail) => {
|
||||
finish = resolve;
|
||||
reject = fail;
|
||||
});
|
||||
const ticket = { promise, finish };
|
||||
pending = ticket;
|
||||
const settle = () => {
|
||||
if (pending === ticket)
|
||||
pending = null;
|
||||
finish();
|
||||
};
|
||||
const failed = (error) => {
|
||||
if (valid(value)) {
|
||||
const current = session;
|
||||
session = null;
|
||||
if (current) {
|
||||
dispose(current);
|
||||
if (current.announced)
|
||||
releaseAll([() => hooks.activate(false)]);
|
||||
}
|
||||
try {
|
||||
hooks.report("open", error);
|
||||
} catch (noticeError) {
|
||||
reject(noticeError);
|
||||
}
|
||||
}
|
||||
};
|
||||
const receive = async (window2) => {
|
||||
if (!valid(value)) {
|
||||
if (session?.window !== window2)
|
||||
releaseAll([() => window2.close()]);
|
||||
return;
|
||||
}
|
||||
const current = { window: window2, releases: [], announced: false };
|
||||
session = current;
|
||||
try {
|
||||
const projection = hooks.project(window2.document);
|
||||
current.releases.push(projection.destroy);
|
||||
projection.mount();
|
||||
if (!valid(value)) {
|
||||
dispose(current);
|
||||
return;
|
||||
}
|
||||
for (const [event, callback] of [["resize", () => {
|
||||
if (valid(value))
|
||||
hooks.nativeResize();
|
||||
}], ["pagehide", () => {
|
||||
void close();
|
||||
}], ["unload", () => {
|
||||
void close();
|
||||
}]]) {
|
||||
current.releases.unshift(() => window2.removeEventListener(event, callback));
|
||||
window2.addEventListener(event, callback);
|
||||
if (!valid(value)) {
|
||||
dispose(current);
|
||||
return;
|
||||
}
|
||||
}
|
||||
current.announced = true;
|
||||
hooks.activate(true);
|
||||
await resizeLater(value);
|
||||
} catch (error) {
|
||||
failed(error);
|
||||
}
|
||||
};
|
||||
try {
|
||||
const request = hooks.request();
|
||||
void Promise.resolve(request).then(receive, failed).then(settle, (error) => {
|
||||
if (valid(value))
|
||||
reject(error);
|
||||
settle();
|
||||
});
|
||||
} catch (error) {
|
||||
try {
|
||||
failed(error);
|
||||
} finally {
|
||||
settle();
|
||||
}
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
return {
|
||||
get active() {
|
||||
return session !== null;
|
||||
},
|
||||
get opening() {
|
||||
return pending !== null;
|
||||
},
|
||||
open,
|
||||
close,
|
||||
destroy() {
|
||||
if (destroyed)
|
||||
return;
|
||||
destroyed = true;
|
||||
void close().catch(() => {
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
function artplayerPluginDocumentPip(userOptions = {}) {
|
||||
const options = { width: 480, height: 270, fallbackToVideoPiP: true, placeholder: "Playing in Document Picture-in-Picture", ...userOptions };
|
||||
return (art) => {
|
||||
const browser = window;
|
||||
const isSupported = "documentPictureInPicture" in browser && typeof browser.documentPictureInPicture?.requestWindow === "function";
|
||||
let host = art;
|
||||
let player = art.template.$player;
|
||||
let closed = art.isDestroy;
|
||||
const utils = art.constructor.utils;
|
||||
const alive = () => !closed && !!host && !host.isDestroy;
|
||||
const session = createWindowSession({
|
||||
alive,
|
||||
request: () => browser.documentPictureInPicture.requestWindow({ width: options.width, height: options.height }),
|
||||
project: (document2) => createProjection(player, document2, options.placeholder),
|
||||
activate(active) {
|
||||
if (!host || !player)
|
||||
return;
|
||||
if (active)
|
||||
utils.addClass(player, "artplayer-document-pip");
|
||||
else
|
||||
utils.removeClass(player, "artplayer-document-pip");
|
||||
if (!alive())
|
||||
return;
|
||||
host.events.bindGlobalEvents?.();
|
||||
if (alive())
|
||||
host.emit("document-pip", active);
|
||||
},
|
||||
resize: () => {
|
||||
if (alive())
|
||||
host.emit("resize");
|
||||
},
|
||||
nativeResize: () => {
|
||||
if (alive())
|
||||
host.resize?.();
|
||||
},
|
||||
report(action, error) {
|
||||
if (!alive())
|
||||
return;
|
||||
host.notice.show = `Document Picture-in-Picture ${action} failed`;
|
||||
console.warn(`[artplayer-plugin-document-pip] ${action} failed:`, error);
|
||||
}
|
||||
});
|
||||
async function open() {
|
||||
if (!alive())
|
||||
return;
|
||||
if (!isSupported && options.fallbackToVideoPiP) {
|
||||
art.pip = true;
|
||||
host.pip = true;
|
||||
console.warn("[artplayer-plugin-document-pip] Document Picture-in-Picture is not supported, falling back to Video Picture-in-Picture");
|
||||
return;
|
||||
}
|
||||
if (state.win)
|
||||
return;
|
||||
try {
|
||||
const pipWin = await window.documentPictureInPicture.requestWindow({
|
||||
width: options.width,
|
||||
height: options.height
|
||||
});
|
||||
state.win = pipWin;
|
||||
state.currentDoc = pipWin.document;
|
||||
state.placeholder = document.createElement("div");
|
||||
state.placeholder.className = "artplayer-document-pip-placeholder";
|
||||
state.placeholder.style.cssText = `display:flex;justify-content:center;align-items:center;width:100%;height:100%;`;
|
||||
state.placeholder.textContent = options.placeholder;
|
||||
state.originalParent = $player.parentNode;
|
||||
state.originalNext = $player.nextSibling;
|
||||
state.originalParent.insertBefore(state.placeholder, state.originalNext);
|
||||
const root = pipWin.document.createElement("div");
|
||||
root.id = "__art_dpip_root";
|
||||
pipWin.document.body.appendChild(root);
|
||||
copyStylesTo(pipWin.document);
|
||||
const adopted = pipWin.document.adoptNode($player);
|
||||
root.appendChild(adopted);
|
||||
state.currentDoc = pipWin.document;
|
||||
const onResize = () => art.resize?.();
|
||||
const onClose = () => close();
|
||||
pipWin.addEventListener("resize", onResize);
|
||||
pipWin.addEventListener("pagehide", onClose);
|
||||
pipWin.addEventListener("unload", onClose);
|
||||
state.cleanup = () => {
|
||||
pipWin.removeEventListener("resize", onResize);
|
||||
pipWin.removeEventListener("pagehide", onClose);
|
||||
pipWin.removeEventListener("unload", onClose);
|
||||
};
|
||||
addClass($player, "artplayer-document-pip");
|
||||
art.events.bindGlobalEvents?.();
|
||||
art.emit("document-pip", true);
|
||||
await sleep(100);
|
||||
art.emit("resize");
|
||||
} catch (err) {
|
||||
art.notice.show = "Document Picture-in-Picture open failed";
|
||||
console.warn("[artplayer-plugin-document-pip] open failed:", err);
|
||||
}
|
||||
}
|
||||
function restoreToOriginalDocument() {
|
||||
if (!state.placeholder)
|
||||
return;
|
||||
const backDoc = state.placeholder.ownerDocument || document;
|
||||
const adoptedBack = backDoc.adoptNode($player);
|
||||
state.originalParent.insertBefore(adoptedBack, state.placeholder);
|
||||
state.placeholder.remove();
|
||||
state.placeholder = null;
|
||||
state.currentDoc = backDoc;
|
||||
}
|
||||
async function close() {
|
||||
if (!state.win)
|
||||
return;
|
||||
try {
|
||||
state.cleanup?.();
|
||||
restoreToOriginalDocument();
|
||||
state.win.close();
|
||||
state.win = null;
|
||||
removeClass($player, "artplayer-document-pip");
|
||||
art.events.bindGlobalEvents?.();
|
||||
art.emit("document-pip", false);
|
||||
await sleep(100);
|
||||
art.emit("resize");
|
||||
} catch (err) {
|
||||
art.notice.show = "Document Picture-in-Picture close failed";
|
||||
console.warn("[artplayer-plugin-document-pip] close failed:", err);
|
||||
}
|
||||
return session.open();
|
||||
}
|
||||
function toggle() {
|
||||
if (state.win) {
|
||||
close();
|
||||
} else {
|
||||
open();
|
||||
}
|
||||
if (!alive())
|
||||
return;
|
||||
if (session.active || session.opening)
|
||||
void session.close();
|
||||
else
|
||||
void open();
|
||||
}
|
||||
art.controls.add({
|
||||
name: "document-pip",
|
||||
position: "right",
|
||||
index: 40,
|
||||
tooltip: art.i18n.get("PIP Mode"),
|
||||
mounted: ($control) => {
|
||||
append($control, icons.pip);
|
||||
proxy($control, "click", toggle);
|
||||
art.on("document-pip", (value) => {
|
||||
tooltip($control, i18n.get(value ? "Exit PIP Mode" : "PIP Mode"));
|
||||
});
|
||||
}
|
||||
});
|
||||
art.on("destroy", close);
|
||||
return {
|
||||
let control = createControl(art, toggle, alive);
|
||||
function destroy() {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
const current = host;
|
||||
const previousControl = control;
|
||||
control = null;
|
||||
const errors = releaseAll([session.destroy, () => previousControl?.destroy(), () => current?.off("destroy", destroy)]);
|
||||
host = null;
|
||||
player = null;
|
||||
if (errors.length)
|
||||
console.warn("[artplayer-plugin-document-pip] cleanup failed:", errors[0]);
|
||||
}
|
||||
const result = {
|
||||
name: "artplayerPluginDocumentPip",
|
||||
get isSupported() {
|
||||
return isSupported;
|
||||
},
|
||||
get isActive() {
|
||||
return !!state.win;
|
||||
return session.active;
|
||||
},
|
||||
open,
|
||||
close,
|
||||
close: session.close,
|
||||
toggle
|
||||
};
|
||||
if (closed) {
|
||||
host = null;
|
||||
player = null;
|
||||
return result;
|
||||
}
|
||||
try {
|
||||
art.on("destroy", destroy);
|
||||
if (alive())
|
||||
control?.mount();
|
||||
else
|
||||
art.off("destroy", destroy);
|
||||
} catch (error) {
|
||||
destroy();
|
||||
throw error;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
if (typeof document !== "undefined") {
|
||||
const id = "artplayer-plugin-document-pip";
|
||||
let $style = document.getElementById(id);
|
||||
if (!$style) {
|
||||
$style = document.createElement("style");
|
||||
$style.id = id;
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
document.head.appendChild($style);
|
||||
});
|
||||
} else {
|
||||
(document.head || document.documentElement).appendChild($style);
|
||||
}
|
||||
}
|
||||
$style.textContent = style;
|
||||
}
|
||||
const index = Object.assign(artplayerPluginDocumentPip, { default: artplayerPluginDocumentPip });
|
||||
if (typeof document !== "undefined")
|
||||
installStyle(document);
|
||||
export {
|
||||
artplayerPluginDocumentPip as default
|
||||
index as default
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-hls-control.js v1.1.0
|
||||
* artplayer-plugin-hls-control.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginHlsControl=e(),define(function(){return t.artplayerPluginHlsControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginHlsControl=e()}(this,function(){"use strict";function t(t,e){const l=new Map;return t.filter(t=>{const o=t[e];return void 0===o||!l.has(o)&&l.set(o,1)})}return function(e={}){return l=>{const{$video:o}=l.template,{errorHandle:n}=l.constructor.utils;function i(){n(l.hls?.media===o,'Cannot find instance of HLS from "art.hls"'),function(o){if(!o.levels.length)return;const n=e.quality||{},i=n.auto||"Auto",s=n.title||"Quality",a=n.getName||(t=>t.name||`${t.height}P`),c=o.levels[o.currentLevel],r=c?a(c):i,u=t(o.levels.map((t,e)=>({html:a(t,e),value:e,default:o.currentLevel===e})),"html").sort((t,e)=>e.value-t.value);u.push({html:i,value:-1,default:-1===o.currentLevel});const h=t=>(o.currentLevel=t.value,l.notice.show=`${s}: ${t.html}`,n.control&&l.controls.check(t),n.setting&&l.setting.check(t),t.html);n.control&&l.controls.update({name:"hls-quality",position:"right",html:r,style:{padding:"0 10px"},selector:u,onSelect:h}),n.setting&&l.setting.update({name:"hls-quality",tooltip:r,html:s,icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>',width:200,selector:u,onSelect:h})}(l.hls),function(o){if(!o.audioTracks.length)return;const n=e.audio||{},i=n.auto||"Auto",s=n.title||"Audio",a=n.getName||(t=>t.name||t.lang||t.language),c=o.audioTracks[o.audioTrack],r=c?a(c):i,u=t(o.audioTracks.map((t,e)=>({html:a(t,e),value:t.id,default:o.audioTrack===t.id})),"html"),h=t=>(o.audioTrack=t.value,l.notice.show=`${s}: ${t.html}`,n.control&&l.controls.check(t),n.setting&&l.setting.check(t),t.html);n.control&&l.controls.update({name:"hls-audio",position:"right",html:r,style:{padding:"0 10px"},selector:u,onSelect:h}),n.setting&&l.setting.update({name:"hls-audio",tooltip:r,html:s,icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>',width:200,selector:u,onSelect:h})}(l.hls)}return l.on("ready",i),l.on("restart",i),{name:"artplayerPluginHlsControl",update:i}}}});
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginHlsControl=e(),define(function(){return t.artplayerPluginHlsControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginHlsControl=e()}(this,function(){"use strict";function t(t){const e=new Map;return t.filter(t=>{if(void 0===t.html)return!0;const o=e.get(t.html);return o?(t.default&&(o.default=!0,o.value=t.value),!1):(e.set(t.html,t),!0)})}function e(t,e,o,n,l,i){let r;const c={control:!1,setting:!1};function s(o){c[o]&&(c[o]=!1,t["control"===o?"controls":"setting"].remove(e))}function u(){r=void 0,s("control"),s("setting")}function a(e,o){for(const t of e.model.selector)t.default=t===o;e.config.control&&t.controls.check(o),e===r&&l(e.hls)&&e.config.setting&&t.setting.check(o)}return{update:function(f,d,h,m){if(!h)return void u();const g=r,v=h.selector.findIndex(t=>t.default);if(!m&&g?.hls===f&&g.model.title===h.title&&(-1!==v||!g.model.selector.some(t=>t.default)&&g.model.html===h.html)&&c.control===Boolean(d.control)&&c.setting===Boolean(d.setting)&&g.model.selector.length===h.selector.length&&g.model.selector.every((t,e)=>t.html===h.selector[e].html&&t.value===h.selector[e].value)){g.config=d;const t=g.model.selector[v];return void(!t||t.default&&g.model.html===h.html||(g.model.html=h.html,a(g,t)))}const p={hls:f,config:d,model:h};r=p;const y=()=>r===p&&l(f),T=e=>i(()=>y()?(f[o]=e.value,y()?(h.html=e.html,t.notice.show=`${h.title}: ${e.html}`,y()&&a(p,e),e.html):e.html):e.html);d.control?(c.control=!0,t.controls.update({name:e,position:"right",html:h.html,style:{padding:"0 10px"},selector:h.selector,onSelect:T})):s("control"),y()&&(d.setting?(c.setting=!0,t.setting.update({name:e,tooltip:h.html,html:h.title,icon:n,width:200,selector:h.selector,onSelect:T})):s("setting"))},clear:u,invalidate:function(){r=void 0}}}return function(o={}){return n=>{const l=n,{$video:i}=l.template,{errorHandle:r}=l.constructor.utils;let c,s,u=!1,a=0,f=()=>{},d=0;const h=new WeakSet,m=t=>!u&&!h.has(t)&&l.hls===t&&t.media===i,g=e(l,"hls-quality","currentLevel",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>',m,p),v=e(l,"hls-audio","audioTrack",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>',m,p);function p(t){d++;let e=!1;try{const o=t();return e=!0,o}finally{if(d--,!d){const t=s;s=void 0,e&&t&&y(t,!1)}}}function y(e,n){if(!m(e))return;const l=++a,i=o.quality||{},r=function(e,o){if(!e.levels.length)return null;const n=o.auto||"Auto",l=o.getName||(t=>t.name||`${t.height}P`),i=function(t){return!0===t.autoLevelEnabled?-1:t.currentLevel}(e),r=e.levels[i],c=r?l(r):n,s=t(e.levels.map((t,e)=>({html:l(t,e),value:e,default:i===e}))).sort((t,e)=>e.value-t.value);return s.push({html:n,value:-1,default:-1===i}),{html:c,title:o.title||"Quality",selector:s}}(e,i);if(!m(e)||l!==a)return;if(g.update(e,i,r,n),!m(e)||l!==a)return;const c=o.audio||{},s=function(e,o){if(!e.audioTracks.length)return null;const n=o.auto||"Auto",l=o.getName||(t=>t.name||t.lang||t.language),i=e.audioTracks[e.audioTrack],r=i?l(i):n,c=t(e.audioTracks.map((t,o)=>({html:l(t,o),value:t.id,default:e.audioTrack===t.id})));return{html:r,title:o.title||"Audio",selector:c}}(e,c);m(e)&&l===a&&v.update(e,c,s,n)}function T(){if(u)return;const t=l.hls;if(r(t?.media===i,'Cannot find instance of HLS from "art.hls"'),!h.has(t)){if(c!==t){f(),c=t;try{f=function(t,e,o){const n=t.constructor?.Events;if(!n||"function"!==typeof t.on||"function"!==typeof t.off)return()=>{};const l=t,i=[];let r=!0;function c(){if(r){r=!1;for(const[t,e]of i)l.off(t,e);i.length=0}}try{for(const t of["MANIFEST_PARSED","LEVELS_UPDATED","LEVEL_SWITCHED","AUDIO_TRACKS_UPDATED","AUDIO_TRACK_SWITCHED","DESTROYING"]){const c=n[t];if("string"!==typeof c||i.some(([t])=>t===c))continue;const s=()=>{r&&("DESTROYING"===t?o():e())};i.push([c,s]),l.on(c,s)}}catch(s){throw c(),s}return c}(t,()=>{d?s=t:y(t,!1)},()=>{h.add(t),f(),c===t&&(c=void 0,u||(g.clear(),v.clear()))})}catch(e){throw c=void 0,e}}y(t,!0)}}return l.on("ready",T),l.on("restart",T),l.on("destroy",function t(){u||(u=!0,a++,s=void 0,g.invalidate(),v.invalidate(),f(),l.offLine truncated
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-hls-control.js v1.1.0
|
||||
* artplayer-plugin-hls-control.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginHlsControl=e(),define(function(){return t.artplayerPluginHlsControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginHlsControl=e()}(this,function(){"use strict";function t(t,e){const l=new Map;return t.filter(t=>{const o=t[e];return void 0===o||!l.has(o)&&l.set(o,1)})}return function(e={}){return l=>{const{$video:o}=l.template,{errorHandle:n}=l.constructor.utils;function i(){var i;n((null==(i=l.hls)?void 0:i.media)===o,'Cannot find instance of HLS from "art.hls"'),function(o){if(!o.levels.length)return;const n=e.quality||{},i=n.auto||"Auto",a=n.title||"Quality",s=n.getName||(t=>t.name||`${t.height}P`),c=o.levels[o.currentLevel],r=c?s(c):i,u=t(o.levels.map((t,e)=>({html:s(t,e),value:e,default:o.currentLevel===e})),"html").sort((t,e)=>e.value-t.value);u.push({html:i,value:-1,default:-1===o.currentLevel});const h=t=>(o.currentLevel=t.value,l.notice.show=`${a}: ${t.html}`,n.control&&l.controls.check(t),n.setting&&l.setting.check(t),t.html);n.control&&l.controls.update({name:"hls-quality",position:"right",html:r,style:{padding:"0 10px"},selector:u,onSelect:h}),n.setting&&l.setting.update({name:"hls-quality",tooltip:r,html:a,icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>',width:200,selector:u,onSelect:h})}(l.hls),function(o){if(!o.audioTracks.length)return;const n=e.audio||{},i=n.auto||"Auto",a=n.title||"Audio",s=n.getName||(t=>t.name||t.lang||t.language),c=o.audioTracks[o.audioTrack],r=c?s(c):i,u=t(o.audioTracks.map((t,e)=>({html:s(t,e),value:t.id,default:o.audioTrack===t.id})),"html"),h=t=>(o.audioTrack=t.value,l.notice.show=`${a}: ${t.html}`,n.control&&l.controls.check(t),n.setting&&l.setting.check(t),t.html);n.control&&l.controls.update({name:"hls-audio",position:"right",html:r,style:{padding:"0 10px"},selector:u,onSelect:h}),n.setting&&l.setting.update({name:"hls-audio",tooltip:r,html:a,icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>',width:200,selector:u,onSelect:h})}(l.hls)}return l.on("ready",i),l.on("restart",i),{name:"artplayerPluginHlsControl",update:i}}}});
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginHlsControl=e(),define(function(){return t.artplayerPluginHlsControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginHlsControl=e()}(this,function(){"use strict";function t(t){const e=new Map;return t.filter(t=>{if(void 0===t.html)return!0;const o=e.get(t.html);return o?(t.default&&(o.default=!0,o.value=t.value),!1):(e.set(t.html,t),!0)})}function e(t,e,o,l,n,i){let r;const c={control:!1,setting:!1};function s(o){c[o]&&(c[o]=!1,t["control"===o?"controls":"setting"].remove(e))}function u(){r=void 0,s("control"),s("setting")}function a(e,o){for(const t of e.model.selector)t.default=t===o;e.config.control&&t.controls.check(o),e===r&&n(e.hls)&&e.config.setting&&t.setting.check(o)}return{update:function(f,d,h,m){if(!h)return void u();const g=r,v=h.selector.findIndex(t=>t.default);if(!m&&(null==g?void 0:g.hls)===f&&g.model.title===h.title&&(-1!==v||!g.model.selector.some(t=>t.default)&&g.model.html===h.html)&&c.control===Boolean(d.control)&&c.setting===Boolean(d.setting)&&g.model.selector.length===h.selector.length&&g.model.selector.every((t,e)=>t.html===h.selector[e].html&&t.value===h.selector[e].value)){g.config=d;const t=g.model.selector[v];return void(!t||t.default&&g.model.html===h.html||(g.model.html=h.html,a(g,t)))}const p={hls:f,config:d,model:h};r=p;const y=()=>r===p&&n(f),T=e=>i(()=>y()?(f[o]=e.value,y()?(h.html=e.html,t.notice.show=`${h.title}: ${e.html}`,y()&&a(p,e),e.html):e.html):e.html);d.control?(c.control=!0,t.controls.update({name:e,position:"right",html:h.html,style:{padding:"0 10px"},selector:h.selector,onSelect:T})):s("control"),y()&&(d.setting?(c.setting=!0,t.setting.update({name:e,tooltip:h.html,html:h.title,icon:l,width:200,selector:h.selector,onSelect:T})):s("setting"))},clear:u,invalidate:function(){r=void 0}}}return function(o={}){return l=>{const n=l,{$video:i}=n.template,{errorHandle:r}=n.constructor.utils;let c,s,u=!1,a=0,f=()=>{},d=0;const h=new WeakSet,m=t=>!u&&!h.has(t)&&n.hls===t&&t.media===i,g=e(n,"hls-quality","currentLevel",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>',m,p),v=e(n,"hls-audio","audioTrack",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>',m,p);function p(t){d++;let e=!1;try{const o=t();return e=!0,o}finally{if(d--,!d){const t=s;s=void 0,e&&t&&y(t,!1)}}}function y(e,l){if(!m(e))return;const n=++a,i=o.quality||{},r=function(e,o){if(!e.levels.length)return null;const l=o.auto||"Auto",n=o.getName||(t=>t.name||`${t.height}P`),i=function(t){return!0===t.autoLevelEnabled?-1:t.currentLevel}(e),r=e.levels[i],c=r?n(r):l,s=t(e.levels.map((t,e)=>({html:n(t,e),value:e,default:i===e}))).sort((t,e)=>e.value-t.value);return s.push({html:l,value:-1,default:-1===i}),{html:c,title:o.title||"Quality",selector:s}}(e,i);if(!m(e)||n!==a)return;if(g.update(e,i,r,l),!m(e)||n!==a)return;const c=o.audio||{},s=function(e,o){if(!e.audioTracks.length)return null;const l=o.auto||"Auto",n=o.getName||(t=>t.name||t.lang||t.language),i=e.audioTracks[e.audioTrack],r=i?n(i):l,c=t(e.audioTracks.map((t,o)=>({html:n(t,o),value:t.id,default:e.audioTrack===t.id})));return{html:r,title:o.title||"Audio",selector:c}}(e,c);m(e)&&n===a&&v.update(e,c,s,l)}function T(){if(u)return;const t=n.hls;if(r((null==t?void 0:t.media)===i,'Cannot find instance of HLS from "art.hls"'),!h.has(t)){if(c!==t){f(),c=t;try{f=function(t,e,o){var l;const n=null==(l=t.constructor)?void 0:l.Events;if(!n||"function"!==typeof t.on||"function"!==typeof t.off)return()=>{};const i=t,r=[];let c=!0;function s(){if(c){c=!1;for(const[t,e]of r)i.off(t,e);r.length=0}}try{for(const t of["MANIFEST_PARSED","LEVELS_UPDATED","LEVEL_SWITCHED","AUDIO_TRACKS_UPDATED","AUDIO_TRACK_SWITCHED","DESTROYING"]){const l=n[t];if("string"!==typeof l||r.some(([t])=>t===l))continue;const s=()=>{c&&("DESTROYING"===t?o():e())};r.push([l,s]),i.on(l,s)}}catch(u){throw s(),u}return s}(t,()=>{d?s=t:y(t,!1)},()=>{h.add(t),f(),c===t&&(c=void 0,u||(g.clear(),v.clear()))})}catch(e){throw c=void 0,e}}y(t,!0)}}return n.on("ready",T),n.on("restart",T),n.on("destroy",function t(){u||(uLine truncated
|
||||
@@ -1,141 +1,267 @@
|
||||
/*!
|
||||
* artplayer-plugin-hls-control.js v1.1.0
|
||||
* artplayer-plugin-hls-control.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
const $audio = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>';
|
||||
const $quality = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>';
|
||||
function uniqBy(array, property) {
|
||||
function uniqueLabels(items) {
|
||||
const seen = /* @__PURE__ */ new Map();
|
||||
return array.filter((item) => {
|
||||
const key = item[property];
|
||||
if (key === void 0) {
|
||||
return items.filter((item) => {
|
||||
if (item.html === void 0)
|
||||
return true;
|
||||
const first = seen.get(item.html);
|
||||
if (first) {
|
||||
if (item.default) {
|
||||
first.default = true;
|
||||
first.value = item.value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return !seen.has(key) && seen.set(key, 1);
|
||||
seen.set(item.html, item);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
function qualitySelection(hls) {
|
||||
return hls.autoLevelEnabled === true ? -1 : hls.currentLevel;
|
||||
}
|
||||
function qualityModel(hls, config) {
|
||||
if (!hls.levels.length)
|
||||
return null;
|
||||
const auto = config.auto || "Auto";
|
||||
const getName = config.getName || ((level2) => level2.name || `${level2.height}P`);
|
||||
const selected = qualitySelection(hls);
|
||||
const level = hls.levels[selected];
|
||||
const html = level ? getName(level) : auto;
|
||||
const selector = uniqueLabels(hls.levels.map((item, index) => ({ html: getName(item, index), value: index, default: selected === index }))).sort((a, b) => b.value - a.value);
|
||||
selector.push({ html: auto, value: -1, default: selected === -1 });
|
||||
return { html, title: config.title || "Quality", selector };
|
||||
}
|
||||
function audioModel(hls, config) {
|
||||
if (!hls.audioTracks.length)
|
||||
return null;
|
||||
const auto = config.auto || "Auto";
|
||||
const getName = config.getName || ((track2) => track2.name || track2.lang || track2.language);
|
||||
const track = hls.audioTracks[hls.audioTrack];
|
||||
const html = track ? getName(track) : auto;
|
||||
const selector = uniqueLabels(hls.audioTracks.map((item, index) => ({ html: getName(item, index), value: item.id, default: hls.audioTrack === item.id })));
|
||||
return { html, title: config.title || "Audio", selector };
|
||||
}
|
||||
function createMenu(art, name, field, icon, active, select) {
|
||||
let current;
|
||||
const owned = { control: false, setting: false };
|
||||
function remove(surface) {
|
||||
if (!owned[surface])
|
||||
return;
|
||||
owned[surface] = false;
|
||||
art[surface === "control" ? "controls" : "setting"].remove(name);
|
||||
}
|
||||
function clear() {
|
||||
current = void 0;
|
||||
remove("control");
|
||||
remove("setting");
|
||||
}
|
||||
function check(state, item) {
|
||||
for (const entry of state.model.selector)
|
||||
entry.default = entry === item;
|
||||
if (state.config.control)
|
||||
art.controls.check(item);
|
||||
if (state !== current || !active(state.hls))
|
||||
return;
|
||||
if (state.config.setting)
|
||||
art.setting.check(item);
|
||||
}
|
||||
function update(hls, config, model, force) {
|
||||
if (!model) {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
const previous = current;
|
||||
const selectedIndex = model.selector.findIndex((item) => item.default);
|
||||
const reusable = !force && previous?.hls === hls && previous.model.title === model.title && (selectedIndex !== -1 || !previous.model.selector.some((item) => item.default) && previous.model.html === model.html) && owned.control === Boolean(config.control) && owned.setting === Boolean(config.setting) && previous.model.selector.length === model.selector.length && previous.model.selector.every((item, index) => item.html === model.selector[index].html && item.value === model.selector[index].value);
|
||||
if (reusable) {
|
||||
previous.config = config;
|
||||
const target = previous.model.selector[selectedIndex];
|
||||
if (target && (!target.default || previous.model.html !== model.html)) {
|
||||
previous.model.html = model.html;
|
||||
check(previous, target);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const state = { hls, config, model };
|
||||
current = state;
|
||||
const valid = () => current === state && active(hls);
|
||||
const onSelect = (item) => select(() => {
|
||||
if (!valid())
|
||||
return item.html;
|
||||
hls[field] = item.value;
|
||||
if (!valid())
|
||||
return item.html;
|
||||
model.html = item.html;
|
||||
art.notice.show = `${model.title}: ${item.html}`;
|
||||
if (valid())
|
||||
check(state, item);
|
||||
return item.html;
|
||||
});
|
||||
if (config.control) {
|
||||
owned.control = true;
|
||||
art.controls.update({ name, position: "right", html: model.html, style: { padding: "0 10px" }, selector: model.selector, onSelect });
|
||||
} else {
|
||||
remove("control");
|
||||
}
|
||||
if (!valid())
|
||||
return;
|
||||
if (config.setting) {
|
||||
owned.setting = true;
|
||||
art.setting.update({ name, tooltip: model.html, html: model.title, icon, width: 200, selector: model.selector, onSelect });
|
||||
} else {
|
||||
remove("setting");
|
||||
}
|
||||
}
|
||||
function invalidate() {
|
||||
current = void 0;
|
||||
}
|
||||
return { update, clear, invalidate };
|
||||
}
|
||||
const $quality = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>';
|
||||
function subscribeHls(hls, refresh, destroyed) {
|
||||
const events = hls.constructor?.Events;
|
||||
if (!events || typeof hls.on !== "function" || typeof hls.off !== "function")
|
||||
return () => {
|
||||
};
|
||||
const source = hls;
|
||||
const subscriptions = [];
|
||||
let active = true;
|
||||
function release() {
|
||||
if (!active)
|
||||
return;
|
||||
active = false;
|
||||
for (const [event, callback] of subscriptions)
|
||||
source.off(event, callback);
|
||||
subscriptions.length = 0;
|
||||
}
|
||||
try {
|
||||
for (const key of ["MANIFEST_PARSED", "LEVELS_UPDATED", "LEVEL_SWITCHED", "AUDIO_TRACKS_UPDATED", "AUDIO_TRACK_SWITCHED", "DESTROYING"]) {
|
||||
const event = events[key];
|
||||
if (typeof event !== "string" || subscriptions.some(([name]) => name === event))
|
||||
continue;
|
||||
const callback = () => {
|
||||
if (!active)
|
||||
return;
|
||||
if (key === "DESTROYING")
|
||||
destroyed();
|
||||
else
|
||||
refresh();
|
||||
};
|
||||
subscriptions.push([event, callback]);
|
||||
source.on(event, callback);
|
||||
}
|
||||
} catch (error) {
|
||||
release();
|
||||
throw error;
|
||||
}
|
||||
return release;
|
||||
}
|
||||
function artplayerPluginHlsControl(option = {}) {
|
||||
return (art) => {
|
||||
return (player) => {
|
||||
const art = player;
|
||||
const { $video } = art.template;
|
||||
const { errorHandle } = art.constructor.utils;
|
||||
function updateQuality(hls) {
|
||||
if (!hls.levels.length)
|
||||
return;
|
||||
const config = option.quality || {};
|
||||
const auto = config.auto || "Auto";
|
||||
const title = config.title || "Quality";
|
||||
const getName = config.getName || ((level) => level.name || `${level.height}P`);
|
||||
const defaultLevel = hls.levels[hls.currentLevel];
|
||||
const defaultHtml = defaultLevel ? getName(defaultLevel) : auto;
|
||||
const selector = uniqBy(
|
||||
hls.levels.map((item, index) => {
|
||||
return {
|
||||
html: getName(item, index),
|
||||
value: index,
|
||||
default: hls.currentLevel === index
|
||||
};
|
||||
}),
|
||||
"html"
|
||||
).sort((a, b) => b.value - a.value);
|
||||
selector.push({
|
||||
html: auto,
|
||||
value: -1,
|
||||
default: hls.currentLevel === -1
|
||||
});
|
||||
const onSelect = (item) => {
|
||||
hls.currentLevel = item.value;
|
||||
art.notice.show = `${title}: ${item.html}`;
|
||||
if (config.control)
|
||||
art.controls.check(item);
|
||||
if (config.setting)
|
||||
art.setting.check(item);
|
||||
return item.html;
|
||||
};
|
||||
if (config.control) {
|
||||
art.controls.update({
|
||||
name: "hls-quality",
|
||||
position: "right",
|
||||
html: defaultHtml,
|
||||
style: { padding: "0 10px" },
|
||||
selector,
|
||||
onSelect
|
||||
});
|
||||
}
|
||||
if (config.setting) {
|
||||
art.setting.update({
|
||||
name: "hls-quality",
|
||||
tooltip: defaultHtml,
|
||||
html: title,
|
||||
icon: $quality,
|
||||
width: 200,
|
||||
selector,
|
||||
onSelect
|
||||
});
|
||||
let closed = false;
|
||||
let revision = 0;
|
||||
let engine;
|
||||
let unsubscribe = () => {
|
||||
};
|
||||
let selecting = 0;
|
||||
let pending;
|
||||
const retired = /* @__PURE__ */ new WeakSet();
|
||||
const active = (hls) => !closed && !retired.has(hls) && art.hls === hls && hls.media === $video;
|
||||
const quality = createMenu(art, "hls-quality", "currentLevel", $quality, active, select);
|
||||
const audio = createMenu(art, "hls-audio", "audioTrack", $audio, active, select);
|
||||
function select(callback) {
|
||||
selecting++;
|
||||
let succeeded = false;
|
||||
try {
|
||||
const result = callback();
|
||||
succeeded = true;
|
||||
return result;
|
||||
} finally {
|
||||
selecting--;
|
||||
if (!selecting) {
|
||||
const hls = pending;
|
||||
pending = void 0;
|
||||
if (succeeded && hls)
|
||||
refresh(hls, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
function updateAudio(hls) {
|
||||
if (!hls.audioTracks.length)
|
||||
function refresh(hls, force) {
|
||||
if (!active(hls))
|
||||
return;
|
||||
const config = option.audio || {};
|
||||
const auto = config.auto || "Auto";
|
||||
const title = config.title || "Audio";
|
||||
const getName = config.getName || ((track) => track.name || track.lang || track.language);
|
||||
const defaultTrack = hls.audioTracks[hls.audioTrack];
|
||||
const defaultHtml = defaultTrack ? getName(defaultTrack) : auto;
|
||||
const selector = uniqBy(
|
||||
hls.audioTracks.map((item, index) => {
|
||||
return {
|
||||
html: getName(item, index),
|
||||
value: item.id,
|
||||
default: hls.audioTrack === item.id
|
||||
};
|
||||
}),
|
||||
"html"
|
||||
);
|
||||
const onSelect = (item) => {
|
||||
hls.audioTrack = item.value;
|
||||
art.notice.show = `${title}: ${item.html}`;
|
||||
if (config.control)
|
||||
art.controls.check(item);
|
||||
if (config.setting)
|
||||
art.setting.check(item);
|
||||
return item.html;
|
||||
};
|
||||
if (config.control) {
|
||||
art.controls.update({
|
||||
name: "hls-audio",
|
||||
position: "right",
|
||||
html: defaultHtml,
|
||||
style: { padding: "0 10px" },
|
||||
selector,
|
||||
onSelect
|
||||
});
|
||||
}
|
||||
if (config.setting) {
|
||||
art.setting.update({
|
||||
name: "hls-audio",
|
||||
tooltip: defaultHtml,
|
||||
html: title,
|
||||
icon: $audio,
|
||||
width: 200,
|
||||
selector,
|
||||
onSelect
|
||||
});
|
||||
}
|
||||
const version = ++revision;
|
||||
const config = option.quality || {};
|
||||
const model = qualityModel(hls, config);
|
||||
if (!active(hls) || version !== revision)
|
||||
return;
|
||||
quality.update(hls, config, model, force);
|
||||
if (!active(hls) || version !== revision)
|
||||
return;
|
||||
const audioConfig = option.audio || {};
|
||||
const audioView = audioModel(hls, audioConfig);
|
||||
if (active(hls) && version === revision)
|
||||
audio.update(hls, audioConfig, audioView, force);
|
||||
}
|
||||
function update() {
|
||||
errorHandle(art.hls?.media === $video, 'Cannot find instance of HLS from "art.hls"');
|
||||
updateQuality(art.hls);
|
||||
updateAudio(art.hls);
|
||||
if (closed)
|
||||
return;
|
||||
const hls = art.hls;
|
||||
errorHandle(hls?.media === $video, 'Cannot find instance of HLS from "art.hls"');
|
||||
if (retired.has(hls))
|
||||
return;
|
||||
if (engine !== hls) {
|
||||
unsubscribe();
|
||||
engine = hls;
|
||||
try {
|
||||
unsubscribe = subscribeHls(hls, () => {
|
||||
if (selecting)
|
||||
pending = hls;
|
||||
else
|
||||
refresh(hls, false);
|
||||
}, () => {
|
||||
retired.add(hls);
|
||||
unsubscribe();
|
||||
if (engine === hls) {
|
||||
engine = void 0;
|
||||
if (!closed) {
|
||||
quality.clear();
|
||||
audio.clear();
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
engine = void 0;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
refresh(hls, true);
|
||||
}
|
||||
function destroy() {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
revision++;
|
||||
pending = void 0;
|
||||
quality.invalidate();
|
||||
audio.invalidate();
|
||||
unsubscribe();
|
||||
art.off("ready", update);
|
||||
art.off("restart", update);
|
||||
art.off("destroy", destroy);
|
||||
}
|
||||
art.on("ready", update);
|
||||
art.on("restart", update);
|
||||
return {
|
||||
name: "artplayerPluginHlsControl",
|
||||
update
|
||||
};
|
||||
art.on("destroy", destroy);
|
||||
return { name: "artplayerPluginHlsControl", update };
|
||||
};
|
||||
}
|
||||
export {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-jassub.js v1.1.0
|
||||
* artplayer-plugin-jassub.js v2.0.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.artplayerPluginJassub=t(),define(function(){return t.artplayerPluginJassub})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginJassub=t()}(this,function(){"use strict";var e=Object.defineProperty,t=(t,s,i)=>((t,s,i)=>s in t?e(t,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[s]=i)(t,"symbol"!==typeof s?s+"":s,i);typeof HTMLVideoElement<"u"&&!("requestVideoFrameCallback"in HTMLVideoElement.prototype)&&"getVideoPlaybackQuality"in HTMLVideoElement.prototype&&(HTMLVideoElement.prototype._rvfcpolyfillmap={},HTMLVideoElement.prototype.requestVideoFrameCallback=function(e){const t=performance.now(),s=this.getVideoPlaybackQuality(),i=this.mozPresentedFrames||this.mozPaintedFrames||s.totalVideoFrames-s.droppedVideoFrames,a=(r,n)=>{const o=this.getVideoPlaybackQuality(),h=this.mozPresentedFrames||this.mozPaintedFrames||o.totalVideoFrames-o.droppedVideoFrames;if(h>i){const i=this.mozFrameDelay||o.totalFrameDelay-s.totalFrameDelay||0,a=n-r;e(n,{presentationTime:n+1e3*i,expectedDisplayTime:n+a,width:this.videoWidth,height:this.videoHeight,mediaTime:Math.max(0,this.currentTime||0)+a/1e3,presentedFrames:h,processingDuration:i}),delete this._rvfcpolyfillmap[t]}else this._rvfcpolyfillmap[t]=requestAnimationFrame(e=>a(n,e))};return this._rvfcpolyfillmap[t]=requestAnimationFrame(e=>a(t,e)),t},HTMLVideoElement.prototype.cancelVideoFrameCallback=function(e){cancelAnimationFrame(this._rvfcpolyfillmap[e]),delete this._rvfcpolyfillmap[e]});const s={bt709:"BT709",bt470bg:"BT601",smpte170m:"BT601"},i={BT601:{BT709:"1.0863 -0.0723 -0.014 0 0 0.0965 0.8451 0.0584 0 0 -0.0141 -0.0277 1.0418"},BT709:{BT601:"0.9137 0.0784 0.0079 0 0 -0.1049 1.1722 -0.0671 0 0 0.0096 0.0322 0.9582"},FCC:{BT709:"1.0873 -0.0736 -0.0137 0 0 0.0974 0.8494 0.0531 0 0 -0.0127 -0.0251 1.0378",BT601:"1.001 -0.0008 -0.0002 0 0 0.0009 1.005 -0.006 0 0 0.0013 0.0027 0.996"},SMPTE240M:{BT709:"0.9993 0.0006 0.0001 0 0 -0.0004 0.9812 0.0192 0 0 -0.0034 -0.0114 1.0148",BT601:"0.913 0.0774 0.0096 0 0 -0.1051 1.1508 -0.0456 0 0 0.0063 0.0207 0.973"}},a=class e extends EventTarget{constructor(t){if(super(),!globalThis.Worker)throw this.destroy("Worker not supported");if(!t)throw this.destroy("No options provided");this._loaded=new Promise(e=>{this._init=e});const s=e._test();if(this._onDemandRender="requestVideoFrameCallback"in HTMLVideoElement.prototype&&(t.onDemandRender??!0),this._offscreenRender="transferControlToOffscreen"in HTMLCanvasElement.prototype&&!t.canvas&&(t.offscreenRender??!0),this.timeOffset=t.timeOffset||0,this._video=t.video,this._videoHeight=0,this._videoWidth=0,this._videoColorSpace=null,this._canvas=t.canvas,this._video&&!this._canvas)this._canvasParent=document.createElement("div"),this._canvasParent.className="JASSUB",this._canvasParent.style.position="relative",this._canvas=this._createCanvas(),this._video.insertAdjacentElement("afterend",this._canvasParent);else if(!this._canvas)throw this.destroy("Don't know where to render: you should give video or canvas in options.");if(this._bufferCanvas=document.createElement("canvas"),this._bufferCtx=this._bufferCanvas.getContext("2d"),!this._bufferCtx)throw this.destroy("Canvas rendering not supported");this._canvasctrl=this._offscreenRender?this._canvas.transferControlToOffscreen():this._canvas,this._ctx=!this._offscreenRender&&this._canvasctrl.getContext("2d"),this._lastRenderTime=0,this.debug=!!t.debug,this.prescaleFactor=t.prescaleFactor||1,this.prescaleHeightLimit=t.prescaleHeightLimit||1080,this.maxRenderHeight=t.maxRenderHeight||0,this._boundResize=this.resize.bind(this),this._boundTimeUpdate=this._timeupdate.bind(this),this._boundSetRate=this.setRate.bind(this),this._boundUpdateColorSpace=this._updateColorSpace.bind(this),this._video&&this.setVideo(t.video),this._onDemandRender&&(this.busy=!1,this._lastDemandTime=null),this._worker=new Worker(t.workerUrl||"jassub-worker.js"),this._worker.onmessage=e=>this._onmessage(e),this._worker.onerror=e=>this._error(e),s.then(()=>{this._worker.postMessage({target:"init",wasmUrl:e._supportsSIMD&&t.modernWasmUrl?t.modernWasmUrl:t.wasmUrl??"jassub-worker.wasm",legacyWasmUrl:t.legacyWasmUrl??"jassub-worker.wasm.js",asyncRender:typeof createImageBitmap<"u"&&(t.asyncRender??!0),onDemandRender:this._onDemandRender,width:this._canvasctrl.width||0,height:this._canvasctrl.height||0,blendMode:t.blendMode||"js",subUrl:t.subUrl,subContent:t.subContent||null,fonts:t.fonts||[],availableFonts:t.availableFonts||{"liberation sans":"./default.woff2"},fallbackFont:t.fallbackFont||"liberation sans",debug:this.debug,targetFps:t.targetFps||24,dropAllAnimations:t.dropAllAnimations,dropAllBlur:t.dropAllBlur,libassMemoryLimit:t.libassMemoryLimit||0,libassGlyphLimit:t.libassGlyphLimit||0,useLocalFonts:typeof queryLocalFonts<"u"&&(t.useLocalFonts??!0),hasBitmapBug:e._hasBitmapBug}),!0===this._offscreenRender&&this.sendMessage("ofLine truncated
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginJassub=t(),define(function(){return e.artplayerPluginJassub})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginJassub=t()}(this,function(){"use strict";var e=Object.defineProperty,t=(t,s,i)=>((t,s,i)=>s in t?e(t,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[s]=i)(t,"symbol"!==typeof s?s+"":s,i);typeof HTMLVideoElement<"u"&&!("requestVideoFrameCallback"in HTMLVideoElement.prototype)&&"getVideoPlaybackQuality"in HTMLVideoElement.prototype&&(HTMLVideoElement.prototype.requestVideoFrameCallback=function(e){Object.prototype.hasOwnProperty.call(this,"_rvfcpolyfillmap")||(this._rvfcpolyfillmap={});const t=this._rvfcpolyfillid=(this._rvfcpolyfillid||0)+1,s=performance.now(),i=this.getVideoPlaybackQuality(),a=this.currentTime,r=this.mozPresentedFrames||this.mozPaintedFrames||i.totalVideoFrames-i.droppedVideoFrames,n=(o,h)=>{if(!(t in this._rvfcpolyfillmap))return;const d=this.getVideoPlaybackQuality(),l=this.mozPresentedFrames||this.mozPaintedFrames||d.totalVideoFrames-d.droppedVideoFrames,c=l>r,_=0===r&&0===l&&0===i.totalVideoFrames&&0===i.droppedVideoFrames&&0===d.totalVideoFrames&&0===d.droppedVideoFrames&&Number.isFinite(this.currentTime)&&this.currentTime!==a&&this.readyState>=2&&!this.seeking&&h-s>=1e3/30;if(c||_){const s=this.mozFrameDelay||d.totalFrameDelay-i.totalFrameDelay||0,a=h-o;delete this._rvfcpolyfillmap[t],e(h,{presentationTime:h+1e3*s,expectedDisplayTime:h+a,width:this.videoWidth,height:this.videoHeight,mediaTime:_&&!c?Math.max(0,this.currentTime):Math.max(0,this.currentTime||0)+a/1e3,presentedFrames:l,processingDuration:s})}else this._rvfcpolyfillmap[t]=requestAnimationFrame(e=>n(h,e))};return this._rvfcpolyfillmap[t]=requestAnimationFrame(e=>n(s,e)),t},HTMLVideoElement.prototype.cancelVideoFrameCallback=function(e){const t=this._rvfcpolyfillmap;t&&e in t&&(cancelAnimationFrame(t[e]),delete t[e])});const s={bt709:"BT709",bt470bg:"BT601",smpte170m:"BT601"},i={BT601:{BT709:"1.0863 -0.0723 -0.014 0 0 0.0965 0.8451 0.0584 0 0 -0.0141 -0.0277 1.0418"},BT709:{BT601:"0.9137 0.0784 0.0079 0 0 -0.1049 1.1722 -0.0671 0 0 0.0096 0.0322 0.9582"},FCC:{BT709:"1.0873 -0.0736 -0.0137 0 0 0.0974 0.8494 0.0531 0 0 -0.0127 -0.0251 1.0378",BT601:"1.001 -0.0008 -0.0002 0 0 0.0009 1.005 -0.006 0 0 0.0013 0.0027 0.996"},SMPTE240M:{BT709:"0.9993 0.0006 0.0001 0 0 -0.0004 0.9812 0.0192 0 0 -0.0034 -0.0114 1.0148",BT601:"0.913 0.0774 0.0096 0 0 -0.1051 1.1508 -0.0456 0 0 0.0063 0.0207 0.973"}},a=class e extends EventTarget{constructor(t){let s;super(),this._requests=new Set;try{if(!globalThis.Worker)throw this.destroy("Worker not supported");if(!t)throw this.destroy("No options provided");if(this._loaded=new Promise(e=>{this._init=e}),s=e._test(),this._onDemandRender="requestVideoFrameCallback"in HTMLVideoElement.prototype&&(t.onDemandRender??!0),this._offscreenRender="transferControlToOffscreen"in HTMLCanvasElement.prototype&&!t.canvas&&(t.offscreenRender??!0),this.timeOffset=t.timeOffset||0,this._video=t.video,this._videoHeight=0,this._videoWidth=0,this._videoColorSpace=null,this._canvas=t.canvas,this._video&&!this._canvas)this._canvasParent=document.createElement("div"),this._canvasParent.className="JASSUB",this._canvasParent.style.position="relative",this._canvas=this._createCanvas(),this._video.insertAdjacentElement("afterend",this._canvasParent);else if(!this._canvas)throw this.destroy("Don't know where to render: you should give video or canvas in options.");if(this._bufferCanvas=document.createElement("canvas"),this._bufferCtx=this._bufferCanvas.getContext("2d"),!this._bufferCtx)throw this.destroy("Canvas rendering not supported");this._canvasctrl=this._offscreenRender?this._canvas.transferControlToOffscreen():this._canvas,this._ctx=!this._offscreenRender&&this._canvasctrl.getContext("2d"),this._lastRenderTime=0,this.debug=!!t.debug,this.prescaleFactor=t.prescaleFactor||1,this.prescaleHeightLimit=t.prescaleHeightLimit||1080,this.maxRenderHeight=t.maxRenderHeight||0,this._boundResize=this.resize.bind(this),this._boundTimeUpdate=this._timeupdate.bind(this),this._boundSetRate=()=>{this._destroyed||this.setRate(this._video.playbackRate)},this._boundUpdateColorSpace=this._updateColorSpace.bind(this),this._video&&this.setVideo(t.video),this._onDemandRender&&(this.busy=!1,this._lastDemandTime=null),this._worker=new Worker(t.workerUrl||"jassub-worker.js"),this._worker.onmessage=e=>this._onmessage(e),this._worker.onerror=e=>this._error(e),s.then(()=>{this._destroyed||this._worker.postMessage({target:"init",wasmUrl:e._supportsSIMD&&t.modernWasmUrl?t.modernWasmUrl:t.wasmUrl??"jassub-worker.wasm",legacyWasmUrl:t.legacyWasmUrl??"jassub-worker.wasm.js",asyncRender:typeof createImageBitmap<"u"&&(t.asyncRender??!0),onDemandRender:this._onDemandRender,width:this._canvasctrl.width||0,height:this._canvasctrl.height||0,blendMode:t.blendMode||"js",subUrl:t.subLine truncated
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-jassub.js v1.1.0
|
||||
* artplayer-plugin-jassub.js v2.0.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.artplayerPluginJassub=t(),define(function(){return t.artplayerPluginJassub})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginJassub=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,s=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable,a=(t,s,i)=>s in t?e(t,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[s]=i,r=(e,r)=>{for(var n in r||(r={}))s.call(r,n)&&a(e,n,r[n]);if(t)for(var n of t(r))i.call(r,n)&&a(e,n,r[n]);return e},n=(e,t,s)=>a(e,"symbol"!==typeof t?t+"":t,s),o=(e,t,s)=>new Promise((i,a)=>{var r=e=>{try{o(s.next(e))}catch(t){a(t)}},n=e=>{try{o(s.throw(e))}catch(t){a(t)}},o=e=>e.done?i(e.value):Promise.resolve(e.value).then(r,n);o((s=s.apply(e,t)).next())});typeof HTMLVideoElement<"u"&&!("requestVideoFrameCallback"in HTMLVideoElement.prototype)&&"getVideoPlaybackQuality"in HTMLVideoElement.prototype&&(HTMLVideoElement.prototype._rvfcpolyfillmap={},HTMLVideoElement.prototype.requestVideoFrameCallback=function(e){const t=performance.now(),s=this.getVideoPlaybackQuality(),i=this.mozPresentedFrames||this.mozPaintedFrames||s.totalVideoFrames-s.droppedVideoFrames,a=(r,n)=>{const o=this.getVideoPlaybackQuality(),h=this.mozPresentedFrames||this.mozPaintedFrames||o.totalVideoFrames-o.droppedVideoFrames;if(h>i){const i=this.mozFrameDelay||o.totalFrameDelay-s.totalFrameDelay||0,a=n-r;e(n,{presentationTime:n+1e3*i,expectedDisplayTime:n+a,width:this.videoWidth,height:this.videoHeight,mediaTime:Math.max(0,this.currentTime||0)+a/1e3,presentedFrames:h,processingDuration:i}),delete this._rvfcpolyfillmap[t]}else this._rvfcpolyfillmap[t]=requestAnimationFrame(e=>a(n,e))};return this._rvfcpolyfillmap[t]=requestAnimationFrame(e=>a(t,e)),t},HTMLVideoElement.prototype.cancelVideoFrameCallback=function(e){cancelAnimationFrame(this._rvfcpolyfillmap[e]),delete this._rvfcpolyfillmap[e]});const h={bt709:"BT709",bt470bg:"BT601",smpte170m:"BT601"},d={BT601:{BT709:"1.0863 -0.0723 -0.014 0 0 0.0965 0.8451 0.0584 0 0 -0.0141 -0.0277 1.0418"},BT709:{BT601:"0.9137 0.0784 0.0079 0 0 -0.1049 1.1722 -0.0671 0 0 0.0096 0.0322 0.9582"},FCC:{BT709:"1.0873 -0.0736 -0.0137 0 0 0.0974 0.8494 0.0531 0 0 -0.0127 -0.0251 1.0378",BT601:"1.001 -0.0008 -0.0002 0 0 0.0009 1.005 -0.006 0 0 0.0013 0.0027 0.996"},SMPTE240M:{BT709:"0.9993 0.0006 0.0001 0 0 -0.0004 0.9812 0.0192 0 0 -0.0034 -0.0114 1.0148",BT601:"0.913 0.0774 0.0096 0 0 -0.1051 1.1508 -0.0456 0 0 0.0063 0.0207 0.973"}},l=class e extends EventTarget{constructor(t){var s,i;if(super(),!globalThis.Worker)throw this.destroy("Worker not supported");if(!t)throw this.destroy("No options provided");this._loaded=new Promise(e=>{this._init=e});const a=e._test();if(this._onDemandRender="requestVideoFrameCallback"in HTMLVideoElement.prototype&&(null==(s=t.onDemandRender)||s),this._offscreenRender="transferControlToOffscreen"in HTMLCanvasElement.prototype&&!t.canvas&&(null==(i=t.offscreenRender)||i),this.timeOffset=t.timeOffset||0,this._video=t.video,this._videoHeight=0,this._videoWidth=0,this._videoColorSpace=null,this._canvas=t.canvas,this._video&&!this._canvas)this._canvasParent=document.createElement("div"),this._canvasParent.className="JASSUB",this._canvasParent.style.position="relative",this._canvas=this._createCanvas(),this._video.insertAdjacentElement("afterend",this._canvasParent);else if(!this._canvas)throw this.destroy("Don't know where to render: you should give video or canvas in options.");if(this._bufferCanvas=document.createElement("canvas"),this._bufferCtx=this._bufferCanvas.getContext("2d"),!this._bufferCtx)throw this.destroy("Canvas rendering not supported");this._canvasctrl=this._offscreenRender?this._canvas.transferControlToOffscreen():this._canvas,this._ctx=!this._offscreenRender&&this._canvasctrl.getContext("2d"),this._lastRenderTime=0,this.debug=!!t.debug,this.prescaleFactor=t.prescaleFactor||1,this.prescaleHeightLimit=t.prescaleHeightLimit||1080,this.maxRenderHeight=t.maxRenderHeight||0,this._boundResize=this.resize.bind(this),this._boundTimeUpdate=this._timeupdate.bind(this),this._boundSetRate=this.setRate.bind(this),this._boundUpdateColorSpace=this._updateColorSpace.bind(this),this._video&&this.setVideo(t.video),this._onDemandRender&&(this.busy=!1,this._lastDemandTime=null),this._worker=new Worker(t.workerUrl||"jassub-worker.js"),this._worker.onmessage=e=>this._onmessage(e),this._worker.onerror=e=>this._error(e),a.then(()=>{var s,i,a,r;this._worker.postMessage({target:"init",wasmUrl:e._supportsSIMD&&t.modernWasmUrl?t.modernWasmUrl:null!=(s=t.wasmUrl)?s:"jassub-worker.wasm",legacyWasmUrl:null!=(i=t.legacyWasmUrl)?i:"jassub-worker.wasm.js",asyncRender:typeof createImageBitmap<"u"&&(null==(a=t.asyncRender)||a),onDemandRender:this._onDemandRender,width:this._canvasctrl.width||0,height:this._canvasctrl.height||0,blendMode:t.blendMode||"js",subUrl:t.subUrl,subLine truncated
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginJassub=t(),define(function(){return e.artplayerPluginJassub})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginJassub=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,s=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable,a=(t,s,i)=>s in t?e(t,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[s]=i,r=(e,r)=>{for(var n in r||(r={}))s.call(r,n)&&a(e,n,r[n]);if(t)for(var n of t(r))i.call(r,n)&&a(e,n,r[n]);return e},n=(e,t,s)=>a(e,"symbol"!==typeof t?t+"":t,s),o=(e,t,s)=>new Promise((i,a)=>{var r=e=>{try{o(s.next(e))}catch(t){a(t)}},n=e=>{try{o(s.throw(e))}catch(t){a(t)}},o=e=>e.done?i(e.value):Promise.resolve(e.value).then(r,n);o((s=s.apply(e,t)).next())});typeof HTMLVideoElement<"u"&&!("requestVideoFrameCallback"in HTMLVideoElement.prototype)&&"getVideoPlaybackQuality"in HTMLVideoElement.prototype&&(HTMLVideoElement.prototype.requestVideoFrameCallback=function(e){Object.prototype.hasOwnProperty.call(this,"_rvfcpolyfillmap")||(this._rvfcpolyfillmap={});const t=this._rvfcpolyfillid=(this._rvfcpolyfillid||0)+1,s=performance.now(),i=this.getVideoPlaybackQuality(),a=this.currentTime,r=this.mozPresentedFrames||this.mozPaintedFrames||i.totalVideoFrames-i.droppedVideoFrames,n=(o,h)=>{if(!(t in this._rvfcpolyfillmap))return;const l=this.getVideoPlaybackQuality(),d=this.mozPresentedFrames||this.mozPaintedFrames||l.totalVideoFrames-l.droppedVideoFrames,c=d>r,_=0===r&&0===d&&0===i.totalVideoFrames&&0===i.droppedVideoFrames&&0===l.totalVideoFrames&&0===l.droppedVideoFrames&&Number.isFinite(this.currentTime)&&this.currentTime!==a&&this.readyState>=2&&!this.seeking&&h-s>=1e3/30;if(c||_){const s=this.mozFrameDelay||l.totalFrameDelay-i.totalFrameDelay||0,a=h-o;delete this._rvfcpolyfillmap[t],e(h,{presentationTime:h+1e3*s,expectedDisplayTime:h+a,width:this.videoWidth,height:this.videoHeight,mediaTime:_&&!c?Math.max(0,this.currentTime):Math.max(0,this.currentTime||0)+a/1e3,presentedFrames:d,processingDuration:s})}else this._rvfcpolyfillmap[t]=requestAnimationFrame(e=>n(h,e))};return this._rvfcpolyfillmap[t]=requestAnimationFrame(e=>n(s,e)),t},HTMLVideoElement.prototype.cancelVideoFrameCallback=function(e){const t=this._rvfcpolyfillmap;t&&e in t&&(cancelAnimationFrame(t[e]),delete t[e])});const h={bt709:"BT709",bt470bg:"BT601",smpte170m:"BT601"},l={BT601:{BT709:"1.0863 -0.0723 -0.014 0 0 0.0965 0.8451 0.0584 0 0 -0.0141 -0.0277 1.0418"},BT709:{BT601:"0.9137 0.0784 0.0079 0 0 -0.1049 1.1722 -0.0671 0 0 0.0096 0.0322 0.9582"},FCC:{BT709:"1.0873 -0.0736 -0.0137 0 0 0.0974 0.8494 0.0531 0 0 -0.0127 -0.0251 1.0378",BT601:"1.001 -0.0008 -0.0002 0 0 0.0009 1.005 -0.006 0 0 0.0013 0.0027 0.996"},SMPTE240M:{BT709:"0.9993 0.0006 0.0001 0 0 -0.0004 0.9812 0.0192 0 0 -0.0034 -0.0114 1.0148",BT601:"0.913 0.0774 0.0096 0 0 -0.1051 1.1508 -0.0456 0 0 0.0063 0.0207 0.973"}},d=class e extends EventTarget{constructor(t){var s,i;let a;super(),this._requests=new Set;try{if(!globalThis.Worker)throw this.destroy("Worker not supported");if(!t)throw this.destroy("No options provided");if(this._loaded=new Promise(e=>{this._init=e}),a=e._test(),this._onDemandRender="requestVideoFrameCallback"in HTMLVideoElement.prototype&&(null==(s=t.onDemandRender)||s),this._offscreenRender="transferControlToOffscreen"in HTMLCanvasElement.prototype&&!t.canvas&&(null==(i=t.offscreenRender)||i),this.timeOffset=t.timeOffset||0,this._video=t.video,this._videoHeight=0,this._videoWidth=0,this._videoColorSpace=null,this._canvas=t.canvas,this._video&&!this._canvas)this._canvasParent=document.createElement("div"),this._canvasParent.className="JASSUB",this._canvasParent.style.position="relative",this._canvas=this._createCanvas(),this._video.insertAdjacentElement("afterend",this._canvasParent);else if(!this._canvas)throw this.destroy("Don't know where to render: you should give video or canvas in options.");if(this._bufferCanvas=document.createElement("canvas"),this._bufferCtx=this._bufferCanvas.getContext("2d"),!this._bufferCtx)throw this.destroy("Canvas rendering not supported");this._canvasctrl=this._offscreenRender?this._canvas.transferControlToOffscreen():this._canvas,this._ctx=!this._offscreenRender&&this._canvasctrl.getContext("2d"),this._lastRenderTime=0,this.debug=!!t.debug,this.prescaleFactor=t.prescaleFactor||1,this.prescaleHeightLimit=t.prescaleHeightLimit||1080,this.maxRenderHeight=t.maxRenderHeight||0,this._boundResize=this.resize.bind(this),this._boundTimeUpdate=this._timeupdate.bind(this),this._boundSetRate=()=>{this._destroyed||this.setRate(this._video.playbackRate)},this._boundUpdateColorSpace=this._updateColorSpace.bind(this),this._video&&this.setVideo(t.video),this._onDemandRender&&(this.busy=!1,this._lastDemandTime=null),this._worker=new Worker(t.workerUrl||"jassub-worker.js"),this._worker.onmessage=e=>this._onmessage(e),this._Line truncated
|
||||
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* artplayer-plugin-jassub.js v1.1.0
|
||||
* artplayer-plugin-jassub.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
@@ -7,27 +7,46 @@
|
||||
var __defProp = Object.defineProperty;
|
||||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
||||
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
||||
typeof HTMLVideoElement < "u" && !("requestVideoFrameCallback" in HTMLVideoElement.prototype) && "getVideoPlaybackQuality" in HTMLVideoElement.prototype && (HTMLVideoElement.prototype._rvfcpolyfillmap = {}, HTMLVideoElement.prototype.requestVideoFrameCallback = function(c) {
|
||||
const e = performance.now(), t = this.getVideoPlaybackQuality(), s = this.mozPresentedFrames || this.mozPaintedFrames || t.totalVideoFrames - t.droppedVideoFrames, r = (n, a) => {
|
||||
const i = this.getVideoPlaybackQuality(), h = this.mozPresentedFrames || this.mozPaintedFrames || i.totalVideoFrames - i.droppedVideoFrames;
|
||||
if (h > s) {
|
||||
const d = this.mozFrameDelay || i.totalFrameDelay - t.totalFrameDelay || 0, l = a - n;
|
||||
c(a, {
|
||||
presentationTime: a + d * 1e3,
|
||||
expectedDisplayTime: a + l,
|
||||
width: this.videoWidth,
|
||||
height: this.videoHeight,
|
||||
mediaTime: Math.max(0, this.currentTime || 0) + l / 1e3,
|
||||
presentedFrames: h,
|
||||
processingDuration: d
|
||||
}), delete this._rvfcpolyfillmap[e];
|
||||
} else
|
||||
this._rvfcpolyfillmap[e] = requestAnimationFrame((d) => r(a, d));
|
||||
if (typeof HTMLVideoElement < "u" && !("requestVideoFrameCallback" in HTMLVideoElement.prototype) && "getVideoPlaybackQuality" in HTMLVideoElement.prototype) {
|
||||
HTMLVideoElement.prototype.requestVideoFrameCallback = function(callback) {
|
||||
if (!Object.prototype.hasOwnProperty.call(this, "_rvfcpolyfillmap"))
|
||||
this._rvfcpolyfillmap = {};
|
||||
const id = this._rvfcpolyfillid = (this._rvfcpolyfillid || 0) + 1;
|
||||
const started = performance.now(), initial = this.getVideoPlaybackQuality(), initialTime = this.currentTime;
|
||||
const initialFrames = this.mozPresentedFrames || this.mozPaintedFrames || initial.totalVideoFrames - initial.droppedVideoFrames;
|
||||
const poll = (previous, now) => {
|
||||
if (!(id in this._rvfcpolyfillmap)) return;
|
||||
const quality = this.getVideoPlaybackQuality();
|
||||
const frames = this.mozPresentedFrames || this.mozPaintedFrames || quality.totalVideoFrames - quality.droppedVideoFrames;
|
||||
const advanced = frames > initialFrames;
|
||||
const mediaFallback = initialFrames === 0 && frames === 0 && initial.totalVideoFrames === 0 && initial.droppedVideoFrames === 0 && quality.totalVideoFrames === 0 && quality.droppedVideoFrames === 0 && Number.isFinite(this.currentTime) && this.currentTime !== initialTime && this.readyState >= 2 && !this.seeking && now - started >= 1e3 / 30;
|
||||
if (advanced || mediaFallback) {
|
||||
const delay = this.mozFrameDelay || quality.totalFrameDelay - initial.totalFrameDelay || 0;
|
||||
const elapsed = now - previous;
|
||||
delete this._rvfcpolyfillmap[id];
|
||||
callback(now, {
|
||||
presentationTime: now + delay * 1e3,
|
||||
expectedDisplayTime: now + elapsed,
|
||||
width: this.videoWidth,
|
||||
height: this.videoHeight,
|
||||
mediaTime: mediaFallback && !advanced ? Math.max(0, this.currentTime) : Math.max(0, this.currentTime || 0) + elapsed / 1e3,
|
||||
presentedFrames: frames,
|
||||
processingDuration: delay
|
||||
});
|
||||
} else {
|
||||
this._rvfcpolyfillmap[id] = requestAnimationFrame((time) => poll(now, time));
|
||||
}
|
||||
};
|
||||
this._rvfcpolyfillmap[id] = requestAnimationFrame((time) => poll(started, time));
|
||||
return id;
|
||||
};
|
||||
return this._rvfcpolyfillmap[e] = requestAnimationFrame((n) => r(e, n)), e;
|
||||
}, HTMLVideoElement.prototype.cancelVideoFrameCallback = function(c) {
|
||||
cancelAnimationFrame(this._rvfcpolyfillmap[c]), delete this._rvfcpolyfillmap[c];
|
||||
});
|
||||
HTMLVideoElement.prototype.cancelVideoFrameCallback = function(id) {
|
||||
const callbacks = this._rvfcpolyfillmap;
|
||||
if (!callbacks || !(id in callbacks)) return;
|
||||
cancelAnimationFrame(callbacks[id]);
|
||||
delete callbacks[id];
|
||||
};
|
||||
}
|
||||
const _ = {
|
||||
bt709: "BT709",
|
||||
// these might not be exactly correct? oops?
|
||||
@@ -82,47 +101,65 @@ const _o = class _o extends EventTarget {
|
||||
* @param {Number} [options.libassGlyphLimit] libass glyph cache memory limit in MiB (approximate).
|
||||
*/
|
||||
constructor(e) {
|
||||
if (super(), !globalThis.Worker)
|
||||
throw this.destroy("Worker not supported");
|
||||
if (!e)
|
||||
throw this.destroy("No options provided");
|
||||
this._loaded = /** @type {Promise<void>} */
|
||||
new Promise((s) => {
|
||||
this._init = s;
|
||||
});
|
||||
const t = _o._test();
|
||||
if (this._onDemandRender = "requestVideoFrameCallback" in HTMLVideoElement.prototype && (e.onDemandRender ?? true), this._offscreenRender = "transferControlToOffscreen" in HTMLCanvasElement.prototype && !e.canvas && (e.offscreenRender ?? true), this.timeOffset = e.timeOffset || 0, this._video = e.video, this._videoHeight = 0, this._videoWidth = 0, this._videoColorSpace = null, this._canvas = e.canvas, this._video && !this._canvas)
|
||||
this._canvasParent = document.createElement("div"), this._canvasParent.className = "JASSUB", this._canvasParent.style.position = "relative", this._canvas = this._createCanvas(), this._video.insertAdjacentElement("afterend", this._canvasParent);
|
||||
else if (!this._canvas)
|
||||
throw this.destroy("Don't know where to render: you should give video or canvas in options.");
|
||||
if (this._bufferCanvas = document.createElement("canvas"), this._bufferCtx = this._bufferCanvas.getContext("2d"), !this._bufferCtx)
|
||||
throw this.destroy("Canvas rendering not supported");
|
||||
this._canvasctrl = this._offscreenRender ? this._canvas.transferControlToOffscreen() : this._canvas, this._ctx = !this._offscreenRender && this._canvasctrl.getContext("2d"), this._lastRenderTime = 0, this.debug = !!e.debug, this.prescaleFactor = e.prescaleFactor || 1, this.prescaleHeightLimit = e.prescaleHeightLimit || 1080, this.maxRenderHeight = e.maxRenderHeight || 0, this._boundResize = this.resize.bind(this), this._boundTimeUpdate = this._timeupdate.bind(this), this._boundSetRate = this.setRate.bind(this), this._boundUpdateColorSpace = this._updateColorSpace.bind(this), this._video && this.setVideo(e.video), this._onDemandRender && (this.busy = false, this._lastDemandTime = null), this._worker = new Worker(e.workerUrl || "jassub-worker.js"), this._worker.onmessage = (s) => this._onmessage(s), this._worker.onerror = (s) => this._error(s), t.then(() => {
|
||||
this._worker.postMessage({
|
||||
target: "init",
|
||||
wasmUrl: _o._supportsSIMD && e.modernWasmUrl ? e.modernWasmUrl : e.wasmUrl ?? "jassub-worker.wasm",
|
||||
legacyWasmUrl: e.legacyWasmUrl ?? "jassub-worker.wasm.js",
|
||||
asyncRender: typeof createImageBitmap < "u" && (e.asyncRender ?? true),
|
||||
onDemandRender: this._onDemandRender,
|
||||
width: this._canvasctrl.width || 0,
|
||||
height: this._canvasctrl.height || 0,
|
||||
blendMode: e.blendMode || "js",
|
||||
subUrl: e.subUrl,
|
||||
subContent: e.subContent || null,
|
||||
fonts: e.fonts || [],
|
||||
availableFonts: e.availableFonts || { "liberation sans": "./default.woff2" },
|
||||
fallbackFont: e.fallbackFont || "liberation sans",
|
||||
debug: this.debug,
|
||||
targetFps: e.targetFps || 24,
|
||||
dropAllAnimations: e.dropAllAnimations,
|
||||
dropAllBlur: e.dropAllBlur,
|
||||
libassMemoryLimit: e.libassMemoryLimit || 0,
|
||||
libassGlyphLimit: e.libassGlyphLimit || 0,
|
||||
// @ts-ignore
|
||||
useLocalFonts: typeof queryLocalFonts < "u" && (e.useLocalFonts ?? true),
|
||||
hasBitmapBug: _o._hasBitmapBug
|
||||
}), this._offscreenRender === true && this.sendMessage("offscreenCanvas", null, [this._canvasctrl]);
|
||||
});
|
||||
super();
|
||||
this._requests = /* @__PURE__ */ new Set();
|
||||
let t;
|
||||
try {
|
||||
if (!globalThis.Worker)
|
||||
throw this.destroy("Worker not supported");
|
||||
if (!e)
|
||||
throw this.destroy("No options provided");
|
||||
this._loaded = /** @type {Promise<void>} */
|
||||
new Promise((s) => {
|
||||
this._init = s;
|
||||
});
|
||||
t = _o._test();
|
||||
if (this._onDemandRender = "requestVideoFrameCallback" in HTMLVideoElement.prototype && (e.onDemandRender ?? true), this._offscreenRender = "transferControlToOffscreen" in HTMLCanvasElement.prototype && !e.canvas && (e.offscreenRender ?? true), this.timeOffset = e.timeOffset || 0, this._video = e.video, this._videoHeight = 0, this._videoWidth = 0, this._videoColorSpace = null, this._canvas = e.canvas, this._video && !this._canvas)
|
||||
this._canvasParent = document.createElement("div"), this._canvasParent.className = "JASSUB", this._canvasParent.style.position = "relative", this._canvas = this._createCanvas(), this._video.insertAdjacentElement("afterend", this._canvasParent);
|
||||
else if (!this._canvas)
|
||||
throw this.destroy("Don't know where to render: you should give video or canvas in options.");
|
||||
if (this._bufferCanvas = document.createElement("canvas"), this._bufferCtx = this._bufferCanvas.getContext("2d"), !this._bufferCtx)
|
||||
throw this.destroy("Canvas rendering not supported");
|
||||
this._canvasctrl = this._offscreenRender ? this._canvas.transferControlToOffscreen() : this._canvas, this._ctx = !this._offscreenRender && this._canvasctrl.getContext("2d"), this._lastRenderTime = 0, this.debug = !!e.debug, this.prescaleFactor = e.prescaleFactor || 1, this.prescaleHeightLimit = e.prescaleHeightLimit || 1080, this.maxRenderHeight = e.maxRenderHeight || 0, this._boundResize = this.resize.bind(this), this._boundTimeUpdate = this._timeupdate.bind(this), this._boundSetRate = () => {
|
||||
if (!this._destroyed) this.setRate(this._video.playbackRate);
|
||||
}, this._boundUpdateColorSpace = this._updateColorSpace.bind(this), this._video && this.setVideo(e.video), this._onDemandRender && (this.busy = false, this._lastDemandTime = null), this._worker = new Worker(e.workerUrl || "jassub-worker.js"), this._worker.onmessage = (s) => this._onmessage(s), this._worker.onerror = (s) => this._error(s), t.then(() => {
|
||||
if (this._destroyed) return;
|
||||
this._worker.postMessage({
|
||||
target: "init",
|
||||
wasmUrl: _o._supportsSIMD && e.modernWasmUrl ? e.modernWasmUrl : e.wasmUrl ?? "jassub-worker.wasm",
|
||||
legacyWasmUrl: e.legacyWasmUrl ?? "jassub-worker.wasm.js",
|
||||
asyncRender: typeof createImageBitmap < "u" && (e.asyncRender ?? true),
|
||||
onDemandRender: this._onDemandRender,
|
||||
width: this._canvasctrl.width || 0,
|
||||
height: this._canvasctrl.height || 0,
|
||||
blendMode: e.blendMode || "js",
|
||||
subUrl: e.subUrl,
|
||||
subContent: e.subContent || null,
|
||||
fonts: e.fonts || [],
|
||||
availableFonts: e.availableFonts || { "liberation sans": "./default.woff2" },
|
||||
fallbackFont: e.fallbackFont || "liberation sans",
|
||||
debug: this.debug,
|
||||
targetFps: e.targetFps || 24,
|
||||
dropAllAnimations: e.dropAllAnimations,
|
||||
dropAllBlur: e.dropAllBlur,
|
||||
libassMemoryLimit: e.libassMemoryLimit || 0,
|
||||
libassGlyphLimit: e.libassGlyphLimit || 0,
|
||||
// @ts-ignore
|
||||
useLocalFonts: typeof queryLocalFonts < "u" && (e.useLocalFonts ?? true),
|
||||
hasBitmapBug: _o._hasBitmapBug
|
||||
});
|
||||
}).catch((error) => {
|
||||
if (!this._destroyed) this.destroy(error);
|
||||
});
|
||||
} catch (error) {
|
||||
t?.catch(() => {
|
||||
});
|
||||
try {
|
||||
this.destroy();
|
||||
} catch {
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
_createCanvas() {
|
||||
return this._canvas = document.createElement("canvas"), this._canvas.style.display = "block", this._canvas.style.position = "absolute", this._canvas.style.pointerEvents = "none", this._canvasParent.appendChild(this._canvas), this._canvas;
|
||||
@@ -183,6 +220,7 @@ const _o = class _o extends EventTarget {
|
||||
* @param {Boolean} [force=false]
|
||||
*/
|
||||
resize(e = 0, t = 0, s = 0, r = 0, n = this._video?.paused) {
|
||||
if (this._destroyed) return;
|
||||
if ((!e || !t) && this._video) {
|
||||
const a = this._getVideoPosition();
|
||||
let i = null;
|
||||
@@ -193,7 +231,7 @@ const _o = class _o extends EventTarget {
|
||||
i = this._computeCanvasSize(a.width || 0, a.height || 0);
|
||||
e = i.width, t = i.height, this._canvasParent && (s = a.y - (this._canvasParent.getBoundingClientRect().top - this._video.getBoundingClientRect().top), r = a.x), this._canvas.style.width = a.width + "px", this._canvas.style.height = a.height + "px";
|
||||
}
|
||||
this._canvas.style.top = s + "px", this._canvas.style.left = r + "px", n && this.busy === false ? this.busy = true : n = false, this.sendMessage("canvas", { width: e, height: t, videoWidth: this._videoWidth || this._video.videoWidth, videoHeight: this._videoHeight || this._video.videoHeight, force: n });
|
||||
this._canvas.style.top = s + "px", this._canvas.style.left = r + "px", n && this.busy === false ? this.busy = true : n = false, this.sendMessage("canvas", { width: e, height: t, videoWidth: this._videoWidth || this._video?.videoWidth || e, videoHeight: this._videoHeight || this._video?.videoHeight || t, force: n });
|
||||
}
|
||||
_getVideoPosition(e = this._video.videoWidth, t = this._video.videoHeight) {
|
||||
const s = e / t, { offsetWidth: r, offsetHeight: n } = this._video, a = r / n;
|
||||
@@ -213,6 +251,7 @@ const _o = class _o extends EventTarget {
|
||||
return { width: e, height: t };
|
||||
}
|
||||
_timeupdate({ type: e }) {
|
||||
if (this._destroyed) return;
|
||||
const s = {
|
||||
seeking: true,
|
||||
waiting: true,
|
||||
@@ -225,7 +264,34 @@ const _o = class _o extends EventTarget {
|
||||
* @param {HTMLVideoElement} video
|
||||
*/
|
||||
setVideo(e) {
|
||||
e instanceof HTMLVideoElement ? (this._removeListeners(), this._video = e, this._onDemandRender ? this._video.requestVideoFrameCallback(this._handleRVFC.bind(this)) : (this._playstate = e.paused, e.addEventListener("timeupdate", this._boundTimeUpdate, false), e.addEventListener("progress", this._boundTimeUpdate, false), e.addEventListener("waiting", this._boundTimeUpdate, false), e.addEventListener("seeking", this._boundTimeUpdate, false), e.addEventListener("playing", this._boundTimeUpdate, false), e.addEventListener("ratechange", this._boundSetRate, false), e.addEventListener("resize", this._boundResize, false)), "VideoFrame" in window && (e.addEventListener("loadedmetadata", this._boundUpdateColorSpace, false), e.readyState > 2 && this._updateColorSpace()), e.videoWidth > 0 && this.resize(), typeof ResizeObserver < "u" && (this._ro || (this._ro = new ResizeObserver(() => this.resize())), this._ro.observe(e))) : this._error("Video element invalid!");
|
||||
if (this._destroyed) return;
|
||||
if (!(e instanceof HTMLVideoElement)) {
|
||||
this._error("Video element invalid!");
|
||||
return;
|
||||
}
|
||||
this._removeListeners();
|
||||
this._video = e;
|
||||
this._videoWidth = this._videoHeight = 0;
|
||||
this._videoColorSpace = null;
|
||||
if (this._canvasParent && this._canvasParent.parentNode !== e.parentNode)
|
||||
e.insertAdjacentElement("afterend", this._canvasParent);
|
||||
if (this._onDemandRender) this._requestFrame();
|
||||
else {
|
||||
this._playstate = e.paused;
|
||||
for (const name of ["timeupdate", "progress", "waiting", "seeking", "playing"])
|
||||
e.addEventListener(name, this._boundTimeUpdate, false);
|
||||
e.addEventListener("ratechange", this._boundSetRate, false);
|
||||
e.addEventListener("resize", this._boundResize, false);
|
||||
}
|
||||
if ("VideoFrame" in window) {
|
||||
e.addEventListener("loadedmetadata", this._boundUpdateColorSpace, false);
|
||||
if (e.readyState > 2) this._updateColorSpace();
|
||||
}
|
||||
if (e.videoWidth > 0) this.resize();
|
||||
if (typeof ResizeObserver < "u") {
|
||||
this._ro || (this._ro = new ResizeObserver(() => this.resize()));
|
||||
this._ro.observe(e);
|
||||
}
|
||||
}
|
||||
runBenchmark() {
|
||||
this.sendMessage("runBenchmark");
|
||||
@@ -317,7 +383,7 @@ const _o = class _o extends EventTarget {
|
||||
getEvents(e) {
|
||||
this._fetchFromWorker({
|
||||
target: "getEvents"
|
||||
}, (t, { events: s }) => {
|
||||
}, (t, { events: s } = {}) => {
|
||||
e(t, s);
|
||||
});
|
||||
}
|
||||
@@ -392,7 +458,7 @@ const _o = class _o extends EventTarget {
|
||||
getStyles(e) {
|
||||
this._fetchFromWorker({
|
||||
target: "getStyles"
|
||||
}, (t, { styles: s }) => {
|
||||
}, (t, { styles: s } = {}) => {
|
||||
e(t, s);
|
||||
});
|
||||
}
|
||||
@@ -434,12 +500,22 @@ const _o = class _o extends EventTarget {
|
||||
}
|
||||
}
|
||||
_unbusy() {
|
||||
if (this._destroyed) return;
|
||||
this._lastDemandTime ? this._demandRender(this._lastDemandTime) : this.busy = false;
|
||||
}
|
||||
_handleRVFC(e, { mediaTime: t, width: s, height: r }) {
|
||||
if (this._destroyed)
|
||||
return null;
|
||||
this.busy ? this._lastDemandTime = { mediaTime: t, width: s, height: r } : (this.busy = true, this._demandRender({ mediaTime: t, width: s, height: r })), this._video.requestVideoFrameCallback(this._handleRVFC.bind(this));
|
||||
this.busy ? this._lastDemandTime = { mediaTime: t, width: s, height: r } : (this.busy = true, this._demandRender({ mediaTime: t, width: s, height: r })), this._requestFrame();
|
||||
}
|
||||
_requestFrame() {
|
||||
if (this._destroyed || !this._video || this._frameCallback != null) return;
|
||||
const video = this._video, generation = this._videoGeneration;
|
||||
this._frameCallback = video.requestVideoFrameCallback((time, metadata) => {
|
||||
if (this._destroyed || generation !== this._videoGeneration || video !== this._video) return;
|
||||
this._frameCallback = null;
|
||||
this._handleRVFC(time, metadata);
|
||||
});
|
||||
}
|
||||
_demandRender({ mediaTime: e, width: t, height: s }) {
|
||||
this._lastDemandTime = null, (t !== this._videoWidth || s !== this._videoHeight) && (this._videoWidth = t, this._videoHeight = s, this.resize()), this.sendMessage("demand", { time: e + this.timeOffset });
|
||||
@@ -452,17 +528,25 @@ const _o = class _o extends EventTarget {
|
||||
}
|
||||
// if the video or track changed, we need to re-attach the offscreen canvas
|
||||
_reAttachOffscreen() {
|
||||
if (!this._offscreenRender || !this._ctx)
|
||||
if (this._destroyed || !this._offscreenRender || !this._ctx)
|
||||
return null;
|
||||
this._canvas.remove(), this._createCanvas(), this._canvasctrl = this._canvas.transferControlToOffscreen(), this._ctx = false, this.sendMessage("offscreenCanvas", null, [this._canvasctrl]), this.resize(0, 0, 0, 0, true);
|
||||
this._canvas.remove(), this._createCanvas(), this._canvasctrl = this._canvas.transferControlToOffscreen(), this._ctx = false, this.busy = false, this._lastDemandTime = null, this.sendMessage("offscreenCanvas", null, [this._canvasctrl]), this.resize(0, 0, 0, 0, true);
|
||||
}
|
||||
_updateColorSpace() {
|
||||
this._video.requestVideoFrameCallback(() => {
|
||||
if (this._destroyed || this._colorCallback != null) return;
|
||||
const video = this._video, generation = this._videoGeneration;
|
||||
this._colorCallback = video.requestVideoFrameCallback(() => {
|
||||
if (this._destroyed || generation !== this._videoGeneration || video !== this._video) return;
|
||||
this._colorCallback = null;
|
||||
let frame;
|
||||
try {
|
||||
const e = new VideoFrame(this._video);
|
||||
this._videoColorSpace = _[e.colorSpace.matrix], e.close(), this.sendMessage("getColorSpace");
|
||||
frame = new VideoFrame(video);
|
||||
this._videoColorSpace = _[frame.colorSpace.matrix];
|
||||
this.sendMessage("getColorSpace");
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
} finally {
|
||||
frame?.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -476,9 +560,17 @@ const _o = class _o extends EventTarget {
|
||||
!e || !t || e !== t && (this._detachOffscreen(), this._ctx.filter = `url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'><filter id='f'><feColorMatrix type='matrix' values='${f[e][t]} 0 0 0 0 0 1 0'/></filter></svg>#f")`);
|
||||
}
|
||||
_render({ images: e, asyncRender: t, times: s, width: r, height: n, colorSpace: a }) {
|
||||
this._unbusy(), this.debug && (s.IPCTime = Date.now() - s.JSRenderTime), (this._canvasctrl.width !== r || this._canvasctrl.height !== n) && (this._canvasctrl.width = r, this._canvasctrl.height = n, this._verifyColorSpace({ subtitleColorSpace: a })), this._ctx.clearRect(0, 0, this._canvasctrl.width, this._canvasctrl.height);
|
||||
for (const i of e)
|
||||
i.image && (t ? (this._ctx.drawImage(i.image, i.x, i.y), i.image.close()) : (this._bufferCanvas.width = i.w, this._bufferCanvas.height = i.h, this._bufferCtx.putImageData(new ImageData(this._fixAlpha(new Uint8ClampedArray(i.image)), i.w, i.h), 0, 0), this._ctx.drawImage(this._bufferCanvas, i.x, i.y)));
|
||||
if (!this._ctx) {
|
||||
for (const image of e) image.image?.close?.();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this._unbusy(), this.debug && (s.IPCTime = Date.now() - s.JSRenderTime), (this._canvasctrl.width !== r || this._canvasctrl.height !== n) && (this._canvasctrl.width = r, this._canvasctrl.height = n, this._verifyColorSpace({ subtitleColorSpace: a })), this._ctx.clearRect(0, 0, this._canvasctrl.width, this._canvasctrl.height);
|
||||
for (const i of e)
|
||||
i.image && (t ? this._ctx.drawImage(i.image, i.x, i.y) : (this._bufferCanvas.width = i.w, this._bufferCanvas.height = i.h, this._bufferCtx.putImageData(new ImageData(this._fixAlpha(new Uint8ClampedArray(i.image)), i.w, i.h), 0, 0), this._ctx.drawImage(this._bufferCanvas, i.x, i.y)));
|
||||
} finally {
|
||||
if (t) for (const i of e) i.image?.close();
|
||||
}
|
||||
if (this.debug) {
|
||||
s.JSRenderTime = Date.now() - s.JSRenderTime - s.IPCTime;
|
||||
let i = 0;
|
||||
@@ -496,6 +588,11 @@ const _o = class _o extends EventTarget {
|
||||
return e;
|
||||
}
|
||||
_ready() {
|
||||
if (this._destroyed) return;
|
||||
if (this._offscreenRender === true && !this._initialOffscreenSent) {
|
||||
this._initialOffscreenSent = true;
|
||||
this._worker.postMessage({ target: "offscreenCanvas", transferable: [this._canvasctrl] }, [this._canvasctrl]);
|
||||
}
|
||||
this._init(), this.dispatchEvent(new CustomEvent("ready"));
|
||||
}
|
||||
/**
|
||||
@@ -505,7 +602,10 @@ const _o = class _o extends EventTarget {
|
||||
* @param {Transferable[]} [transferable] Array of transferables.
|
||||
*/
|
||||
async sendMessage(e, t = {}, s) {
|
||||
await this._loaded, s ? this._worker.postMessage({
|
||||
if (this._destroyed) return;
|
||||
await this._loaded;
|
||||
if (this._destroyed) return;
|
||||
s ? this._worker.postMessage({
|
||||
target: e,
|
||||
transferable: s,
|
||||
...t
|
||||
@@ -515,23 +615,53 @@ const _o = class _o extends EventTarget {
|
||||
});
|
||||
}
|
||||
_fetchFromWorker(e, t) {
|
||||
if (this._destroyed) {
|
||||
t(new Error("JASSUB instance destroyed"));
|
||||
return;
|
||||
}
|
||||
const worker = this._worker;
|
||||
let timer, settled = false;
|
||||
const cleanup = () => {
|
||||
worker.removeEventListener("message", onMessage);
|
||||
worker.removeEventListener("error", onError);
|
||||
clearTimeout(timer);
|
||||
this._requests.delete(cancel);
|
||||
};
|
||||
const finish = (error, data) => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
cleanup();
|
||||
t(error, data);
|
||||
};
|
||||
const onMessage = ({ data }) => {
|
||||
if (data.target === e.target) finish(null, data);
|
||||
};
|
||||
const onError = (error) => finish(error);
|
||||
const cancel = () => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
cleanup();
|
||||
return () => t(new Error("JASSUB instance destroyed"));
|
||||
};
|
||||
try {
|
||||
const s = e.target, r = setTimeout(() => {
|
||||
a(new Error("Error: Timeout while try to fetch " + s));
|
||||
}, 5e3), n = ({ data: i }) => {
|
||||
i.target === s && (t(null, i), this._worker.removeEventListener("message", n), this._worker.removeEventListener("error", a), clearTimeout(r));
|
||||
}, a = (i) => {
|
||||
t(i), this._worker.removeEventListener("message", n), this._worker.removeEventListener("error", a), clearTimeout(r);
|
||||
};
|
||||
this._worker.addEventListener("message", n), this._worker.addEventListener("error", a), this._worker.postMessage(e);
|
||||
this._requests.add(cancel);
|
||||
worker.addEventListener("message", onMessage);
|
||||
worker.addEventListener("error", onError);
|
||||
timer = setTimeout(() => onError(new Error("Error: Timeout while try to fetch " + e.target)), 5e3);
|
||||
worker.postMessage(e);
|
||||
} catch (s) {
|
||||
this._error(s);
|
||||
if (settled) throw s;
|
||||
finish(s);
|
||||
}
|
||||
}
|
||||
_console({ content: e, command: t }) {
|
||||
console[t].apply(console, JSON.parse(e));
|
||||
}
|
||||
_onmessage({ data: e }) {
|
||||
if (this._destroyed) {
|
||||
for (const image of e.images || []) image.image?.close?.();
|
||||
return;
|
||||
}
|
||||
this["_" + e.target] && this["_" + e.target](e);
|
||||
}
|
||||
_error(e) {
|
||||
@@ -539,6 +669,12 @@ const _o = class _o extends EventTarget {
|
||||
return this.dispatchEvent(s), console.error(t), t;
|
||||
}
|
||||
_removeListeners() {
|
||||
this._videoGeneration = (this._videoGeneration || 0) + 1;
|
||||
for (const id of [this._frameCallback, this._colorCallback])
|
||||
if (id != null) this._video?.cancelVideoFrameCallback?.(id);
|
||||
this._frameCallback = this._colorCallback = null;
|
||||
this._lastDemandTime = null;
|
||||
if (this._onDemandRender) this.busy = false;
|
||||
this._video && (this._ro && this._ro.unobserve(this._video), this._ctx && (this._ctx.filter = "none"), this._video.removeEventListener("timeupdate", this._boundTimeUpdate), this._video.removeEventListener("progress", this._boundTimeUpdate), this._video.removeEventListener("waiting", this._boundTimeUpdate), this._video.removeEventListener("seeking", this._boundTimeUpdate), this._video.removeEventListener("playing", this._boundTimeUpdate), this._video.removeEventListener("ratechange", this._boundSetRate), this._video.removeEventListener("resize", this._boundResize), this._video.removeEventListener("loadedmetadata", this._boundUpdateColorSpace));
|
||||
}
|
||||
/**
|
||||
@@ -546,7 +682,38 @@ const _o = class _o extends EventTarget {
|
||||
* @param {String|Error} [err] Error to throw when destroying.
|
||||
*/
|
||||
destroy(e) {
|
||||
return e && (e = this._error(e)), this._video && this._canvasParent && this._video.parentNode?.removeChild(this._canvasParent), this._destroyed = true, this._removeListeners(), this.sendMessage("destroy"), this._worker?.terminate(), e;
|
||||
if (this._destroyed) return e && this._error(e);
|
||||
this._destroyed = true;
|
||||
let failure, failed = false;
|
||||
const attempt = (callback) => {
|
||||
try {
|
||||
callback();
|
||||
} catch (error) {
|
||||
if (!failed) {
|
||||
failure = error;
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
if (e) attempt(() => {
|
||||
e = this._error(e);
|
||||
});
|
||||
attempt(() => this._removeListeners());
|
||||
attempt(() => this._ro?.disconnect());
|
||||
attempt(() => this._canvasParent?.remove());
|
||||
this._init?.();
|
||||
const callbacks = [];
|
||||
for (const cancel of [...this._requests || []]) attempt(() => {
|
||||
const notify = cancel();
|
||||
if (notify) callbacks.push(notify);
|
||||
});
|
||||
for (const notify of callbacks) attempt(notify);
|
||||
if (this._worker) {
|
||||
this._worker.onmessage = this._worker.onerror = null;
|
||||
attempt(() => this._worker.terminate());
|
||||
}
|
||||
if (failed) throw failure;
|
||||
return e;
|
||||
}
|
||||
};
|
||||
// test support for WASM, ImageData, alphaBug, but only once, on init so it doesn't run when first running the page
|
||||
@@ -557,21 +724,39 @@ __publicField(_o, "_hasAlphaBug", null);
|
||||
/** @type {boolean|null} */
|
||||
__publicField(_o, "_hasBitmapBug", null);
|
||||
let o = _o;
|
||||
function artplayerPluginJassub(option) {
|
||||
return (art) => {
|
||||
const instance = new o({
|
||||
video: art.video,
|
||||
...option
|
||||
});
|
||||
instance._canvasParent.style.zIndex = 20;
|
||||
art.on("destroy", () => {
|
||||
function registerJassub(art, option) {
|
||||
const instance = new o({ video: art.video, ...option });
|
||||
let disposed = false;
|
||||
const dispose = () => {
|
||||
if (disposed || instance._destroyed)
|
||||
return;
|
||||
disposed = true;
|
||||
try {
|
||||
instance.destroy();
|
||||
});
|
||||
return {
|
||||
name: "artplayerPluginJassub",
|
||||
instance
|
||||
};
|
||||
} catch (error) {
|
||||
disposed = false;
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
try {
|
||||
if (instance._canvasParent)
|
||||
instance._canvasParent.style.zIndex = 20;
|
||||
art.on("destroy", dispose);
|
||||
} catch (error) {
|
||||
try {
|
||||
art.off("destroy", dispose);
|
||||
} catch {
|
||||
}
|
||||
try {
|
||||
dispose();
|
||||
} catch {
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
return { name: "artplayerPluginJassub", instance };
|
||||
}
|
||||
function artplayerPluginJassub(option) {
|
||||
return (art) => registerJassub(art, option);
|
||||
}
|
||||
export {
|
||||
artplayerPluginJassub as default
|
||||
|
||||
@@ -1,7 +1,58 @@
|
||||
/*!
|
||||
* artplayer-plugin-multiple-subtitles.js v1.2.0
|
||||
* artplayer-plugin-multiple-subtitles.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*
|
||||
* This package includes WebVTT parser and serializer code from w3c/webvtt.js.
|
||||
* Reference revision: 380cfcce34ba8b472d3a31474874eb72a0e5f460
|
||||
* https://github.com/w3c/webvtt.js/tree/380cfcce34ba8b472d3a31474874eb72a0e5f460
|
||||
* The parser has a CC0 public-domain dedication. Local adaptations replace
|
||||
* the IIFE/global exports with named ESM exports and format the code.
|
||||
* The ArtPlayer plugin wrapper remains MIT licensed.
|
||||
*
|
||||
* ## creative commons
|
||||
*
|
||||
* # CC0 1.0 Universal
|
||||
*
|
||||
* CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER.
|
||||
*
|
||||
* ### Statement of Purpose
|
||||
*
|
||||
* The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
|
||||
*
|
||||
* Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
|
||||
*
|
||||
* For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
*
|
||||
* 1. __Copyright and Related Rights.__ A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
|
||||
*
|
||||
* i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
|
||||
*
|
||||
* ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
*
|
||||
* iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
|
||||
*
|
||||
* iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
|
||||
*
|
||||
* v. rights protecting the extraction, dissemination, use and reuse of data in a Work;
|
||||
*
|
||||
* vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
|
||||
*
|
||||
* vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
|
||||
*
|
||||
* 2. __Waiver.__ To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||
*
|
||||
* 3. __Public License Fallback.__ Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
|
||||
*
|
||||
* 4. __Limitations and Disclaimers.__
|
||||
*
|
||||
* a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
|
||||
*
|
||||
* b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
|
||||
*
|
||||
* c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
|
||||
*
|
||||
* d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
|
||||
*/
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerPluginMultipleSubtitles=t(),define(function(){return t.artplayerPluginMultipleSubtitles})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginMultipleSubtitles=t()}(this,function(){"use strict";var e={direction:"horizontal",snapToLines:!0,linePosition:"auto",lineAlign:"start",textPosition:"auto",positionAlign:"auto",size:100,alignment:"center"},t=function(t){t||(t={"&":"&","<":"<",">":">","&lrm":"\u200e","&rlm":"\u200f"," ":"\xa0"}),this.entities=t,this.parse=function(a,s){a=a.replace(/\0/g,"\ufffd");var r=Date.now(),o=0,l=a.split(/\r\n|\r|\n/),f=!1,c=[],u=[],d=[];function p(e,t){d.push({message:e,line:o+1,col:t})}var m=l[o],g=m.length,h="WEBVTT",v=0,b=6;for("\ufeff"===m[0]&&(v=1,b+=1),(g<b||m.indexOf(h)!==0+v||g>b&&" "!==m[b]&&"\t"!==m[b])&&p('No valid signature. (File needs to start with "WEBVTT".)'),o++;""!=l[o]&&void 0!=l[o];){if(p("No blank line after the signature."),-1!=l[o].indexOf("--\x3e")){f=!0;break}o++}for(;void 0!=l[o];){for(var x;!f&&""==l[o];)o++;if(!f&&void 0==l[o])break;x=Object.assign({},e,{id:"",startTime:0,endTime:0,pauseOnExit:!1,direction:"horizontal",snapToLines:!0,linePosition:"auto",lineAlign:"start",textPosition:"auto",positionAlign:"auto",size:100,alignment:"center",text:"",tree:null});var T=!0;if(-1==l[o].indexOf("--\x3e")){if(x.id=l[o],/^NOTE($|[ \t])/.test(x.id)){for(o++;""!=l[o]&&void 0!=l[o];)-1!=l[o].indexOf("--\x3e")&&p("Cannot have timestamp in a comment."),o++;continue}if(/^STYLE($|[ \t])/.test(x.id)){var y=[],w=!1;for(o++;""!=l[o]&&void 0!=l[o];)-1!=l[o].indexOf("--\x3e")&&(p("Cannot have timestamp in a style block."),w=!0),y.push(l[o]),o++;if(u.length){p("Style blocks cannot appear after the first cue.");continue}w||c.push(y.join("\n"));continue}if(""==l[++o]||void 0==l[o]){p("Cue identifier cannot be standalone.");continue}if(-1==l[o].indexOf("--\x3e")){T=!1,p("Cue identifier needs to be followed by timestamp.");continue}}f=!1;var O=new n(l[o],p),L=0;if(u.length>0&&(L=u[u.length-1].startTime),!T||O.parse(x,L)){for(o++;""!=l[o]&&void 0!=l[o];){if(-1!=l[o].indexOf("--\x3e")){p("Blank line missing before cue."),f=!0;break}""!=x.text&&(x.text+="\n"),x.text+=l[o],o++}var I=new i(x.text,p,s,t);x.tree=I.parse(x.startTime,x.endTime),u.push(x)}else for(x=null,o++;""!=l[o]&&void 0!=l[o];){if(-1!=l[o].indexOf("--\x3e")){f=!0;break}o++}}return u.sort(function(e,t){return e.startTime<t.startTime?-1:e.startTime>t.startTime?1:e.endTime>t.endTime?-1:e.endTime<t.endTime?1:0}),{cues:u,errors:d,time:Date.now()-r,styles:c}}},n=function(e,t){var n=/[\u0020\t\f]/,i=/[^\u0020\t\f]/,a=(e=e,0),s=function(e){t(e,a+1)};function r(t){for(;void 0!=e[a]&&t.test(e[a]);)a++}function o(t){for(var n="";void 0!=e[a]&&t.test(e[a]);)n+=e[a],a++;return n}function l(){var t,n,i,r,l="minutes";if(void 0!=e[a])if(/\d/.test(e[a]))if(((t=o(/\d/)).length>2||parseInt(t,10)>59)&&(l="hours"),":"==e[a])if(a++,2==(n=o(/\d/)).length){if("hours"==l||":"==e[a]){if(":"!=e[a])return void s("No seconds found or minutes is greater than 59.");if(a++,2!=(i=o(/\d/)).length)return void s("Must be exactly two digits.")}else{if(2!=t.length)return void s("Must be exactly two digits.");i=n,n=t,t="0"}if("."==e[a])if(a++,3==(r=o(/\d/)).length)if(parseInt(n,10)>59)s("You cannot have more than 59 minutes.");else{if(!(parseInt(i,10)>59))return 60*parseInt(t,10)*60+60*parseInt(n,10)+parseInt(i,10)+parseInt(r,10)/1e3;s("You cannot have more than 59 seconds.")}else s("Milliseconds must be given in three digits.");else s('No decimal separator (".") found.')}else s("Must be exactly two digits.");else s("No time unit separator found.");else s("Timestamp must start with a character in the range 0-9.");else s("No timestamp found.")}this.parse=function(t,o){if(r(n),t.startTime=l(),void 0!=t.startTime)if(t.startTime<o&&s("Start timestamp is not greater than or equal to start timestamp of previous cue."),i.test(e[a])&&s("Timestamp not separated from '--\x3e' by whitespace."),r(n),"-"==e[a])if(a++,"-"==e[a])if(a++,">"==e[a]){if(a++,i.test(e[a])&&s("'--\x3e' not separated from timestamp by whitespace."),r(n),t.endTime=l(),void 0!=t.endTime)return t.endTime<=t.startTime&&s("End timestamp is not greater than start timestamp."),i.test(e[a]),r(n),function(e,t){for(var i=e.split(n),a=[],r=0;r<i.length;r++)if(""!=i[r]){var o=i[r].indexOf(":"),l=i[r].slice(0,o),f=i[r].slice(o+1);if(-1!=a.indexOf(l)&&s("Duplicate setting."),a.push(l),""==f)return void s("No value for setting defined.");if("vertical"==l){if("rl"!=f&&"lr"!=f){s("Writing direction can only be set to 'rl' or 'rl'.");continue}t.direction=f}else if("line"==l){if(/,/.test(f)){var c=f.split(",");f=c[0];var u=c[1]}if(!/^[-\d](\d*)(\.\d+)?%?$/.test(f)){s("Line position takes a number or percentage.");continue}if(-1!=f.indexOf("-",1)){s("Line position can only have '-' at the start.");continue}if(-1!=f.indexOf("%")&&f.indexOf("%")!=f.Line truncated
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginMultipleSubtitles=t(),define(function(){return e.artplayerPluginMultipleSubtitles})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginMultipleSubtitles=t()}(this,function(){"use strict";var e={direction:"horizontal",snapToLines:!0,linePosition:"auto",lineAlign:"start",textPosition:"auto",positionAlign:"auto",size:100,alignment:"center"},t=function(t){t||(t={"&":"&","<":"<",">":">","&lrm":"\u200e","&rlm":"\u200f"," ":"\xa0"}),this.entities=t,this.parse=function(s,a){s=s.replace(/\0/g,"\ufffd");var r=Date.now(),o=0,l=s.split(/\r\n|\r|\n/),c=!1,f=[],u=[],d=[];function p(e,t){d.push({message:e,line:o+1,col:t})}var m=l[o],g=m.length,h="WEBVTT",v=0,b=6;for("\ufeff"===m[0]&&(v=1,b+=1),(g<b||m.indexOf(h)!==0+v||g>b&&" "!==m[b]&&"\t"!==m[b])&&p('No valid signature. (File needs to start with "WEBVTT".)'),o++;""!=l[o]&&void 0!=l[o];){if(p("No blank line after the signature."),-1!=l[o].indexOf("--\x3e")){c=!0;break}o++}for(;void 0!=l[o];){for(var x;!c&&""==l[o];)o++;if(!c&&void 0==l[o])break;x=Object.assign({},e,{id:"",startTime:0,endTime:0,pauseOnExit:!1,direction:"horizontal",snapToLines:!0,linePosition:"auto",lineAlign:"start",textPosition:"auto",positionAlign:"auto",size:100,alignment:"center",text:"",tree:null});var T=!0;if(-1==l[o].indexOf("--\x3e")){if(x.id=l[o],/^NOTE($|[ \t])/.test(x.id)){for(o++;""!=l[o]&&void 0!=l[o];)-1!=l[o].indexOf("--\x3e")&&p("Cannot have timestamp in a comment."),o++;continue}if(/^STYLE($|[ \t])/.test(x.id)){var y=[],w=!1;for(o++;""!=l[o]&&void 0!=l[o];)-1!=l[o].indexOf("--\x3e")&&(p("Cannot have timestamp in a style block."),w=!0),y.push(l[o]),o++;if(u.length){p("Style blocks cannot appear after the first cue.");continue}w||f.push(y.join("\n"));continue}if(""==l[++o]||void 0==l[o]){p("Cue identifier cannot be standalone.");continue}if(-1==l[o].indexOf("--\x3e")){T=!1,p("Cue identifier needs to be followed by timestamp.");continue}}c=!1;var $=new n(l[o],p),A=0;if(u.length>0&&(A=u[u.length-1].startTime),!T||$.parse(x,A)){for(o++;""!=l[o]&&void 0!=l[o];){if(-1!=l[o].indexOf("--\x3e")){p("Blank line missing before cue."),c=!0;break}""!=x.text&&(x.text+="\n"),x.text+=l[o],o++}var O=new i(x.text,p,a,t);x.tree=O.parse(x.startTime,x.endTime),u.push(x)}else for(x=null,o++;""!=l[o]&&void 0!=l[o];){if(-1!=l[o].indexOf("--\x3e")){c=!0;break}o++}}return u.sort(function(e,t){return e.startTime<t.startTime?-1:e.startTime>t.startTime?1:e.endTime>t.endTime?-1:e.endTime<t.endTime?1:0}),{cues:u,errors:d,time:Date.now()-r,styles:f}}},n=function(e,t){var n=/[\u0020\t\f]/,i=/[^\u0020\t\f]/,s=(e=e,0),a=function(e){t(e,s+1)};function r(t){for(;void 0!=e[s]&&t.test(e[s]);)s++}function o(t){for(var n="";void 0!=e[s]&&t.test(e[s]);)n+=e[s],s++;return n}function l(){var t,n,i,r,l="minutes";if(void 0!=e[s])if(/\d/.test(e[s]))if(((t=o(/\d/)).length>2||parseInt(t,10)>59)&&(l="hours"),":"==e[s])if(s++,2==(n=o(/\d/)).length){if("hours"==l||":"==e[s]){if(":"!=e[s])return void a("No seconds found or minutes is greater than 59.");if(s++,2!=(i=o(/\d/)).length)return void a("Must be exactly two digits.")}else{if(2!=t.length)return void a("Must be exactly two digits.");i=n,n=t,t="0"}if("."==e[s])if(s++,3==(r=o(/\d/)).length)if(parseInt(n,10)>59)a("You cannot have more than 59 minutes.");else{if(!(parseInt(i,10)>59))return 60*parseInt(t,10)*60+60*parseInt(n,10)+parseInt(i,10)+parseInt(r,10)/1e3;a("You cannot have more than 59 seconds.")}else a("Milliseconds must be given in three digits.");else a('No decimal separator (".") found.')}else a("Must be exactly two digits.");else a("No time unit separator found.");else a("Timestamp must start with a character in the range 0-9.");else a("No timestamp found.")}this.parse=function(t,o){if(r(n),t.startTime=l(),void 0!=t.startTime)if(t.startTime<o&&a("Start timestamp is not greater than or equal to start timestamp of previous cue."),i.test(e[s])&&a("Timestamp not separated from '--\x3e' by whitespace."),r(n),"-"==e[s])if(s++,"-"==e[s])if(s++,">"==e[s]){if(s++,i.test(e[s])&&a("'--\x3e' not separated from timestamp by whitespace."),r(n),t.endTime=l(),void 0!=t.endTime)return t.endTime<=t.startTime&&a("End timestamp is not greater than start timestamp."),i.test(e[s]),r(n),function(e,t){for(var i=e.split(n),s=[],r=0;r<i.length;r++)if(""!=i[r]){var o=i[r].indexOf(":"),l=i[r].slice(0,o),c=i[r].slice(o+1);if(-1!=s.indexOf(l)&&a("Duplicate setting."),s.push(l),""==c)return void a("No value for setting defined.");if("vertical"==l){if("rl"!=c&&"lr"!=c){a("Writing direction can only be set to 'rl' or 'rl'.");continue}t.direction=c}else if("line"==l){if(/,/.test(c)){var f=c.split(",");c=f[0];var u=f[1]}if(!/^[-\d](\d*)(\.\d+)?%?$/.test(c)){a("Line position takes a number or percentage.");continue}if(-1!=c.indexOf("-",1)){a("Line position can only have '-' at the start.");continue}if(-1!=c.indexOf("%")&&c.indexOf("%")!=c.Line truncated
|
||||
@@ -1,7 +1,58 @@
|
||||
/*!
|
||||
* artplayer-plugin-multiple-subtitles.js v1.2.0
|
||||
* artplayer-plugin-multiple-subtitles.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*
|
||||
* This package includes WebVTT parser and serializer code from w3c/webvtt.js.
|
||||
* Reference revision: 380cfcce34ba8b472d3a31474874eb72a0e5f460
|
||||
* https://github.com/w3c/webvtt.js/tree/380cfcce34ba8b472d3a31474874eb72a0e5f460
|
||||
* The parser has a CC0 public-domain dedication. Local adaptations replace
|
||||
* the IIFE/global exports with named ESM exports and format the code.
|
||||
* The ArtPlayer plugin wrapper remains MIT licensed.
|
||||
*
|
||||
* ## creative commons
|
||||
*
|
||||
* # CC0 1.0 Universal
|
||||
*
|
||||
* CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER.
|
||||
*
|
||||
* ### Statement of Purpose
|
||||
*
|
||||
* The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
|
||||
*
|
||||
* Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
|
||||
*
|
||||
* For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
*
|
||||
* 1. __Copyright and Related Rights.__ A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
|
||||
*
|
||||
* i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
|
||||
*
|
||||
* ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
*
|
||||
* iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
|
||||
*
|
||||
* iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
|
||||
*
|
||||
* v. rights protecting the extraction, dissemination, use and reuse of data in a Work;
|
||||
*
|
||||
* vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
|
||||
*
|
||||
* vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
|
||||
*
|
||||
* 2. __Waiver.__ To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||
*
|
||||
* 3. __Public License Fallback.__ Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
|
||||
*
|
||||
* 4. __Limitations and Disclaimers.__
|
||||
*
|
||||
* a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
|
||||
*
|
||||
* b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
|
||||
*
|
||||
* c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
|
||||
*
|
||||
* d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
|
||||
*/
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerPluginMultipleSubtitles=t(),define(function(){return t.artplayerPluginMultipleSubtitles})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginMultipleSubtitles=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.defineProperties,n=Object.getOwnPropertyDescriptors,i=Object.getOwnPropertySymbols,a=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,r=(t,n,i)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[n]=i,o=(e,t)=>{for(var n in t||(t={}))a.call(t,n)&&r(e,n,t[n]);if(i)for(var n of i(t))s.call(t,n)&&r(e,n,t[n]);return e},l=(e,t,n)=>new Promise((i,a)=>{var s=e=>{try{o(n.next(e))}catch(t){a(t)}},r=e=>{try{o(n.throw(e))}catch(t){a(t)}},o=e=>e.done?i(e.value):Promise.resolve(e.value).then(s,r);o((n=n.apply(e,t)).next())}),f={direction:"horizontal",snapToLines:!0,linePosition:"auto",lineAlign:"start",textPosition:"auto",positionAlign:"auto",size:100,alignment:"center"},c=function(e){e||(e={"&":"&","<":"<",">":">","&lrm":"\u200e","&rlm":"\u200f"," ":"\xa0"}),this.entities=e,this.parse=function(t,n){t=t.replace(/\0/g,"\ufffd");var i=Date.now(),a=0,s=t.split(/\r\n|\r|\n/),r=!1,o=[],l=[],c=[];function p(e,t){c.push({message:e,line:a+1,col:t})}var m=s[a],g=m.length,h="WEBVTT",v=0,b=6;for("\ufeff"===m[0]&&(v=1,b+=1),(g<b||m.indexOf(h)!==0+v||g>b&&" "!==m[b]&&"\t"!==m[b])&&p('No valid signature. (File needs to start with "WEBVTT".)'),a++;""!=s[a]&&void 0!=s[a];){if(p("No blank line after the signature."),-1!=s[a].indexOf("--\x3e")){r=!0;break}a++}for(;void 0!=s[a];){for(var x;!r&&""==s[a];)a++;if(!r&&void 0==s[a])break;x=Object.assign({},f,{id:"",startTime:0,endTime:0,pauseOnExit:!1,direction:"horizontal",snapToLines:!0,linePosition:"auto",lineAlign:"start",textPosition:"auto",positionAlign:"auto",size:100,alignment:"center",text:"",tree:null});var T=!0;if(-1==s[a].indexOf("--\x3e")){if(x.id=s[a],/^NOTE($|[ \t])/.test(x.id)){for(a++;""!=s[a]&&void 0!=s[a];)-1!=s[a].indexOf("--\x3e")&&p("Cannot have timestamp in a comment."),a++;continue}if(/^STYLE($|[ \t])/.test(x.id)){var y=[],w=!1;for(a++;""!=s[a]&&void 0!=s[a];)-1!=s[a].indexOf("--\x3e")&&(p("Cannot have timestamp in a style block."),w=!0),y.push(s[a]),a++;if(l.length){p("Style blocks cannot appear after the first cue.");continue}w||o.push(y.join("\n"));continue}if(""==s[++a]||void 0==s[a]){p("Cue identifier cannot be standalone.");continue}if(-1==s[a].indexOf("--\x3e")){T=!1,p("Cue identifier needs to be followed by timestamp.");continue}}r=!1;var O=new u(s[a],p),P=0;if(l.length>0&&(P=l[l.length-1].startTime),!T||O.parse(x,P)){for(a++;""!=s[a]&&void 0!=s[a];){if(-1!=s[a].indexOf("--\x3e")){p("Blank line missing before cue."),r=!0;break}""!=x.text&&(x.text+="\n"),x.text+=s[a],a++}var I=new d(x.text,p,n,e);x.tree=I.parse(x.startTime,x.endTime),l.push(x)}else for(x=null,a++;""!=s[a]&&void 0!=s[a];){if(-1!=s[a].indexOf("--\x3e")){r=!0;break}a++}}return l.sort(function(e,t){return e.startTime<t.startTime?-1:e.startTime>t.startTime?1:e.endTime>t.endTime?-1:e.endTime<t.endTime?1:0}),{cues:l,errors:c,time:Date.now()-i,styles:o}}},u=function(e,t){var n=/[\u0020\t\f]/,i=/[^\u0020\t\f]/,a=(e=e,0),s=function(e){t(e,a+1)};function r(t){for(;void 0!=e[a]&&t.test(e[a]);)a++}function o(t){for(var n="";void 0!=e[a]&&t.test(e[a]);)n+=e[a],a++;return n}function l(){var t,n,i,r,l="minutes";if(void 0!=e[a])if(/\d/.test(e[a]))if(((t=o(/\d/)).length>2||parseInt(t,10)>59)&&(l="hours"),":"==e[a])if(a++,2==(n=o(/\d/)).length){if("hours"==l||":"==e[a]){if(":"!=e[a])return void s("No seconds found or minutes is greater than 59.");if(a++,2!=(i=o(/\d/)).length)return void s("Must be exactly two digits.")}else{if(2!=t.length)return void s("Must be exactly two digits.");i=n,n=t,t="0"}if("."==e[a])if(a++,3==(r=o(/\d/)).length)if(parseInt(n,10)>59)s("You cannot have more than 59 minutes.");else{if(!(parseInt(i,10)>59))return 60*parseInt(t,10)*60+60*parseInt(n,10)+parseInt(i,10)+parseInt(r,10)/1e3;s("You cannot have more than 59 seconds.")}else s("Milliseconds must be given in three digits.");else s('No decimal separator (".") found.')}else s("Must be exactly two digits.");else s("No time unit separator found.");else s("Timestamp must start with a character in the range 0-9.");else s("No timestamp found.")}this.parse=function(t,o){if(r(n),t.startTime=l(),void 0!=t.startTime)if(t.startTime<o&&s("Start timestamp is not greater than or equal to start timestamp of previous cue."),i.test(e[a])&&s("Timestamp not separated from '--\x3e' by whitespace."),r(n),"-"==e[a])if(a++,"-"==e[a])if(a++,">"==e[a]){if(a++,i.test(e[a])&&s("'--\x3e' not separated from timestamp by whitespace."),r(n),t.endTime=l(),void 0!=t.endTime)return t.endTime<=t.startTime&&s("End timestamp is not greater than start timestamp."),i.test(e[a]),r(n),function(e,t){for(var i=e.split(n),a=[],r=0;r<i.length;r++)ifLine truncated
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginMultipleSubtitles=t(),define(function(){return e.artplayerPluginMultipleSubtitles})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginMultipleSubtitles=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.defineProperties,n=Object.getOwnPropertyDescriptors,i=Object.getOwnPropertySymbols,r=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,o=(t,n,i)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[n]=i,a=(e,t)=>{for(var n in t||(t={}))r.call(t,n)&&o(e,n,t[n]);if(i)for(var n of i(t))s.call(t,n)&&o(e,n,t[n]);return e},l=(e,i)=>t(e,n(i)),c=(e,t,n)=>new Promise((i,r)=>{var s=e=>{try{a(n.next(e))}catch(t){r(t)}},o=e=>{try{a(n.throw(e))}catch(t){r(t)}},a=e=>e.done?i(e.value):Promise.resolve(e.value).then(s,o);a((n=n.apply(e,t)).next())});var u={direction:"horizontal",snapToLines:!0,linePosition:"auto",lineAlign:"start",textPosition:"auto",positionAlign:"auto",size:100,alignment:"center"},f=function(e){e||(e={"&":"&","<":"<",">":">","&lrm":"\u200e","&rlm":"\u200f"," ":"\xa0"}),this.entities=e,this.parse=function(t,n){t=t.replace(/\0/g,"\ufffd");var i=Date.now(),r=0,s=t.split(/\r\n|\r|\n/),o=!1,a=[],l=[],c=[];function f(e,t){c.push({message:e,line:r+1,col:t})}var m=s[r],g=m.length,h="WEBVTT",v=0,b=6;for("\ufeff"===m[0]&&(v=1,b+=1),(g<b||m.indexOf(h)!==0+v||g>b&&" "!==m[b]&&"\t"!==m[b])&&f('No valid signature. (File needs to start with "WEBVTT".)'),r++;""!=s[r]&&void 0!=s[r];){if(f("No blank line after the signature."),-1!=s[r].indexOf("--\x3e")){o=!0;break}r++}for(;void 0!=s[r];){for(var y;!o&&""==s[r];)r++;if(!o&&void 0==s[r])break;y=Object.assign({},u,{id:"",startTime:0,endTime:0,pauseOnExit:!1,direction:"horizontal",snapToLines:!0,linePosition:"auto",lineAlign:"start",textPosition:"auto",positionAlign:"auto",size:100,alignment:"center",text:"",tree:null});var x=!0;if(-1==s[r].indexOf("--\x3e")){if(y.id=s[r],/^NOTE($|[ \t])/.test(y.id)){for(r++;""!=s[r]&&void 0!=s[r];)-1!=s[r].indexOf("--\x3e")&&f("Cannot have timestamp in a comment."),r++;continue}if(/^STYLE($|[ \t])/.test(y.id)){var T=[],w=!1;for(r++;""!=s[r]&&void 0!=s[r];)-1!=s[r].indexOf("--\x3e")&&(f("Cannot have timestamp in a style block."),w=!0),T.push(s[r]),r++;if(l.length){f("Style blocks cannot appear after the first cue.");continue}w||a.push(T.join("\n"));continue}if(""==s[++r]||void 0==s[r]){f("Cue identifier cannot be standalone.");continue}if(-1==s[r].indexOf("--\x3e")){x=!1,f("Cue identifier needs to be followed by timestamp.");continue}}o=!1;var O=new d(s[r],f),$=0;if(l.length>0&&($=l[l.length-1].startTime),!x||O.parse(y,$)){for(r++;""!=s[r]&&void 0!=s[r];){if(-1!=s[r].indexOf("--\x3e")){f("Blank line missing before cue."),o=!0;break}""!=y.text&&(y.text+="\n"),y.text+=s[r],r++}var j=new p(y.text,f,n,e);y.tree=j.parse(y.startTime,y.endTime),l.push(y)}else for(y=null,r++;""!=s[r]&&void 0!=s[r];){if(-1!=s[r].indexOf("--\x3e")){o=!0;break}r++}}return l.sort(function(e,t){return e.startTime<t.startTime?-1:e.startTime>t.startTime?1:e.endTime>t.endTime?-1:e.endTime<t.endTime?1:0}),{cues:l,errors:c,time:Date.now()-i,styles:a}}},d=function(e,t){var n=/[\u0020\t\f]/,i=/[^\u0020\t\f]/,r=(e=e,0),s=function(e){t(e,r+1)};function o(t){for(;void 0!=e[r]&&t.test(e[r]);)r++}function a(t){for(var n="";void 0!=e[r]&&t.test(e[r]);)n+=e[r],r++;return n}function l(){var t,n,i,o,l="minutes";if(void 0!=e[r])if(/\d/.test(e[r]))if(((t=a(/\d/)).length>2||parseInt(t,10)>59)&&(l="hours"),":"==e[r])if(r++,2==(n=a(/\d/)).length){if("hours"==l||":"==e[r]){if(":"!=e[r])return void s("No seconds found or minutes is greater than 59.");if(r++,2!=(i=a(/\d/)).length)return void s("Must be exactly two digits.")}else{if(2!=t.length)return void s("Must be exactly two digits.");i=n,n=t,t="0"}if("."==e[r])if(r++,3==(o=a(/\d/)).length)if(parseInt(n,10)>59)s("You cannot have more than 59 minutes.");else{if(!(parseInt(i,10)>59))return 60*parseInt(t,10)*60+60*parseInt(n,10)+parseInt(i,10)+parseInt(o,10)/1e3;s("You cannot have more than 59 seconds.")}else s("Milliseconds must be given in three digits.");else s('No decimal separator (".") found.')}else s("Must be exactly two digits.");else s("No time unit separator found.");else s("Timestamp must start with a character in the range 0-9.");else s("No timestamp found.")}this.parse=function(t,a){if(o(n),t.startTime=l(),void 0!=t.startTime)if(t.startTime<a&&s("Start timestamp is not greater than or equal to start timestamp of previous cue."),i.test(e[r])&&s("Timestamp not separated from '--\x3e' by whitespace."),o(n),"-"==e[r])if(r++,"-"==e[r])if(r++,">"==e[r]){if(r++,i.test(e[r])&&s("'--\x3e' not separated from timestamp by whitespace."),o(n),t.endTime=l(),void 0!=t.endTime)return t.endTime<=t.startTime&&s("End timestamp is not greater than start timestamp."),i.test(e[r]),o(n),function(e,t){for(var i=e.split(n),r=[Line truncated
|
||||
@@ -1,9 +1,80 @@
|
||||
/*!
|
||||
* artplayer-plugin-multiple-subtitles.js v1.2.0
|
||||
* artplayer-plugin-multiple-subtitles.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*
|
||||
* This package includes WebVTT parser and serializer code from w3c/webvtt.js.
|
||||
* Reference revision: 380cfcce34ba8b472d3a31474874eb72a0e5f460
|
||||
* https://github.com/w3c/webvtt.js/tree/380cfcce34ba8b472d3a31474874eb72a0e5f460
|
||||
* The parser has a CC0 public-domain dedication. Local adaptations replace
|
||||
* the IIFE/global exports with named ESM exports and format the code.
|
||||
* The ArtPlayer plugin wrapper remains MIT licensed.
|
||||
*
|
||||
* ## creative commons
|
||||
*
|
||||
* # CC0 1.0 Universal
|
||||
*
|
||||
* CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER.
|
||||
*
|
||||
* ### Statement of Purpose
|
||||
*
|
||||
* The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
|
||||
*
|
||||
* Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
|
||||
*
|
||||
* For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
*
|
||||
* 1. __Copyright and Related Rights.__ A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
|
||||
*
|
||||
* i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
|
||||
*
|
||||
* ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
*
|
||||
* iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
|
||||
*
|
||||
* iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
|
||||
*
|
||||
* v. rights protecting the extraction, dissemination, use and reuse of data in a Work;
|
||||
*
|
||||
* vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
|
||||
*
|
||||
* vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
|
||||
*
|
||||
* 2. __Waiver.__ To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||
*
|
||||
* 3. __Public License Fallback.__ Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
|
||||
*
|
||||
* 4. __Limitations and Disclaimers.__
|
||||
*
|
||||
* a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
|
||||
*
|
||||
* b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
|
||||
*
|
||||
* c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
|
||||
*
|
||||
* d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
|
||||
*/
|
||||
function renderLegacyCaptions(art) {
|
||||
const cues = art.subtitle?.textTrack?.activeCues;
|
||||
if (!cues || cues.length < 2)
|
||||
return;
|
||||
const texts = Array.from(cues, (cue) => "text" in cue && typeof cue.text === "string" ? cue.text : "");
|
||||
const target = art.template.$subtitle;
|
||||
if (art.option?.subtitle?.escape) {
|
||||
target.innerHTML = "";
|
||||
for (const text of texts) {
|
||||
for (const line of text.split(/\r?\n/)) {
|
||||
const element = target.ownerDocument.createElement("div");
|
||||
element.className = "art-subtitle-line";
|
||||
element.textContent = line;
|
||||
target.appendChild(element);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
target.innerHTML = texts.join("");
|
||||
}
|
||||
}
|
||||
var defaultCueSettings = {
|
||||
direction: "horizontal",
|
||||
snapToLines: true,
|
||||
@@ -242,7 +313,7 @@ var WebVTTCueTimingsAndSettingsParser = function(line, errorHandler) {
|
||||
var settings = input.split(SPACE), seen = [];
|
||||
for (var i = 0; i < settings.length; i++) {
|
||||
if (settings[i] == "") continue;
|
||||
var index = settings[i].indexOf(":"), setting = settings[i].slice(0, index), value = settings[i].slice(index + 1);
|
||||
var index2 = settings[i].indexOf(":"), setting = settings[i].slice(0, index2), value = settings[i].slice(index2 + 1);
|
||||
if (seen.indexOf(setting) != -1) {
|
||||
err("Duplicate setting.");
|
||||
}
|
||||
@@ -748,87 +819,301 @@ var WebVTTSerializer = function() {
|
||||
return result;
|
||||
};
|
||||
};
|
||||
async function loadVtt(option, { getExt, srtToVtt, assToVtt }) {
|
||||
const response = await fetch(option.url);
|
||||
const buffer = await response.arrayBuffer();
|
||||
const decoder = new TextDecoder(option.encoding || "utf-8");
|
||||
const text = decoder.decode(buffer);
|
||||
switch (option.type || getExt(option.url)) {
|
||||
case "srt": {
|
||||
return srtToVtt(text);
|
||||
}
|
||||
case "ass": {
|
||||
return assToVtt(text);
|
||||
}
|
||||
case "vtt": {
|
||||
return text;
|
||||
}
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
const cueEntities = {
|
||||
"&": "&",
|
||||
"&": "&",
|
||||
"<": "<",
|
||||
"<": "<",
|
||||
">": ">",
|
||||
">": ">",
|
||||
"&lrm": "",
|
||||
"‎": "",
|
||||
"&rlm": "",
|
||||
"‏": "",
|
||||
" ": " ",
|
||||
" ": " "
|
||||
};
|
||||
function escapeCueText(value) {
|
||||
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
||||
}
|
||||
function mergeTrees(trees) {
|
||||
const parser = new WebVTTParser();
|
||||
const result = parser.parse("", "metadata");
|
||||
for (let i = 0; i < trees.length; i++) {
|
||||
const tree = trees[i];
|
||||
if (!tree.updated) {
|
||||
tree.updated = true;
|
||||
for (let j = 0; j < tree.cues.length; j++) {
|
||||
const cue = tree.cues[j];
|
||||
for (let k = 0; k < cue.tree.children.length; k++) {
|
||||
const children = cue.tree.children[k];
|
||||
children.value = `<div class="art-subtitle-${tree.name}">${children.value}</div>`;
|
||||
const TIMESTAMP_CLASS = "artplayer-multiple-subtitles-timestamp";
|
||||
function markTimestamp(node) {
|
||||
return { type: "object", name: "c", classes: [TIMESTAMP_CLASS], children: [node] };
|
||||
}
|
||||
function prepareCueNode(node) {
|
||||
if (node.type === "timestamp")
|
||||
return markTimestamp(node);
|
||||
if (node.type === "object")
|
||||
return { ...node, children: node.children.map(prepareCueNode) };
|
||||
return { ...node, value: escapeCueText(node.value) };
|
||||
}
|
||||
function parseTracks(vtts, subtitles) {
|
||||
const parser = new WebVTTParser(cueEntities);
|
||||
return vtts.map((vtt, index2) => {
|
||||
const tree = parser.parse(vtt, "metadata");
|
||||
return { ...tree, url: subtitles[index2].url, name: subtitles[index2].name };
|
||||
});
|
||||
}
|
||||
function serializeTracks(trees) {
|
||||
const cues = [];
|
||||
for (const selected of trees) {
|
||||
const tree = selected;
|
||||
for (const cue of tree.cues) {
|
||||
const children = [];
|
||||
for (const child of cue.tree.children) {
|
||||
if (child.type === "timestamp") {
|
||||
children.push(markTimestamp(child));
|
||||
} else {
|
||||
children.push(
|
||||
{ type: "text", value: `<div class="art-subtitle-${tree.name}">` },
|
||||
prepareCueNode(child),
|
||||
{ type: "text", value: "</div>" }
|
||||
);
|
||||
}
|
||||
}
|
||||
cues.push({
|
||||
...cue,
|
||||
tree: {
|
||||
...cue.tree,
|
||||
children
|
||||
}
|
||||
});
|
||||
}
|
||||
result.cues.push(...tree.cues);
|
||||
}
|
||||
return result;
|
||||
return new WebVTTSerializer().serialize(cues);
|
||||
}
|
||||
function installCaptionView(art, lifetime) {
|
||||
const legacy = !!art.subtitle && "activeCue" in art.subtitle && !("activeCues" in art.subtitle);
|
||||
const event = legacy ? "subtitleUpdate" : "subtitleAfterUpdate";
|
||||
function update() {
|
||||
if (lifetime.closed)
|
||||
return;
|
||||
if (legacy)
|
||||
renderLegacyCaptions(art);
|
||||
for (const marker of Array.from(art.template.$subtitle.getElementsByTagName(`c.${TIMESTAMP_CLASS}`))) {
|
||||
const first = marker.firstChild;
|
||||
if (first?.nodeType === 3)
|
||||
first.nodeValue = (first.nodeValue || "").replace(/^<(?:\d+:)?\d{2}:\d{2}\.\d{3}>/, "");
|
||||
marker.replaceWith(...Array.from(marker.childNodes));
|
||||
}
|
||||
}
|
||||
if (lifetime.closed)
|
||||
return;
|
||||
lifetime.own(() => art.off(event, update));
|
||||
art.on(event, update);
|
||||
}
|
||||
function createLifetime(art) {
|
||||
let closed = Boolean(art.isDestroy);
|
||||
const cleanups = /* @__PURE__ */ new Set();
|
||||
let cancel;
|
||||
const cancelled = new Promise((resolve) => {
|
||||
cancel = resolve;
|
||||
});
|
||||
function run(cleanup) {
|
||||
try {
|
||||
cleanup();
|
||||
} catch (error) {
|
||||
console.warn("Failed to clean up multiple subtitles:", error);
|
||||
}
|
||||
}
|
||||
const lifetime = {
|
||||
get closed() {
|
||||
return closed;
|
||||
},
|
||||
own(cleanup) {
|
||||
if (closed)
|
||||
run(cleanup);
|
||||
else
|
||||
cleanups.add(cleanup);
|
||||
return () => cleanups.delete(cleanup);
|
||||
},
|
||||
wait(value) {
|
||||
return Promise.race([value, cancelled]);
|
||||
},
|
||||
dispose() {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
cancel();
|
||||
const pending = [...cleanups].reverse();
|
||||
cleanups.clear();
|
||||
for (const cleanup of pending)
|
||||
run(cleanup);
|
||||
}
|
||||
};
|
||||
if (!closed) {
|
||||
lifetime.own(() => art.off("destroy", lifetime.dispose));
|
||||
try {
|
||||
art.on("destroy", lifetime.dispose);
|
||||
} catch (error) {
|
||||
lifetime.dispose();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
return lifetime;
|
||||
}
|
||||
function createRenderer(art, lifetime, unescape) {
|
||||
let current = null;
|
||||
function own(url) {
|
||||
let freed = false;
|
||||
let release = () => {
|
||||
};
|
||||
const entry = {
|
||||
free() {
|
||||
if (freed)
|
||||
return;
|
||||
freed = true;
|
||||
release();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
};
|
||||
release = lifetime.own(entry.free);
|
||||
return entry;
|
||||
}
|
||||
return (vtt) => {
|
||||
if (lifetime.closed)
|
||||
return;
|
||||
const url = URL.createObjectURL(new Blob([vtt], { type: "text/vtt" }));
|
||||
const entry = own(url);
|
||||
if (lifetime.closed)
|
||||
return;
|
||||
const previous = current;
|
||||
let option;
|
||||
let escape;
|
||||
let configured = false;
|
||||
current = entry;
|
||||
try {
|
||||
option = art.option.subtitle;
|
||||
escape = option.escape;
|
||||
if (lifetime.closed || current !== entry)
|
||||
return;
|
||||
option.escape = false;
|
||||
configured = true;
|
||||
const config = { ...option, url, type: "vtt", onVttLoad: unescape };
|
||||
if (lifetime.closed || current !== entry)
|
||||
return;
|
||||
const pending = art.subtitle.init(config);
|
||||
Promise.resolve(pending).catch((error) => {
|
||||
if (current === entry) {
|
||||
current = null;
|
||||
entry.free();
|
||||
}
|
||||
if (!lifetime.closed)
|
||||
console.warn("Failed to initialize multiple subtitles:", error);
|
||||
});
|
||||
} catch (error) {
|
||||
if (current === entry) {
|
||||
current = previous;
|
||||
if (configured && option.escape === false)
|
||||
option.escape = escape;
|
||||
}
|
||||
entry.free();
|
||||
throw error;
|
||||
} finally {
|
||||
if (previous !== current)
|
||||
previous?.free();
|
||||
if (entry !== current)
|
||||
entry.free();
|
||||
}
|
||||
};
|
||||
}
|
||||
function convertAss(text, converter) {
|
||||
const converted = converter(text);
|
||||
if (!/^WEBVTT \d+ \d+:/.test(converted))
|
||||
return converted;
|
||||
const cues = [];
|
||||
for (const line of text.split(/\r?\n/)) {
|
||||
const match = line.match(/Dialogue:\s\d,(\d+:\d{2}:\d{2}\.\d{2}),(\d+:\d{2}:\d{2}\.\d{2}),(?:[^,]*,){6}([\s\S]*)$/i);
|
||||
if (!match)
|
||||
continue;
|
||||
const [, start = "", end = "", content = ""] = match;
|
||||
cues.push({
|
||||
start: `${start.replace(/^(\d):/, "0$1:")}0`,
|
||||
end: `${end.replace(/^(\d):/, "0$1:")}0`,
|
||||
text: content.replace(/\{[\s\S]*?\}/g, "").replace(/\\N/g, "\n").trim().split(/\r?\n/).map((line2) => line2.trim()).join("\n")
|
||||
});
|
||||
}
|
||||
const collapsed = `WEBVTT ${cues.map((cue, index2) => `${index2 + 1} ${cue.start} --> ${cue.end} ${cue.text}`).join("\n\n")}`;
|
||||
if (converted !== collapsed)
|
||||
return converted;
|
||||
return `WEBVTT
|
||||
|
||||
${cues.map((cue, index2) => `${index2 + 1}
|
||||
${cue.start} --> ${cue.end}
|
||||
${cue.text}`).join("\n\n")}`;
|
||||
}
|
||||
async function loadVtt(option, { getExt, srtToVtt, assToVtt }, lifetime) {
|
||||
if (lifetime.closed)
|
||||
return;
|
||||
const controller = typeof AbortController === "function" ? new AbortController() : null;
|
||||
const release = lifetime.own(() => controller?.abort());
|
||||
try {
|
||||
const url = option.url;
|
||||
if (lifetime.closed)
|
||||
return;
|
||||
const response = await lifetime.wait(controller ? fetch(url, { signal: controller.signal }) : fetch(url));
|
||||
if (lifetime.closed)
|
||||
return;
|
||||
if (response.ok === false)
|
||||
throw new Error(`Failed to fetch multiple subtitles: HTTP ${response.status}`);
|
||||
const buffer = await lifetime.wait(response.arrayBuffer());
|
||||
if (lifetime.closed)
|
||||
return;
|
||||
const text = new TextDecoder(option.encoding || "utf-8").decode(buffer);
|
||||
switch (option.type || getExt(option.url)) {
|
||||
case "srt":
|
||||
return srtToVtt(text);
|
||||
case "ass":
|
||||
return convertAss(text, assToVtt);
|
||||
case "vtt":
|
||||
return text;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
} catch (error) {
|
||||
controller?.abort();
|
||||
throw error;
|
||||
} finally {
|
||||
release();
|
||||
}
|
||||
}
|
||||
function artplayerPluginMultipleSubtitles({ subtitles = [] }) {
|
||||
return async (art) => {
|
||||
const { unescape, getExt, srtToVtt, assToVtt } = art.constructor.utils;
|
||||
const parser = new WebVTTParser();
|
||||
const seri = new WebVTTSerializer();
|
||||
const vtts = await Promise.all(
|
||||
subtitles.map((option) => {
|
||||
return loadVtt(option, { getExt, srtToVtt, assToVtt });
|
||||
})
|
||||
);
|
||||
const trees = vtts.map((vtt, index) => {
|
||||
const tree = parser.parse(vtt, "metadata");
|
||||
tree.url = subtitles[index].url;
|
||||
tree.name = subtitles[index].name;
|
||||
return tree;
|
||||
});
|
||||
let lastUrl = "";
|
||||
function setTracks(trees2 = []) {
|
||||
const tree = mergeTrees(trees2);
|
||||
const vtt = seri.serialize(tree.cues);
|
||||
URL.revokeObjectURL(lastUrl);
|
||||
const url = URL.createObjectURL(new Blob([vtt], { type: "text/vtt" }));
|
||||
lastUrl = url;
|
||||
art.option.subtitle.escape = false;
|
||||
art.subtitle.init({
|
||||
...art.option.subtitle,
|
||||
url,
|
||||
type: "vtt",
|
||||
onVttLoad: unescape
|
||||
});
|
||||
const lifetime = createLifetime(art);
|
||||
const render = createRenderer(art, lifetime, unescape);
|
||||
let trees = [];
|
||||
function setTracks(selected) {
|
||||
if (!lifetime.closed)
|
||||
render(serializeTracks(selected));
|
||||
}
|
||||
setTracks(trees);
|
||||
return {
|
||||
const result = {
|
||||
name: "multipleSubtitles",
|
||||
tracks(names = []) {
|
||||
return setTracks(names.map((name) => trees.find((tree) => tree.name === name)));
|
||||
if (!lifetime.closed)
|
||||
setTracks(names.map((name) => trees.find((tree) => tree.name === name)));
|
||||
},
|
||||
reset() {
|
||||
return setTracks(trees);
|
||||
setTracks(trees);
|
||||
}
|
||||
};
|
||||
try {
|
||||
if (lifetime.closed)
|
||||
return result;
|
||||
const vtts = await Promise.all(subtitles.map((option) => loadVtt(option, { getExt, srtToVtt, assToVtt }, lifetime)));
|
||||
if (lifetime.closed)
|
||||
return result;
|
||||
trees = parseTracks(vtts, subtitles);
|
||||
installCaptionView(art, lifetime);
|
||||
setTracks(trees);
|
||||
return result;
|
||||
} catch (error) {
|
||||
lifetime.dispose();
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
const index = Object.assign(artplayerPluginMultipleSubtitles, { default: artplayerPluginMultipleSubtitles });
|
||||
export {
|
||||
artplayerPluginMultipleSubtitles as default
|
||||
index as default
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-vast.js v1.2.0
|
||||
* artplayer-plugin-vast.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVast=e(),define(function(){return t.artplayerPluginVast})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVast=e()}(this,function(){"use strict";var t=null,e=function(){t=null};function i(t,e,i){return e&&function(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}(t.prototype,e),t}function n(){return n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n])}return t},n.apply(this,arguments)}function s(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,o(t,e)}function r(t){return(r=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,e){return(o=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function a(t,e,i){return(a=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}()?Reflect.construct:function(t,e,i){var n=[null];n.push.apply(n,e);var s=new(Function.bind.apply(t,n));return i&&o(s,i.prototype),s}).apply(null,arguments)}function d(t){var e="function"==typeof Map?new Map:void 0;return d=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,i)}function i(){return a(t,arguments,r(this).constructor)}return i.prototype=Object.create(t.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),o(i,t)},d(t)}function h(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function u(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i<e;i++)n[i]=t[i];return n}var l=0;function c(t){return"__private_"+l+++"_"+t}function f(t,e){if(!Object.prototype.hasOwnProperty.call(t,e))throw new TypeError("attempted to use private field on non-instance");return t}var v={};v.CustomEvent="function"==typeof CustomEvent?CustomEvent:function(t){return e[t]=new e("").constructor[t],e;function e(t,e){e||(e={});var i=document.createEvent("CustomEvent");return i.initCustomEvent(t,!!e.bubbles,!!e.cancelable,e.detail),i}}("prototype");var p,E,y,A=v.CustomEvent,m=c("mediaElement"),b=c("currentTime"),g=c("enabled"),O=function(){function t(t){Object.defineProperty(this,m,{writable:!0,value:void 0}),Object.defineProperty(this,b,{writable:!0,value:void 0}),Object.defineProperty(this,g,{writable:!0,value:void 0}),this.seeking=void 0,f(this,m)[m]=t,f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.t=this.t.bind(this),this.i=this.i.bind(this),this.h=this.h.bind(this),this.enable()}var e=t.prototype;return e.i=function(){this.seeking=!0},e.h=function(){this.seeking=!1},e.t=function(){var t,e;this.seeking||null!=(t=f(this,m)[m])&&t.paused||(f(this,b)[b]=null==(e=f(this,m)[m])?void 0:e.currentTime)},e.enable=function(){var t,e,i;f(this,g)[g]||(null==(t=f(this,m)[m])||t.addEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.addEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.addEventListener("timeupdate",this.t),f(this,g)[g]=!0)},e.disable=function(){var t,e,i;f(this,g)[g]&&(null==(t=f(this,m)[m])||t.removeEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.removeEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.removeEventListener("timeupdate",this.t),f(this,g)[g]=!1)},e.play=function(){var t=this;return new Promise(function(e){var i;e(null==(i=f(t,m)[m])?void 0:i.play())})},e.pause=function(){var t;null==(t=f(this,m)[m])||t.pause()},e.reset=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.enable()},e.destroy=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.disable(),f(this,m)[m]=void 0},i(t,[{key:"enabled",get:function(){return f(this,g)[g]}},{key:"currentTime",get:function(){return f(this,b)[b]}},{key:"duration",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.duration}},{key:"muted",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.muted}},{key:"volume",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.volume}}]),t}(),w=function(){function t(){this.delegate=document.createDocumentFragment()}var e=t.prototype;return e.addEventListener=function(){this.delegate.addEventListener.apply(this.delegate,[].slice.call(arguments))},e.dispatchEvent=function(){return this.delegate.dispatchEvent.apply(this.delegate,[].slice.call(arguments))},e.removeEventListener=function(){return this.delegate.removeEventListener.apply(this.delegate,[].slicLine truncated
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVast=e(),define(function(){return t.artplayerPluginVast})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVast=e()}(this,function(){"use strict";var t=null,e=function(){t=null};function i(t,e,i){return e&&function(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}(t.prototype,e),t}function n(){return n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n])}return t},n.apply(this,arguments)}function r(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,o(t,e)}function s(t){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,e){return(o=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function a(t,e,i){return(a=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}()?Reflect.construct:function(t,e,i){var n=[null];n.push.apply(n,e);var r=new(Function.bind.apply(t,n));return i&&o(r,i.prototype),r}).apply(null,arguments)}function u(t){var e="function"==typeof Map?new Map:void 0;return u=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,i)}function i(){return a(t,arguments,s(this).constructor)}return i.prototype=Object.create(t.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),o(i,t)},u(t)}function d(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function h(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i<e;i++)n[i]=t[i];return n}var l=0;function c(t){return"__private_"+l+++"_"+t}function f(t,e){if(!Object.prototype.hasOwnProperty.call(t,e))throw new TypeError("attempted to use private field on non-instance");return t}var p={};p.CustomEvent="function"==typeof CustomEvent?CustomEvent:function(t){return e[t]=new e("").constructor[t],e;function e(t,e){e||(e={});var i=document.createEvent("CustomEvent");return i.initCustomEvent(t,!!e.bubbles,!!e.cancelable,e.detail),i}}("prototype");var v,y,E,A=p.CustomEvent,m=c("mediaElement"),b=c("currentTime"),g=c("enabled"),O=function(){function t(t){Object.defineProperty(this,m,{writable:!0,value:void 0}),Object.defineProperty(this,b,{writable:!0,value:void 0}),Object.defineProperty(this,g,{writable:!0,value:void 0}),this.seeking=void 0,f(this,m)[m]=t,f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.t=this.t.bind(this),this.i=this.i.bind(this),this.h=this.h.bind(this),this.enable()}var e=t.prototype;return e.i=function(){this.seeking=!0},e.h=function(){this.seeking=!1},e.t=function(){var t,e;this.seeking||null!=(t=f(this,m)[m])&&t.paused||(f(this,b)[b]=null==(e=f(this,m)[m])?void 0:e.currentTime)},e.enable=function(){var t,e,i;f(this,g)[g]||(null==(t=f(this,m)[m])||t.addEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.addEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.addEventListener("timeupdate",this.t),f(this,g)[g]=!0)},e.disable=function(){var t,e,i;f(this,g)[g]&&(null==(t=f(this,m)[m])||t.removeEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.removeEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.removeEventListener("timeupdate",this.t),f(this,g)[g]=!1)},e.play=function(){var t=this;return new Promise(function(e){var i;e(null==(i=f(t,m)[m])?void 0:i.play())})},e.pause=function(){var t;null==(t=f(this,m)[m])||t.pause()},e.reset=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.enable()},e.destroy=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.disable(),f(this,m)[m]=void 0},i(t,[{key:"enabled",get:function(){return f(this,g)[g]}},{key:"currentTime",get:function(){return f(this,b)[b]}},{key:"duration",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.duration}},{key:"muted",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.muted}},{key:"volume",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.volume}}]),t}(),w=function(){function t(){this.delegate=document.createDocumentFragment()}var e=t.prototype;return e.addEventListener=function(){this.delegate.addEventListener.apply(this.delegate,[].slice.call(arguments))},e.dispatchEvent=function(){return this.delegate.dispatchEvent.apply(this.delegate,[].slice.call(arguments))},e.removeEventListener=function(){return this.delegate.removeEventListener.apply(this.delegate,[].slicLine truncated
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-vast.js v1.2.0
|
||||
* artplayer-plugin-vast.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVast=e(),define(function(){return t.artplayerPluginVast})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVast=e()}(this,function(){"use strict";var t=null,e=function(){t=null};function i(t,e,i){return e&&function(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}(t.prototype,e),t}function n(){return n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n])}return t},n.apply(this,arguments)}function s(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,o(t,e)}function r(t){return(r=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,e){return(o=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function a(t,e,i){return(a=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}()?Reflect.construct:function(t,e,i){var n=[null];n.push.apply(n,e);var s=new(Function.bind.apply(t,n));return i&&o(s,i.prototype),s}).apply(null,arguments)}function d(t){var e="function"==typeof Map?new Map:void 0;return d=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,i)}function i(){return a(t,arguments,r(this).constructor)}return i.prototype=Object.create(t.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),o(i,t)},d(t)}function h(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function u(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i<e;i++)n[i]=t[i];return n}var l=0;function c(t){return"__private_"+l+++"_"+t}function v(t,e){if(!Object.prototype.hasOwnProperty.call(t,e))throw new TypeError("attempted to use private field on non-instance");return t}var f={};f.CustomEvent="function"==typeof CustomEvent?CustomEvent:function(t){return e[t]=new e("").constructor[t],e;function e(t,e){e||(e={});var i=document.createEvent("CustomEvent");return i.initCustomEvent(t,!!e.bubbles,!!e.cancelable,e.detail),i}}("prototype");var p,y,E,A=f.CustomEvent,m=c("mediaElement"),b=c("currentTime"),g=c("enabled"),O=function(){function t(t){Object.defineProperty(this,m,{writable:!0,value:void 0}),Object.defineProperty(this,b,{writable:!0,value:void 0}),Object.defineProperty(this,g,{writable:!0,value:void 0}),this.seeking=void 0,v(this,m)[m]=t,v(this,b)[b]=0,v(this,g)[g]=!1,this.seeking=!1,this.t=this.t.bind(this),this.i=this.i.bind(this),this.h=this.h.bind(this),this.enable()}var e=t.prototype;return e.i=function(){this.seeking=!0},e.h=function(){this.seeking=!1},e.t=function(){var t,e;this.seeking||null!=(t=v(this,m)[m])&&t.paused||(v(this,b)[b]=null==(e=v(this,m)[m])?void 0:e.currentTime)},e.enable=function(){var t,e,i;v(this,g)[g]||(null==(t=v(this,m)[m])||t.addEventListener("seeking",this.i),null==(e=v(this,m)[m])||e.addEventListener("seeked",this.h),null==(i=v(this,m)[m])||i.addEventListener("timeupdate",this.t),v(this,g)[g]=!0)},e.disable=function(){var t,e,i;v(this,g)[g]&&(null==(t=v(this,m)[m])||t.removeEventListener("seeking",this.i),null==(e=v(this,m)[m])||e.removeEventListener("seeked",this.h),null==(i=v(this,m)[m])||i.removeEventListener("timeupdate",this.t),v(this,g)[g]=!1)},e.play=function(){var t=this;return new Promise(function(e){var i;e(null==(i=v(t,m)[m])?void 0:i.play())})},e.pause=function(){var t;null==(t=v(this,m)[m])||t.pause()},e.reset=function(){v(this,b)[b]=0,v(this,g)[g]=!1,this.seeking=!1,this.enable()},e.destroy=function(){v(this,b)[b]=0,v(this,g)[g]=!1,this.seeking=!1,this.disable(),v(this,m)[m]=void 0},i(t,[{key:"enabled",get:function(){return v(this,g)[g]}},{key:"currentTime",get:function(){return v(this,b)[b]}},{key:"duration",get:function(){var t;return null==(t=v(this,m)[m])?void 0:t.duration}},{key:"muted",get:function(){var t;return null==(t=v(this,m)[m])?void 0:t.muted}},{key:"volume",get:function(){var t;return null==(t=v(this,m)[m])?void 0:t.volume}}]),t}(),w=function(){function t(){this.delegate=document.createDocumentFragment()}var e=t.prototype;return e.addEventListener=function(){this.delegate.addEventListener.apply(this.delegate,[].slice.call(arguments))},e.dispatchEvent=function(){return this.delegate.dispatchEvent.apply(this.delegate,[].slice.call(arguments))},e.removeEventListener=function(){return this.delegate.removeEventListener.apply(this.delegate,[].slicLine truncated
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVast=e(),define(function(){return t.artplayerPluginVast})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVast=e()}(this,function(){"use strict";var t=null,e=function(){t=null};function i(t,e,i){return e&&function(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}(t.prototype,e),t}function n(){return n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n])}return t},n.apply(this,arguments)}function r(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,o(t,e)}function s(t){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,e){return(o=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function a(t,e,i){return(a=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}()?Reflect.construct:function(t,e,i){var n=[null];n.push.apply(n,e);var r=new(Function.bind.apply(t,n));return i&&o(r,i.prototype),r}).apply(null,arguments)}function u(t){var e="function"==typeof Map?new Map:void 0;return u=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,i)}function i(){return a(t,arguments,s(this).constructor)}return i.prototype=Object.create(t.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),o(i,t)},u(t)}function l(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function d(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i<e;i++)n[i]=t[i];return n}var h=0;function c(t){return"__private_"+h+++"_"+t}function f(t,e){if(!Object.prototype.hasOwnProperty.call(t,e))throw new TypeError("attempted to use private field on non-instance");return t}var p={};p.CustomEvent="function"==typeof CustomEvent?CustomEvent:function(t){return e[t]=new e("").constructor[t],e;function e(t,e){e||(e={});var i=document.createEvent("CustomEvent");return i.initCustomEvent(t,!!e.bubbles,!!e.cancelable,e.detail),i}}("prototype");var v,y,E,A=p.CustomEvent,m=c("mediaElement"),b=c("currentTime"),g=c("enabled"),O=function(){function t(t){Object.defineProperty(this,m,{writable:!0,value:void 0}),Object.defineProperty(this,b,{writable:!0,value:void 0}),Object.defineProperty(this,g,{writable:!0,value:void 0}),this.seeking=void 0,f(this,m)[m]=t,f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.t=this.t.bind(this),this.i=this.i.bind(this),this.h=this.h.bind(this),this.enable()}var e=t.prototype;return e.i=function(){this.seeking=!0},e.h=function(){this.seeking=!1},e.t=function(){var t,e;this.seeking||null!=(t=f(this,m)[m])&&t.paused||(f(this,b)[b]=null==(e=f(this,m)[m])?void 0:e.currentTime)},e.enable=function(){var t,e,i;f(this,g)[g]||(null==(t=f(this,m)[m])||t.addEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.addEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.addEventListener("timeupdate",this.t),f(this,g)[g]=!0)},e.disable=function(){var t,e,i;f(this,g)[g]&&(null==(t=f(this,m)[m])||t.removeEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.removeEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.removeEventListener("timeupdate",this.t),f(this,g)[g]=!1)},e.play=function(){var t=this;return new Promise(function(e){var i;e(null==(i=f(t,m)[m])?void 0:i.play())})},e.pause=function(){var t;null==(t=f(this,m)[m])||t.pause()},e.reset=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.enable()},e.destroy=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.disable(),f(this,m)[m]=void 0},i(t,[{key:"enabled",get:function(){return f(this,g)[g]}},{key:"currentTime",get:function(){return f(this,b)[b]}},{key:"duration",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.duration}},{key:"muted",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.muted}},{key:"volume",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.volume}}]),t}(),w=function(){function t(){this.delegate=document.createDocumentFragment()}var e=t.prototype;return e.addEventListener=function(){this.delegate.addEventListener.apply(this.delegate,[].slice.call(arguments))},e.dispatchEvent=function(){return this.delegate.dispatchEvent.apply(this.delegate,[].slice.call(arguments))},e.removeEventListener=function(){return this.delegate.removeEventListener.apply(this.delegate,[].slicLine truncated
|
||||
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* artplayer-plugin-vast.js v1.2.0
|
||||
* artplayer-plugin-vast.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
@@ -436,117 +436,244 @@ var S = b("mediaElement"), M = b("adElement"), x = b("customPlayhead"), I = b("a
|
||||
return [].concat(w(this, $)[$]);
|
||||
} }]), i2;
|
||||
})(C);
|
||||
function artplayerPluginVast(callback) {
|
||||
return async (art) => {
|
||||
const { template, constructor } = art;
|
||||
const { createElement, setStyles } = constructor.utils;
|
||||
const { $video, $player } = template;
|
||||
await e();
|
||||
const google = window.google;
|
||||
const ima = google.ima;
|
||||
const adsRenderingSettings = new ima.AdsRenderingSettings();
|
||||
function createRequest(ima, field, value, config) {
|
||||
const request = new ima.AdsRequest();
|
||||
request[field] = value;
|
||||
const fields = request;
|
||||
for (const key in config)
|
||||
fields[key] = config[key];
|
||||
return request;
|
||||
}
|
||||
let nextId = 0;
|
||||
function createContainer(utils, workspaceMode) {
|
||||
const container = utils.createElement("div");
|
||||
container.id = `${workspaceMode ? "art-vast-" : "art-"}${Date.now()}-${++nextId}`;
|
||||
utils.setStyles(container, {
|
||||
position: "absolute",
|
||||
inset: "0",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
zIndex: "150",
|
||||
display: "none"
|
||||
});
|
||||
if (workspaceMode)
|
||||
utils.setStyles(container, { backgroundColor: "black", pointerEvents: "auto" });
|
||||
return container;
|
||||
}
|
||||
function createSession(art, ima, utils, closed, workspaceMode) {
|
||||
const { $video, $player } = art.template;
|
||||
const adsRenderingSettings = new ima.AdsRenderingSettings();
|
||||
if (workspaceMode) {
|
||||
adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;
|
||||
adsRenderingSettings.enablePreloading = true;
|
||||
const playerOptions = new E();
|
||||
let isAdPlaying = false;
|
||||
let imaPlayer = null;
|
||||
let $container = null;
|
||||
function createContainer() {
|
||||
const container = createElement("div");
|
||||
const id = `art-vast-${Date.now()}`;
|
||||
container.id = id;
|
||||
setStyles(container, {
|
||||
position: "absolute",
|
||||
inset: "0",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
zIndex: "150",
|
||||
backgroundColor: "black",
|
||||
display: "none",
|
||||
pointerEvents: "auto"
|
||||
});
|
||||
return container;
|
||||
}
|
||||
const playerOptions = new E();
|
||||
let current = null;
|
||||
let initializing = false;
|
||||
let releasing = 0;
|
||||
const context = {
|
||||
art,
|
||||
playUrl: (url, config = {}) => play("adTagUrl", url, config),
|
||||
playRes: (response, config = {}) => play("adsResponse", response, config),
|
||||
init,
|
||||
ima,
|
||||
adsRenderingSettings,
|
||||
playerOptions,
|
||||
imaPlayer: null,
|
||||
id: null,
|
||||
$container: null,
|
||||
get container() {
|
||||
return current?.container || null;
|
||||
}
|
||||
function initPlayer() {
|
||||
if (imaPlayer)
|
||||
return imaPlayer;
|
||||
$container = createContainer();
|
||||
$player.appendChild($container);
|
||||
imaPlayer = new nt(ima, $video, $container, adsRenderingSettings, playerOptions);
|
||||
imaPlayer.addEventListener("AdContentPauseRequested", () => {
|
||||
isAdPlaying = true;
|
||||
$container.style.display = "block";
|
||||
});
|
||||
imaPlayer.addEventListener("AdContentResumeRequested", () => {
|
||||
isAdPlaying = false;
|
||||
$container.style.display = "none";
|
||||
});
|
||||
imaPlayer.addEventListener("AdStarted", () => {
|
||||
isAdPlaying = true;
|
||||
$container.style.display = "block";
|
||||
});
|
||||
imaPlayer.addEventListener("AdError", (event) => {
|
||||
console.error("VAST Ad Error:", event.detail);
|
||||
isAdPlaying = false;
|
||||
$container.style.display = "none";
|
||||
});
|
||||
return imaPlayer;
|
||||
}
|
||||
function destroyPlayer() {
|
||||
if (imaPlayer?.destroy)
|
||||
imaPlayer.destroy();
|
||||
if ($container?.parentNode)
|
||||
$container.parentNode.removeChild($container);
|
||||
$container = null;
|
||||
imaPlayer = null;
|
||||
}
|
||||
function playUrl(url, config = {}) {
|
||||
if (isAdPlaying)
|
||||
return;
|
||||
if (!imaPlayer)
|
||||
initPlayer();
|
||||
const request = new ima.AdsRequest();
|
||||
request.adTagUrl = url;
|
||||
for (const key in config) {
|
||||
request[key] = config[key];
|
||||
}
|
||||
imaPlayer.playAds(request);
|
||||
}
|
||||
function playRes(res, config = {}) {
|
||||
if (isAdPlaying)
|
||||
return;
|
||||
if (!imaPlayer)
|
||||
initPlayer();
|
||||
const request = new ima.AdsRequest();
|
||||
request.adsResponse = res;
|
||||
for (const key in config) {
|
||||
request[key] = config[key];
|
||||
}
|
||||
imaPlayer.playAds(request);
|
||||
}
|
||||
if (typeof callback === "function") {
|
||||
await callback({
|
||||
art,
|
||||
playUrl,
|
||||
playRes,
|
||||
init: initPlayer,
|
||||
ima,
|
||||
adsRenderingSettings,
|
||||
playerOptions,
|
||||
get imaPlayer() {
|
||||
return imaPlayer;
|
||||
},
|
||||
get container() {
|
||||
return $container;
|
||||
};
|
||||
if (workspaceMode) {
|
||||
Object.defineProperties(context, {
|
||||
imaPlayer: { get: () => current?.player || null },
|
||||
id: { get: () => current?.container.id || null },
|
||||
$container: { get: () => current?.container || null }
|
||||
});
|
||||
}
|
||||
const live = (owner) => current === owner && !owner.released && !closed();
|
||||
function release(owner) {
|
||||
if (current === owner)
|
||||
current = null;
|
||||
owner.released = true;
|
||||
owner.playing = false;
|
||||
const player = owner.player;
|
||||
owner.player = null;
|
||||
const listeners = owner.listeners.splice(0);
|
||||
let failed = false;
|
||||
let failure;
|
||||
const attempt = (cleanup) => {
|
||||
try {
|
||||
cleanup();
|
||||
} catch (error) {
|
||||
if (!failed) {
|
||||
failed = true;
|
||||
failure = error;
|
||||
} else {
|
||||
console.error("VAST cleanup error:", error);
|
||||
}
|
||||
});
|
||||
}
|
||||
return {
|
||||
name: "artplayerPluginVast",
|
||||
destroy: destroyPlayer
|
||||
}
|
||||
};
|
||||
releasing++;
|
||||
try {
|
||||
if (player) {
|
||||
for (const [name, callback] of listeners)
|
||||
attempt(() => player.removeEventListener(name, callback));
|
||||
attempt(() => player.destroy());
|
||||
}
|
||||
attempt(() => {
|
||||
if (owner.container.parentNode)
|
||||
owner.container.parentNode.removeChild(owner.container);
|
||||
});
|
||||
} finally {
|
||||
releasing--;
|
||||
}
|
||||
if (failed)
|
||||
throw failure;
|
||||
}
|
||||
function init() {
|
||||
if (closed() || releasing)
|
||||
return null;
|
||||
if (initializing)
|
||||
throw new Error("VAST initialization is already in progress");
|
||||
if (current?.player)
|
||||
return current.player;
|
||||
initializing = true;
|
||||
let owner;
|
||||
try {
|
||||
owner = { container: createContainer(utils, workspaceMode), player: null, listeners: [], playing: false, released: false };
|
||||
current = owner;
|
||||
if (!live(owner)) {
|
||||
release(owner);
|
||||
return null;
|
||||
}
|
||||
$player.appendChild(owner.container);
|
||||
if (!live(owner)) {
|
||||
release(owner);
|
||||
return null;
|
||||
}
|
||||
owner.player = new nt(ima, $video, owner.container, adsRenderingSettings, playerOptions);
|
||||
if (!live(owner)) {
|
||||
release(owner);
|
||||
return null;
|
||||
}
|
||||
const allocated = owner;
|
||||
const events = workspaceMode ? [
|
||||
["AdContentPauseRequested", true],
|
||||
["AdContentResumeRequested", false],
|
||||
["AdStarted", true],
|
||||
["AdError", false]
|
||||
] : [];
|
||||
for (const [name, playing] of events) {
|
||||
const callback = (event) => {
|
||||
if (!live(allocated))
|
||||
return;
|
||||
if (name === "AdError")
|
||||
console.error("VAST Ad Error:", event.detail);
|
||||
allocated.playing = playing;
|
||||
allocated.container.style.display = playing ? "block" : "none";
|
||||
};
|
||||
owner.listeners.push([name, callback]);
|
||||
owner.player.addEventListener(name, callback);
|
||||
if (!live(owner)) {
|
||||
release(owner);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (!workspaceMode) {
|
||||
Object.defineProperties(context, {
|
||||
imaPlayer: { value: owner.player },
|
||||
id: { value: owner.container.id },
|
||||
$container: { value: owner.container }
|
||||
});
|
||||
}
|
||||
return owner.player;
|
||||
} catch (error) {
|
||||
if (owner) {
|
||||
try {
|
||||
release(owner);
|
||||
} catch (cleanupError) {
|
||||
console.error("VAST cleanup error:", cleanupError);
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
initializing = false;
|
||||
}
|
||||
}
|
||||
function play(field, value, config) {
|
||||
if (closed() || workspaceMode && current?.playing)
|
||||
return;
|
||||
const player = init();
|
||||
const owner = current;
|
||||
if (!player || !owner)
|
||||
return;
|
||||
const request = createRequest(ima, field, value, config);
|
||||
if (live(owner) && owner.player === player)
|
||||
player.playAds(request);
|
||||
}
|
||||
function destroy() {
|
||||
if (current)
|
||||
release(current);
|
||||
}
|
||||
return { context, destroy };
|
||||
}
|
||||
function artplayerPluginVast(callback, options = {}) {
|
||||
const compatibility = options.compatibility;
|
||||
if (compatibility !== void 0 && compatibility !== "workspace-1.2")
|
||||
throw new TypeError("Unsupported VAST compatibility mode");
|
||||
const workspaceMode = compatibility === "workspace-1.2";
|
||||
return async (art) => {
|
||||
let disposed = false;
|
||||
let session;
|
||||
const closed = () => disposed || art.isDestroy;
|
||||
const result = { name: "artplayerPluginVast", destroy: () => session?.destroy() };
|
||||
function dispose() {
|
||||
if (disposed)
|
||||
return;
|
||||
disposed = true;
|
||||
try {
|
||||
art.off("destroy", dispose);
|
||||
} finally {
|
||||
session?.destroy();
|
||||
}
|
||||
}
|
||||
if (closed())
|
||||
return result;
|
||||
art.on("destroy", dispose);
|
||||
try {
|
||||
if (closed())
|
||||
return result;
|
||||
const ima = await e();
|
||||
if (closed())
|
||||
return result;
|
||||
const utils = art.constructor.utils;
|
||||
session = createSession(art, ima, utils, closed, workspaceMode);
|
||||
if (closed()) {
|
||||
dispose();
|
||||
return result;
|
||||
}
|
||||
if (!workspaceMode) {
|
||||
session.context.init();
|
||||
if (closed())
|
||||
return result;
|
||||
}
|
||||
if (typeof callback === "function")
|
||||
await callback(session.context);
|
||||
return result;
|
||||
} catch (error) {
|
||||
try {
|
||||
dispose();
|
||||
} catch (cleanupError) {
|
||||
console.error("VAST cleanup error:", cleanupError);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
artplayerPluginVast.default = artplayerPluginVast;
|
||||
export {
|
||||
artplayerPluginVast as default
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-vtt-thumbnail.js v1.1.0
|
||||
* artplayer-plugin-vtt-thumbnail.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVttThumbnail=e(),define(function(){return t.artplayerPluginVttThumbnail})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVttThumbnail=e()}(this,function(){"use strict";function t(t){const e=t.split("."),n=e[0].split(":")||[],i=(l=e[1]||"0",o=3,s="0",l.length>o?String(l):((o-=l.length)>s.length&&(s+=s.repeat(o/s.length)),String(l)+s.slice(0,o)));var l,o,s;const r=Number(i)/1e3;return 3600*Number(n[n.length-3]||0)+60*Number(n[n.length-2]||0)+Number(n[n.length-1]||0)+r}return function(e){return async n=>{const{constructor:{utils:{setStyle:i,isMobile:l,addClass:o}},template:{$progress:s}}=n;let r=null;const a=await async function(e=""){const n=(await(await fetch(e)).text()).split(/[\n\r]/g).filter(t=>t.trim()),i=[];for(let l=1;l<n.length;l+=2){const o=n[l],s=n[l+1];if(!s.trim())continue;const r=/((?:\d{2}:)?(?:\d{2}:)?\d{2}(?:.\d{3})?) ?--> ?((?:\d{2}:)?(?:\d{2}:)?\d{2}(?:.\d{3})?)/,a=o.match(r),u=/(.*)#(\w{4})=(.*)/,c=s.match(u),d=Math.floor(t(a[1])),p=Math.floor(t(a[2]));let f=c[1];if(!/^\/|(?:https?|ftp|file):\/\//i.test(f)){const t=e.split("/");t.pop(),t.push(f),f=t.join("/")}const h={start:d,end:p,url:f},m=c[2].split(""),g=c[3].split(",");for(let t=0;t<m.length;t++)h[m[t]]=g[t];i.push(h)}return i}(e.vtt);return n.controls.add({name:"vtt-thumbnail",position:"top",index:20,style:e.style||{},mounted(t){o(t,"art-control-thumbnails"),n.on("setBar",async(e,o,u)=>{const c="played"===e&&u&&l;if("hover"===e||c){const e=s.clientWidth*o,u=o*n.duration;i(t,"display","flex");const d=a.find(t=>u>=t.start&&u<=t.end);if(!d)return i(t,"display","none");e>0&&e<s.clientWidth?function(t,e,n){i(t,"backgroundImage",`url(${e.url})`),i(t,"height",`${e.h}px`),i(t,"width",`${e.w}px`),i(t,"backgroundPosition",`-${e.x}px -${e.y}px`),n<=e.w/2?i(t,"left",0):n>s.clientWidth-e.w/2?i(t,"left",s.clientWidth-e.w+"px"):i(t,"left",n-e.w/2+"px")}(t,d,e):l||i(t,"display","none"),c&&(clearTimeout(r),r=setTimeout(()=>{i(t,"display","none")},500))}})}}),{name:"artplayerPluginVttThumbnail"}}}});
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVttThumbnail=e(),define(function(){return t.artplayerPluginVttThumbnail})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVttThumbnail=e()}(this,function(){"use strict";function t(t,e){throw new TypeError(`Invalid VTT thumbnail at line ${t}: ${e}`)}function e(e,n){/^\d{2,}(?::\d{2}){0,2}(?:\.\d{3})?$/.test(e)||t(n,"invalid timestamp");const[i,o="0"]=e.split("."),r=i.split(":").reduce((t,e)=>60*t+Number(e),0)+Number(o)/1e3;return Number.isSafeInteger(Math.floor(r))||t(n,"timestamp exceeds the supported numeric range"),r}function n(e,n,i){const o=e.match(/^(.+)#([xywh]{4})=(.*)$/);o&&4===new Set(o[2]).size||t(i,"expected an image URL and four distinct xywh keys");const r=o[3].split(",").map(t=>t.trim());4!==r.length&&t(i,"expected four rectangle coordinates");const s={};for(let c=0;c<4;c++){const e=o[2][c],n=r[c];/^(?:\d+(?:\.\d+)?|\.\d+)$/.test(n)&&Number.isFinite(Number(n))||t(i,"rectangle coordinates must be finite non-negative decimals"),"w"!==e&&"h"!==e||0!==Number(n)||t(i,"rectangle width and height must be positive"),s[e]=n}let l=o[1];if(!/^\/|(?:https?|ftp|file):\/\//i.test(l)){const t=n.split("/");t.pop(),t.push(l),l=t.join("/")}return{url:l,...s}}function i({lifetime:t,thumbnails:e,progress:n,duration:i,setStyle:o,isMobile:r}){let s=null,l=0;function c(e,n,i){t.closed||o(e,n,i)}return t.own(()=>{if(l++,null!==s){const t=s;s=null,clearTimeout(t)}}),o=>async(u,a,d)=>{if(t.closed)return;const f="played"===u&&d&&r;if("hover"!==u&&!f)return;const m=n.clientWidth*a,h=a*i();if(c(o,"display","flex"),t.closed)return;const p=function(t,e){return t.find(t=>e>=t.start&&e<=t.end)}(e,h);if(!p)return c(o,"display","none");if(m>0&&m<n.clientWidth?function(t,e,i){c(t,"backgroundImage",`url(${e.url})`),c(t,"height",`${e.h}px`),c(t,"width",`${e.w}px`),c(t,"backgroundPosition",`-${e.x}px -${e.y}px`),i<=Number(e.w)/2?c(t,"left",0):i>n.clientWidth-Number(e.w)/2?c(t,"left",n.clientWidth-Number(e.w)+"px"):c(t,"left",i-Number(e.w)/2+"px")}(o,p,m):r||c(o,"display","none"),f&&!t.closed){const e=++l;if(null!==s&&clearTimeout(s),t.closed)return;const n=setTimeout(()=>{e!==l||t.closed||(s=null,c(o,"display","none"))},500);t.closed||e!==l?clearTimeout(n):s=n}}}function o(o){return async r=>{const{setStyle:s,isMobile:l,addClass:c}=r.constructor.utils,{$progress:u}=r.template,a=function(t){let e=Boolean(t.isDestroy);const n=new Set;let i;const o=new Promise(t=>{i=t}),r={get closed(){return e},own:t=>(e?s(t):n.add(t),()=>n.delete(t)),listen(n,i){e||(r.own(()=>t.off(n,i)),t.on(n,i))},wait:t=>Promise.race([t,o]),dispose(){if(e)return;e=!0,i();const t=[...n].reverse();n.clear();for(const e of t)s(e)}};function s(t){try{t()}catch(e){console.warn("Failed to clean up VTT thumbnails:",e)}}try{r.listen("destroy",r.dispose)}catch(l){throw r.dispose(),l}return r}(r),d={name:"artplayerPluginVttThumbnail"};try{if(a.closed)return d;const f=o.vtt,m=await async function(t="",e){if(e.closed)return;const n="function"===typeof AbortController?new AbortController:null,i=e.own(()=>n?.abort());try{if(e.closed)return;const i=await e.wait(n?fetch(t,{signal:n.signal}):fetch(t));if(e.closed)return;if(!1===i.ok)throw new Error(`Failed to fetch VTT thumbnails: HTTP ${i.status}`);if(e.closed)return;return await e.wait(i.text())}finally{i()}}(f,a);if(a.closed)return d;const h=function(i,o=""){"string"!==typeof i&&t(1,"expected text");const r=i.replace(/^\uFEFF/,"").split(/\r\n|\r|\n/);let s=0;function l(){for(;s<r.length&&!r[s].trim();)s++}if(l(),s===r.length)return[];/^WEBVTT(?:[\t ].*)?$/.test(r[s].trim())&&!r[s].includes("--\x3e")||t(s+1,"expected WEBVTT header"),s++;const c=[];for(;s<r.length&&(l(),s!==r.length);){const i=r[s].trim();if(/^NOTE(?:[\t ]|$)/.test(i)||"STYLE"===i||"REGION"===i){for(;s<r.length&&r[s].trim();)s++;continue}const u=s+1;i.includes("--\x3e")||(s++,s!==r.length&&r[s].trim()||t(u,"cue identifier must be followed by timing"));const a=s+1,d=r[s].trim().match(/^([\d:.]+)[\t ]*-->[\t ]*([\d:.]+)(?:[\t ].*)?$/);d||t(a,"invalid cue timing");const f=e(d[1],a),m=e(d[2],a);m<f&&t(a,"cue end precedes its start"),s++,l(),s===r.length&&t(a,"missing sprite image");const h=n(r[s].trim(),o,s+1);c.push({start:Math.floor(f),end:Math.floor(m),...h}),s++}return c}(m,f),p=i({lifetime:a,thumbnails:h,progress:u,duration:()=>r.duration,setStyle:s,isMobile:l}),b=o.style||{};return a.closed||r.controls.add({name:"vtt-thumbnail",position:"top",index:20,style:b,mounted(t){a.own(()=>{r.controls["vtt-thumbnail"]===t&&r.controls.remove("vtt-thumbnail")}),a.closed||(c(t,"art-control-thumbnails"),a.listen("setBar",p(t)))}}),d}catch(f){throw a.dispose(),f}}}return Object.assign(o,{default:o})});
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-plugin-vtt-thumbnail.js v1.1.0
|
||||
* artplayer-plugin-vtt-thumbnail.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVttThumbnail=e(),define(function(){return t.artplayerPluginVttThumbnail})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVttThumbnail=e()}(this,function(){"use strict";var t=(t,e,n)=>new Promise((l,i)=>{var o=t=>{try{s(n.next(t))}catch(e){i(e)}},r=t=>{try{s(n.throw(t))}catch(e){i(e)}},s=t=>t.done?l(t.value):Promise.resolve(t.value).then(o,r);s((n=n.apply(t,e)).next())});function e(t){const e=t.split("."),n=e[0].split(":")||[],l=(i=e[1]||"0",o=3,r="0",i.length>o?String(i):((o-=i.length)>r.length&&(r+=r.repeat(o/r.length)),String(i)+r.slice(0,o)));var i,o,r;const s=Number(l)/1e3;return 3600*Number(n[n.length-3]||0)+60*Number(n[n.length-2]||0)+Number(n[n.length-1]||0)+s}return function(n){return l=>t(null,null,function*(){const{constructor:{utils:{setStyle:i,isMobile:o,addClass:r}},template:{$progress:s}}=l;let u=null;const a=yield function(n=""){return t(this,null,function*(){const t=(yield(yield fetch(n)).text()).split(/[\n\r]/g).filter(t=>t.trim()),l=[];for(let i=1;i<t.length;i+=2){const o=t[i],r=t[i+1];if(!r.trim())continue;const s=/((?:\d{2}:)?(?:\d{2}:)?\d{2}(?:.\d{3})?) ?--> ?((?:\d{2}:)?(?:\d{2}:)?\d{2}(?:.\d{3})?)/,u=o.match(s),a=/(.*)#(\w{4})=(.*)/,c=r.match(a),d=Math.floor(e(u[1])),h=Math.floor(e(u[2]));let p=c[1];if(!/^\/|(?:https?|ftp|file):\/\//i.test(p)){const t=n.split("/");t.pop(),t.push(p),p=t.join("/")}const f={start:d,end:h,url:p},m=c[2].split(""),g=c[3].split(",");for(let t=0;t<m.length;t++)f[m[t]]=g[t];l.push(f)}return l})}(n.vtt);return l.controls.add({name:"vtt-thumbnail",position:"top",index:20,style:n.style||{},mounted(e){r(e,"art-control-thumbnails"),l.on("setBar",(n,r,c)=>t(null,null,function*(){const t="played"===n&&c&&o;if("hover"===n||t){const n=s.clientWidth*r,c=r*l.duration;i(e,"display","flex");const d=a.find(t=>c>=t.start&&c<=t.end);if(!d)return i(e,"display","none");n>0&&n<s.clientWidth?function(t,e,n){i(t,"backgroundImage",`url(${e.url})`),i(t,"height",`${e.h}px`),i(t,"width",`${e.w}px`),i(t,"backgroundPosition",`-${e.x}px -${e.y}px`),n<=e.w/2?i(t,"left",0):n>s.clientWidth-e.w/2?i(t,"left",s.clientWidth-e.w+"px"):i(t,"left",n-e.w/2+"px")}(e,d,n):o||i(e,"display","none"),t&&(clearTimeout(u),u=setTimeout(()=>{i(e,"display","none")},500))}}))}}),{name:"artplayerPluginVttThumbnail"}})}});
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVttThumbnail=e(),define(function(){return t.artplayerPluginVttThumbnail})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVttThumbnail=e()}(this,function(){"use strict";var t=Object.defineProperty,e=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,r=(e,n,o)=>n in e?t(e,n,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[n]=o,i=(t,i)=>{for(var l in i||(i={}))n.call(i,l)&&r(t,l,i[l]);if(e)for(var l of e(i))o.call(i,l)&&r(t,l,i[l]);return t},l=(t,e,n)=>new Promise((o,r)=>{var i=t=>{try{s(n.next(t))}catch(e){r(e)}},l=t=>{try{s(n.throw(t))}catch(e){r(e)}},s=t=>t.done?o(t.value):Promise.resolve(t.value).then(i,l);s((n=n.apply(t,e)).next())});function s(t,e){throw new TypeError(`Invalid VTT thumbnail at line ${t}: ${e}`)}function c(t,e){/^\d{2,}(?::\d{2}){0,2}(?:\.\d{3})?$/.test(t)||s(e,"invalid timestamp");const[n,o="0"]=t.split("."),r=n.split(":").reduce((t,e)=>60*t+Number(e),0)+Number(o)/1e3;return Number.isSafeInteger(Math.floor(r))||s(e,"timestamp exceeds the supported numeric range"),r}function u(t,e,n){const o=t.match(/^(.+)#([xywh]{4})=(.*)$/);o&&4===new Set(o[2]).size||s(n,"expected an image URL and four distinct xywh keys");const r=o[3].split(",").map(t=>t.trim());4!==r.length&&s(n,"expected four rectangle coordinates");const l={};for(let i=0;i<4;i++){const t=o[2][i],e=r[i];/^(?:\d+(?:\.\d+)?|\.\d+)$/.test(e)&&Number.isFinite(Number(e))||s(n,"rectangle coordinates must be finite non-negative decimals"),"w"!==t&&"h"!==t||0!==Number(e)||s(n,"rectangle width and height must be positive"),l[t]=e}let c=o[1];if(!/^\/|(?:https?|ftp|file):\/\//i.test(c)){const t=e.split("/");t.pop(),t.push(c),c=t.join("/")}return i({url:c},l)}function a({lifetime:t,thumbnails:e,progress:n,duration:o,setStyle:r,isMobile:i}){let s=null,c=0;function u(e,n,o){t.closed||r(e,n,o)}return t.own(()=>{if(c++,null!==s){const t=s;s=null,clearTimeout(t)}}),r=>(a,d,f)=>l(null,null,function*(){if(t.closed)return;const l="played"===a&&f&&i;if("hover"!==a&&!l)return;const m=n.clientWidth*d,p=d*o();if(u(r,"display","flex"),t.closed)return;const h=function(t,e){return t.find(t=>e>=t.start&&e<=t.end)}(e,p);if(!h)return u(r,"display","none");if(m>0&&m<n.clientWidth?function(t,e,o){u(t,"backgroundImage",`url(${e.url})`),u(t,"height",`${e.h}px`),u(t,"width",`${e.w}px`),u(t,"backgroundPosition",`-${e.x}px -${e.y}px`),o<=Number(e.w)/2?u(t,"left",0):o>n.clientWidth-Number(e.w)/2?u(t,"left",n.clientWidth-Number(e.w)+"px"):u(t,"left",o-Number(e.w)/2+"px")}(r,h,m):i||u(r,"display","none"),l&&!t.closed){const e=++c;if(null!==s&&clearTimeout(s),t.closed)return;const n=setTimeout(()=>{e!==c||t.closed||(s=null,u(r,"display","none"))},500);t.closed||e!==c?clearTimeout(n):s=n}})}function d(t){return e=>l(null,null,function*(){const{setStyle:n,isMobile:o,addClass:r}=e.constructor.utils,{$progress:d}=e.template,f=function(t){let e=Boolean(t.isDestroy);const n=new Set;let o;const r=new Promise(t=>{o=t}),i={get closed(){return e},own:t=>(e?l(t):n.add(t),()=>n.delete(t)),listen(n,o){e||(i.own(()=>t.off(n,o)),t.on(n,o))},wait:t=>Promise.race([t,r]),dispose(){if(e)return;e=!0,o();const t=[...n].reverse();n.clear();for(const e of t)l(e)}};function l(t){try{t()}catch(e){console.warn("Failed to clean up VTT thumbnails:",e)}}try{i.listen("destroy",i.dispose)}catch(s){throw i.dispose(),s}return i}(e),m={name:"artplayerPluginVttThumbnail"};try{if(f.closed)return m;const p=t.vtt,h=yield function(t="",e){return l(this,null,function*(){if(e.closed)return;const n="function"===typeof AbortController?new AbortController:null,o=e.own(()=>null==n?void 0:n.abort());try{if(e.closed)return;const o=yield e.wait(n?fetch(t,{signal:n.signal}):fetch(t));if(e.closed)return;if(!1===o.ok)throw new Error(`Failed to fetch VTT thumbnails: HTTP ${o.status}`);if(e.closed)return;return yield e.wait(o.text())}finally{o()}})}(p,f);if(f.closed)return m;const b=function(t,e=""){"string"!==typeof t&&s(1,"expected text");const n=t.replace(/^\uFEFF/,"").split(/\r\n|\r|\n/);let o=0;function r(){for(;o<n.length&&!n[o].trim();)o++}if(r(),o===n.length)return[];/^WEBVTT(?:[\t ].*)?$/.test(n[o].trim())&&!n[o].includes("--\x3e")||s(o+1,"expected WEBVTT header"),o++;const l=[];for(;o<n.length&&(r(),o!==n.length);){const t=n[o].trim();if(/^NOTE(?:[\t ]|$)/.test(t)||"STYLE"===t||"REGION"===t){for(;o<n.length&&n[o].trim();)o++;continue}const a=o+1;t.includes("--\x3e")||(o++,o!==n.length&&n[o].trim()||s(a,"cue identifier must be followed by timing"));const d=o+1,f=n[o].trim().match(/^([\d:.]+)[\t ]*-->[\t ]*([\d:.]+)(?:[\t ].*)?$/);f||s(d,"invalid cue timing");const m=c(f[1],d),p=c(f[2],d);p<m&&s(d,"cue end precedes its start"),o++,r(),o===n.length&&s(d,"missing sprite image");const h=u(n[o].trim(),e,o+1);l.push(i({start:Math.floor(m),end:Math.floor(p)},h)),o++}return l}(h,p),y=a({lifetime:f,thuLine truncated
|
||||
@@ -1,124 +1,279 @@
|
||||
/*!
|
||||
* artplayer-plugin-vtt-thumbnail.js v1.1.0
|
||||
* artplayer-plugin-vtt-thumbnail.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
function padEnd(str, targetLength, padString) {
|
||||
if (str.length > targetLength) {
|
||||
return String(str);
|
||||
} else {
|
||||
targetLength = targetLength - str.length;
|
||||
if (targetLength > padString.length) {
|
||||
padString += padString.repeat(targetLength / padString.length);
|
||||
function createLifetime(art) {
|
||||
let closed = Boolean(art.isDestroy);
|
||||
const cleanups = /* @__PURE__ */ new Set();
|
||||
let cancel;
|
||||
const cancelled = new Promise((resolve) => {
|
||||
cancel = resolve;
|
||||
});
|
||||
const lifetime = {
|
||||
get closed() {
|
||||
return closed;
|
||||
},
|
||||
own(cleanup) {
|
||||
if (closed)
|
||||
run(cleanup);
|
||||
else
|
||||
cleanups.add(cleanup);
|
||||
return () => cleanups.delete(cleanup);
|
||||
},
|
||||
listen(name, callback) {
|
||||
if (closed)
|
||||
return;
|
||||
lifetime.own(() => art.off(name, callback));
|
||||
art.on(name, callback);
|
||||
},
|
||||
wait(value) {
|
||||
return Promise.race([value, cancelled]);
|
||||
},
|
||||
dispose() {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
cancel();
|
||||
const pending = [...cleanups].reverse();
|
||||
cleanups.clear();
|
||||
for (const cleanup of pending)
|
||||
run(cleanup);
|
||||
}
|
||||
};
|
||||
function run(cleanup) {
|
||||
try {
|
||||
cleanup();
|
||||
} catch (error) {
|
||||
console.warn("Failed to clean up VTT thumbnails:", error);
|
||||
}
|
||||
return String(str) + padString.slice(0, targetLength);
|
||||
}
|
||||
try {
|
||||
lifetime.listen("destroy", lifetime.dispose);
|
||||
} catch (error) {
|
||||
lifetime.dispose();
|
||||
throw error;
|
||||
}
|
||||
return lifetime;
|
||||
}
|
||||
function t2d(time) {
|
||||
const arr = time.split(".");
|
||||
const left = arr[0].split(":") || [];
|
||||
const right = padEnd(arr[1] || "0", 3, "0");
|
||||
const ms = Number(right) / 1e3;
|
||||
const h = Number(left[left.length - 3] || 0) * 3600;
|
||||
const m = Number(left[left.length - 2] || 0) * 60;
|
||||
const s = Number(left[left.length - 1] || 0);
|
||||
return h + m + s + ms;
|
||||
function invalid(line, message) {
|
||||
throw new TypeError(`Invalid VTT thumbnail at line ${line}: ${message}`);
|
||||
}
|
||||
async function getVttArray(vttUrl = "") {
|
||||
const vttString = await (await fetch(vttUrl)).text();
|
||||
const lines = vttString.split(/[\n\r]/g).filter((item) => item.trim());
|
||||
const vttArray = [];
|
||||
for (let i = 1; i < lines.length; i += 2) {
|
||||
const time = lines[i];
|
||||
const text = lines[i + 1];
|
||||
if (!text.trim())
|
||||
function timestamp(value, line) {
|
||||
if (!/^\d{2,}(?::\d{2}){0,2}(?:\.\d{3})?$/.test(value))
|
||||
invalid(line, "invalid timestamp");
|
||||
const [whole, fraction = "0"] = value.split(".");
|
||||
const seconds = whole.split(":").reduce((total, part) => total * 60 + Number(part), 0) + Number(fraction) / 1e3;
|
||||
if (!Number.isSafeInteger(Math.floor(seconds)))
|
||||
invalid(line, "timestamp exceeds the supported numeric range");
|
||||
return seconds;
|
||||
}
|
||||
function rectangle(text, vttUrl, line) {
|
||||
const match = text.match(/^(.+)#([xywh]{4})=(.*)$/);
|
||||
if (!match || new Set(match[2]).size !== 4)
|
||||
invalid(line, "expected an image URL and four distinct xywh keys");
|
||||
const values = match[3].split(",").map((value) => value.trim());
|
||||
if (values.length !== 4)
|
||||
invalid(line, "expected four rectangle coordinates");
|
||||
const rect = {};
|
||||
for (let index2 = 0; index2 < 4; index2++) {
|
||||
const key = match[2][index2];
|
||||
const value = values[index2];
|
||||
if (!/^(?:\d+(?:\.\d+)?|\.\d+)$/.test(value) || !Number.isFinite(Number(value)))
|
||||
invalid(line, "rectangle coordinates must be finite non-negative decimals");
|
||||
if ((key === "w" || key === "h") && Number(value) === 0)
|
||||
invalid(line, "rectangle width and height must be positive");
|
||||
rect[key] = value;
|
||||
}
|
||||
let url = match[1];
|
||||
if (!/^\/|(?:https?|ftp|file):\/\//i.test(url)) {
|
||||
const segments = vttUrl.split("/");
|
||||
segments.pop();
|
||||
segments.push(url);
|
||||
url = segments.join("/");
|
||||
}
|
||||
return { url, ...rect };
|
||||
}
|
||||
function findThumbnail(thumbnails, second) {
|
||||
return thumbnails.find((item) => second >= item.start && second <= item.end);
|
||||
}
|
||||
function parseVtt(text, vttUrl = "") {
|
||||
if (typeof text !== "string")
|
||||
invalid(1, "expected text");
|
||||
const lines = text.replace(/^\uFEFF/, "").split(/\r\n|\r|\n/);
|
||||
let index2 = 0;
|
||||
function skipEmpty() {
|
||||
while (index2 < lines.length && !lines[index2].trim())
|
||||
index2++;
|
||||
}
|
||||
skipEmpty();
|
||||
if (index2 === lines.length)
|
||||
return [];
|
||||
if (!/^WEBVTT(?:[\t ].*)?$/.test(lines[index2].trim()) || lines[index2].includes("-->"))
|
||||
invalid(index2 + 1, "expected WEBVTT header");
|
||||
index2++;
|
||||
const thumbnails = [];
|
||||
while (index2 < lines.length) {
|
||||
skipEmpty();
|
||||
if (index2 === lines.length)
|
||||
break;
|
||||
const first = lines[index2].trim();
|
||||
if (/^NOTE(?:[\t ]|$)/.test(first) || first === "STYLE" || first === "REGION") {
|
||||
while (index2 < lines.length && lines[index2].trim())
|
||||
index2++;
|
||||
continue;
|
||||
const timeReg = /((?:\d{2}:)?(?:\d{2}:)?\d{2}(?:.\d{3})?) ?--> ?((?:\d{2}:)?(?:\d{2}:)?\d{2}(?:.\d{3})?)/;
|
||||
const timeMatch = time.match(timeReg);
|
||||
const textReg = /(.*)#(\w{4})=(.*)/;
|
||||
const textMatch = text.match(textReg);
|
||||
const start = Math.floor(t2d(timeMatch[1]));
|
||||
const end = Math.floor(t2d(timeMatch[2]));
|
||||
let url = textMatch[1];
|
||||
const isAbsoluteUrl = /^\/|(?:https?|ftp|file):\/\//i.test(url);
|
||||
if (!isAbsoluteUrl) {
|
||||
const urlArr = vttUrl.split("/");
|
||||
urlArr.pop();
|
||||
urlArr.push(url);
|
||||
url = urlArr.join("/");
|
||||
}
|
||||
const result = { start, end, url };
|
||||
const keys = textMatch[2].split("");
|
||||
const values = textMatch[3].split(",");
|
||||
for (let j = 0; j < keys.length; j++) {
|
||||
result[keys[j]] = values[j];
|
||||
const identifierLine = index2 + 1;
|
||||
if (!first.includes("-->")) {
|
||||
index2++;
|
||||
if (index2 === lines.length || !lines[index2].trim())
|
||||
invalid(identifierLine, "cue identifier must be followed by timing");
|
||||
}
|
||||
vttArray.push(result);
|
||||
const timingLine = index2 + 1;
|
||||
const timing = lines[index2].trim().match(/^([\d:.]+)[\t ]*-->[\t ]*([\d:.]+)(?:[\t ].*)?$/);
|
||||
if (!timing)
|
||||
invalid(timingLine, "invalid cue timing");
|
||||
const start = timestamp(timing[1], timingLine);
|
||||
const end = timestamp(timing[2], timingLine);
|
||||
if (end < start)
|
||||
invalid(timingLine, "cue end precedes its start");
|
||||
index2++;
|
||||
skipEmpty();
|
||||
if (index2 === lines.length)
|
||||
invalid(timingLine, "missing sprite image");
|
||||
const image = rectangle(lines[index2].trim(), vttUrl, index2 + 1);
|
||||
thumbnails.push({ start: Math.floor(start), end: Math.floor(end), ...image });
|
||||
index2++;
|
||||
}
|
||||
return thumbnails;
|
||||
}
|
||||
function createPreview({ lifetime, thumbnails, progress, duration, setStyle, isMobile }) {
|
||||
let timer = null;
|
||||
let generation = 0;
|
||||
lifetime.own(() => {
|
||||
generation++;
|
||||
if (timer !== null) {
|
||||
const previous = timer;
|
||||
timer = null;
|
||||
clearTimeout(previous);
|
||||
}
|
||||
});
|
||||
function style(control, key, value) {
|
||||
if (!lifetime.closed)
|
||||
setStyle(control, key, value);
|
||||
}
|
||||
function show(control, cue, width) {
|
||||
style(control, "backgroundImage", `url(${cue.url})`);
|
||||
style(control, "height", `${cue.h}px`);
|
||||
style(control, "width", `${cue.w}px`);
|
||||
style(control, "backgroundPosition", `-${cue.x}px -${cue.y}px`);
|
||||
if (width <= Number(cue.w) / 2)
|
||||
style(control, "left", 0);
|
||||
else if (width > progress.clientWidth - Number(cue.w) / 2)
|
||||
style(control, "left", `${progress.clientWidth - Number(cue.w)}px`);
|
||||
else
|
||||
style(control, "left", `${width - Number(cue.w) / 2}px`);
|
||||
}
|
||||
return (control) => async (type, percentage, event) => {
|
||||
if (lifetime.closed)
|
||||
return;
|
||||
const dragging = type === "played" && event && isMobile;
|
||||
if (type !== "hover" && !dragging)
|
||||
return;
|
||||
const width = progress.clientWidth * percentage;
|
||||
const second = percentage * duration();
|
||||
style(control, "display", "flex");
|
||||
if (lifetime.closed)
|
||||
return;
|
||||
const cue = findThumbnail(thumbnails, second);
|
||||
if (!cue)
|
||||
return style(control, "display", "none");
|
||||
if (width > 0 && width < progress.clientWidth)
|
||||
show(control, cue, width);
|
||||
else if (!isMobile)
|
||||
style(control, "display", "none");
|
||||
if (dragging && !lifetime.closed) {
|
||||
const current = ++generation;
|
||||
if (timer !== null)
|
||||
clearTimeout(timer);
|
||||
if (lifetime.closed)
|
||||
return;
|
||||
const id = setTimeout(() => {
|
||||
if (current !== generation || lifetime.closed)
|
||||
return;
|
||||
timer = null;
|
||||
style(control, "display", "none");
|
||||
}, 500);
|
||||
if (lifetime.closed || current !== generation)
|
||||
clearTimeout(id);
|
||||
else
|
||||
timer = id;
|
||||
}
|
||||
};
|
||||
}
|
||||
async function requestVtt(url = "", lifetime) {
|
||||
if (lifetime.closed)
|
||||
return;
|
||||
const controller = typeof AbortController === "function" ? new AbortController() : null;
|
||||
const release = lifetime.own(() => controller?.abort());
|
||||
try {
|
||||
if (lifetime.closed)
|
||||
return;
|
||||
const response = await lifetime.wait(controller ? fetch(url, { signal: controller.signal }) : fetch(url));
|
||||
if (lifetime.closed)
|
||||
return;
|
||||
if (response.ok === false)
|
||||
throw new Error(`Failed to fetch VTT thumbnails: HTTP ${response.status}`);
|
||||
if (lifetime.closed)
|
||||
return;
|
||||
return await lifetime.wait(response.text());
|
||||
} finally {
|
||||
release();
|
||||
}
|
||||
return vttArray;
|
||||
}
|
||||
function artplayerPluginVttThumbnail(option) {
|
||||
return async (art) => {
|
||||
const {
|
||||
constructor: {
|
||||
utils: { setStyle, isMobile, addClass }
|
||||
},
|
||||
template: { $progress }
|
||||
} = art;
|
||||
let timer = null;
|
||||
const thumbnails = await getVttArray(option.vtt);
|
||||
function showThumbnails($control, find, width) {
|
||||
setStyle($control, "backgroundImage", `url(${find.url})`);
|
||||
setStyle($control, "height", `${find.h}px`);
|
||||
setStyle($control, "width", `${find.w}px`);
|
||||
setStyle($control, "backgroundPosition", `-${find.x}px -${find.y}px`);
|
||||
if (width <= find.w / 2) {
|
||||
setStyle($control, "left", 0);
|
||||
} else if (width > $progress.clientWidth - find.w / 2) {
|
||||
setStyle($control, "left", `${$progress.clientWidth - find.w}px`);
|
||||
} else {
|
||||
setStyle($control, "left", `${width - find.w / 2}px`);
|
||||
}
|
||||
const { setStyle, isMobile, addClass } = art.constructor.utils;
|
||||
const { $progress } = art.template;
|
||||
const lifetime = createLifetime(art);
|
||||
const result = { name: "artplayerPluginVttThumbnail" };
|
||||
try {
|
||||
if (lifetime.closed)
|
||||
return result;
|
||||
const url = option.vtt;
|
||||
const text = await requestVtt(url, lifetime);
|
||||
if (lifetime.closed)
|
||||
return result;
|
||||
const thumbnails = parseVtt(text, url);
|
||||
const preview = createPreview({ lifetime, thumbnails, progress: $progress, duration: () => art.duration, setStyle, isMobile });
|
||||
const style = option.style || {};
|
||||
if (lifetime.closed)
|
||||
return result;
|
||||
art.controls.add({
|
||||
name: "vtt-thumbnail",
|
||||
position: "top",
|
||||
index: 20,
|
||||
style,
|
||||
mounted(control) {
|
||||
lifetime.own(() => {
|
||||
if (art.controls["vtt-thumbnail"] === control)
|
||||
art.controls.remove("vtt-thumbnail");
|
||||
});
|
||||
if (lifetime.closed)
|
||||
return;
|
||||
addClass(control, "art-control-thumbnails");
|
||||
lifetime.listen("setBar", preview(control));
|
||||
}
|
||||
});
|
||||
return result;
|
||||
} catch (error) {
|
||||
lifetime.dispose();
|
||||
throw error;
|
||||
}
|
||||
art.controls.add({
|
||||
name: "vtt-thumbnail",
|
||||
position: "top",
|
||||
index: 20,
|
||||
style: option.style || {},
|
||||
mounted($control) {
|
||||
addClass($control, "art-control-thumbnails");
|
||||
art.on("setBar", async (type, percentage, event) => {
|
||||
const isMobileDroging = type === "played" && event && isMobile;
|
||||
if (type === "hover" || isMobileDroging) {
|
||||
const width = $progress.clientWidth * percentage;
|
||||
const second = percentage * art.duration;
|
||||
setStyle($control, "display", "flex");
|
||||
const find = thumbnails.find((item) => second >= item.start && second <= item.end);
|
||||
if (!find)
|
||||
return setStyle($control, "display", "none");
|
||||
if (width > 0 && width < $progress.clientWidth) {
|
||||
showThumbnails($control, find, width);
|
||||
} else {
|
||||
if (!isMobile) {
|
||||
setStyle($control, "display", "none");
|
||||
}
|
||||
}
|
||||
if (isMobileDroging) {
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
setStyle($control, "display", "none");
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return {
|
||||
name: "artplayerPluginVttThumbnail"
|
||||
};
|
||||
};
|
||||
}
|
||||
const index = Object.assign(artplayerPluginVttThumbnail, { default: artplayerPluginVttThumbnail });
|
||||
export {
|
||||
artplayerPluginVttThumbnail as default
|
||||
index as default
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-proxy-canvas.js v1.1.0
|
||||
* artplayer-proxy-canvas.js v2.0.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.artplayerProxyCanvas=t(),define(function(){return t.artplayerProxyCanvas})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyCanvas=t()}(this,function(){"use strict";return function(e){return t=>{const{constructor:n}=t,{createElement:i}=n.utils,o=i("canvas"),a=i("video"),r=o.getContext("2d");let c=null;const d={};for(const e in o)"function"===typeof o[e]&&(d[e]=o[e].bind(o));for(const e in a)e in o||Object.defineProperty(o,e,{get(){const t=a[e];return"function"===typeof t?t.bind(a):t},set(t){a[e]=t},configurable:!0,enumerable:!0});for(const e in d)o[e]=function(...t){return e in d?d[e](...t):a[e](...t)};return function(){const{events:e}=n.config;setTimeout(()=>{e.forEach(e=>{t.proxy(a,e,e=>{t.emit(`video:${e.type}`,e)})})})}(),t.on("video:loadedmetadata",()=>{o.width=a.videoWidth,o.height=a.videoHeight}),t.on("video:play",()=>{cancelAnimationFrame(c),f()}),t.on("video:pause",()=>{cancelAnimationFrame(c)}),t.on("resize",()=>{!function(){const e=t.template?.$player;if(!e||t.option.autoSize)return;const n=a.videoWidth/a.videoHeight,i=e.clientWidth,r=e.clientHeight;let c,d;i/r>n?(d=r,c=d*n):(c=i,d=c/n),o.width=c,o.height=d;const s=(i-c)/2,f=(r-d)/2;Object.assign(o.style,{padding:`${f}px ${s}px`})}(),s()}),t.on("destroy",()=>{cancelAnimationFrame(c)}),o;async function s(){try{if("undefined"!==typeof createImageBitmap){const e=await createImageBitmap(a);r.drawImage(e,0,0,o.width,o.height),e.close()}else r.drawImage(a,0,0,o.width,o.height);e&&e(r,a),t.emit("artplayerProxyCanvas:draw",r,a)}catch(n){t.emit("artplayerProxyCanvas:error",n)}}async function f(){await s(),c=requestAnimationFrame(f)}}}});
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerProxyCanvas=t(),define(function(){return e.artplayerProxyCanvas})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyCanvas=t()}(this,function(){"use strict";function e(e){return Number.isFinite(e.videoWidth)&&Number.isFinite(e.videoHeight)&&e.videoWidth>0&&e.videoHeight>0}function t(e,t){let n=!1,i=!1,o=!1,r=!1,a=0,l=null;function s(){null!==l&&cancelAnimationFrame(l),l=null}function c(){if(!o&&!i&&t())if(r){r=!1,o=!0;const n=a,l=()=>{o=!1,c()};e(()=>!i&&t()&&a===n).then(l,l)}else n&&null===l&&(l=requestAnimationFrame(()=>{l=null,r=!0,c()}))}function u(){!i&&t()&&(a++,r=!0,s(),c())}function d(){n=!1,r=!1,a++,s()}return{request:u,start(){n||i||!t()||(n=!0,u())},stop:d,destroy(){i=!0,d()}}}function n(n){return i=>{const o=i.constructor,r=o.utils.createElement("canvas"),a=o.utils.createElement("video");let l=i,s=i.isDestroy,c=null;const u=[],d=()=>!s&&!l?.isDestroy,f=function(e,t,n){let i=!1;return{mount(){if(i||!n())return;const o=t();o&&(e.setAttribute("aria-hidden","true"),e.tabIndex=-1,e.playsInline=!0,Object.assign(e.style,{position:"absolute",width:"auto",height:"auto",opacity:"0",pointerEvents:"none",left:"0",top:"0"}),o.appendChild(e),i=!0,n()||e.remove())},destroy(){const t=[],n=()=>{e.srcObject=null};for(const i of[()=>e.pause(),()=>e.removeAttribute("src"),n,()=>e.load(),()=>e.remove()])try{i()}catch(o){t.push(o)}if(i=!1,t.length)throw t[0]}}}(a,()=>l?.template?.$player,d),p=function(t,n,i,o,r){const a=t.getContext("2d");let l=!1;return{available:()=>!!a||(l||(l=!0,r(new Error("Canvas 2D context is unavailable"))),!1),async draw(l){const s=()=>l()&&n.readyState>=2&&!n.seeking;if(!a||!s()||!e(n)||!t.width||!t.height)return;let c=!1;try{if("undefined"!==typeof createImageBitmap){c=!0;const e=await createImageBitmap(n);c=!1;try{s()&&a.drawImage(e,0,0,t.width,t.height)}finally{e.close()}}else a.drawImage(n,0,0,t.width,t.height);if(!s())return;i&&i(a,n),s()&&o(a,n)}catch(u){const e=c&&"object"===typeof u&&null!==u&&"name"in u&&"InvalidStateError"===u.name&&0===n.currentTime&&"function"===typeof n.getVideoPlaybackQuality&&0===n.getVideoPlaybackQuality().totalVideoFrames;s()&&!e&&r(u)}}}}(r,a,n,(e,t)=>l?.emit("artplayerProxyCanvas:draw",e,t),e=>l?.emit("artplayerProxyCanvas:error",e)),h=t(p.draw,d);if(function(e,t,n,i,o){const r=new Map;for(const a in e){const t=Reflect.get(e,a);"function"===typeof t&&r.set(a,(...n)=>Reflect.apply(t,e,n))}for(const a in t)a in e||Object.defineProperty(e,a,{get(){const e=Reflect.get(t,a);return"function"!==typeof e?e:(...r)=>n()?("load"===a&&i(),"play"===a&&o(),Reflect.apply(e,t,r)):"play"===a?Promise.resolve():void 0},set(e){n()&&("src"!==a&&"srcObject"!==a||i(),Reflect.set(t,a,e))},configurable:!0,enumerable:!0});for(const[a,l]of r)Reflect.set(e,a,l)}(r,a,d,h.stop,f.mount),s)return l=null,r;function y(){if(s)return;s=!0,h.destroy(),null!==c&&clearTimeout(c),c=null;const e=[];for(const n of[...u.splice(0).reverse(),f.destroy])try{n()}catch(t){e.push(t)}if(l=null,r.width=0,r.height=0,e.length)throw e[0]}function m(e,t){if(!d())return;const n=()=>{("destroy"===e||d())&&t()},o=()=>i.off(e,n);u.push(o),i.on(e,n),s&&o()}function v(){p.available()&&h.request()}try{!function(e,t,n,i){if(!i())return;const o=e.appendChild;n.kind="metadata",n.default=!0,t.appendChild(n),e.appendChild=r=>i()&&1===r.nodeType&&"TRACK"===r.nodeName&&"namespaceURI"in r&&"http://www.w3.org/1999/xhtml"===r.namespaceURI?(n.remove(),t.appendChild(r)):o.call(e,r)}(r,a,o.utils.createElement("track"),d),m("destroy",y),m("video:loadedmetadata",()=>{e(a)&&(r.width=a.videoWidth,r.height=a.videoHeight)}),m("video:play",()=>{f.mount(),p.available()&&h.start()}),m("video:pause",h.stop),m("video:emptied",h.stop),m("video:seeked",v),m("resize",()=>{!function(t,n,i,o){if(!i||o||!e(n))return;const r=i.clientWidth,a=i.clientHeight;if(!Number.isFinite(r)||!Number.isFinite(a)||r<=0||a<=0)return;const l=n.videoWidth/n.videoHeight,s=r/a>l?a*l:r,c=r/a>l?a:r/l;t.width=s,t.height=c,t.style.padding=`${(a-c)/2}px ${(r-s)/2}px`}(r,a,l?.template?.$player,l?.option.autoSize),v()}),d()&&(c=setTimeout(()=>{if(c=null,d())try{f.mount();for(const e of o.config.events){if(!d())break;const t=e=>{d()&&l?.emit(`video:${e.type}`,e)},n=()=>a.removeEventListener(e,t);u.push(n);const o=i.proxy(a,e,t);d()?u.push(o):o()}}catch(e){try{y()}catch{}i.emit("artplayerProxyCanvas:error",e)}}))}catch(g){try{y()}catch{}throw g}return r}}return Object.assign(n,{default:n})});
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-proxy-canvas.js v1.1.0
|
||||
* artplayer-proxy-canvas.js v2.0.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.artplayerProxyCanvas=t(),define(function(){return t.artplayerProxyCanvas})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyCanvas=t()}(this,function(){"use strict";var e=(e,t,n)=>new Promise((i,o)=>{var r=e=>{try{c(n.next(e))}catch(t){o(t)}},a=e=>{try{c(n.throw(e))}catch(t){o(t)}},c=e=>e.done?i(e.value):Promise.resolve(e.value).then(r,a);c((n=n.apply(e,t)).next())});return function(t){return n=>{const{constructor:i}=n,{createElement:o}=i.utils,r=o("canvas"),a=o("video"),c=r.getContext("2d");let d=null;const l={};for(const e in r)"function"===typeof r[e]&&(l[e]=r[e].bind(r));for(const e in a)e in r||Object.defineProperty(r,e,{get(){const t=a[e];return"function"===typeof t?t.bind(a):t},set(t){a[e]=t},configurable:!0,enumerable:!0});for(const e in l)r[e]=function(...t){return e in l?l[e](...t):a[e](...t)};return function(){const{events:e}=i.config;setTimeout(()=>{e.forEach(e=>{n.proxy(a,e,e=>{n.emit(`video:${e.type}`,e)})})})}(),n.on("video:loadedmetadata",()=>{r.width=a.videoWidth,r.height=a.videoHeight}),n.on("video:play",()=>{cancelAnimationFrame(d),u()}),n.on("video:pause",()=>{cancelAnimationFrame(d)}),n.on("resize",()=>{!function(){var e;const t=null==(e=n.template)?void 0:e.$player;if(!t||n.option.autoSize)return;const i=a.videoWidth/a.videoHeight,o=t.clientWidth,c=t.clientHeight;let d,l;o/c>i?(l=c,d=l*i):(d=o,l=d/i),r.width=d,r.height=l;const s=(o-d)/2,u=(c-l)/2;Object.assign(r.style,{padding:`${u}px ${s}px`})}(),s()}),n.on("destroy",()=>{cancelAnimationFrame(d)}),r;function s(){return e(this,null,function*(){try{if("undefined"!==typeof createImageBitmap){const e=yield createImageBitmap(a);c.drawImage(e,0,0,r.width,r.height),e.close()}else c.drawImage(a,0,0,r.width,r.height);t&&t(c,a),n.emit("artplayerProxyCanvas:draw",c,a)}catch(e){n.emit("artplayerProxyCanvas:error",e)}})}function u(){return e(this,null,function*(){yield s(),d=requestAnimationFrame(u)})}}}});
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerProxyCanvas=t(),define(function(){return e.artplayerProxyCanvas})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyCanvas=t()}(this,function(){"use strict";function e(e){return Number.isFinite(e.videoWidth)&&Number.isFinite(e.videoHeight)&&e.videoWidth>0&&e.videoHeight>0}function t(t,n,i,o,r){const a=t.getContext("2d");let l=!1;return{available:()=>!!a||(l||(l=!0,r(new Error("Canvas 2D context is unavailable"))),!1),draw(l){return s=this,u=null,c=function*(){const s=()=>l()&&n.readyState>=2&&!n.seeking;if(!a||!s()||!e(n)||!t.width||!t.height)return;let u=!1;try{if("undefined"!==typeof createImageBitmap){u=!0;const e=yield createImageBitmap(n);u=!1;try{s()&&a.drawImage(e,0,0,t.width,t.height)}finally{e.close()}}else a.drawImage(n,0,0,t.width,t.height);if(!s())return;i&&i(a,n),s()&&o(a,n)}catch(c){const e=u&&"object"===typeof c&&null!==c&&"name"in c&&"InvalidStateError"===c.name&&0===n.currentTime&&"function"===typeof n.getVideoPlaybackQuality&&0===n.getVideoPlaybackQuality().totalVideoFrames;s()&&!e&&r(c)}},new Promise((e,t)=>{var n=e=>{try{o(c.next(e))}catch(n){t(n)}},i=e=>{try{o(c.throw(e))}catch(n){t(n)}},o=t=>t.done?e(t.value):Promise.resolve(t.value).then(n,i);o((c=c.apply(s,u)).next())});var s,u,c}}}function n(e,t){let n=!1,i=!1,o=!1,r=!1,a=0,l=null;function s(){null!==l&&cancelAnimationFrame(l),l=null}function u(){if(!o&&!i&&t())if(r){r=!1,o=!0;const n=a,l=()=>{o=!1,u()};e(()=>!i&&t()&&a===n).then(l,l)}else n&&null===l&&(l=requestAnimationFrame(()=>{l=null,r=!0,u()}))}function c(){!i&&t()&&(a++,r=!0,s(),u())}function d(){n=!1,r=!1,a++,s()}return{request:c,start(){n||i||!t()||(n=!0,c())},stop:d,destroy(){i=!0,d()}}}function i(i){return o=>{const r=o.constructor,a=r.utils.createElement("canvas"),l=r.utils.createElement("video");let s=o,u=o.isDestroy,c=null;const d=[],f=()=>!u&&!(null==s?void 0:s.isDestroy),p=function(e,t,n){let i=!1;return{mount(){if(i||!n())return;const o=t();o&&(e.setAttribute("aria-hidden","true"),e.tabIndex=-1,e.playsInline=!0,Object.assign(e.style,{position:"absolute",width:"auto",height:"auto",opacity:"0",pointerEvents:"none",left:"0",top:"0"}),o.appendChild(e),i=!0,n()||e.remove())},destroy(){const t=[],n=()=>{e.srcObject=null};for(const i of[()=>e.pause(),()=>e.removeAttribute("src"),n,()=>e.load(),()=>e.remove()])try{i()}catch(o){t.push(o)}if(i=!1,t.length)throw t[0]}}}(l,()=>{var e;return null==(e=null==s?void 0:s.template)?void 0:e.$player},f),h=t(a,l,i,(e,t)=>null==s?void 0:s.emit("artplayerProxyCanvas:draw",e,t),e=>null==s?void 0:s.emit("artplayerProxyCanvas:error",e)),y=n(h.draw,f);if(function(e,t,n,i,o){const r=new Map;for(const a in e){const t=Reflect.get(e,a);"function"===typeof t&&r.set(a,(...n)=>Reflect.apply(t,e,n))}for(const a in t)a in e||Object.defineProperty(e,a,{get(){const e=Reflect.get(t,a);return"function"!==typeof e?e:(...r)=>n()?("load"===a&&i(),"play"===a&&o(),Reflect.apply(e,t,r)):"play"===a?Promise.resolve():void 0},set(e){n()&&("src"!==a&&"srcObject"!==a||i(),Reflect.set(t,a,e))},configurable:!0,enumerable:!0});for(const[a,l]of r)Reflect.set(e,a,l)}(a,l,f,y.stop,p.mount),u)return s=null,a;function m(){if(u)return;u=!0,y.destroy(),null!==c&&clearTimeout(c),c=null;const e=[];for(const n of[...d.splice(0).reverse(),p.destroy])try{n()}catch(t){e.push(t)}if(s=null,a.width=0,a.height=0,e.length)throw e[0]}function v(e,t){if(!f())return;const n=()=>{("destroy"===e||f())&&t()},i=()=>o.off(e,n);d.push(i),o.on(e,n),u&&i()}function g(){h.available()&&y.request()}try{!function(e,t,n,i){if(!i())return;const o=e.appendChild;n.kind="metadata",n.default=!0,t.appendChild(n),e.appendChild=r=>i()&&1===r.nodeType&&"TRACK"===r.nodeName&&"namespaceURI"in r&&"http://www.w3.org/1999/xhtml"===r.namespaceURI?(n.remove(),t.appendChild(r)):o.call(e,r)}(a,l,r.utils.createElement("track"),f),v("destroy",m),v("video:loadedmetadata",()=>{e(l)&&(a.width=l.videoWidth,a.height=l.videoHeight)}),v("video:play",()=>{p.mount(),h.available()&&y.start()}),v("video:pause",y.stop),v("video:emptied",y.stop),v("video:seeked",g),v("resize",()=>{var t;!function(t,n,i,o){if(!i||o||!e(n))return;const r=i.clientWidth,a=i.clientHeight;if(!Number.isFinite(r)||!Number.isFinite(a)||r<=0||a<=0)return;const l=n.videoWidth/n.videoHeight,s=r/a>l?a*l:r,u=r/a>l?a:r/l;t.width=s,t.height=u,t.style.padding=`${(a-u)/2}px ${(r-s)/2}px`}(a,l,null==(t=null==s?void 0:s.template)?void 0:t.$player,null==s?void 0:s.option.autoSize),g()}),f()&&(c=setTimeout(()=>{if(c=null,f())try{p.mount();for(const e of r.config.events){if(!f())break;const t=e=>{f()&&(null==s||s.emit(`video:${e.type}`,e))},n=()=>l.removeEventListener(e,t);d.push(n);const i=o.proxy(l,e,t);f()?d.push(i):i()}}catch(e){try{m()}catch(t){}o.emit("artplayerProxyCanvas:error",e)}}))}catch(b){try{m()}catch(w){}throw b}return a}}return Object.assign(i,{default:i})});
|
||||
@@ -1,124 +1,344 @@
|
||||
/*!
|
||||
* artplayer-proxy-canvas.js v1.1.0
|
||||
* artplayer-proxy-canvas.js v2.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
function artplayerProxyCanvas(callback) {
|
||||
return (art) => {
|
||||
const { constructor } = art;
|
||||
const { createElement } = constructor.utils;
|
||||
const canvas = createElement("canvas");
|
||||
const video = createElement("video");
|
||||
const ctx = canvas.getContext("2d");
|
||||
let animationId = null;
|
||||
const originalCanvasMethods = {};
|
||||
for (const prop in canvas) {
|
||||
if (typeof canvas[prop] === "function") {
|
||||
originalCanvasMethods[prop] = canvas[prop].bind(canvas);
|
||||
}
|
||||
}
|
||||
for (const prop in video) {
|
||||
if (!(prop in canvas)) {
|
||||
Object.defineProperty(canvas, prop, {
|
||||
get() {
|
||||
const value = video[prop];
|
||||
return typeof value === "function" ? value.bind(video) : value;
|
||||
},
|
||||
set(value) {
|
||||
video[prop] = value;
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const prop in originalCanvasMethods) {
|
||||
canvas[prop] = function(...args) {
|
||||
if (prop in originalCanvasMethods) {
|
||||
return originalCanvasMethods[prop](...args);
|
||||
}
|
||||
return video[prop](...args);
|
||||
};
|
||||
}
|
||||
setupEventListeners();
|
||||
setupArtPlayerEvents();
|
||||
return canvas;
|
||||
function setupEventListeners() {
|
||||
const { events } = constructor.config;
|
||||
setTimeout(() => {
|
||||
events.forEach((event) => {
|
||||
art.proxy(video, event, (event2) => {
|
||||
art.emit(`video:${event2.type}`, event2);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
async function draw() {
|
||||
try {
|
||||
if (typeof createImageBitmap !== "undefined") {
|
||||
const bitmap = await createImageBitmap(video);
|
||||
ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
|
||||
bitmap.close();
|
||||
} else {
|
||||
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
callback && callback(ctx, video);
|
||||
art.emit("artplayerProxyCanvas:draw", ctx, video);
|
||||
} catch (error) {
|
||||
art.emit("artplayerProxyCanvas:error", error);
|
||||
}
|
||||
}
|
||||
async function animation() {
|
||||
await draw();
|
||||
animationId = requestAnimationFrame(animation);
|
||||
}
|
||||
function resize() {
|
||||
const player = art.template?.$player;
|
||||
if (!player || art.option.autoSize)
|
||||
function forwardMedia(canvas, video, active, invalidate, mount) {
|
||||
const methods = /* @__PURE__ */ new Map();
|
||||
for (const name in canvas) {
|
||||
const value = Reflect.get(canvas, name);
|
||||
if (typeof value === "function")
|
||||
methods.set(name, (...args) => Reflect.apply(value, canvas, args));
|
||||
}
|
||||
for (const name in video) {
|
||||
if (name in canvas)
|
||||
continue;
|
||||
Object.defineProperty(canvas, name, {
|
||||
get() {
|
||||
const value = Reflect.get(video, name);
|
||||
if (typeof value !== "function")
|
||||
return value;
|
||||
return (...args) => {
|
||||
if (!active())
|
||||
return name === "play" ? Promise.resolve() : void 0;
|
||||
if (name === "load")
|
||||
invalidate();
|
||||
if (name === "play")
|
||||
mount();
|
||||
return Reflect.apply(value, video, args);
|
||||
};
|
||||
},
|
||||
set(value) {
|
||||
if (!active())
|
||||
return;
|
||||
if (name === "src" || name === "srcObject")
|
||||
invalidate();
|
||||
Reflect.set(video, name, value);
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
});
|
||||
}
|
||||
for (const [name, method] of methods)
|
||||
Reflect.set(canvas, name, method);
|
||||
}
|
||||
function hasDimensions(video) {
|
||||
return Number.isFinite(video.videoWidth) && Number.isFinite(video.videoHeight) && video.videoWidth > 0 && video.videoHeight > 0;
|
||||
}
|
||||
function resizeCanvas(canvas, video, player, autoSize) {
|
||||
if (!player || autoSize || !hasDimensions(video))
|
||||
return;
|
||||
const width = player.clientWidth;
|
||||
const height = player.clientHeight;
|
||||
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0)
|
||||
return;
|
||||
const aspect = video.videoWidth / video.videoHeight;
|
||||
const canvasWidth = width / height > aspect ? height * aspect : width;
|
||||
const canvasHeight = width / height > aspect ? height : width / aspect;
|
||||
canvas.width = canvasWidth;
|
||||
canvas.height = canvasHeight;
|
||||
canvas.style.padding = `${(height - canvasHeight) / 2}px ${(width - canvasWidth) / 2}px`;
|
||||
}
|
||||
function ownMedia(video, parent, active) {
|
||||
let mounted = false;
|
||||
return {
|
||||
mount() {
|
||||
if (mounted || !active())
|
||||
return;
|
||||
const aspectRatio = video.videoWidth / video.videoHeight;
|
||||
const containerWidth = player.clientWidth;
|
||||
const containerHeight = player.clientHeight;
|
||||
const containerRatio = containerWidth / containerHeight;
|
||||
let canvasWidth, canvasHeight;
|
||||
if (containerRatio > aspectRatio) {
|
||||
canvasHeight = containerHeight;
|
||||
canvasWidth = canvasHeight * aspectRatio;
|
||||
} else {
|
||||
canvasWidth = containerWidth;
|
||||
canvasHeight = canvasWidth / aspectRatio;
|
||||
const target = parent();
|
||||
if (!target)
|
||||
return;
|
||||
video.setAttribute("aria-hidden", "true");
|
||||
video.tabIndex = -1;
|
||||
video.playsInline = true;
|
||||
Object.assign(video.style, { position: "absolute", width: "auto", height: "auto", opacity: "0", pointerEvents: "none", left: "0", top: "0" });
|
||||
target.appendChild(video);
|
||||
mounted = true;
|
||||
if (!active())
|
||||
video.remove();
|
||||
},
|
||||
destroy() {
|
||||
const failures = [];
|
||||
const clearObject = () => {
|
||||
video.srcObject = null;
|
||||
};
|
||||
for (const release of [() => video.pause(), () => video.removeAttribute("src"), clearObject, () => video.load(), () => video.remove()]) {
|
||||
try {
|
||||
release();
|
||||
} catch (error) {
|
||||
failures.push(error);
|
||||
}
|
||||
}
|
||||
canvas.width = canvasWidth;
|
||||
canvas.height = canvasHeight;
|
||||
const paddingLeft = (containerWidth - canvasWidth) / 2;
|
||||
const paddingTop = (containerHeight - canvasHeight) / 2;
|
||||
Object.assign(canvas.style, {
|
||||
padding: `${paddingTop}px ${paddingLeft}px`
|
||||
});
|
||||
}
|
||||
function setupArtPlayerEvents() {
|
||||
art.on("video:loadedmetadata", () => {
|
||||
canvas.width = video.videoWidth;
|
||||
canvas.height = video.videoHeight;
|
||||
});
|
||||
art.on("video:play", () => {
|
||||
cancelAnimationFrame(animationId);
|
||||
animation();
|
||||
});
|
||||
art.on("video:pause", () => {
|
||||
cancelAnimationFrame(animationId);
|
||||
});
|
||||
art.on("resize", () => {
|
||||
resize();
|
||||
draw();
|
||||
});
|
||||
art.on("destroy", () => {
|
||||
cancelAnimationFrame(animationId);
|
||||
});
|
||||
mounted = false;
|
||||
if (failures.length)
|
||||
throw failures[0];
|
||||
}
|
||||
};
|
||||
}
|
||||
function createRenderer(canvas, video, callback, notify, error) {
|
||||
const context = canvas.getContext("2d");
|
||||
let reported = false;
|
||||
return {
|
||||
available() {
|
||||
if (context)
|
||||
return true;
|
||||
if (!reported) {
|
||||
reported = true;
|
||||
error(new Error("Canvas 2D context is unavailable"));
|
||||
}
|
||||
return false;
|
||||
},
|
||||
async draw(valid) {
|
||||
const usable = () => valid() && video.readyState >= 2 && !video.seeking;
|
||||
if (!context || !usable() || !hasDimensions(video) || !canvas.width || !canvas.height)
|
||||
return;
|
||||
let acquiring = false;
|
||||
try {
|
||||
if (typeof createImageBitmap !== "undefined") {
|
||||
acquiring = true;
|
||||
const bitmap = await createImageBitmap(video);
|
||||
acquiring = false;
|
||||
try {
|
||||
if (usable())
|
||||
context.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
|
||||
} finally {
|
||||
bitmap.close();
|
||||
}
|
||||
} else {
|
||||
context.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
if (!usable())
|
||||
return;
|
||||
if (callback)
|
||||
callback(context, video);
|
||||
if (usable())
|
||||
notify(context, video);
|
||||
} catch (failure) {
|
||||
const awaitingFirstFrame = acquiring && typeof failure === "object" && failure !== null && "name" in failure && failure.name === "InvalidStateError" && video.currentTime === 0 && typeof video.getVideoPlaybackQuality === "function" && video.getVideoPlaybackQuality().totalVideoFrames === 0;
|
||||
if (usable() && !awaitingFirstFrame)
|
||||
error(failure);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
function createFrameScheduler(draw, active) {
|
||||
let running = false;
|
||||
let closed = false;
|
||||
let busy = false;
|
||||
let pending = false;
|
||||
let generation = 0;
|
||||
let frame = null;
|
||||
function cancel() {
|
||||
if (frame !== null)
|
||||
cancelAnimationFrame(frame);
|
||||
frame = null;
|
||||
}
|
||||
function drain() {
|
||||
if (busy || closed || !active())
|
||||
return;
|
||||
if (pending) {
|
||||
pending = false;
|
||||
busy = true;
|
||||
const version = generation;
|
||||
const valid = () => !closed && active() && generation === version;
|
||||
const complete = () => {
|
||||
busy = false;
|
||||
drain();
|
||||
};
|
||||
void draw(valid).then(complete, complete);
|
||||
} else if (running && frame === null) {
|
||||
frame = requestAnimationFrame(() => {
|
||||
frame = null;
|
||||
pending = true;
|
||||
drain();
|
||||
});
|
||||
}
|
||||
}
|
||||
function request() {
|
||||
if (closed || !active())
|
||||
return;
|
||||
generation++;
|
||||
pending = true;
|
||||
cancel();
|
||||
drain();
|
||||
}
|
||||
function stop() {
|
||||
running = false;
|
||||
pending = false;
|
||||
generation++;
|
||||
cancel();
|
||||
}
|
||||
return {
|
||||
request,
|
||||
start() {
|
||||
if (running || closed || !active())
|
||||
return;
|
||||
running = true;
|
||||
request();
|
||||
},
|
||||
stop,
|
||||
destroy() {
|
||||
closed = true;
|
||||
stop();
|
||||
}
|
||||
};
|
||||
}
|
||||
function forwardSubtitleTrack(canvas, video, initialTrack, active) {
|
||||
if (!active())
|
||||
return;
|
||||
const append = canvas.appendChild;
|
||||
initialTrack.kind = "metadata";
|
||||
initialTrack.default = true;
|
||||
video.appendChild(initialTrack);
|
||||
canvas.appendChild = (node) => {
|
||||
if (active() && node.nodeType === 1 && node.nodeName === "TRACK" && "namespaceURI" in node && node.namespaceURI === "http://www.w3.org/1999/xhtml") {
|
||||
initialTrack.remove();
|
||||
return video.appendChild(node);
|
||||
}
|
||||
return append.call(canvas, node);
|
||||
};
|
||||
}
|
||||
function artplayerProxyCanvas(callback) {
|
||||
return (art) => {
|
||||
const constructor = art.constructor;
|
||||
const canvas = constructor.utils.createElement("canvas");
|
||||
const video = constructor.utils.createElement("video");
|
||||
let host = art;
|
||||
let closed = art.isDestroy;
|
||||
let timer = null;
|
||||
const releases = [];
|
||||
const active = () => !closed && !host?.isDestroy;
|
||||
const media = ownMedia(video, () => host?.template?.$player, active);
|
||||
const renderer = createRenderer(canvas, video, callback, (context, source) => host?.emit("artplayerProxyCanvas:draw", context, source), (error) => host?.emit("artplayerProxyCanvas:error", error));
|
||||
const scheduler = createFrameScheduler(renderer.draw, active);
|
||||
forwardMedia(canvas, video, active, scheduler.stop, media.mount);
|
||||
if (closed) {
|
||||
host = null;
|
||||
return canvas;
|
||||
}
|
||||
function destroy() {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
scheduler.destroy();
|
||||
if (timer !== null)
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
const failures = [];
|
||||
for (const release of [...releases.splice(0).reverse(), media.destroy]) {
|
||||
try {
|
||||
release();
|
||||
} catch (error) {
|
||||
failures.push(error);
|
||||
}
|
||||
}
|
||||
host = null;
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
if (failures.length)
|
||||
throw failures[0];
|
||||
}
|
||||
function listen(name, handler) {
|
||||
if (!active())
|
||||
return;
|
||||
const listener = () => {
|
||||
if (name === "destroy" || active())
|
||||
handler();
|
||||
};
|
||||
const release = () => art.off(name, listener);
|
||||
releases.push(release);
|
||||
art.on(name, listener);
|
||||
if (closed)
|
||||
release();
|
||||
}
|
||||
function request() {
|
||||
if (renderer.available())
|
||||
scheduler.request();
|
||||
}
|
||||
try {
|
||||
forwardSubtitleTrack(canvas, video, constructor.utils.createElement("track"), active);
|
||||
listen("destroy", destroy);
|
||||
listen("video:loadedmetadata", () => {
|
||||
if (hasDimensions(video)) {
|
||||
canvas.width = video.videoWidth;
|
||||
canvas.height = video.videoHeight;
|
||||
}
|
||||
});
|
||||
listen("video:play", () => {
|
||||
media.mount();
|
||||
if (renderer.available())
|
||||
scheduler.start();
|
||||
});
|
||||
listen("video:pause", scheduler.stop);
|
||||
listen("video:emptied", scheduler.stop);
|
||||
listen("video:seeked", request);
|
||||
listen("resize", () => {
|
||||
resizeCanvas(canvas, video, host?.template?.$player, host?.option.autoSize);
|
||||
request();
|
||||
});
|
||||
if (active()) {
|
||||
timer = setTimeout(() => {
|
||||
timer = null;
|
||||
if (!active())
|
||||
return;
|
||||
try {
|
||||
media.mount();
|
||||
for (const name of constructor.config.events) {
|
||||
if (!active())
|
||||
break;
|
||||
const forward = (event) => {
|
||||
if (active())
|
||||
host?.emit(`video:${event.type}`, event);
|
||||
};
|
||||
const remove = () => video.removeEventListener(name, forward);
|
||||
releases.push(remove);
|
||||
const release = art.proxy(video, name, forward);
|
||||
if (active())
|
||||
releases.push(release);
|
||||
else
|
||||
release();
|
||||
}
|
||||
} catch (error) {
|
||||
try {
|
||||
destroy();
|
||||
} catch {
|
||||
}
|
||||
art.emit("artplayerProxyCanvas:error", error);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
try {
|
||||
destroy();
|
||||
} catch {
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
return canvas;
|
||||
};
|
||||
}
|
||||
const index = Object.assign(artplayerProxyCanvas, { default: artplayerProxyCanvas });
|
||||
export {
|
||||
artplayerProxyCanvas as default
|
||||
index as default
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-proxy-mediabunny.js v1.1.0
|
||||
* artplayer-proxy-mediabunny.js v2.0.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";class e{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 r=this.listeners.get(e);if(!r)return;const i=r.indexOf(t);i>=0&&r.splice(i,1)}emit(e,t){const r=new Event(e);r.detail=t;const i=this.listeners.get(e);i&&i.forEach(e=>e(r))}}function t(e){if(!e)throw new Error("Assertion failed.")}const r=e=>{const t=(e%360+360)%360;if(0===t||90===t||180===t||270===t)return t;throw new Error(`Invalid rotation ${e}.`)},i=e=>e&&e[e.length-1];class a{constructor(e){this.bytes=e,this.pos=0}seekToByte(e){this.pos=8*e}readBit(){const e=Math.floor(this.pos/8),t=this.bytes[e]??0,r=7-(7&this.pos),i=(t&1<<r)>>r;return this.pos++,i}readBits(e){if(1===e)return this.readBit();let t=0;for(let r=0;r<e;r++)t<<=1,t|=this.readBit();return t}writeBits(e,t){const r=this.pos+e;for(let i=this.pos;i<r;i++){const e=Math.floor(i/8);let a=this.bytes[e];const s=7-(7&i);a&=~(1<<s),a|=(t&1<<r-i-1)>>r-i-1<<s,this.bytes[e]=a}this.pos=r}readAlignedByte(){if(this.pos%8!==0)throw new Error("Bitstream is not byte-aligned.");const e=this.pos/8,t=this.bytes[e]??0;return this.pos+=8,t}skipBits(e){this.pos+=e}getBitsLeft(){return 8*this.bytes.length-this.pos}clone(){const e=new a(this.bytes);return e.pos=this.pos,e}}const 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)},n=e=>{const t=s(e);return 0===(1&t)?-(t>>1):t+1>>1},o=e=>e.constructor===Uint8Array?e:ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e),c=e=>e.constructor===DataView?e:ArrayBuffer.isView(e)?new DataView(e.buffer,e.byteOffset,e.byteLength):new DataView(e),l=new TextDecoder,d=e=>Object.fromEntries(Object.entries(e).map(([e,t])=>[t,e])),u={bt709:1,bt470bg:5,smpte170m:6,bt2020:9,smpte432:12},h=d(u),m={bt709:1,smpte170m:6,linear:8,"iec61966-2-1":13,pq:16,hlg:18},f=d(m),p={rgb:0,bt709:1,bt470bg:5,smpte170m:6,"bt2020-ncl":9},g=d(p),k=e=>e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e);class b{constructor(){this.currentPromise=Promise.resolve()}async acquire(){let e;const t=new Promise(t=>{e=t}),r=this.currentPromise;return this.currentPromise=t,await r,e}}const T=e=>[...e].map(e=>e.toString(16).padStart(2,"0")).join(""),y=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,w=(e,t,r)=>{let i=0,a=e.length-1,s=-1;for(;i<=a;){const n=i+a>>1,o=r(e[n]);o===t?(s=n,a=n-1):o<t?i=n+1:a=n-1}return s},S=(e,t,r)=>{let i=0,a=e.length-1,s=-1;for(;i<=a;){const n=i+(a-i+1)/2|0;r(e[n])<=t?(s=n,i=n+1):a=n-1}return s},I=(e,t,r)=>{const i=S(e,r(t),r);e.splice(i+1,0,t)},v=()=>{let e,t;return{promise:new Promise((r,i)=>{e=r,t=i}),resolve:e,reject:t}},P=(e,t)=>{for(let r=e.length-1;r>=0;r--)if(t(e[r]))return e[r]},x=(e,t)=>{for(let r=e.length-1;r>=0;r--)if(t(e[r]))return r;return-1},C=e=>{throw new Error(`Unexpected value: ${e}`)},_=(e,t,r)=>{const i=e.getUint8(t),a=e.getUint8(t+1),s=e.getUint8(t+2);return r?i|a<<8|s<<16:i<<16|a<<8|s},B=(e,t,r,i)=>{r>>>=0,r&=16777215,e.setUint8(t,r>>>16&255),e.setUint8(t+1,r>>>8&255),e.setUint8(t+2,255&r)},E=(e,t)=>({async next(){const r=await e.next();return r.done?{value:void 0,done:!0}:{value:t(r.value),done:!1}},return:()=>e.return(),throw:t=>e.throw(t),[Symbol.asyncIterator](){return this}}),F=(e,t,r)=>Math.max(t,Math.min(r,e)),D="und",A=e=>{const t=Math.round(e);return Math.abs(e/t-1)<10*Number.EPSILON?t:e},R=/^[a-z]{3}$/,M=e=>R.test(e),N=1e6*(1+Number.EPSILON),z=(e,t)=>{const r={...e,...t};if(e.headers||t.headers){const i=e.headers?O(e.headers):{},a=t.headers?O(t.headers):{},s={...i};Object.entries(a).forEach(([e,t])=>{const r=Object.keys(s).find(t=>t.toLowerCase()===e.toLowerCase());r&&delete s[r],s[e]=t}),r.headers=s}return r},O=e=>{if(e instanceof Headers){const t={};return e.forEach((e,r)=>{t[r]=e}),t}if(Array.isArray(e)){const t={};return e.forEach(([e,r])=>{t[e]=r}),t}return e},L=async(e,t,r,i,a)=>{let s=0;for(;;)try{return await e(t,r)}catch(n){if(a())throw n;s++;const e=i(s,n,t);if(null===e)throw n;if(console.error("Retrying failed fetch. Error:",n),!Number.isFinite(e)||e<0)throw new TypeError("Retry delay must be a non-negative finite number.");if(e>0&&await new Promise(t=>setTimeout(t,1e3*e)),a())throw n}};class U{constructor(){this.currentPromise=Promise.resolve()}call(e){return this.currentPromise=this.currentPromise.then(e)}}let V=null;const q=()=>null!==V?V:V=!("undefined"===typeof navigator||!(navigator.vendor?Line truncated
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerProxyMediabunny=t(),define(function(){return e.artplayerProxyMediabunny})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyMediabunny=t()}(this,function(){"use strict";var e,t,i,r,a,s,n,o,c,l,u,h,d,f,m,p,g,k,y,b,w,T,S,v,P,I,x,C,B,E,_,R,F,A=e=>{throw TypeError(e)},M=(e,t,i)=>t.has(e)||A("Cannot "+i),D=(e,t,i)=>(M(e,t,"read from private field"),i?i.call(e):t.get(e)),N=(e,t,i)=>t.has(e)?A("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,i),O=(e,t,i,r)=>(M(e,t,"write to private field"),r?r.call(e,i):t.set(e,i),i),L=(e,t,i)=>(M(e,t,"access private method"),i),z=(e,t,i,r)=>({set _(r){O(e,t,r,i)},get _(){return D(e,t,r)}});function U(e){const t=[];for(const r of e)try{r()}catch(i){t.push(i)}if(t.length)throw t[0]}function q(e,t,i){const r={control:!1,setting:!1};let a=null;function s(i){r[i]&&(r[i]=!1,"control"===i?e.controls.cache.has(t)&&e.controls.remove(t):e.setting.find(t)&&e.setting.remove(t))}function n(){a=null,U([()=>s("control"),()=>s("setting")])}return{update:function(o,c,l,u){if(!o)return void n();a=o;const h=()=>a===o&&l(),d=async e=>h()&&o.selector.some(t=>t.value===e.value)?u(e,o.title):e.html;c.control?(r.control=!0,e.controls.update({name:t,position:"right",html:o.html,style:{padding:"0 10px"},selector:o.selector,onSelect:d})):s("control"),h()&&(c.setting?(r.setting=!0,e.setting.update({name:t,tooltip:o.html,html:o.title,icon:i,width:200,selector:o.selector,onSelect:d})):s("setting"))},clear:n}}function W(e){const t=new Map,i=[];for(const r of e){const e=t.get(r.html);void 0!==r.html&&void 0!==e?r.default&&(i[e]=r):(t.set(r.html,i.length),i.push(r))}return i}function H({art:e,shim:t,option:i}){if(!i.m3u8)return;let r=!1,a=0,s=0;const n=q(e,"mediabunny-quality",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>'),o=q(e,"mediabunny-audio",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>'),c=e=>!r&&!t.engine.destroyed&&t.engine.loadSeq===e;async function l(){if(r||t.engine.destroyed)return;const e=++a,s=t.engine.loadSeq,l=()=>e===a&&c(s);try{const e=await t.getM3u8State();if(!l())return;const r=i.m3u8?.quality||{},a=function(e,t,i){if(!t.control&&!t.setting||!e?.levels.length)return null;const r=t.auto||"Auto",a=t.getName||(e=>e.name||`${e.height}P`),s=e.currentLevel?a(e.currentLevel):r,n=[];for(const l of e.levels){if(!i())return null;n.push({html:a(l),value:l.id,default:e.currentLevel?.id===l.id})}const o=new Map(e.levels.map(e=>[e.id,e.height])),c=W(n).sort((e,t)=>("auto"===t.value?0:o.get(t.value)||0)-("auto"===e.value?0:o.get(e.value)||0));return c.push({html:r,value:"auto",default:!e.currentLevel}),{title:t.title||"Quality",html:s,selector:c}}(e,r,l);if(!l())return;if(n.update(a,r,()=>c(s),(e,t)=>u("quality",e,t)),!l())return;const h=i.m3u8?.audio||{},d=function(e,t,i){if(!t.control&&!t.setting||!e||e.audios.length<2)return null;const r=t.auto||"Auto",a=t.getName||(e=>e.name||e.lang||e.language),s=e.currentAudio?a(e.currentAudio):r,n=[];for(const c of e.audios){if(!i())return null;n.push({html:a(c),value:c.id,default:e.currentAudio?.id===c.id})}const o=W(n);return o.push({html:r,value:"auto",default:!e.currentAudio}),{title:t.title||"Audio",html:s,selector:o}}(e,h,l);l()&&o.update(d,h,()=>c(s),(e,t)=>u("audio",e,t))}catch(h){if(l())throw h}}async function u(i,r,n){const o=++s,u=t.engine.loadSeq;a++;const d=()=>o===s&&c(u);try{"quality"===i?await t.switchM3u8Quality(r.value):await t.switchM3u8Audio(r.value),d()&&(await l(),d()&&(e.notice.show=`${n}: ${r.html}`))}catch(f){if(d()&&(await h(),d()))throw f}return r.html}function h(){return l().catch(e=>console.warn("MediaBunny HLS menu update:",e))}function d(){a++,s++;try{U([n.clear,o.clear])}catch(e){console.warn("MediaBunny HLS menu cleanup:",e)}}function f(){if(!r){r=!0,d();try{U([()=>e.off("video:loadedmetadata",h),()=>e.off("restart",h),()=>e.off("video:loadstart",d),()=>e.off("video:error",d),()=>e.off("destroy",f)])}catch(t){console.warn("MediaBunny HLS listener cleanup:",t)}}}try{e.on("video:loadedmetadata",h),e.on("restarLine truncated
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* artplayer-proxy-mediabunny.js v1.1.0
|
||||
* artplayer-proxy-mediabunny.js v2.0.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,r=Object.getOwnPropertyDescriptors,i=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,r,i)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[r]=i,c=(e,t)=>{for(var r in t||(t={}))n.call(t,r)&&l(e,r,t[r]);if(i)for(var r of i(t))s.call(t,r)&&l(e,r,t[r]);return e},u=(e,t,r)=>new Promise((i,n)=>{var s=e=>{try{o(r.next(e))}catch(t){n(t)}},a=e=>{try{o(r.throw(e))}catch(t){n(t)}},o=e=>e.done?i(e.value):Promise.resolve(e.value).then(s,a);o((r=r.apply(e,t)).next())}),d=function(e,t){this[0]=e,this[1]=t},h=e=>{var t,r=e[a("asyncIterator")],i=!1,n={};return null==r?(r=e[a("iterator")](),t=e=>n[e]=t=>r[e](t)):(r=r.call(e),t=e=>n[e]=t=>{if(i){if(i=!1,"throw"===e)throw t;return t}return i=!0,{done:!1,value:new d(new Promise(i=>{var n=r[e](t);n instanceof Object||(e=>{throw TypeError(e)})("Object expected"),i(n)}),1)}}),n[a("iterator")]=()=>n,t("next"),"throw"in r?t("throw"):n.throw=e=>{throw e},"return"in r&&t("return"),n},m=(e,t,r)=>(t=e[a("asyncIterator")])?t.call(e):(e=e[a("iterator")](),t={},(r=(r,i)=>(i=e[r])&&(t[r]=t=>new Promise((r,n,s)=>(t=i.call(e,t),s=t.done,Promise.resolve(t.value).then(e=>r({value:e,done:s}),n)))))("next"),r("return"),t);class f{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 r=this.listeners.get(e);if(!r)return;const i=r.indexOf(t);i>=0&&r.splice(i,1)}emit(e,t){const r=new Event(e);r.detail=t;const i=this.listeners.get(e);i&&i.forEach(e=>e(r))}}function p(e){if(!e)throw new Error("Assertion failed.")}const g=e=>{const t=(e%360+360)%360;if(0===t||90===t||180===t||270===t)return t;throw new Error(`Invalid rotation ${e}.`)},k=e=>e&&e[e.length-1];class b{constructor(e){this.bytes=e,this.pos=0}seekToByte(e){this.pos=8*e}readBit(){var e;const t=Math.floor(this.pos/8),r=null!=(e=this.bytes[t])?e:0,i=7-(7&this.pos),n=(r&1<<i)>>i;return this.pos++,n}readBits(e){if(1===e)return this.readBit();let t=0;for(let r=0;r<e;r++)t<<=1,t|=this.readBit();return t}writeBits(e,t){const r=this.pos+e;for(let i=this.pos;i<r;i++){const e=Math.floor(i/8);let n=this.bytes[e];const s=7-(7&i);n&=~(1<<s),n|=(t&1<<r-i-1)>>r-i-1<<s,this.bytes[e]=n}this.pos=r}readAlignedByte(){var e;if(this.pos%8!==0)throw new Error("Bitstream is not byte-aligned.");const t=this.pos/8,r=null!=(e=this.bytes[t])?e:0;return this.pos+=8,r}skipBits(e){this.pos+=e}getBitsLeft(){return 8*this.bytes.length-this.pos}clone(){const e=new b(this.bytes);return e.pos=this.pos,e}}const y=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)},T=e=>{const t=y(e);return 0===(1&t)?-(t>>1):t+1>>1},S=e=>e.constructor===Uint8Array?e:ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e),v=e=>e.constructor===DataView?e:ArrayBuffer.isView(e)?new DataView(e.buffer,e.byteOffset,e.byteLength):new DataView(e),w=new TextDecoder,I=e=>Object.fromEntries(Object.entries(e).map(([e,t])=>[t,e])),P={bt709:1,bt470bg:5,smpte170m:6,bt2020:9,smpte432:12},x=I(P),C={bt709:1,smpte170m:6,linear:8,"iec61966-2-1":13,pq:16,hlg:18},_=I(C),B={rgb:0,bt709:1,bt470bg:5,smpte170m:6,"bt2020-ncl":9},E=I(B),F=e=>e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e);class D{constructor(){this.currentPromise=Promise.resolve()}acquire(){return u(this,null,function*(){let e;const t=new Promise(t=>{e=t}),r=this.currentPromise;return this.currentPromise=t,yield r,e})}}const A=e=>[...e].map(e=>e.toString(16).padStart(2,"0")).join(""),R=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,M=(e,t,r)=>{let i=0,n=e.length-1,s=-1;for(;i<=n;){const a=i+n>>1,o=r(e[a]);o===t?(s=a,n=a-1):o<t?i=a+1:n=a-1}return s},N=(e,t,r)=>{let i=0,n=e.length-1,s=-1;for(;i<=n;){const a=i+(n-i+1)/2|0;r(e[a])<=t?(s=a,i=a+1):n=a-1}return s},z=(e,t,r)=>{const i=N(e,r(t),r);e.splice(i+1,0,t)},O=()=>{let e,t;return{promise:new Promise((r,i)=>{e=r,t=i}),resolve:e,reject:t}},L=(e,t)=>{for(let r=e.length-1;r>=0;r--)if(t(e[r]))return e[r]},U=(e,t)=>{for(let r=e.length-1;r>=0;r--)if(t(e[r]))return r;return-1},V=function(e){return((e,t,r)=>{var i=(e,t,n,s)=>{try{var a=r[e](t),o=(t=a.value)instanceof d,l=a.done;Promise.resolve(o?t[0]:t).then(r=>o?i("return"===e?e:"next",t[1]?{done:r.done,value:r.value}:r,n,s):n({vaLine truncated
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerProxyMediabunny=t(),define(function(){return e.artplayerProxyMediabunny})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyMediabunny=t()}(this,function(){"use strict";var e,t,i,r,n,s,a,o,l,c,u,d,h,f,m,p,g,k,y,b,T,v,w,S,P,I,x,C,B,E,_,R,F,A=Object.defineProperty,M=Object.defineProperties,D=Object.getOwnPropertyDescriptors,N=Object.getOwnPropertySymbols,O=Object.prototype.hasOwnProperty,L=Object.prototype.propertyIsEnumerable,z=(e,t)=>(t=Symbol[e])?t:Symbol.for("Symbol."+e),U=e=>{throw TypeError(e)},q=Math.pow,W=(e,t,i)=>t in e?A(e,t,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[t]=i,H=(e,t)=>{for(var i in t||(t={}))O.call(t,i)&&W(e,i,t[i]);if(N)for(var i of N(t))L.call(t,i)&&W(e,i,t[i]);return e},V=(e,t)=>M(e,D(t)),j=(e,t,i)=>t.has(e)||U("Cannot "+i),K=(e,t,i)=>(j(e,t,"read from private field"),i?i.call(e):t.get(e)),X=(e,t,i)=>t.has(e)?U("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,i),$=(e,t,i,r)=>(j(e,t,"write to private field"),r?r.call(e,i):t.set(e,i),i),G=(e,t,i)=>(j(e,t,"access private method"),i),Q=(e,t,i,r)=>({set _(r){$(e,t,r,i)},get _(){return K(e,t,r)}}),Y=(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())}),J=function(e,t){this[0]=e,this[1]=t},Z=(e,t,i)=>{var r,n=(e,t,r,s)=>{try{var a=i[e](t),o=(t=a.value)instanceof J,l=a.done;Promise.resolve(o?t[0]:t).then(i=>o?n("return"===e?e:"next",t[1]?{done:i.done,value:i.value}:i,r,s):r({value:i,done:l})).catch(e=>n("throw",e,r,s))}catch(c){s(c)}},s=(e,t,i,s)=>a[e]=a=>(t=new Promise((t,i,s)=>(s=()=>n(e,a,t,i),r?r.then(s):s())),s=()=>r===i&&(r=0),r=i=t.then(s,s),t),a={};return i=i.apply(e,t),a[z("asyncIterator")]=()=>a,s("next"),s("throw"),s("return"),a},ee=e=>{var t,i=e[z("asyncIterator")],r=!1,n={};return null==i?(i=e[z("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 J(new Promise(r=>{var n=i[e](t);n instanceof Object||U("Object expected"),r(n)}),1)}}),n[z("iterator")]=()=>n,t("next"),"throw"in i?t("throw"):n.throw=e=>{throw e},"return"in i&&t("return"),n},te=(e,t,i)=>(t=e[z("asyncIterator")])?t.call(e):(e=e[z("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 ie(e){const t=[];for(const r of e)try{r()}catch(i){t.push(i)}if(t.length)throw t[0]}function re(e,t,i){const r={control:!1,setting:!1};let n=null;function s(i){r[i]&&(r[i]=!1,"control"===i?e.controls.cache.has(t)&&e.controls.remove(t):e.setting.find(t)&&e.setting.remove(t))}function a(){n=null,ie([()=>s("control"),()=>s("setting")])}return{update:function(o,l,c,u){if(!o)return void a();n=o;const d=()=>n===o&&c(),h=e=>Y(null,null,function*(){return d()&&o.selector.some(t=>t.value===e.value)?u(e,o.title):e.html});l.control?(r.control=!0,e.controls.update({name:t,position:"right",html:o.html,style:{padding:"0 10px"},selector:o.selector,onSelect:h})):s("control"),d()&&(l.setting?(r.setting=!0,e.setting.update({name:t,tooltip:o.html,html:o.title,icon:i,width:200,selector:o.selector,onSelect:h})):s("setting"))},clear:a}}function ne(e){const t=new Map,i=[];for(const r of e){const e=t.get(r.html);void 0!==r.html&&void 0!==e?r.default&&(i[e]=r):(t.set(r.html,i.length),i.push(r))}return i}function se({art:e,shim:t,option:i}){if(!i.m3u8)return;let r=!1,n=0,s=0;const a=re(e,"mediabunny-quality",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>'),o=re(e,"mediabunny-audio",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>'),l=e=>!r&&!t.engine.destroyed&&t.engine.loadSeq===e;function c(){return Y(this,null,function*(){var e,s;if(r||t.engine.destroyed)return;const c=++n,d=t.engine.loadSeq,h=()=>c===n&&l(d);try{const r=yield t.getM3u8State();if(!h())return;const n=(null==(e=i.m3u8)?void 0:e.quality)||{},c=function(e,t,i){vaLine truncated
|
||||
+20232
-9361
File diff suppressed because it is too large.
Load diff
Loaded 100 of 3716 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user