mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-10 21:06:15 -08:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6d2b81d05 | ||
|
|
0896841d23 |
No files matched your search
@@ -1,10 +0,0 @@
|
||||
# See editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
@@ -1,55 +0,0 @@
|
||||
* text=auto
|
||||
*.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
|
||||
@@ -1,3 +0,0 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
custom: https://paypal.me/harveyzack
|
||||
@@ -1,21 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Report an issue or unexpected behaviour with Artplayer
|
||||
---
|
||||
|
||||
### Expected behaviour
|
||||
|
||||
### Actual behaviour
|
||||
|
||||
### Steps to reproduce
|
||||
|
||||
### Environment
|
||||
|
||||
- Browser:
|
||||
- Version:
|
||||
- Operating System:
|
||||
- Version:
|
||||
|
||||
### Console errors (if any)
|
||||
|
||||
### Link to where the bug is happening
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
name: New feature
|
||||
about: Request new functionality
|
||||
---
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
name: Improvement
|
||||
about: Request a change that isn't a bug or new feature
|
||||
---
|
||||
@@ -1 +0,0 @@
|
||||
PLEASE USE OUR SPECIFIC ISSUE TEMPLATES for bug reports, features and improvement suggestions.
|
||||
@@ -1,370 +0,0 @@
|
||||
name: Node CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
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:
|
||||
coverage:
|
||||
name: TS coverage (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest ]
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
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 toolchain 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
|
||||
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: |
|
||||
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:
|
||||
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
|
||||
@@ -1,34 +0,0 @@
|
||||
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
|
||||
@@ -1,7 +0,0 @@
|
||||
.env
|
||||
.vscode
|
||||
.DS_Store
|
||||
node_modules
|
||||
**/package-lock.json
|
||||
lerna-debug.log
|
||||
refactor/.cache/
|
||||
@@ -1 +0,0 @@
|
||||
24.21.0
|
||||
File renamed without changes.
@@ -1,362 +0,0 @@
|
||||
# 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.
|
||||
-435
@@ -1,435 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [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`
|
||||
- Change `Artplayer.FULLSCREEN_WEB_IN_BODY` defaults to `true`
|
||||
- The `reset` method is used to reset video request
|
||||
- Fix [#1014](https://github.com/zhw2590582/ArtPlayer/issues/1014)
|
||||
- Fix [#1023](https://github.com/zhw2590582/ArtPlayer/issues/1023)
|
||||
- Fix [#1028](https://github.com/zhw2590582/ArtPlayer/issues/1028)
|
||||
- Add `artplayer-plugin-jassub` plugin
|
||||
- Add `artplayer-proxy-mediabunny` plugin
|
||||
- Add `artplayer-plugin-audio-track` plugin
|
||||
- Add `artplayer-plugin-asr` plugin
|
||||
- Add `artplayer-plugin-danmuku-mask` plugin
|
||||
- Deprecate `artplayer-plugin-libass` plugin
|
||||
- Prevent `Hint.css` from polluting global styles
|
||||
|
||||
## [5.3.0] - 2025-09-06
|
||||
|
||||
- Rename `.esm.js` to `.mjs`
|
||||
- Remove the default `fill` color value of `svg`
|
||||
- Optimize the `autoOrientation` logic
|
||||
- Add `Artplayer.REMOVE_SRC_WHEN_DESTROY`
|
||||
- Add `artplayer-plugin-document-pip` plugin
|
||||
- Add `art.events.bindGlobalEvents` method for rebinding global methods
|
||||
- Optimize `artplayer.d.ts`, now you can directly import `Option`
|
||||
|
||||
```ts
|
||||
import type { Option } from 'artplayer'
|
||||
|
||||
const option: Option = {
|
||||
container: '.artplayer-app',
|
||||
url: './assets/sample/video.mp4',
|
||||
}
|
||||
```
|
||||
|
||||
- Simplify `i18n` import
|
||||
|
||||
```ts
|
||||
import fr from 'artplayer/i18n/fr'
|
||||
import id from 'artplayer/i18n/id'
|
||||
|
||||
const option = {
|
||||
container: '.artplayer-app',
|
||||
url: './assets/sample/video.mp4',
|
||||
i18n: { id, fr },
|
||||
lang: 'fr',
|
||||
}
|
||||
```
|
||||
|
||||
## [5.2.5] - 2025-08-01
|
||||
|
||||
- Add `ESM` version for all packages, such as `artplayer/dist/artplayer.esm.js`
|
||||
- Recognize `globalThis.CUSTOM_USER_AGENT` global variable for customizing `navigator.userAgent`
|
||||
- Fix missing `mount` parameter when initializing `artplayer-plugin-danmuku`
|
||||
|
||||
## [5.2.3] - 2025-04-20
|
||||
|
||||
- Add Vietnamese `vi`
|
||||
- Clear the `video.src` property on destroy
|
||||
- Add `onClick` option for `Setting`
|
||||
- Fix style loading failure of danmuku and chapter plugins when the page has no head tag
|
||||
- Add `gesture` option to enable or disable gesture events on mobile `video` element
|
||||
|
||||
## [5.2.2] - 2025-01-19
|
||||
|
||||
- Fix thumbnail crossover issue
|
||||
- Fix style loading failure when the page has no head tag
|
||||
- Add slider support in subtitle plugin settings panel for mobile dragging
|
||||
- Fix positioning error of settings panel when rotating screen
|
||||
- Fix classname switching error when fullscreen state changes
|
||||
|
||||
## [5.2.1] - 2024-10-26
|
||||
|
||||
- Refactor `Setting` component, fix state loss issue
|
||||
- For `Setting` of type `range`, callback now returns an array of numbers instead of a single number
|
||||
- Remove `isStringOrNumber` utility function
|
||||
- Fix inconsistent state issue in `artplayer-plugin-hls-control`
|
||||
- Deprecate `artplayer-plugin-dash-quality` plugin
|
||||
- Add new `artplayer-plugin-dash-control` plugin
|
||||
- Use `code` instead of deprecated `keyCode` for keyboard events
|
||||
- Add `keydown` event to listen for `keydown` from `document`
|
||||
|
||||
## [5.2.0] - 2024-10-19
|
||||
|
||||
- Add `option.proxy` for proxying third-party `video` and `canvas`
|
||||
- Add `artplayer-proxy-canvas` proxy, enabling video playback via `canvas`
|
||||
- Add `option.thumbnails.scale` for preview image scaling
|
||||
- Fix bug where changing `art.url` didn’t trigger `autoPlayback`: [#797](https://github.com/zhw2590582/ArtPlayer/issues/797)
|
||||
- Add `art.subtitle.cues` property for retrieving all subtitle list
|
||||
- Add `art.subtitle.activeCues` property for retrieving active subtitles
|
||||
- Add `subtitleBeforeUpdate` event triggered before subtitle element rendering
|
||||
- Change `subtitleUpdate` event to `subtitleAfterUpdate`, triggered after subtitle element rendering
|
||||
- Optimize trigger timing and callback parameters of `subtitleLoad` event
|
||||
- Remove `subtitleSwitch` event; use `subtitleLoad` instead
|
||||
- Upgrade `artplayer-plugin-hls-quality` to `artplayer-plugin-hls-control`
|
||||
- Add `artplayer-plugin-ambilight` plugin
|
||||
- Fix `thumbnails` display bug
|
||||
|
||||
## [5.1.7] - 2024-08-15
|
||||
|
||||
- Add `Artplayer.STYLE` property to return player style text
|
||||
- `art.screenshot('your-name')` now supports custom file names
|
||||
- When `Artplayer.CONTEXTMENU` is `false`, default context menu is no longer hidden
|
||||
- Add `art.thumbnails` property for dynamically setting `thumbnails`
|
||||
|
||||
## [5.1.6] - 2024-06-15
|
||||
|
||||
- Optimize `setBar` event
|
||||
- Add `artplayerPluginChapter` plugin
|
||||
- Add `art.plugins.artplayerPluginDanmuku.load(target)` parameter for appending danmuku library
|
||||
- Add `width` option to danmuku plugin; when player width is smaller than this, danmuku sender is placed at the bottom
|
||||
- Fix `artplayerPluginVttThumbnail` not displaying on mobile
|
||||
- Fix danmuku plugin style and percentage font-size bug
|
||||
- `thumbnails` are now visible on mobile too
|
||||
- Restore `screen.orientation.lock` functionality
|
||||
|
||||
## [5.1.5] - 2024-06-01
|
||||
|
||||
- Refactor `artplayerPluginDanmuku` plugin
|
||||
- Add `artplayerPluginChromecast` plugin
|
||||
- Add `fullscreenError` event
|
||||
- Optimize double-click event: [#728](https://github.com/zhw2590582/ArtPlayer/pull/728)
|
||||
- Fix delayed display of `thumbnails`
|
||||
- Add `art.plugins.lock.state = true/false` for manually controlling `lock` state
|
||||
- Control bar no longer auto-hides when mouse is on it or when settings panel is open
|
||||
- Remove `screen.orientation.lock` due to compatibility issues
|
||||
- Fix `fullscreen` bug on mobile
|
||||
|
||||
## [5.1.1] - 2024-01-11
|
||||
|
||||
- Plugin functions now support both synchronous and asynchronous returns
|
||||
|
||||
## [5.1.0] - 2023-12-23
|
||||
|
||||
- Plugin functions now support async return
|
||||
- Player will no longer be destroyed after reaching error limit for playback address
|
||||
- Split language files, core no longer bundles multiple languages [Language Settings](https://artplayer.org/document/start/i18n.html)
|
||||
- Updating components now supports updating only specified fields [pull/549](https://github.com/zhw2590582/ArtPlayer/pull/549)
|
||||
- Add `muted` event triggered when mute state changes
|
||||
- Add `Artplayer.LOG_VERSION` global config to control whether to print player version (default `true`)
|
||||
- Add `Artplayer.USE_RAF` global config to control whether to use `requestAnimationFrame` (default `false`), currently for smooth progress bar effect
|
||||
- Remove default styles `margin:0;padding:0;` to avoid conflicts with third-party libraries
|
||||
- Subtitle line changed from `p` to `div` tag, with classname `art-subtitle-line`
|
||||
- On mobile, tapping video toggles control bar display
|
||||
- Remove `art.loop` interval playback feature (not commonly used)
|
||||
- Subtitle track now has `label` attribute to display subtitle names on mobile
|
||||
- Add utility functions `unescape`, `isBrowser`, `setStyleText`
|
||||
- Add `artplayerPluginMultipleSubtitles` plugin for merged subtitle files: [demo](https://www.artplayer.org/?libs=./uncompiled/artplayer-plugin-multiple-subtitles/index.js&example=multiple.subtitles)
|
||||
- Modify mini progress bar display
|
||||
|
||||
## [5.0.9] - 2023-05-14
|
||||
|
||||
- Fix `art.autoOrientation` style bug
|
||||
- Remove animation effect of player container
|
||||
|
||||
## [5.0.8] - 2023-05-13
|
||||
|
||||
- Fix conflict of `art.mini`
|
||||
- Fix animation bug of `art.aspectRatio`
|
||||
|
||||
## [5.0.7] - 2023-05-13
|
||||
|
||||
- Switching via `switchUrl` or `switchQuality` preserves existing adjustments such as `aspectRatio`, `playbackRate`, `flip`, `autoSize`
|
||||
- Remove the second `name` parameter from `switchUrl` and `switchQuality`
|
||||
- Add `isIOS13` utility to fix inaccurate `isMobile` detection on iOS 13+
|
||||
- `art.autoSize` and `art.autoHeight` are now methods: `art.autoSize()` and `art.autoHeight()`
|
||||
- Add new property `art.quality` for dynamically updating quality list
|
||||
- Fix incorrect `art.aspectRatio` property
|
||||
- Add `art.switch` setter property, same as `art.switchUrl` method
|
||||
|
||||
## [5.0.6] - 2023-05-03
|
||||
|
||||
- Fix style bug of settings panel
|
||||
|
||||
## [5.0.5] - 2023-05-03
|
||||
|
||||
- Add `heatmap` option to danmuku plugin for enabling heatmap (default: off)
|
||||
- Fix English subtitle line break style bug
|
||||
- Fix settings panel style bug
|
||||
- Remove unnecessary global properties
|
||||
- Remove `title` option (not useful now)
|
||||
- Remove `whitelist` option (not useful now)
|
||||
|
||||
## [5.0.4] - 2023-04-27
|
||||
|
||||
- Fix controller dropdown list style bug
|
||||
|
||||
## [5.0.3] - 2023-04-26
|
||||
|
||||
- Fix `event.pageY` value error in volume controller
|
||||
- Update build config, `artplayer.legacy.js` now compatible with IE 11
|
||||
|
||||
## [5.0.2] - 2023-04-24
|
||||
|
||||
- Fix style compatibility issue of control bar position
|
||||
|
||||
## [5.0.1] - 2023-04-24
|
||||
|
||||
- Fix web fullscreen style bug
|
||||
- Fix built-in settings text error
|
||||
|
||||
## [5.0.0] - 2023-04-23
|
||||
|
||||
- Rewrite volume controller
|
||||
- Fix incorrect progress drag angle on mobile
|
||||
- Rewrite `mini` mode, now video detaches from original container
|
||||
- All components (layers, controller, contextmenu, settings panel) support dynamic deletion and updating
|
||||
- Subtitle option adds `onVttLoad` for modifying vtt text before output
|
||||
- Rewrite all styles, add many `css` variables
|
||||
- Add `cssVar` option for initializing `css` variables
|
||||
- Add `cssVar` method for getting/setting `css` variables
|
||||
- `artplayer-plugin-hls-quality` adds `getResolution` function option for getting resolution text from level
|
||||
- Add `artplayer-plugin-dash-quality` plugin for adding Dash quality list to player
|
||||
- Fix `lock` and `loop` event issues
|
||||
- Add Russian `ru` and Indonesian `id` languages
|
||||
- Update `artplayer-plugin-control` for `artplayer@5.0.0`
|
||||
- Update `artplayer-plugin-dash-quality` for `artplayer@5.0.0`
|
||||
- Update `artplayer-plugin-hls-quality` for `artplayer@5.0.0`
|
||||
- Update `artplayer-plugin-danmuku` for `artplayer@5.0.0`
|
||||
|
||||
## [4.6.2] - 2023-01-26
|
||||
|
||||
- Default `Artplayer.PROGRESS_HEIGHT` changed to `6`
|
||||
- Add `artplayer-plugin-vtt-thumbnail` to generate video preview images from vtt subtitle files
|
||||
- Add `Artplayer.FULLSCREEN_WEB_IN_BODY` for whether to mount player to `document.body` in web fullscreen (default `false`)
|
||||
- Change subtitle offset adjustment to slider
|
||||
- Subtitle option adds `escape` (default `true`) for HTML escaping
|
||||
|
||||
## [4.6.1] - 2023-01-11
|
||||
|
||||
- Write brand new docs
|
||||
- Optimize `d.ts`
|
||||
- Remove redundant events
|
||||
- Optimize some styles
|
||||
- Add `i18n` option
|
||||
|
||||
## [4.6.0] - 2022-12-31
|
||||
|
||||
- Optimize style effects of control bar icons
|
||||
- Optimize style effects of settings panel
|
||||
- Fix incorrect `art.fullscreen` state detection
|
||||
- Add `artplayer-plugin-control` plugin to change control bar style
|
||||
|
||||
## [4.5.12] - 2022-11-20
|
||||
|
||||
- Fix `art.loop = []` display bug
|
||||
|
||||
## [4.5.11] - 2022-11-06
|
||||
|
||||
- Add `Artplayer.CONTEXTMENU` for controlling whether to show contextmenu (default `true`)
|
||||
- Whitelist function default `true` on mobile, all devices use player UI
|
||||
|
||||
## [4.5.10] - 2022-11-05
|
||||
|
||||
- Fix subtitle not showing in Firefox: [#pull/415](https://github.com/zhw2590582/ArtPlayer/pull/415)
|
||||
- Info popup supports clicking to select video property text
|
||||
|
||||
## [4.5.9] - 2022-11-05
|
||||
|
||||
- Add `art.type` property to get/set video type
|
||||
- Add `art.video` property to get video element
|
||||
- Add `artplayer-tool-iframe` plugin to control player inside iframe
|
||||
- Add `artplayer-plugin-hls-quality` plugin for adding Hls quality list
|
||||
- Add `Artplayer.PLAYBACK_RATE` for default playback rates `[0.5, 0.75, 1, 1.25, 1.5, 2]`
|
||||
- Add `Artplayer.ASPECT_RATIO` for default ratios `['default','4:3','16:9']`
|
||||
- Add `Artplayer.FLIP` for default flip options `['normal','horizontal','vertical']`
|
||||
- Add `Artplayer.PROGRESS_HEIGHT` (default: `4`)
|
||||
- Add `legacy.js` version for older browsers (larger size)
|
||||
- Remove `examples` dir, no longer provide Vue/React examples
|
||||
|
||||
## [4.5.8] - 2022-10-09
|
||||
|
||||
- Add Farsi language
|
||||
- Add `Artplayer.DEBUG` (default `false`) for debug logs
|
||||
- Add `art.setting.update()` for dynamic settings update
|
||||
- Optimize `artplayer.d.ts`
|
||||
|
||||
## [4.5.7] - 2022-09-28
|
||||
|
||||
- Add `Artplayer.VOLUME_STEP` for controlling volume step (default `0.1`)
|
||||
- Add `Artplayer.SEEK_STEP` for controlling seek step (default `5s`)
|
||||
- Fix some svg icons not showing on mobile
|
||||
- Fix desktop progress bar cannot click+drag simultaneously
|
||||
- Fix mobile progress bar cannot click+drag
|
||||
- Add `art.isRotate` property for detecting auto fullscreen rotation
|
||||
- Settings panel `range` adds `onChange` option for real-time values
|
||||
|
||||
```js
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
setting: true,
|
||||
settings: [
|
||||
{
|
||||
html: 'Slider',
|
||||
tooltip: '5x',
|
||||
range: [5, 1, 10, 0.1],
|
||||
onChange: function (item) {
|
||||
return item.range + 'x';
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
## [4.5.6] - 2022-09-19
|
||||
|
||||
- Fix hls.js not working in Safari
|
||||
|
||||
## [4.5.5] - 2022-09-19
|
||||
|
||||
- Ad plugin adds `option.muted` for autoplay muted ads
|
||||
- Danmuku plugin exposes `art.plugins.artplayerPluginDanmuku.reset()` to clear display
|
||||
- Danmuku plugin exposes `art.plugins.artplayerPluginDanmuku.option` for current config
|
||||
- Fix subtitle bug in iOS fullscreen
|
||||
- Add Spanish `es`
|
||||
|
||||
## [4.5.4] - 2022-08-01
|
||||
|
||||
### Added
|
||||
|
||||
- Add `Artplayer.AUTO_PLAYBACK_MIN` for min playback memory value (default `5s`)
|
||||
- Add `Artplayer.TOUCH_MOVE_RATIO` for mobile progress drag ratio (default `0.5`)
|
||||
- `option.thumbnails` adds optional `width`/`height`
|
||||
- Add `option.id` for unique playback memory identifier
|
||||
|
||||
## [4.5.3] - 2022-07-13
|
||||
|
||||
### Added
|
||||
|
||||
- `url` option allows empty string for async `art.url`
|
||||
|
||||
```js
|
||||
const art = new Artplayer({
|
||||
url: '',
|
||||
container: '.artplayer-app',
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
art.url = '/assets/sample/video.mp4';
|
||||
}, 1000);
|
||||
```
|
||||
|
||||
- `art.play()` always returns Promise; `play` event is async
|
||||
|
||||
```js
|
||||
const art = new Artplayer({
|
||||
url: '/assets/sample/video.mp4',
|
||||
container: '.artplayer-app',
|
||||
});
|
||||
|
||||
art.on('ready', async () => {
|
||||
try {
|
||||
await art.play();
|
||||
console.log('Play success');
|
||||
} catch (error) {
|
||||
console.log('Play failed', error.message);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
- Add `airplay` (only Safari)
|
||||
|
||||
```js
|
||||
const art = new Artplayer({
|
||||
url: '/assets/sample/video.mp4',
|
||||
container: '.artplayer-app',
|
||||
airplay: true,
|
||||
});
|
||||
```
|
||||
|
||||
## [4.5.2] - 2022-06-22
|
||||
|
||||
- Optimize auto-playback to allow user choice
|
||||
|
||||
## [4.5.0] - 2022-06-21
|
||||
|
||||
- Remove built-in ads
|
||||
- Add ad plugin
|
||||
|
||||
## [4.4.7] - 2022-06-13
|
||||
|
||||
- Support danmuku lib d.ts
|
||||
- Update deps
|
||||
|
||||
## [4.4.6] - 2022-06-11
|
||||
|
||||
- Add danmuku lib d.ts
|
||||
- Adjust subtitle font-size param
|
||||
- Optimize regex parsing of xml danmuku
|
||||
|
||||
## [4.4.5] - 2022-06-02
|
||||
|
||||
- Fix theme color missing in mini mode
|
||||
|
||||
## [4.4.3] - 2022-05-26
|
||||
|
||||
- Fix custom mounted input residual on danmuku destroy
|
||||
- Fix mini mode size calculation error
|
||||
|
||||
## [4.4.2] - 2022-05-20
|
||||
|
||||
- Remove UI init `video:loadedmetadata` event
|
||||
- Danmuku exposes `load` for switching sources
|
||||
- Add error icon after video load error limit
|
||||
- Fix multiple init of setting panel bug
|
||||
|
||||
## [4.4.1] - 2022-05-17
|
||||
|
||||
- Add `art.isInput`, when true control bar won’t auto-hide (e.g. typing danmuku)
|
||||
- Add `art.isLock`, when true on mobile prevents seek/play/pause
|
||||
- Fix fixed width bug of danmuku input box
|
||||
- Settings panel supports `range` and `onRange`
|
||||
- Add `isAndroid` and `isIOS` utils
|
||||
- Danmuku adds `lockTime`, `maxLength`, `minWidth`, `maxWidth`, `mount`, `beforeEmit`, `theme`
|
||||
|
||||
## [4.4.0] - 2022-05-15
|
||||
|
||||
- Settings panel supports `switch` and `onSwitch`
|
||||
- Danmuku plugin adds settings panel and send
|
||||
- Danmuku adds default mode and font-size
|
||||
- Danmuku font-size supports percentage of player
|
||||
- Fix flip icon missing
|
||||
- Player with focus won’t auto-hide control bar
|
||||
- Remove subtitle toggle button (manual config required)
|
||||
@@ -1,202 +0,0 @@
|
||||
# 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
|
||||
File renamed without changes.
@@ -1,35 +0,0 @@
|
||||
This project uses `vite` as a development and packaging tool, so there are few overall configuration options
|
||||
|
||||
## 1. Install dependencies
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
yarn
|
||||
```
|
||||
|
||||
## 2. Develop the project and open the demo page
|
||||
|
||||
```base
|
||||
npm run dev
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
## 3. Package the project
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
```bash
|
||||
yarn build
|
||||
```
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Harvey Zhao
|
||||
|
||||
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.
|
||||
@@ -1,174 +0,0 @@
|
||||
<h2 align="center">
|
||||
<p><img src="./images/logo.png" width="100" alt="logo"></p>
|
||||
<a href="https://artplayer.org">ArtPlayer.js</a>
|
||||
</h2>
|
||||
|
||||
<p align="center">
|
||||
:art: ArtPlayer.js is a modern and full featured HTML5 video player
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.npmjs.com/package/artplayer">
|
||||
<img src="https://img.shields.io/bundlephobia/minzip/artplayer" alt="Size">
|
||||
<img src="https://img.shields.io/npm/dm/artplayer.svg?sanitize=true" alt="Downloads">
|
||||
<img src="https://img.shields.io/npm/v/artplayer.svg?sanitize=true" alt="Version">
|
||||
<img src="https://img.shields.io/npm/l/artplayer.svg?sanitize=true" alt="License">
|
||||
<img src="https://data.jsdelivr.com/v1/package/npm/artplayer/badge?style=rounded" alt="jsdelivr">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<span>・</span>
|
||||
<a href="https://artplayer.org">Online Editor</a>
|
||||
<span>・</span>
|
||||
<a href="https://artplayer.org/document">API Document</a>
|
||||
<span>・</span>
|
||||
<a href="https://artplayer.org/?libs=./uncompiled/artplayer-plugin-danmuku/index.js&example=danmuku">Danmuku</a>
|
||||
<span>・</span>
|
||||
<a href="./CHANGELOG.md">Changelog</a>
|
||||
<span>・</span>
|
||||
<a href="https://artplayer.org/llms.txt">🤖LLMs</a>
|
||||
<span>・</span>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://artplayer.org">
|
||||
<img src="./images/screenshot.png" alt="screenshot" width="720">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## Home Page
|
||||
|
||||
[https://artplayer.org](https://artplayer.org)
|
||||
|
||||
## Mobile Demo
|
||||
|
||||
<img src="./images/qrcode.png" width="250">
|
||||
|
||||
## Features
|
||||
|
||||
[ArtPlayer.js](https://artplayer.org) is an easy-to-use and feature-rich HTML5 video player, and most of the player's functional controls support customization, which makes it easy to connect with your business logic. In addition, it directly supports `.vtt`, `.ass` and `.srt` subtitle formats. Integration with other dependencies such as `flv.js`, `hls.js`, `dash.js`, etc. is also very simple. The code is highly decoupled, the structure and logic are clear, and it is easy to track errors and add new features.
|
||||
|
||||
## Install
|
||||
|
||||
Install with `npm`:
|
||||
|
||||
```bash
|
||||
$ npm install artplayer
|
||||
```
|
||||
|
||||
Or install with `yarn`:
|
||||
|
||||
```bash
|
||||
$ yarn add artplayer
|
||||
```
|
||||
|
||||
Or install with `pnpm`:
|
||||
|
||||
```bash
|
||||
$ pnpm add artplayer
|
||||
```
|
||||
|
||||
Or install with `bun`:
|
||||
|
||||
```bash
|
||||
$ bun add artplayer
|
||||
```
|
||||
|
||||
```js
|
||||
import Artplayer from 'artplayer'
|
||||
```
|
||||
|
||||
Or umd build also available:
|
||||
|
||||
```html
|
||||
<script src="path/to/artplayer.js"></script>
|
||||
```
|
||||
|
||||
Or from CDN:
|
||||
|
||||
```html
|
||||
<!-- jsdelivr -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.js"></script>
|
||||
|
||||
<!-- unpkg -->
|
||||
<script src="https://unpkg.com/artplayer/dist/artplayer.js"></script>
|
||||
```
|
||||
|
||||
Will expose the global variable to `window.Artplayer`.
|
||||
|
||||
## Usage
|
||||
|
||||
```html
|
||||
<div class="artplayer-app"></div>
|
||||
```
|
||||
|
||||
```js
|
||||
let art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: 'path/to/video.mp4',
|
||||
})
|
||||
```
|
||||
|
||||
## Plugins
|
||||
|
||||
| Name | Describe | State |
|
||||
| :--- | :--- | :--- |
|
||||
| [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/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"> |
|
||||
| [artplayer-plugin-vast](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-vast/index.js&example=vast) | VAST/VPAID advertising | <img src="https://img.shields.io/npm/v/artplayer-plugin-vast.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-vast.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-chapter](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-chapter/index.js&example=chapter) | Video chapters support | <img src="https://img.shields.io/npm/v/artplayer-plugin-chapter.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-chapter.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-auto-thumbnail](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-auto-thumbnail/index.js&example=auto.thumbnail) | Auto-generated thumbnails | <img src="https://img.shields.io/npm/v/artplayer-plugin-auto-thumbnail.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-auto-thumbnail.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-ambilight](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-ambilight/index.js&example=ambilight) | Ambilight effect | <img src="https://img.shields.io/npm/v/artplayer-plugin-ambilight.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-ambilight.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-document-pip](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-document-pip/index.js&example=document.pip) | Document Picture-in-Picture | <img src="https://img.shields.io/npm/v/artplayer-plugin-document-pip.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-document-pip.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-audio-track](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-audio-track/index.js&example=audio.track) | Independent audio track playback | <img src="https://img.shields.io/npm/v/artplayer-plugin-audio-track.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-audio-track.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-jassub](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-jassub/index.js&example=jassub) | ASS/SSA subtitle support | <img src="https://img.shields.io/npm/v/artplayer-plugin-jassub.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-jassub.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-danmuku-mask](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-danmuku/index.js%0A./uncompiled/artplayer-plugin-danmuku-mask/index.js&example=danmuku.mask) | Danmuku masking (smart blocking) | <img src="https://img.shields.io/npm/v/artplayer-plugin-danmuku-mask.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-danmuku-mask.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-asr](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-asr/index.js&example=asr) | Automatic Speech Recognition | <img src="https://img.shields.io/npm/v/artplayer-plugin-asr.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-asr.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-ads](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-ads/index.js&example=ads) | Video advertising plugin | WIP |
|
||||
|
||||
## Libraries
|
||||
|
||||
| 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/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"> |
|
||||
|
||||
## Proxys
|
||||
|
||||
| Name | Describe | State |
|
||||
| :--- | :--- | :--- |
|
||||
| [Canvas](https://artplayer.org/?libs=./uncompiled/artplayer-proxy-canvas/index.js&example=canvas) | Proxy video to canvas | <img src="https://img.shields.io/npm/v/artplayer-proxy-canvas.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-proxy-canvas.svg?sanitize=true"> |
|
||||
| [Mediabunny](https://artplayer.org/?libs=./uncompiled/artplayer-proxy-mediabunny/index.js&example=mediabunny) | Mediabunny proxy | <img src="https://img.shields.io/npm/v/artplayer-proxy-mediabunny.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-proxy-mediabunny.svg?sanitize=true"> |
|
||||
|
||||
## Changelog
|
||||
|
||||
[CHANGELOG.md](./CHANGELOG.md)
|
||||
|
||||
## Contributing
|
||||
|
||||
[CONTRIBUTING.md](./CONTRIBUTING.md)
|
||||
|
||||
## Donations
|
||||
|
||||
We accept donations through these channels:
|
||||
|
||||

|
||||
|
||||
- [Patreon](https://www.patreon.com/artplayer)
|
||||
- [Paypal](https://www.paypal.me/harveyzack)
|
||||
|
||||
## QQ Group
|
||||
|
||||

|
||||
|
||||
## License
|
||||
|
||||
MIT © Harvey Zhao
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -20,9 +20,6 @@ const art = new Artplayer({
|
||||
miniProgressBar: true,
|
||||
autoPlayback: true,
|
||||
autoOrientation: true,
|
||||
subtitle: {
|
||||
url: '/assets/sample/subtitle.srt',
|
||||
},
|
||||
thumbnails: {
|
||||
url: '/assets/sample/thumbnails.png',
|
||||
number: 60,
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,52 @@
|
||||
// npm i dashjs
|
||||
// npm i artplayer-plugin-dash-control
|
||||
|
||||
// import dashjs from 'dashjs';
|
||||
// import artplayerPluginDashControl from 'artplayer-plugin-dash-control';
|
||||
|
||||
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',
|
||||
},
|
||||
}),
|
||||
],
|
||||
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)
|
||||
art.dash = dash
|
||||
art.on('destroy', () => dash.destroy())
|
||||
}
|
||||
else {
|
||||
art.notice.show = 'Unsupported playback format: mpd'
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,56 @@
|
||||
// npm i hls.js
|
||||
// npm i artplayer-plugin-hls-control
|
||||
|
||||
// import Hls from 'hls.js';
|
||||
// import artplayerPluginHlsControl from 'artplayer-plugin-hls-control';
|
||||
|
||||
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',
|
||||
},
|
||||
}),
|
||||
],
|
||||
customType: {
|
||||
m3u8: function playM3u8(video, url, art) {
|
||||
if (Hls.isSupported()) {
|
||||
if (art.hls)
|
||||
art.hls.destroy()
|
||||
const hls = new 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
|
||||
}
|
||||
else {
|
||||
art.notice.show = 'Unsupported playback format: m3u8'
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
File renamed without changes.
@@ -15,11 +15,6 @@ 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':
|
||||
@@ -49,7 +44,4 @@ iframe.commit(() => {
|
||||
data: state,
|
||||
})
|
||||
})
|
||||
}).catch((error) => {
|
||||
if (!iframe.destroyed)
|
||||
console.error(error)
|
||||
})
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,312 @@
|
||||
(function () {
|
||||
Artplayer.DEBUG = true
|
||||
|
||||
if (Artplayer.utils.isMobile) {
|
||||
window.location.href = `./mobile.html${location.search}`
|
||||
}
|
||||
|
||||
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,
|
||||
},
|
||||
model: monaco.editor.createModel(
|
||||
[
|
||||
'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)
|
||||
}
|
||||
script.onerror = () => {
|
||||
window.define = originalDefine
|
||||
reject(new Error(`Loading script failed: ${url}`))
|
||||
}
|
||||
document.head.appendChild(script)
|
||||
})
|
||||
}
|
||||
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
})
|
||||
|
||||
$lib.value = libsDecoded
|
||||
return Promise.all(libPromises)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
else if (code) {
|
||||
editor.setValue(decodeURIComponent(code).trim())
|
||||
runCode()
|
||||
}
|
||||
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 (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()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
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()
|
||||
}
|
||||
})
|
||||
})()
|
||||
File renamed without changes.
@@ -0,0 +1,100 @@
|
||||
(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;
|
||||
}, {});
|
||||
}
|
||||
|
||||
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(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);
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
})
|
||||
})();
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 4155 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user