Compare commits

...
Author SHA1 Message Date
Harvey Zhao fec539dbe3 docs(refactor): [DOC-HANDOFF-01] defer remaining work for user self-testing 2026-09-16 12:22:43 +08:00
Harvey Zhao 78e3107b68 test(mediabunny): [PKG-MB-09] preserve long-run AV tolerance breach 2026-09-16 11:54:08 +08:00
Harvey Zhao 58a648fd05 docs(maintenance): [DOC-03] align AI entrypoints with migrated modules 2026-09-16 11:26:06 +08:00
Harvey Zhao d71b6fea38 test(mediabunny): [PKG-MB-09] start hour-scale installed playback checks 2026-09-16 11:20:49 +08:00
Harvey Zhao 5795492f0f feat(release): [CI-NPM-03] add read-only registry recovery checks 2026-09-16 11:06:23 +08:00
Harvey Zhao 783d1e3fd4 test(chromecast): [PKG-CAST-05] record real Chrome SDK initialization 2026-09-16 10:49:54 +08:00
Harvey Zhao 681eccfa76 build(release): [REL-02] refresh candidates after site and integration changes 2026-09-16 10:37:43 +08:00
Harvey Zhao 8aa99ef03f test(thumbnail): [PKG-TOOL-THUMB-05] verify generated sheets across core versions 2026-09-16 10:29:20 +08:00
Harvey Zhao fb78328c43 test(site): [SITE-05] enforce built links and validate online editors 2026-09-16 09:55:00 +08:00
Harvey Zhao 6b580d1667 fix(site): [SITE-05] repair search interactions and align peer dependency 2026-09-16 09:36:39 +08:00
Harvey Zhao 61fe8deb59 docs(site): [SITE-04] complete core and ecosystem content verification 2026-09-16 09:11:39 +08:00
Harvey Zhao 54e5cbf49c docs(core): [SITE-04] clarify playback and source transitions 2026-09-16 08:59:21 +08:00
Harvey Zhao e8b48cbaed docs(core): [SITE-04] document lifecycle and media capabilities 2026-09-16 08:47:41 +08:00
Harvey Zhao cec5049c40 docs(core): [SITE-04] document CSS variables and theme behavior 2026-09-16 08:27:47 +08:00
Harvey Zhao 24011ea266 docs(core): [SITE-04] clarify constructor options and initialization boundaries 2026-09-16 08:13:56 +08:00
Harvey Zhao 8d2ec199d7 docs(core): [SITE-04] document event payloads and synchronous dispatch 2026-09-16 08:00:16 +08:00
Harvey Zhao 0a060e6088 docs(core): [SITE-04] clarify shared configuration and global timing 2026-09-16 07:38:15 +08:00
Harvey Zhao 9afbf9940d docs(core): [SITE-04] document public utility contracts 2026-09-16 07:27:34 +08:00
Harvey Zhao bd3f3c0689 docs(core): [SITE-04] document subtitle loading and resource ownership 2026-09-16 07:18:10 +08:00
Harvey Zhao de45f5b978 docs(core): [SITE-04] clarify plugin registration and lifecycle 2026-09-16 07:09:58 +08:00
Harvey Zhao 5bf1a36183 chore(release): [REL-02] refresh all library candidates after tooling fix 2026-09-16 06:59:18 +08:00
Harvey Zhao 96962a69a4 fix(docs): [SITE-04] preserve structural chunks and clarify settings 2026-09-16 06:51:47 +08:00
Harvey Zhao bb2fec8dd1 docs(core): [SITE-04] document component lifecycle and selector contracts 2026-09-16 05:13:52 +08:00
Harvey Zhao 5910c3f179 docs(core): [SITE-04] document template and icon contracts 2026-09-16 05:00:45 +08:00
Harvey Zhao a1488f11bb docs(core): [SITE-04] clarify service contracts and hotkey examples 2026-09-16 04:45:05 +08:00
Harvey Zhao 9f454ecd1d build(release): [REL-02] refresh DASH candidate documentation 2026-09-16 04:32:59 +08:00
Harvey Zhao b029062ace docs(site): [SITE-04] cross-check existing plugin guide semantics 2026-09-16 04:28:32 +08:00
Harvey Zhao 4db9789014 docs(site): [SITE-04] document Canvas and Mediabunny proxies 2026-09-16 04:06:40 +08:00
Harvey Zhao e2bd7c9742 build(release): [REL-02] refresh Thumbnail candidate after documentation fix 2026-09-16 03:54:34 +08:00
Harvey Zhao 484a8c903c docs(site): [SITE-04] document Iframe and Thumbnail tools 2026-09-16 03:49:38 +08:00
Harvey Zhao 3aad294aa5 docs(site): [SITE-04] complete bilingual guides for JASSUB Mask and Cast 2026-09-16 03:37:35 +08:00
Harvey Zhao 558e946ae5 docs(site): [SITE-04] document Ads and VAST compatibility in both languages 2026-09-16 03:14:59 +08:00
Harvey Zhao 2305f9d7c7 chore(release): [REL-02] refresh auto-thumbnail candidate after documentation update 2026-09-16 03:04:14 +08:00
Harvey Zhao 3317230f2e docs(site): [SITE-04] document thumbnail extraction and subtitle selection 2026-09-16 02:57:15 +08:00
Harvey Zhao 94adb77fd6 docs(site): [SITE-04] document PiP and ASR contracts in both languages 2026-09-16 02:45:57 +08:00
Harvey Zhao 3138812610 docs(site): [SITE-04] document chapter and ambilight contracts in both languages 2026-09-16 02:30:01 +08:00
Harvey Zhao dba354f8cd test(chapter): [PKG-CHAPTER-05] correlate current-major restart timing failure 2026-09-16 02:06:53 +08:00
Harvey Zhao 6d7900df95 chore(release): [REL-02] register verified major-version build candidates 2026-09-16 02:00:03 +08:00
Harvey Zhao 1b81888347 fix(release): [REL-02] accept Yarn directory entries in candidate archives 2026-09-16 01:52:36 +08:00
Harvey Zhao e54fc998ea fix(release): [REL-02] bind validation inputs and record all-library type checks 2026-09-16 01:37:34 +08:00
Harvey Zhao aa146f07e4 test(audio): [PKG-AUDIO-BUFFER-01] observe switches while network responses are held 2026-09-16 01:19:58 +08:00
Harvey Zhao 6f7fd7931d feat(ci): [CI-NPM-02] verify downloaded bundles against fresh release evidence 2026-09-16 00:59:42 +08:00
Harvey Zhao 2983cb7c51 chore(release): [REL-09] prepare independent major versions and verified artifacts 2026-09-16 00:47:30 +08:00
Harvey Zhao 69ad6fb17e docs(release): [REL-01] freeze independent major version and migration plans 2026-09-16 00:30:33 +08:00
Harvey Zhao 267b21226a fix(danmuku): [PKG-DANMUKU-START-01] retain the initial playback sampling interval 2026-09-16 00:14:48 +08:00
Harvey Zhao b5f8b5e28e refactor(thumbnail): [PKG-TOOL-THUMB-04] preserve approved published defaults 2026-09-15 23:54:24 +08:00
Harvey Zhao 490e157717 docs(ci): [CI-01] record complete WebKit installed regression 2026-09-15 23:28:54 +08:00
Harvey Zhao bb2c12df30 docs(refactor): [DOC-REVIEW-01] wait for user-led release reviews 2026-09-15 23:01:32 +08:00
Harvey Zhao 9cfb6c8b9f docs(ci): [CI-01] record complete Firefox installed regression 2026-09-15 22:58:27 +08:00
Harvey Zhao b3344a7c6d docs(ci): [CI-01] record complete Chromium installed regression 2026-09-15 22:37:33 +08:00
Harvey Zhao 5e0447fc51 test(ci): [CI-JASSUB-SOURCE-01] include source in native JASSUB checks 2026-09-15 22:14:36 +08:00
Harvey Zhao 5862f60b0e docs(ci): [CI-01] record complete WebKit source regression 2026-09-15 21:54:41 +08:00
Harvey Zhao ae56937d3b test(site): [SITE-EDITOR-VAST-01] align Monaco consumer with approved root types 2026-09-15 21:16:24 +08:00
Harvey Zhao 4545c43679 docs(site): [SITE-07] ship selected font notice references 2026-09-15 20:37:46 +08:00
Harvey Zhao 01f3d00e4c test(ci): [CI-TYPES-02] gate installed types across all libraries 2026-09-15 20:15:58 +08:00
Harvey Zhao 00c131bff1 test(ci): [CI-TYPES-01] validate installed Audio and HLS types 2026-09-15 19:59:44 +08:00
Harvey Zhao 210484c443 fix(docs): [SITE-ROUTES-01] track added HTML without replacing baseline 2026-09-15 19:40:48 +08:00
Harvey Zhao 876fa4c328 fix(auto-thumbnail): [PKG-AUTO-THUMB-13] ignore registration after destroy 2026-09-15 19:16:22 +08:00
Harvey Zhao 9ba3c82f99 docs(vtt): [SITE-VTT-01] add bilingual guides and sprite pixel checks 2026-09-15 19:06:44 +08:00
Harvey Zhao d3349e83f2 docs(audio): [SITE-AUDIO-01] add bilingual track guides and browser coverage 2026-09-15 18:48:07 +08:00
Harvey Zhao 6af43208af fix(ci): [CI-01] reject rendering substitutions in installed validation 2026-09-15 18:35:45 +08:00
Harvey Zhao eba8c29fa7 test(jassub): [PKG-JASSUB-09] isolate synchronous native bitmap stalls 2026-09-15 18:24:49 +08:00
Harvey Zhao 319dccb605 docs(dash): [SITE-DASH-01] add bilingual guides and fix example lifecycle 2026-09-15 18:09:30 +08:00
Harvey Zhao 4ea0ba94ae docs(hls): [SITE-HLS-01] add bilingual guides and fix example SDK ownership 2026-09-15 17:55:11 +08:00
Harvey Zhao 2802cbacc5 test(hls): [PKG-HLS-SDK-01] capture scoped Firefox native exceptions 2026-09-15 17:33:49 +08:00
Harvey Zhao e0c5cf27de test(hls): [PKG-HLS-SDK-01] retain controller evidence across page crashes 2026-09-15 17:15:28 +08:00
Harvey Zhao ea3174daa2 docs(danmuku): [SITE-DANMUKU-01] complete bilingual usage guides 2026-09-15 16:45:35 +08:00
Harvey Zhao 520727d762 feat(ci): [CI-NPM-01] prepare exact verified candidate bundles 2026-09-15 16:20:32 +08:00
Harvey Zhao 25faf88e80 fix(dash): [PKG-DASH-CLEANUP-01] preserve first cleanup exception 2026-09-15 15:57:04 +08:00
Harvey Zhao 1c522f181b fix(thumbnail): [PKG-TOOL-THUMB-07] preserve falsy cleanup exceptions 2026-09-15 15:30:26 +08:00
Harvey Zhao 2a38067911 test(hls): [PKG-HLS-SDK-01] compare SDK sequences and capture pre-destroy crash 2026-09-15 15:15:25 +08:00
Harvey Zhao ca967ea1a2 test(hls): [PKG-HLS-SDK-01] preserve group stall evidence and verify ongoing playback 2026-09-15 15:02:14 +08:00
Harvey Zhao f37658d657 test(asr): [PKG-ASR-05] verify initial media failure and first-source recovery 2026-09-15 14:39:50 +08:00
Harvey Zhao 9cf4a58480 fix(asr): [PKG-ASR-10] cancel recognition on native media errors 2026-09-15 14:25:59 +08:00
Harvey Zhao 3c89b48514 test(asr): [PKG-ASR-05] verify video-only input and installed capture recovery 2026-09-15 14:07:40 +08:00
Harvey Zhao 65368809ee build(site): [SITE-07] reproduce historical Unicode data and ship source notices 2026-09-15 13:53:24 +08:00
Harvey Zhao 1fed96a909 build(site): [SITE-07] bind Monaco DOM adaptations and WinJS reference notices 2026-09-15 13:26:55 +08:00
Harvey Zhao 3eb5500525 test(audio): [PKG-AUDIO-05] distinguish prefix startup from native starvation 2026-09-15 13:12:05 +08:00
Harvey Zhao bf56d09178 test(release): [REL-04] complete early rollback and mainline rehearsal 2026-09-15 13:00:06 +08:00
Harvey Zhao 8dcbe9441e refactor(auto-thumbnail): [PKG-AUTO-THUMB-04] verify source and installed type migration 2026-09-15 12:39:13 +08:00
Harvey Zhao 42ddead0cd fix(auto-thumbnail): [PKG-AUTO-THUMB-12] release stalled metadata loads 2026-09-15 12:31:32 +08:00
Harvey Zhao d3aa4bbfe4 build(site): [SITE-07] verify Node path origin and preserve complete notices 2026-09-15 12:18:24 +08:00
Harvey Zhao d2b2f76db8 build(site): [SITE-07] reproduce Monaco CSS sources and verify styled editor 2026-09-15 11:55:22 +08:00
Harvey Zhao 23ac6f7128 build(site): [SITE-07] reproduce complete Monaco contribution assembly 2026-09-15 11:29:17 +08:00
Harvey Zhao 0cfdf4a7e3 build(site): [SITE-07] reproduce core outputs and validate localized editing 2026-09-15 11:02:31 +08:00
Harvey Zhao 244695e726 build(site): [SITE-07] restore Monaco Markdown component notices 2026-09-15 10:41:24 +08:00
Harvey Zhao 426fee8faa build(site): [SITE-07] reproduce basic languages and verify upstream token cases 2026-09-15 10:23:26 +08:00
Harvey Zhao bc9cb61aaf build(site): [SITE-07] reproduce and validate Monaco language modes 2026-09-15 09:42:37 +08:00
Harvey Zhao 99c208aeee docs(thumbnail): [PKG-TOOL-THUMB-04] specify pending default compatibility policy 2026-09-15 09:25:59 +08:00
Harvey Zhao 11c9fefadd build(site): [SITE-07] deliver original Monaco language service notices 2026-09-15 09:20:49 +08:00
Harvey Zhao 0d3ddbf355 build(site): [SITE-07] reproduce Monaco CSS HTML and JSON workers 2026-09-15 09:10:16 +08:00
Harvey Zhao 11296975f1 build(site): [SITE-07] verify Monaco TypeScript worker and original notices 2026-09-15 08:47:23 +08:00
Harvey Zhao fb1faffbe9 build(site): [SITE-07] bind console licenses to verified component sources 2026-09-15 08:27:40 +08:00
Harvey Zhao 4bef084328 build(site): [SITE-07] retain shallowequal upstream attribution 2026-09-15 08:17:49 +08:00
Harvey Zhao 0503fe8aa8 build(site): [SITE-07] preserve exact Stack Overflow revision and attribution 2026-09-15 08:09:53 +08:00
Harvey Zhao 3136eb2402 build(site): [SITE-07] verify modified forks and preserve upstream author notices 2026-09-15 07:50:12 +08:00
Harvey Zhao d2a83f8a69 build(site): [SITE-07] verify embedded inspector and tokenizer sources 2026-09-15 07:34:42 +08:00
Harvey Zhao 199021c8a9 build(site): [SITE-07] distribute verified console package and embedded notices 2026-09-15 07:21:02 +08:00
Harvey Zhao 63e4e8ad92 build(site): [SITE-07] reproduce all console modules and Parcel loader 2026-09-15 07:07:18 +08:00
Harvey Zhao ba1dbd430f build(site): [SITE-07] reproduce 41 more console vendor modules 2026-09-15 06:40:29 +08:00
Harvey Zhao b47ede011a build(site): [SITE-07] reproduce console-feed vendor modules 2026-09-15 06:29:06 +08:00
Harvey Zhao 3dba82a453 refactor(site): [SITE-CONSOLE-01] restore typed console and lifecycle ownership 2026-09-15 06:15:32 +08:00
Harvey Zhao 6cd2d0ffbe test(site): [SITE-07] freeze console contracts and lifecycle failures 2026-09-15 05:52:06 +08:00
Harvey Zhao 7cf6f33130 chore: [ENG-LINT-02] restore clean repository lint 2026-09-15 05:30:05 +08:00
Harvey Zhao d2f4261aa7 build(site): [SITE-07] verify vConsole sources and complete notices 2026-09-15 05:25:33 +08:00
Harvey Zhao bf432ed62a build(site): [SITE-07] preserve historical Codicons attribution 2026-09-15 05:06:58 +08:00
Harvey Zhao a4234230e6 test(ci): [CI-01] validate installed VAST loaders and native IMA 2026-09-15 04:51:55 +08:00
Harvey Zhao ce67eaa73e test(ci): [CI-01] verify installed Iframe tools across window boundaries 2026-09-15 04:34:28 +08:00
Harvey Zhao 4a9ef16b16 ci: [CI-01] split playback engines from browser consumers 2026-09-15 04:18:18 +08:00
Harvey Zhao 92b04d75c0 test(ci): [CI-01] cover installed Danmuku and native Mask combinations 2026-09-15 03:56:05 +08:00
Harvey Zhao 54169fdca1 test(ci): [CI-01] verify installed JASSUB bundles and worker resources 2026-09-15 03:20:10 +08:00
Harvey Zhao 25a0c6303d test(ci): [CI-01] verify installed MediaBunny browser matrix 2026-09-15 03:07:20 +08:00
Harvey Zhao 8379ac7bbf test(ci): [CI-01] centralize installed roster and cover ASR and Cast 2026-09-15 02:56:43 +08:00
Harvey Zhao b90de99bc2 test(ci): [CI-01] checkpoint installed adaptive and thumbnail coverage 2026-09-15 02:33:16 +08:00
Harvey Zhao 7094cf6f9c fix(hls): [PKG-HLS-PACK-01] exclude implementation config from npm package 2026-09-15 02:20:23 +08:00
Harvey Zhao 2d45135873 test(ci): [CI-01] checkpoint installed audio and subtitle coverage 2026-09-15 02:11:36 +08:00
Harvey Zhao 34e4136b43 test(chapter): [PKG-CHAPTER-05] checkpoint native media timing controls 2026-09-15 01:51:33 +08:00
Harvey Zhao a03e5acc50 test(ci): [CI-01] checkpoint verified Ads installed browser coverage 2026-09-15 01:31:28 +08:00
Harvey Zhao 18215b97c0 test(toolchain): [MOD-01] evaluate isolated Bun installs and retain Yarn 2026-09-15 01:14:46 +08:00
Harvey Zhao ddf3d6ccbc test(release): [REL-04] checkpoint exact historical Pages recovery 2026-09-15 00:43:31 +08:00
Harvey Zhao d0c33f6258 test(release): [REL-04] checkpoint renamed rollback and mainline conflict recovery 2026-09-15 00:28:33 +08:00
Harvey Zhao aa29dc9212 test(release): [REL-04] checkpoint independent installed package rollback 2026-09-15 00:16:43 +08:00
Harvey Zhao 09459955c6 test(vast): [PKG-VAST-05] checkpoint native tag requests and skip controls 2026-09-14 23:57:20 +08:00
Harvey Zhao 75da50a454 test(vast): [PKG-VAST-05] checkpoint real IMA playback and recovery evidence 2026-09-14 23:38:06 +08:00
Harvey Zhao e5c73fa620 refactor(vast): [PKG-VAST-04] retain published types and add accurate runtime declarations 2026-09-14 23:07:52 +08:00
Harvey Zhao c162d2b3b3 fix(vast): [PKG-VAST-03] preserve npm initialization with explicit workspace mode 2026-09-14 22:42:57 +08:00
Harvey Zhao 314a1c3163 fix(danmuku): [PKG-DANMUKU-MASK-LOAD-01] recover stalled-frame rows and remove relaxed placement backlog 2026-09-14 22:13:08 +08:00
Harvey Zhao 475d38043e test(danmuku): [PKG-DANMUKU-08] cover old plugin combinations and expose model load failures 2026-09-14 21:32:10 +08:00
Harvey Zhao 30363a5346 test(danmuku): [PKG-DANMUKU-08] verify fullscreen lifetimes and old-core loads 2026-09-14 21:13:03 +08:00
Harvey Zhao b54a890832 test(danmuku): [PKG-DANMUKU-08] verify native PiP and current-source mask combinations 2026-09-14 20:50:31 +08:00
Harvey Zhao 88ce836f85 fix(dash): [PKG-DASH-MENU-01] preserve settings navigation during SDK refresh 2026-09-14 20:35:22 +08:00
Harvey Zhao 30f646be97 fix(dash): [PKG-DASH-SEEK-01] recover paused boundary seeks in SDK 4.5.2 2026-09-14 20:19:04 +08:00
Harvey Zhao 442e1dcc96 test(ci): [CI-01] record complete Chromium source regression 2026-09-14 19:31:39 +08:00
Harvey Zhao fc566f14d5 test(ci): [CI-01] record complete installed five-package regression 2026-09-14 19:13:41 +08:00
Harvey Zhao 37ebb7a034 test(canvas): [PKG-CANVAS-05] checkpoint installed native picture-in-picture 2026-09-14 19:08:22 +08:00
Harvey Zhao c3967bcbf4 fix(canvas): [PKG-CANVAS-SUBTITLE-01] attach native subtitle tracks 2026-09-14 18:51:57 +08:00
Harvey Zhao d89728c0a6 test(chapter): [PKG-CHAPTER-HOVER-01] wait for stable fullscreen geometry 2026-09-14 18:28:07 +08:00
Harvey Zhao 492e58a345 ci: [CI-BROWSER-01] separate source and installed browser scopes 2026-09-14 18:11:00 +08:00
Harvey Zhao 765ddb816f test(ambilight): [PKG-AMBILIGHT-05] checkpoint installed canvas combinations 2026-09-14 17:50:38 +08:00
Harvey Zhao e7f31b6fc8 fix(site): [SITE-VCONSOLE-01] cancel stale console lifecycle work 2026-09-14 17:30:17 +08:00
Harvey Zhao 838c3eb432 build(site): [SITE-07] checkpoint frozen vendor notices and open lifecycle evidence 2026-09-14 17:03:09 +08:00
Harvey Zhao 72d2b9c36b ci(pages): [CI-02] validate staged artifacts and preserve legacy demo paths 2026-09-14 16:43:33 +08:00
Harvey Zhao b1e0b976b0 perf(core): [MOD-03] complete hot-path measurement and compatibility acceptance 2026-09-14 16:23:37 +08:00
Harvey Zhao 48a7f1ecb0 test(performance): [ENG-13] enforce measured teardown observation minimum 2026-09-14 16:02:05 +08:00
Harvey Zhao 23a4f22b72 perf(core): [MOD-03] avoid redundant slider attribute writes 2026-09-14 15:44:18 +08:00
Harvey Zhao 7b0e1d156b fix(jassub): [PKG-JASSUB-10] release bitmap batches on rendering errors 2026-09-14 15:28:52 +08:00
Harvey Zhao 04060aa8b6 feat(REL-08): bind package release gates to candidate evidence 2026-09-14 15:08:26 +08:00
Harvey Zhao 3316b8a867 test(PKG-HLS-SDK-01): checkpoint direct HTTP teardown crashes 2026-09-14 14:42:12 +08:00
Harvey Zhao fe5534ac24 fix(PKG-VAST-07): restore historical default factory calls 2026-09-14 14:31:25 +08:00
Harvey Zhao eb6402fdca fix(PKG-AUTO-THUMB-11): isolate frame handler cleanup failures 2026-09-14 14:22:45 +08:00
Harvey Zhao a8d19ce5ef test(multiple-subtitles): checkpoint native seek diagnostics [PKG-MULTI-SUB-05] 2026-09-14 14:03:22 +08:00
Harvey Zhao 318de37e8a fix(multiple-subtitles): repair old ASS conversion line breaks [PKG-MULTI-SUB-11] 2026-09-14 13:42:46 +08:00
Harvey Zhao 8ae2762a23 fix(multiple-subtitles): render overlapping cues on legacy hosts [PKG-MULTI-SUB-10] 2026-09-14 13:26:42 +08:00
Harvey Zhao 31f9024bff test(multiple-subtitles): [PKG-MULTI-SUB-09] isolate old-core source seeking from caption loss 2026-09-14 13:02:49 +08:00
Harvey Zhao efed847cdf fix(core): [CORE-SUBTITLE-OFFSET-01] refresh paused native cue membership and order 2026-09-14 12:49:22 +08:00
Harvey Zhao b5dee252d4 test(multiple-subtitles): [PKG-MULTI-SUB-05] checkpoint native core combination gaps 2026-09-14 12:30:42 +08:00
Harvey Zhao 675b095b27 fix(multiple-subtitles): [PKG-MULTI-SUB-08] preserve entity text and semantic cue wrappers 2026-09-14 12:14:21 +08:00
Harvey Zhao 4acf85ea69 refactor(auto-thumbnail): [PKG-AUTO-THUMB-10] own JPEG encoding cancellation and deadlines 2026-09-14 11:55:05 +08:00
Harvey Zhao afb632d16f test(auto-thumbnail): [PKG-AUTO-THUMB-03] isolate native first-frame decoding checkpoint 2026-09-14 11:41:33 +08:00
Harvey Zhao 772d79a671 refactor(tooling): [MOD-DEV-01] own dev server lifecycle and report port failures 2026-09-14 11:29:46 +08:00
Harvey Zhao 401d4cdd65 refactor(tooling): [MOD-02] split library build and development into typed modules 2026-09-14 10:46:25 +08:00
Harvey Zhao 28c7abb2bb refactor(tooling): [MOD-PLUGIN-01] generate typed plugins with safe output handling 2026-09-14 10:19:19 +08:00
Harvey Zhao 07d5bfef2e test(vtt-thumbnail): [PKG-VTT-THUMB-05] verify historical core and fullscreen combinations 2026-09-14 09:57:21 +08:00
Harvey Zhao 4fa5c68be9 test(auto-thumbnail): [PKG-AUTO-THUMB-03] verify first-seek diagnostic boundaries 2026-09-14 09:36:10 +08:00
Harvey Zhao 2f130c58f1 refactor(docs): [SITE-03] migrate desktop editor and integrate typed generation 2026-09-14 09:25:46 +08:00
Harvey Zhao a468cb2c39 refactor(build): [SITE-BUILD-01] stage outputs and stabilize documentation builds 2026-09-14 08:51:09 +08:00
Harvey Zhao 078cd9ef72 refactor(docs): [SITE-AI-DOCS-01] make generation offline and translation draft based 2026-09-14 08:22:44 +08:00
Harvey Zhao 647f3e7f12 fix(docs): [SITE-LOAD-01] serialize example loading and preserve navigation 2026-09-14 07:52:32 +08:00
Harvey Zhao 76499e7a3e refactor(docs): [SITE-02] generate and validate standalone editor types 2026-09-14 07:24:03 +08:00
Harvey Zhao 1a5440a67f refactor(docs): [SITE-SMOKE-01] verify example readiness and cleanup 2026-09-14 07:02:49 +08:00
Harvey Zhao d74ecc43cc docs(site): [SITE-01] inventory sources and reconcile demo coverage 2026-09-14 06:21:25 +08:00
Harvey Zhao d62ab13a35 feat(vue): [EX-02] verify installed consumers and preserve lifecycle contracts 2026-09-14 06:02:13 +08:00
Harvey Zhao 4df9689364 chore(lint): [ENG-LINT-01] restore mask manifest ordering 2026-09-14 05:20:25 +08:00
Harvey Zhao e0d785662d fix(react): [EX-01] verify installed consumers and clean up callback failures 2026-09-14 05:17:51 +08:00
Harvey Zhao 3e39fc745f test(auto-thumbnail): [PKG-AUTO-THUMB-03] distinguish render and data readiness 2026-09-14 04:48:39 +08:00
Harvey Zhao f30c701d88 fix(auto-thumbnail): [PKG-AUTO-THUMB-09] restore historical default calls 2026-09-14 04:26:33 +08:00
Harvey Zhao c4f5dcf17f feat(auto-thumbnail): [PKG-AUTO-THUMB-08] add compatible runtime type entry 2026-09-14 04:07:59 +08:00
Harvey Zhao 7be628a983 fix(auto-thumbnail): [PKG-AUTO-THUMB-07] release terminal canvas storage 2026-09-14 03:48:00 +08:00
Harvey Zhao e93d3cbb67 test(chapter): [PKG-CHAPTER-05] correlate restart event and observation timing 2026-09-14 03:36:06 +08:00
Harvey Zhao 814bdc11db test(jassub): [PKG-JASSUB-09] verify composited subtitle screenshots 2026-09-14 03:27:49 +08:00
Harvey Zhao 7ef605fba7 test(jassub): [PKG-JASSUB-09] isolate Firefox bitmap readback stalls 2026-09-14 03:13:55 +08:00
Harvey Zhao 7f185f698d fix(jassub): [PKG-JASSUB-09] checkpoint hybrid canvas ownership and frame completion 2026-09-14 02:50:55 +08:00
Harvey Zhao b4b0276fe9 fix(jassub): [PKG-JASSUB-08] transfer offscreen canvas before queued rendering 2026-09-14 02:29:12 +08:00
Harvey Zhao 0f3c068aae fix(jassub): [PKG-JASSUB-07] repair vendor lifecycle and subtitle frame clock 2026-09-14 02:17:24 +08:00
Harvey Zhao 5e445b1af6 refactor(jassub): [PKG-JASSUB-04] migrate owned TypeScript and preserve public types 2026-09-14 01:41:31 +08:00
Harvey Zhao 38e7b37878 refactor(jassub): [PKG-JASSUB-03] isolate registration and fix adapter cleanup 2026-09-14 01:12:03 +08:00
Harvey Zhao 944e2cc9d0 test(jassub): [PKG-JASSUB-02] establish lifecycle failures and native render baseline 2026-09-14 01:00:06 +08:00
Harvey Zhao 0cf56b64d2 refactor(jassub): [PKG-JASSUB-01] pin exact nightly and font provenance 2026-09-14 00:42:47 +08:00
Harvey Zhao 8abd49bc9c test(mask): [PKG-MASK-05] checkpoint native model and historical-core coverage 2026-09-14 00:36:06 +08:00
Harvey Zhao aca4bc1cd2 refactor(mask): [PKG-MASK-04] migrate strict types and preserve public consumers 2026-09-14 00:05:14 +08:00
Harvey Zhao aba125262a refactor(mask): [PKG-MASK-03] isolate model runs and release stale work 2026-09-13 23:46:15 +08:00
Harvey Zhao 6c989deccd refactor(auto-thumbnail): [PKG-AUTO-THUMB-03] type internal extraction contracts 2026-09-13 23:39:06 +08:00
Harvey Zhao 00e81309ca test(danmuku): [PKG-DANMUKU-07] verify native load and shared layer stability 2026-09-13 23:16:04 +08:00
Harvey Zhao 4f559cb31d fix(danmuku): [PKG-DANMUKU-12] keep frame sampling during async placement 2026-09-13 22:49:26 +08:00
Harvey Zhao df6a6fe82e fix(danmuku): [PKG-DANMUKU-11] start visible lifetime after Worker placement 2026-09-13 22:24:09 +08:00
Harvey Zhao 24b883d862 refactor(danmuku): [PKG-DANMUKU-06] migrate runtime and preserve public types 2026-09-13 22:06:00 +08:00
Harvey Zhao abc8008da7 fix(danmuku): [PKG-DANMUKU-10] bound dense heatmaps for issue 958 2026-09-13 21:20:37 +08:00
Harvey Zhao 053d211fb0 refactor(danmuku): [PKG-DANMUKU-05] own renderer settings and heatmap resources 2026-09-13 20:45:16 +08:00
Harvey Zhao 12332df221 refactor(danmuku): [PKG-DANMUKU-04] own scheduler and worker request lifecycle 2026-09-13 19:19:25 +08:00
Harvey Zhao 0b2efb07f1 refactor(danmuku): [PKG-DANMUKU-03] own input loading parsing and configuration 2026-09-13 18:35:28 +08:00
Harvey Zhao d3c91af92c test(danmuku): [PKG-DANMUKU-02] establish failure browser and load baselines 2026-09-13 18:03:21 +08:00
Harvey Zhao ccf3d6ed14 test(danmuku-mask): [PKG-MASK-02] reproduce historical lifecycle and failure paths 2026-09-13 17:43:25 +08:00
Harvey Zhao d81b881085 test(danmuku): [PKG-DANMUKU-01] freeze public contracts and release provenance 2026-09-13 17:38:25 +08:00
Harvey Zhao 7d44bce06f test(danmuku-mask): [PKG-MASK-01] freeze published contracts and model provenance 2026-09-13 17:36:11 +08:00
Harvey Zhao 8ec9fbe83a refactor(chromecast): [PKG-CAST-04] preserve published types and add runtime entry 2026-09-13 17:34:49 +08:00
Harvey Zhao b0cfbfe3a0 refactor(chromecast): [PKG-CAST-03] isolate SDK and player lifecycles 2026-09-13 17:13:35 +08:00
Harvey Zhao 87cfcf5a6c fix(multiple-subtitles): [PKG-MULTI-SUB-04] preserve historical type shapes 2026-09-13 16:59:44 +08:00
Harvey Zhao 58d2c95d8e fix(vtt-thumbnail): [PKG-VTT-THUMB-04] preserve historical type shapes 2026-09-13 16:57:38 +08:00
Harvey Zhao c4c7491e16 fix(types): [PKG-FACTORY-01] preserve published factory compatibility 2026-09-13 16:53:27 +08:00
Harvey Zhao 1117107032 fix(asr): validate generated editor declarations semantically 2026-09-13 16:47:51 +08:00
Harvey Zhao c723c70251 test(chromecast): [PKG-CAST-02] reproduce SDK and lifecycle failures 2026-09-13 16:42:46 +08:00
Harvey Zhao 30de007102 test(chromecast): [PKG-CAST-01] freeze published contracts and provenance 2026-09-13 16:35:26 +08:00
Harvey Zhao d5562b05b7 docs: record approved historical type compatibility policy 2026-09-13 16:33:25 +08:00
Harvey Zhao 146b78d576 feat(asr): [PKG-ASR-09] add explicit capture ownership and cancel stale restarts 2026-09-13 16:19:49 +08:00
Harvey Zhao 5ab7da6e1f test(asr): [PKG-ASR-05] cover CORS and independent audio combinations 2026-09-13 16:07:01 +08:00
Harvey Zhao 2cede66933 test(asr): [PKG-ASR-05] checkpoint local editor and adjacent core coverage 2026-09-13 15:55:57 +08:00
Harvey Zhao 6d7b9292f8 fix(asr): [PKG-ASR-08] keep captured fallback off the audible route 2026-09-13 15:40:27 +08:00
Harvey Zhao 3e3bed2b93 fix(asr): [PKG-ASR-07] apply native playback volume only once 2026-09-13 15:22:40 +08:00
Harvey Zhao 93208e59e1 refactor(asr): [PKG-ASR-04] preserve old declarations and add precise runtime types 2026-09-13 15:07:04 +08:00
Harvey Zhao 0cf2af4840 refactor(asr): [PKG-ASR-03] own typed audio capture and playback lifetimes 2026-09-13 14:44:23 +08:00
Harvey Zhao 53c295819d test(asr): [PKG-ASR-02] reproduce audio queue and lifecycle failures 2026-09-13 14:09:20 +08:00
Harvey Zhao a22586a172 test(asr): [PKG-ASR-01] freeze published interfaces and source contracts 2026-09-13 14:03:16 +08:00
Harvey Zhao 3b016970f2 fix(core): [CORE-25] read defaults without navigator 2026-09-13 13:53:49 +08:00
Harvey Zhao 4a299eb2d4 fix(build): [ENG-12] exclude declaration sources from library artifacts 2026-09-13 13:37:00 +08:00
Harvey Zhao 38355ae4cf ci: [CI-01] verify identical tarballs on three Node runtimes 2026-09-13 13:21:17 +08:00
Harvey Zhao 585e11c53c ci: [CI-01] add OS matrices, scoped caches and required result gate 2026-09-13 13:02:04 +08:00
Harvey Zhao 2c73e2b105 test(jassub): [PKG-JASSUB-01] freeze published contracts and vendor evidence 2026-09-13 12:35:21 +08:00
Harvey Zhao d44e81ce22 refactor(multiple-subtitles): [PKG-MULTI-SUB-04] expose compatible runtime type entry 2026-09-13 12:14:41 +08:00
Harvey Zhao 7f226ff822 fix(multiple-subtitles): [PKG-MULTI-SUB-07] preserve inline timestamps and caption text 2026-09-13 11:50:50 +08:00
Harvey Zhao da64aae267 refactor(multiple-subtitles): [PKG-MULTI-SUB-04] type runtime modules and vendor boundaries 2026-09-13 11:21:06 +08:00
Harvey Zhao beaa93d6cc refactor(multiple-subtitles): [PKG-MULTI-SUB-03] own requests and subtitle resources 2026-09-13 11:01:47 +08:00
Harvey Zhao 36cd151095 test(multiple-subtitles): [PKG-MULTI-SUB-02] reproduce failures and native resource leaks 2026-09-13 10:38:32 +08:00
Harvey Zhao 5a0d94cb89 test(multiple-subtitles): [PKG-MULTI-SUB-01] freeze contracts and verify parser provenance 2026-09-13 10:12:32 +08:00
Harvey Zhao 0c5bb2bd7a test(vtt-thumbnail): [PKG-VTT-THUMB-04] verify historical module forms and type conflicts 2026-09-13 09:43:18 +08:00
Harvey Zhao db358a3ae4 refactor(vtt-thumbnail): [PKG-VTT-THUMB-04] preserve legacy types and expose async runtime entry 2026-09-13 09:30:57 +08:00
Harvey Zhao 7f2906ae52 refactor(vtt-thumbnail): [PKG-VTT-THUMB-04] type runtime data and resource boundaries 2026-09-13 09:03:20 +08:00
Harvey Zhao 80588a3046 refactor(vtt-thumbnail): [PKG-VTT-THUMB-03] validate cues and separate pure lookup 2026-09-13 08:50:33 +08:00
Harvey Zhao 524ddf784f refactor(vtt-thumbnail): [PKG-VTT-THUMB-03] own pending requests and preview resources 2026-09-13 08:37:48 +08:00
Harvey Zhao 05244d1104 test(vtt-thumbnail): [PKG-VTT-THUMB-02] reproduce parsing and lifecycle failures 2026-09-13 08:21:48 +08:00
Harvey Zhao d4ede650e8 test(vtt-thumbnail): [PKG-VTT-THUMB-01] freeze published runtime contracts 2026-09-13 08:15:39 +08:00
Harvey Zhao 8c57d56f17 refactor(auto-thumbnail): [PKG-AUTO-THUMB-03] wait for native frame presentation 2026-09-13 07:53:29 +08:00
Harvey Zhao a128706fe7 refactor(auto-thumbnail): [PKG-AUTO-THUMB-03] own hidden renderers and reject stale seeks 2026-09-13 07:23:55 +08:00
Harvey Zhao 84721f19ed refactor(auto-thumbnail): [PKG-AUTO-THUMB-03] own extraction jobs and encoded URLs 2026-09-13 06:55:34 +08:00
Harvey Zhao 9cd6659ab4 test(auto-thumbnail): [PKG-AUTO-THUMB-02] reproduce extraction and lifecycle failures 2026-09-13 06:07:37 +08:00
Harvey Zhao cdc252b158 test(auto-thumbnail): [PKG-AUTO-THUMB-01] freeze published and workspace contracts 2026-09-13 05:47:40 +08:00
Harvey Zhao 17befee4b1 fix(thumbnail): [PKG-TOOL-THUMB-04] protect event names and nested once dispatch 2026-09-13 05:29:59 +08:00
Harvey Zhao 3bff236145 fix(thumbnail): [PKG-TOOL-THUMB-04] supply public types and installed module entries 2026-09-13 05:16:36 +08:00
Harvey Zhao 15485b6420 refactor(thumbnail): [PKG-TOOL-THUMB-04] type runtime modules and retain emitter attribution 2026-09-13 04:45:01 +08:00
Harvey Zhao efd9f42fb9 refactor(thumbnail): [PKG-TOOL-THUMB-03] own extraction jobs and source cancellation 2026-09-13 04:25:22 +08:00
Harvey Zhao 426c0c5d42 fix(thumbnail): [PKG-TOOL-THUMB-03] own input resources and separate sheet export 2026-09-13 03:51:26 +08:00
Harvey Zhao 1cb7779192 test(thumbnail): [PKG-TOOL-THUMB-02] reproduce extraction and resource lifecycle gaps 2026-09-13 03:33:22 +08:00
Harvey Zhao 0338e0b8b1 test(thumbnail): [PKG-TOOL-THUMB-01] freeze recovered release and workspace contracts 2026-09-13 03:16:30 +08:00
Harvey Zhao cb6c767731 test(iframe): [PKG-IFRAME-05] verify native cached history and interrupted navigation 2026-09-13 02:55:57 +08:00
Harvey Zhao b35183c7af fix(iframe): [PKG-IFRAME-05] checkpoint player and editor integration 2026-09-13 02:17:44 +08:00
Harvey Zhao 047e2df945 refactor(iframe): [PKG-IFRAME-04] preserve types across module consumers 2026-09-13 01:43:09 +08:00
Harvey Zhao 1342de94ef refactor(iframe): [PKG-IFRAME-03] scope requests to active documents 2026-09-13 01:07:37 +08:00
Harvey Zhao b8cdafedd1 fix(iframe): [PKG-IFRAME-03] release failed setup and bind message peers 2026-09-13 00:03:37 +08:00
Harvey Zhao b8d03e7366 fix(iframe): [PKG-IFRAME-03] own pending requests and cancellation 2026-09-12 23:41:48 +08:00
Harvey Zhao b3f22652c2 test(iframe): [PKG-IFRAME-02] reproduce request and native window failures 2026-09-12 23:23:48 +08:00
Harvey Zhao a52f79a0cc test(iframe): [PKG-IFRAME-01] freeze historical exports and message contract 2026-09-12 23:00:01 +08:00
Harvey Zhao 7e37fd4d0e fix(core): [PKG-DPIP-05] keep web fullscreen in the active document 2026-09-12 22:44:01 +08:00
Harvey Zhao 401c5e9684 test(mediabunny): [PKG-MB-09] add sustained playback checkpoint 2026-09-12 22:24:04 +08:00
Harvey Zhao 190fdb2776 test(mediabunny): [PKG-MB-09] verify native picture-in-picture checkpoint 2026-09-12 22:11:27 +08:00
Harvey Zhao fb9fb23f53 refactor(mediabunny): [PKG-MB-08] finish typed media capability boundaries 2026-09-12 21:51:47 +08:00
Harvey Zhao 5e28dfee95 refactor(mediabunny): [PKG-MB-08] checkpoint typed entry and compatible media declarations 2026-09-12 21:31:34 +08:00
Harvey Zhao 8a2b56e829 refactor(mediabunny): [PKG-MB-07] own HLS selection intent and menu lifecycle 2026-09-12 20:51:31 +08:00
Harvey Zhao ccee9157a7 refactor(mediabunny): [PKG-MB-06] own audio clocks, buffers and context lifecycle 2026-09-12 20:21:25 +08:00
Harvey Zhao 9d037dcbf9 refactor(mediabunny): [PKG-MB-05] own video iterators, frame pools and rendering 2026-09-12 19:47:46 +08:00
Harvey Zhao 5d0b128483 refactor(mediabunny): [PKG-MB-04] isolate typed playback and readiness coordination 2026-09-12 19:00:21 +08:00
Harvey Zhao 9af253a5a9 refactor(mediabunny): [PKG-MB-04] checkpoint typed shim and event cleanup 2026-09-12 18:27:33 +08:00
Harvey Zhao adba8a3d12 refactor(mediabunny): [PKG-MB-03] type inputs and cancel owned loads 2026-09-12 18:08:37 +08:00
Harvey Zhao 03451c029b test(mediabunny): [PKG-MB-02] establish native input and lifecycle baselines 2026-09-12 17:43:56 +08:00
Harvey Zhao 63c8938dd7 test(mediabunny): [PKG-MB-02] checkpoint native playback and late load failures 2026-09-12 17:12:59 +08:00
Harvey Zhao 1cfd2e17f3 test(mediabunny): [PKG-MB-01] freeze published proxy and dependency contracts 2026-09-12 17:05:55 +08:00
Harvey Zhao 1f93bb9ba1 test(types): [PKG-FACTORY-01] checkpoint historical factory compatibility choices 2026-09-12 16:44:44 +08:00
Harvey Zhao ef976136a1 fix(dpip): [PKG-DPIP-04] preserve factory type and export compatibility 2026-09-12 14:53:05 +08:00
Harvey Zhao 80d37d66f8 refactor(dpip): [PKG-DPIP-03] own windows and DOM resources in strict TypeScript 2026-09-12 14:22:09 +08:00
Harvey Zhao 202351934b test(dpip): [PKG-DPIP-02] reproduce window races and DOM rollback failures 2026-09-12 14:02:18 +08:00
Harvey Zhao efbbdb4782 test(dpip): [PKG-DPIP-01] freeze actual releases and window contracts 2026-09-12 13:51:30 +08:00
Harvey Zhao 224572032a fix(canvas): [PKG-CANVAS-04] preserve public type and export compatibility 2026-09-12 13:29:10 +08:00
Harvey Zhao 2b319109cd refactor(canvas): [PKG-CANVAS-03] own media and frame lifecycle in strict TypeScript 2026-09-12 13:11:07 +08:00
Harvey Zhao e931520e66 test(canvas): [PKG-CANVAS-02] reproduce frame leaks and native pixel boundaries 2026-09-12 12:43:39 +08:00
Harvey Zhao 5e26d2298d test(canvas): [PKG-CANVAS-01] freeze published proxy and media adapter contracts 2026-09-12 12:19:25 +08:00
Harvey Zhao 20f062bc90 fix(ambilight): [PKG-AMBILIGHT-PROXY-01] sample canvas output pixels after resizing 2026-09-12 12:04:41 +08:00
Harvey Zhao 959cccf515 refactor(ambilight): [PKG-AMBILIGHT-04] preserve published types and dual CommonJS exports 2026-09-12 11:50:22 +08:00
Harvey Zhao 6caee44dbf refactor(ambilight): [PKG-AMBILIGHT-03] split typed lifecycle and recover native canvas sampling 2026-09-12 11:35:13 +08:00
Harvey Zhao 43f0e9a8c6 test(ambilight): [PKG-AMBILIGHT-02] reproduce historical frame and native canvas failures 2026-09-12 11:09:40 +08:00
Harvey Zhao 06032a6906 test(ambilight): [PKG-AMBILIGHT-01] freeze actual release and invocation contracts 2026-09-12 10:54:28 +08:00
Harvey Zhao c57c7e4b16 ci(refactor): [ENG-09] verify integrated ecosystem and documentation gates 2026-09-12 10:41:40 +08:00
Harvey Zhao f35fb87615 test(refactor): [ENG-COVERAGE-01] index public contracts and exact candidate evidence 2026-09-12 10:38:29 +08:00
Harvey Zhao 6abac891ce ci(refactor): [ENG-IMPACT-01] map workspace changes to required ecosystem checks 2026-09-12 10:14:54 +08:00
Harvey Zhao e0aacc5d6a ci(refactor): [ENG-AUDIT-01] verify dedicated task completion commits 2026-09-12 09:45:21 +08:00
Harvey Zhao 4f324a8438 refactor(vast): [PKG-VAST-03] isolate lifecycle ownership checkpoint 2026-09-12 09:33:54 +08:00
Harvey Zhao d5e1feadf5 test(vast): [PKG-VAST-02] cover SDK failures and lifecycle races 2026-09-12 09:19:01 +08:00
Harvey Zhao 4f39d6f2b9 test(vast): [PKG-VAST-01] freeze published and workspace contracts 2026-09-12 09:06:10 +08:00
Harvey Zhao 29692d2815 fix(ads): [PKG-ADS-05] preserve ownership and verify native browser lifecycle 2026-09-12 08:52:51 +08:00
Harvey Zhao fb1cfa701d refactor(ads): [PKG-ADS-04] reconcile public types and historical imports 2026-09-12 08:25:17 +08:00
Harvey Zhao 39e2d4cdfb refactor(ads): [PKG-ADS-03] split TypeScript lifecycle and preserve legacy behavior 2026-09-12 07:55:55 +08:00
Harvey Zhao 069ad4aae1 test(ads): [PKG-ADS-02] cover legacy timing and real media contracts 2026-09-12 07:26:58 +08:00
Harvey Zhao c6b82c3392 test(ads): [PKG-ADS-01] freeze published contracts and legacy compatibility gaps 2026-09-12 07:05:00 +08:00
Harvey Zhao bafbf2c8b0 test(dash): [PKG-DASH-05] isolate SDK paused-seek buffer metric deadlock 2026-09-12 06:51:25 +08:00
Harvey Zhao a9cf50bc4e fix(dash): [PKG-DASH-05] synchronize SDK events and own refresh lifecycle 2026-09-12 06:34:31 +08:00
Harvey Zhao 2ad00730ee fix(dash): [PKG-DASH-05] align nullable SDK metadata and validate real types 2026-09-12 06:07:03 +08:00
Harvey Zhao c4b5f5f454 test(dash): [PKG-DASH-05] checkpoint real SDK media and seek diagnostics 2026-09-12 05:45:24 +08:00
Harvey Zhao 6840544e0e refactor(dash): [PKG-DASH-04] migrate strict TypeScript and compatible declarations 2026-09-12 05:18:47 +08:00
Harvey Zhao 7de04573b6 refactor(dash): [PKG-DASH-03] adapt SDK generations and own menu lifecycles 2026-09-12 04:59:19 +08:00
Harvey Zhao 762cc63431 test(dash): [PKG-DASH-02] cover released contracts and real menu interactions 2026-09-12 04:42:16 +08:00
Harvey Zhao 3d4c636101 docs(dash): [PKG-DASH-01] freeze released SDK v4 and workspace v5 contracts 2026-09-12 04:23:52 +08:00
Harvey Zhao e0d47ea74b fix(chapter): [PKG-CHAPTER-05] checkpoint composition tests and bounded title layout 2026-09-12 04:16:32 +08:00
Harvey Zhao d18c545675 fix(audio): [PKG-AUDIO-05] checkpoint zero-time resume and native buffering evidence 2026-09-12 03:58:39 +08:00
Harvey Zhao 0218196df9 fix(core): [CORE-24] preserve source playback intent and explicit pauses 2026-09-12 03:26:26 +08:00
Harvey Zhao b5e96664ee test(audio): [PKG-AUDIO-05] checkpoint source-switch regressions 2026-09-12 03:06:54 +08:00
Harvey Zhao 13c898c149 refactor(audio): [PKG-AUDIO-04] migrate strict source and compatible type entries 2026-09-12 02:58:44 +08:00
Harvey Zhao 9c07ea830c refactor(audio): [PKG-AUDIO-03] separate track ownership and native lifecycle 2026-09-12 02:22:13 +08:00
Harvey Zhao 803e87252e test(audio): [PKG-AUDIO-02] cover released behavior and real media 2026-09-12 02:08:57 +08:00
Harvey Zhao 8c0a2feed3 docs(audio): [PKG-AUDIO-01] freeze released synchronization contract 2026-09-12 01:48:42 +08:00
Harvey Zhao 26b2983daf test(hls): [PKG-HLS-SDK-01] checkpoint unresolved Firefox diagnostics 2026-09-12 01:42:47 +08:00
Harvey Zhao 2f9bee4ee0 refactor(hls): [PKG-HLS-04] migrate modules and compatible types 2026-09-12 00:49:50 +08:00
Harvey Zhao ba93b98be5 refactor(hls): [PKG-HLS-03] separate menus and SDK lifecycle 2026-09-12 00:18:19 +08:00
Harvey Zhao 33f6d19b77 test(hls): [PKG-HLS-02] cover released contracts and real SDK playback 2026-09-11 23:53:16 +08:00
Harvey Zhao cbbdc03a7c docs(refactor): [PKG-HLS-01] freeze HLS control release contract 2026-09-11 23:29:39 +08:00
Harvey Zhao adec20213f refactor(core): [CORE-22] validate compatible core and defer initial layout 2026-09-11 23:18:12 +08:00
Harvey Zhao 5efc7f7699 build(tooling): [ENG-11] add module analysis without changing artifacts 2026-09-11 22:22:53 +08:00
Harvey Zhao 4a9a26d4fc test: [ENG-08] add verified TS coverage and paired performance reports 2026-09-11 22:01:48 +08:00
Harvey Zhao 8ed0a5228c refactor(core): [CORE-23] complete keyboard controls and focus lifecycle 2026-09-11 21:06:33 +08:00
Harvey Zhao faaa3e8c2d refactor(core): [CORE-21] generate compatible public and editor declarations 2026-09-11 17:56:05 +08:00
Harvey Zhao ee895a558f refactor(core): [CORE-20] type entry and converge initialization 2026-09-11 16:07:06 +08:00
Harvey Zhao ccf77c4ed2 refactor(core): CORE-19 type capture and preserve progress lifetimes 2026-09-11 14:24:59 +08:00
Harvey Zhao 98a1800032 refactor(core): CORE-18 type builtins and own prompt lifetimes 2026-09-11 12:31:01 +08:00
Harvey Zhao a842058136 refactor(core): CORE-17 type input events and own interaction lifetimes 2026-09-11 11:24:15 +08:00
Harvey Zhao 88aef830df refactor(core): CORE-16 type display modes and own fullscreen lifetimes 2026-09-11 09:42:30 +08:00
Harvey Zhao 1b83081e8f refactor(core): CORE-15 type subtitles and own request and track lifetimes 2026-09-11 07:23:10 +08:00
Harvey Zhao 64d1939daa refactor(core): CORE-14 split typed settings and scope tree lifetimes 2026-09-11 06:49:04 +08:00
Harvey Zhao 697817eceb refactor(core): CORE-13 type component registries and own control lifetimes 2026-09-11 04:54:32 +08:00
Harvey Zhao 9eb7c945ca refactor(core): CORE-12 type template resources and verify bundled notices 2026-09-11 03:50:33 +08:00
Harvey Zhao b8039ad1f1 refactor(core): CORE-11 split media events and scope reconnect lifetimes 2026-09-11 03:19:52 +08:00
Harvey Zhao 5e31274f1d refactor(core): CORE-10 type playback properties and add compatible controls view 2026-09-11 02:51:55 +08:00
Harvey Zhao 44f4e083a9 refactor(core): CORE-09 isolate source operations and settle cancelled switches 2026-09-11 02:34:26 +08:00
Harvey Zhao 874dac9f22 refactor(core): CORE-08 type plugin registration and guard closed instances 2026-09-11 02:09:36 +08:00
Harvey Zhao f9707bad71 refactor(types): CORE-07 reconcile public declarations and preserve legacy consumers 2026-09-11 01:42:32 +08:00
Harvey Zhao ee859e4804 refactor(core): CORE-06 type media surfaces and playback hosts 2026-09-11 01:18:14 +08:00
Harvey Zhao 97d320bd74 refactor(core): CORE-05 separate typed defaults and resolved options 2026-09-11 01:00:15 +08:00
Harvey Zhao 4eec8112fa refactor(core): CORE-04 scope initialization and make destruction reentrant-safe 2026-09-11 00:43:49 +08:00
Harvey Zhao 3e38dd0d19 refactor(core): CORE-03 add typed resource scopes and cleanup adapters 2026-09-11 00:21:32 +08:00
Harvey Zhao 362c616998 refactor(core): CORE-02 type emitter maps and fix nested once dispatch 2026-09-11 00:03:53 +08:00
Harvey Zhao d3c695024a refactor(core): CORE-01 migrate utility contracts to TypeScript 2026-09-10 23:50:47 +08:00
Harvey Zhao e005e5f249 docs(pilot): PILOT-01 verify chapter migration exit evidence 2026-09-10 23:36:05 +08:00
Harvey Zhao 913215885a docs(testing): ENG-10 consolidate failure classification and reliability rules 2026-09-10 23:31:21 +08:00
Harvey Zhao bab80ff886 fix(types): PKG-CHAPTER-04 preserve CJS ESM and legacy consumer contracts 2026-09-10 23:29:06 +08:00
Harvey Zhao 48660c4e12 refactor(chapter): PKG-CHAPTER-03 split runtime into typed lifecycle and view modules 2026-09-10 23:12:56 +08:00
Harvey Zhao a0286c4e95 test(packages): ENG-07 verify installed tarball contracts and browsers 2026-09-10 23:04:19 +08:00
Harvey Zhao 12b047f9a6 test(chapter): PKG-CHAPTER-02 cover behavior and optional factory types 2026-09-10 22:43:01 +08:00
Harvey Zhao 701749520b docs(chapter): PKG-CHAPTER-01 freeze published behavior contracts 2026-09-10 22:28:24 +08:00
Harvey Zhao 7318d33822 test(browser): ENG-05 add real playback projects and artifact mapping 2026-09-10 22:25:13 +08:00
Harvey Zhao 458bc3215d test: ENG-03 share behavior fixtures across source and releases 2026-09-10 21:55:27 +08:00
Harvey Zhao b53461da1c build: ENG-06 support TS entries and preserve AMD globals 2026-09-10 21:47:10 +08:00
Harvey Zhao 771482426f build(types): ENG-04 add strict projects and legacy compiler checks 2026-09-10 21:21:39 +08:00
Harvey Zhao 09902b8b8c docs(refactor): BASE-08 map package consumer and device validation 2026-09-10 21:11:39 +08:00
Harvey Zhao ed293231dc docs(refactor): BASE-07 track compatibility risks and third-party provenance 2026-09-10 21:07:56 +08:00
Harvey Zhao e01f39ffa0 test(BASE-06): capture performance and teardown resource baselines 2026-09-10 20:48:44 +08:00
Harvey Zhao c7a375e146 test(BASE-05): capture published distribution and type consumers 2026-09-10 20:34:04 +08:00
Harvey Zhao 2b7054d8a5 test(BASE-04): freeze published DOM input and demo baselines 2026-09-10 20:16:58 +08:00
Harvey Zhao 9489392905 test(refactor): [BASE-03] capture media and lifecycle behavior 2026-09-10 19:55:55 +08:00
Harvey Zhao b382ec08f7 test(refactor): [BASE-02] freeze real-browser public API contracts 2026-09-10 19:35:55 +08:00
Harvey Zhao 833cc11674 ci(workspace): [ENG-02] add read-only checks and isolated Pages workflow 2026-09-10 19:22:24 +08:00
Harvey Zhao 9a6cfe5c6b build(workspace): [ENG-PM-01] use pinned Yarn with frozen installs 2026-09-10 19:09:26 +08:00
Harvey Zhao 9d1d5fda3d docs(refactor): [DOC-13] allow in-app browser fallback 2026-09-10 18:58:19 +08:00
Harvey Zhao 3781e6bda1 build(workspace): [ENG-01] pin reproducible Node and npm toolchain 2026-09-10 18:52:58 +08:00
Harvey Zhao 3c759f14c2 test(refactor): [BASE-HARNESS-01] add isolated published API fixture 2026-09-10 18:44:08 +08:00
Harvey Zhao 1d705b3056 test(refactor): [BASE-01] freeze published core and chapter baselines 2026-09-10 18:36:02 +08:00
Harvey Zhao 7a5354e356 docs(refactor): [DOC-12] close execution and release planning gaps 2026-09-10 18:30:08 +08:00
Harvey Zhao 9b9739ab61 docs(refactor): [DOC-11] require next major versions for all packages 2026-09-10 18:25:53 +08:00
Harvey Zhao a9197f59b1 docs(refactor): [DOC-10] plan GitHub CI and release automation 2026-09-10 18:23:31 +08:00
Harvey Zhao 21fd40ec07 docs(refactor): [DOC-09] map existing browser test pages 2026-09-10 18:20:16 +08:00
Harvey Zhao 3af9becff9 docs(refactor): [DOC-08] require browser evidence and release reviews 2026-09-10 18:16:28 +08:00
Harvey Zhao 1fa0a57831 docs(refactor): [DOC-07] improve sequencing and release gates 2026-09-10 18:08:40 +08:00
Harvey Zhao d7b348f3a6 docs(refactor): [DOC-06] authorize dependencies and project scripts 2026-09-10 17:58:40 +08:00
Harvey Zhao 570600d2f6 docs(refactor): [DOC-05] establish refactor docs and per-task commits 2026-09-10 17:56:31 +08:00
糖猫猫andrionzhao 40fcda6a37 feat: batch video upscaling with folder upload, directory save, and result comparison (#1051)
* feat: support batch video upscaling with folder upload and directory save

- Add multi-file selection and entire folder upload (webkitdirectory)
- Support drag & drop of both files and folders via FileSystemEntry API
- Add save directory picker using File System Access API (showDirectoryPicker)
- Process videos sequentially with per-file progress and status tracking
- Add right-side result list with click-to-compare functionality
- Add per-video duration and total batch duration display
- Add retry button for failed items with error detail display
- Remove auto-play on comparison viewer load
- Fix worker error handling: handle "error" command to reject stale promises
- Fix event listener accumulation in video comparison (AbortController)
- Fix XSS risk by escaping HTML in all innerHTML injections
- Fix URL revocation timing in download to prevent large file truncation
- Extract writeToSaveDirectory and truncateName helpers to reduce duplication
- Add Usage Guide panel explaining single/multiple/folder upload options

Files changed:
  docs/upscaler/index.html  (+1110/-181)
  docs/upscaler/upscaler.js (+110)

* fix: prevent auto-play and resource consumption during upscaling

- Set preload="metadata" on preview and comparison video elements
- Explicitly pause preview video after setting src in showVideoPreview
- Remove preview video seek sync from batch processing progress callbacks
  (was causing continuous decode during upscaling, wasting GPU resources)
- Remove preview video seek sync from retry progress callback
- All videos now require manual play; no background resource usage

* fix: improve upscaled video quality with higher bitrate and codec support

- Raise base bitrate from 2.5 Mbps (25e5) to 8 Mbps (8e6) for standard and
  firefox processors, preventing quality loss when source videos have high
  bitrates (e.g. 720p @ 16.7 Mbps was producing 1440p @ 10 Mbps, smaller
  than the original file)
- Double the bitrate for mediabunny processor (X.n1 * 2) to account for the
  4x pixel increase from 2x upscaling
- Add H.264 Level 5.1 (avc1.640033) and Level 5.2 (avc1.640034) codecs to
  the fallback lists, since Level 4.0 (avc1.640028, ~24.6 Mbps) cannot
  support the higher bitrates for 1440p+ outputs
- Add latencyMode: "quality" to VideoEncoder configs for both standard and
  firefox processors, prioritizing encoding quality over latency (suitable
  for offline processing)

* feat: add video data comparison panel for original vs upscaled metrics

- Add a comparison data table below the file info bar showing 6 metrics:
  Resolution, File Size, Duration, Est. Bitrate, Pixels, Process Time
- Display per-metric change percentage with color-coded indicators:
  green (↑) for improvements, red (↓) for regressions, gray for neutral
- Estimated bitrate calculated from file size × 8 / video duration
- Table renders after both original and upscaled video metadata loads
- Auto-hide panel on reset

* fix: make video data comparison panel full-width and responsive

- Move comparison data table from inside the left column to the full-width
  area below the left/right layout, so it is no longer constrained by the
  comparison viewer column width
- Remove table-fixed colgroup and overflow-x-auto that caused horizontal
  scrolling on smaller screens
- Table now uses w-full auto-layout, displaying all 4 columns (Metric,
  Original, Upscaled, Change) without requiring horizontal scrolling

---------

Co-authored-by: rionzhao <rionzhao@tencent.com>
2026-09-10 17:19:38 +08:00
Harvey Zhao bb82f899ff Merge pull request #1061 from Mister-Hope/feat/dashjs-v5
feat(artplayer-plugin-dash-control)!: support dash.js v5
2026-09-10 17:19:00 +08:00
Harvey Zhao 59d3c9f50c fix(dash-control): select stable representation IDs 2026-09-10 17:17:54 +08:00
Harvey Zhao 37cbb6f600 Merge pull request #1058 from acaliskol/fix/unhandled-play-rejection
fix: silence unhandled play() rejections from internal callers
2026-09-10 17:06:52 +08:00
Harvey Zhao 72cf3551e2 fix: align promise helper types and test playback rejections 2026-09-10 17:03:07 +08:00
Mr.Hope cb69e4ad66 feat(artplayer-plugin-dash-control)!: support dash.js v5
- replace removed v4 APIs with their v5 equivalents:
  getRepresentationsByType / getCurrentRepresentationForType /
  setRepresentationForTypeByIndex
- bump dash.js CDN references from 4.5.2 to 5.2.1 (modern/umd build)
- rebuild dist, docs/compiled and docs/uncompiled artifacts
- regenerate vitepress docs
2026-09-10 15:58:17 +08:00
Harvey Zhao 42c4ca735d Update version.js 2026-08-31 16:59:25 +08:00
Anıl Çalışkol 0f47e11d63 fix: silence unhandled play() rejections from internal callers
`art.play()` is an async wrapper around the native `video.play()` promise, which
rejects when a pending play request is interrupted (`pause()`, `load()`, a new
`src`, or the element being removed) and when autoplay is blocked.

Every internal caller fires it from an event handler and cannot await it, so the
rejection escapes as a global `unhandledrejection`. Error trackers report it as
an uncaught crash even though the player recovers on its own — for example
destroying the player right after mount, which is routine when the video sits in
a modal the user can close quickly.

Add a `silencePromise` util (the same approach video.js uses) and apply it to the
non-awaited internal call sites: mask, play control, mini player, loop restart,
autoPlayback jump, hotkey and click toggles.

`switchMix` is fixed too, for a second symptom: `await art.play()` inside the
async `video:canplay` handler both leaked the rejection and left the `switchUrl`
promise pending forever, since the throw never reached the enclosing executor's
`reject`. It now settles.

The public API is unchanged: `art.play()` and `art.toggle()` still return the
original promise, so applications that call them keep their own rejection to
handle. Only the internal, non-awaited copy is silenced.
2026-08-30 16:31:40 +03:00
wuhua111 0b9c31a8cf fix(types): correct notice.show getter return type (#1055)
The notice.show getter was declared as boolean while the setter accepts string, Error or false. TypeScript uses the getter return type when checking property assignment, causing TS2322 when assigning a string to notice.show.
2026-08-28 17:52:07 +08:00
Harvey Zhao 02d1ded7b8 Update CNAME 2026-07-13 12:37:59 +08:00
Harvey Zhao 014b21566c feat: expose Artplayer globally in the browser environment
- Added assignment of Artplayer to the window object in both dist and src files to allow global access.
2026-07-13 12:34:21 +08:00
Meta42 4c7d0aa9fa fix: audio pump starvation on large files with audio (#1041)
Root causes fixed:
1. Remove starvation check that suspends AudioContext — it freezes the
   video clock and causes playback to stall permanently
2. Add backpressure (1s BUFFER_AHEAD) to prevent audio pump from decoding
   unbounded buffers, starving the video decoder
3. Add setTimeout(0) yield between batches so video rAF callbacks can run
4. Batch audio buffer reads (16 per iteration) to reduce IPC overhead
5. Fix latestScheduledEndTime time-domain: use media-time (same domain as
   currentTime) instead of AudioContext-time, so backpressure check works
   correctly after seeking

Without these fixes, playing a large file (9+ GB) with audio causes:
- Audio pump decodes hundreds of buffers in 1 second (195s of audio decoded
  in 1s wall clock)
- Main thread blocked by 177 IPC calls/sec from audio iterator
- Video frames never render (rAF starved)
- After seek: backpressure never triggers due to time-domain mismatch,
  causing persistent stutter and eventual silence
2026-06-07 09:18:04 +08:00
Harvey Zhao fc90d4a0df Merge branch 'master' of https://github.com/zhw2590582/ArtPlayer 2026-05-04 13:23:04 +08:00
Harvey Zhao 26841c5b1c feat: enable fullscreenWeb option in Artplayer configuration
feat: add danmuku plugin and i18n setup documentation

- Introduced a new danmuku plugin with multiple run code options in the documentation.
- Added language settings documentation for i18n, including default languages, import instructions, and examples for adding and modifying languages.
- Implemented input handling for media sources in the artplayer-proxy-mediabunny package, supporting various formats including HLS.
- Created m3u8 control functionalities for managing audio and video quality settings in the player.

Update mediabunny.js
2026-05-04 13:22:32 +08:00
Harvey Zhao d6c1e5d25b Update mediabunny.js 2026-05-04 13:16:56 +08:00
Harvey Zhao 63c8966ed7 feat: add danmuku plugin and i18n setup documentation
- Introduced a new danmuku plugin with multiple run code options in the documentation.
- Added language settings documentation for i18n, including default languages, import instructions, and examples for adding and modifying languages.
- Implemented input handling for media sources in the artplayer-proxy-mediabunny package, supporting various formats including HLS.
- Created m3u8 control functionalities for managing audio and video quality settings in the player.
2026-05-04 13:11:27 +08:00
Harvey Zhao 23c8f46878 feat: add bun installation command to documentation 2026-04-04 10:35:07 +08:00
Harvey Zhao 4b75df286a feat: add CLAUDE.md for project guidance and documentation structure 2026-04-03 23:27:55 +08:00
Harvey Zhao 7e0b84ba7c fix: adjust percentage calculation for current time in setCurrentTime function 2026-04-01 12:49:43 +08:00
Harvey Zhao 6aa6f9ad53 feat: add danmuku plugin documentation and i18n setup guide
- Created a new documentation file for the danmuku plugin with code examples.
- Added a comprehensive guide for language settings (i18n) including default languages, importing languages, adding new languages, and modifying existing languages.
- Included code snippets for initializing the Artplayer with different language settings.

feat: implement safe area insets for improved video rotation handling

feat: add console log for safe area insets in autoOrientation plugin

feat: enhance mobile meta tags for better web app support
2026-04-01 12:24:38 +08:00
Harvey Zhao 4501ec2907 feat: update version to 5.4.0 and add play/pause functionality for comparison videos 2026-03-17 17:27:37 +08:00
Harvey Zhao 6c79148da5 feat: add jassub worker scripts and WASM files for subtitle processing 2026-03-16 21:25:51 +08:00
3716 changed files with 2141039 additions and 65310 deletions

No files matched your search

+54 -1
View File
@@ -1,2 +1,55 @@
* text=auto
*.js text eol=lf
*.js text eol=lf
test/browser/media/hls/*.m3u8 text eol=lf
test/browser/fixtures/hls-grouped.m3u8 text eol=lf
test/browser/media/hls/*.mpegts binary
# Preserve generated XML whitespace and its frozen playback-input hashes.
test/browser/media/dash/*.mpd text eol=lf whitespace=-blank-at-eol
test/browser/media/dash/*.m4s binary
test/browser/media/*.m4a binary
refactor/baselines/core-vendor/*.txt text eol=lf
refactor/baselines/thumbnail-vendor/* text eol=lf whitespace=-blank-at-eof
# Preserve the exact upstream WebVTT reference bytes, including license trailing lines.
refactor/baselines/multiple-subtitles-vendor/* text eol=lf whitespace=-blank-at-eof
# Preserve upstream documentation-site license bytes, including final blank lines.
refactor/baselines/site-vendor/*.txt text eol=lf whitespace=-blank-at-eof
docs/licenses/** text eol=lf whitespace=-blank-at-eof
docs/THIRD_PARTY_NOTICES.md text eol=lf
# Preserve historical Codicons archive notice bytes, including CRLF.
refactor/baselines/site-vendor/codicons-0.0.26/LICENSE* -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/site-vendor/codicons-0.0.26/README.txt -text whitespace=-trailing-space,cr-at-eol
docs/licenses/monaco-editor/codicons/LICENSE* -text whitespace=-trailing-space,cr-at-eol
docs/licenses/monaco-editor/codicons/README.md -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/site-vendor/codicons-0.0.26/ATTRIBUTION.txt text eol=lf
refactor/baselines/site-vendor/vconsole-3.15.0/** text eol=lf whitespace=-blank-at-eof
refactor/baselines/site-vendor/console-original.js text eol=lf
refactor/baselines/site-vendor/console-commonjs/** -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/site-vendor/console-esm/** -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/site-vendor/console-embedded/** -text whitespace=-trailing-space,cr-at-eol
docs/licenses/console/** -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/site-vendor/console-attribution/** -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/site-vendor/console-stackoverflow/** -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/site-vendor/monaco-typescript/** -text whitespace=-trailing-space,cr-at-eol
docs/licenses/monaco-editor/typescript/** -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/site-vendor/monaco-languages/** -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/site-vendor/monaco-language-notices/** -text whitespace=-trailing-space,cr-at-eol
docs/licenses/monaco-editor/language-services/** -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/site-vendor/monaco-modes/** -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/site-vendor/monaco-basic/** -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/monaco-basic-fixtures.json text eol=lf
refactor/baselines/site-vendor/monaco-core-origins/** -text whitespace=-trailing-space,cr-at-eol
docs/licenses/monaco-editor/core-origins/** -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/site-vendor/monaco-core-build/** -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/monaco-core-locales.json text eol=lf
refactor/baselines/site-vendor/monaco-contributions/** -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/site-vendor/monaco-css-build/** -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/site-vendor/monaco-node-path/** -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/site-vendor/monaco-dom/** -text whitespace=-trailing-space,cr-at-eol
docs/licenses/monaco-editor/core-dom/** -text whitespace=-trailing-space,cr-at-eol
docs/licenses/monaco-editor/core-path/** -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/monaco-node-path-fixtures.json text eol=lf
refactor/baselines/site-vendor/monaco-unicode/** -text whitespace=-trailing-space,cr-at-eol
docs/licenses/monaco-editor/core-unicode/** -text whitespace=-trailing-space,cr-at-eol
refactor/baselines/site-vendor/jassub-fonts/** -text whitespace=-trailing-space,cr-at-eol
docs/licenses/jassub-fonts/** -text whitespace=-trailing-space,cr-at-eol
+357 -28
View File
@@ -1,41 +1,370 @@
name: Node CI
on:
pull_request:
push:
branches:
- master
branches: [ master, 'codex/**' ]
workflow_dispatch:
workflow_call:
inputs:
pages-artifact:
description: Prepare the checked docs directory for the separate Pages workflow
type: boolean
default: false
permissions:
contents: read
concurrency:
group: checks-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' || github.event_name == 'push' }}
jobs:
build:
runs-on: ubuntu-latest
coverage:
name: TS coverage (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
node-version: [20.x]
os: [ ubuntu-latest, windows-latest ]
defaults:
run:
shell: bash
env:
CI: true
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
node-version: ${{ matrix.node-version }}
- name: install, lint, build, and test
persist-credentials: false
fetch-depth: 0
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: .node-version
package-manager-cache: false
- name: Record source and cache inputs
id: context
run: node scripts/ci-context.mjs
- name: Cache locked Yarn downloads
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 ref verified 2026-09-13; node24
with:
path: ${{ steps.context.outputs.yarn_cache }}
key: yarn-${{ runner.os }}-${{ runner.arch }}-node-${{ steps.context.outputs.node }}-yarn-${{ steps.context.outputs.yarn }}-${{ github.ref }}-${{ hashFiles('yarn.lock') }}
- name: Install the pinned toolchain and dependencies
run: |
yarn
yarn lint
yarn build:all
env:
CI: true
- name: Deploy to GitHub Pages
if: success()
npm install --global --force yarn@1.22.22 2>&1 | tee refactor/.cache/ci/toolchain-install.log
yarn install --frozen-lockfile --non-interactive 2>&1 | tee refactor/.cache/ci/install.log
yarn check:toolchain --strict
- name: Verify source maps and critical lifecycle coverage
run: yarn test:coverage 2>&1 | tee refactor/.cache/ci/coverage.log
- name: Upload coverage and source-map evidence
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: coverage-${{ matrix.os }}-${{ github.run_id }}-${{ github.run_attempt }}
path: |
refactor/.cache/ci/
refactor/.cache/coverage/latest.json
refactor/.cache/coverage/run-*/
include-hidden-files: true
retention-days: 14
if-no-files-found: warn
browser-consumers:
name: Browser consumers (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 60
env:
CI: true
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
fetch-depth: 0
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: .node-version
package-manager-cache: false
- name: Record source and cache inputs
id: context
run: node scripts/ci-context.mjs
- name: Cache locked Yarn downloads
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 ref verified 2026-09-13; node24
with:
path: ${{ steps.context.outputs.yarn_cache }}
key: yarn-${{ runner.os }}-${{ runner.arch }}-node-${{ steps.context.outputs.node }}-yarn-${{ steps.context.outputs.yarn }}-${{ github.ref }}-${{ hashFiles('yarn.lock') }}
- name: Install the pinned package manager and dependencies
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
git add -f docs
git commit -m 'Deploy to GitHub Pages'
git subtree split --prefix docs master -b gh-pages-temp
git push origin gh-pages-temp:refs/heads/gh-pages --force
npm install --global --force yarn@1.22.22 2>&1 | tee refactor/.cache/ci/toolchain-install.log
yarn install --frozen-lockfile --non-interactive 2>&1 | tee refactor/.cache/ci/install.log
- name: Cache versioned browser downloads
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 ref verified 2026-09-13; node24
with:
path: ${{ steps.context.outputs.browser_cache }}
key: playwright-${{ runner.os }}-${{ runner.arch }}-node-${{ steps.context.outputs.node }}-yarn-${{ steps.context.outputs.yarn }}-${{ github.ref }}-${{ hashFiles('yarn.lock') }}-${{ steps.context.outputs.playwright }}
- name: Install test browsers
run: yarn test:browser:install --with-deps 2>&1 | tee refactor/.cache/ci/browser-install.log
- name: Build and check installed tarballs
run: |
yarn test:package 2>&1 | tee refactor/.cache/ci/package.log
node --input-type=module -e 'import fs from "node:fs"; const { output } = JSON.parse(fs.readFileSync("refactor/.cache/packages/latest.json")); fs.appendFileSync(process.env.GITHUB_ENV, `ARTPLAYER_BROWSER_ARTIFACTS=${output}/browser-artifacts.json\n`);'
- name: Select Node 20 consumer runtime
id: consumer-node-20
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 20.19.0
package-manager-cache: false
- name: Verify Node 20 installed consumers
run: node scripts/package-runtime.mjs --expected-node 20.19.0 2>&1 | tee refactor/.cache/ci/consumer-node-20.log
- name: Select Node 22 consumer runtime
id: consumer-node-22
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22.12.0
package-manager-cache: false
- name: Verify Node 22 installed consumers
run: node scripts/package-runtime.mjs --expected-node 22.12.0 2>&1 | tee refactor/.cache/ci/consumer-node-22.log
- name: Restore canonical runtime for browser tools
id: restore-canonical-node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: .node-version
package-manager-cache: false
- name: Verify canonical installed consumers
run: node scripts/package-runtime.mjs --canonical 2>&1 | tee refactor/.cache/ci/consumer-node-canonical.log
- name: Verify React installed consumers
run: yarn test:react-consumer 2>&1 | tee refactor/.cache/ci/react-consumer.log
- name: Verify Vue installed consumers
run: yarn test:vue-consumer 2>&1 | tee refactor/.cache/ci/vue-consumer.log
- name: Verify iframe cached history and interrupted navigation
run: yarn test:iframe-history 2>&1 | tee refactor/.cache/ci/iframe-history.log
- name: Compare installed performance and verify resource cleanup
run: yarn test:performance 2>&1 | tee refactor/.cache/ci/performance.log
- name: Verify all installed library type contracts
run: yarn test:ecosystem-types 2>&1 | tee refactor/.cache/ci/ecosystem-types.log
- name: Upload browser evidence
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: browser-consumers-${{ matrix.os }}-${{ github.run_id }}-${{ github.run_attempt }}
path: |
refactor/.cache/ci/
refactor/.cache/iframe-history/
refactor/.cache/react-consumer-*/
refactor/.cache/vue-consumer-*/
refactor/.cache/performance/
refactor/.cache/ecosystem-types/
refactor/.cache/*-package-types-*/*.json
refactor/.cache/*-package-types-*/*.log
refactor/.cache/packages/latest.json
refactor/.cache/packages/run-*/*.json
refactor/.cache/packages/run-*/*.log
refactor/.cache/packages/run-*/*.tgz
refactor/.cache/packages/run-*/artifacts/
include-hidden-files: true
retention-days: 14
if-no-files-found: warn
defaults:
run:
shell: bash
strategy:
fail-fast: false
max-parallel: 3
matrix:
os:
- ubuntu-latest
- windows-latest
- macos-latest
browser-smoke:
name: Browser playback (${{ matrix.os }}, ${{ matrix.browser }})
runs-on: ${{ matrix.os }}
timeout-minutes: 60
env:
CI: true
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
fetch-depth: 0
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: .node-version
package-manager-cache: false
- name: Record source and cache inputs
id: context
run: node scripts/ci-context.mjs
- name: Cache locked Yarn downloads
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 ref verified 2026-09-13; node24
with:
path: ${{ steps.context.outputs.yarn_cache }}
key: yarn-${{ runner.os }}-${{ runner.arch }}-node-${{ steps.context.outputs.node }}-yarn-${{ steps.context.outputs.yarn }}-${{ github.ref }}-${{ hashFiles('yarn.lock') }}
- name: Install the pinned package manager and dependencies
run: |
npm install --global --force yarn@1.22.22 2>&1 | tee refactor/.cache/ci/toolchain-install.log
yarn install --frozen-lockfile --non-interactive 2>&1 | tee refactor/.cache/ci/install.log
- name: Cache versioned browser downloads
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 ref verified 2026-09-13; node24
with:
path: ${{ steps.context.outputs.browser_cache }}
key: playwright-${{ runner.os }}-${{ runner.arch }}-node-${{ steps.context.outputs.node }}-yarn-${{ steps.context.outputs.yarn }}-${{ github.ref }}-${{ hashFiles('yarn.lock') }}-${{ steps.context.outputs.playwright }}
- name: Install test browsers
run: yarn test:browser:install --with-deps 2>&1 | tee refactor/.cache/ci/browser-install.log
- name: Prepare installed browser plugin packages
# Each engine builds and freezes its own complete installed browser roster.
# Other ecosystem installation/SDK gates remain tracked by CI-01.
run: |
yarn test:package --browser 2>&1 | tee refactor/.cache/ci/browser-packages.log
node --input-type=module -e 'import fs from "node:fs"; const { output } = JSON.parse(fs.readFileSync("refactor/.cache/packages/latest.json")); fs.appendFileSync(process.env.GITHUB_ENV, `ARTPLAYER_BROWSER_ARTIFACTS=${output}/browser-artifacts.json\n`);'
- name: Run all source browser checks
if: ${{ !cancelled() }}
run: yarn test:browser:source --project=${{ matrix.browser }} 2>&1 | tee refactor/.cache/ci/browser-source.log
- name: Run installed browser checks
if: ${{ !cancelled() }}
run: yarn test:browser:installed --project=${{ matrix.browser }} 2>&1 | tee refactor/.cache/ci/browser-installed.log
- name: Upload browser evidence
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: browser-smoke-${{ matrix.os }}-${{ matrix.browser }}-${{ github.run_id }}-${{ github.run_attempt }}
path: |
refactor/.cache/ci/
refactor/.cache/browser-source/
refactor/.cache/browser-installed/
refactor/.cache/packages/latest.json
refactor/.cache/packages/run-*/*.json
refactor/.cache/packages/run-*/*.log
refactor/.cache/packages/run-*/*.tgz
refactor/.cache/packages/run-*/artifacts/
include-hidden-files: true
retention-days: 14
if-no-files-found: warn
defaults:
run:
shell: bash
strategy:
fail-fast: false
max-parallel: 6
matrix:
browser: [chromium, firefox, webkit]
os:
- ubuntu-latest
- windows-latest
- macos-latest
checks:
name: Checks and build (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 45
env:
CI: true
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
fetch-depth: 0
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: .node-version
package-manager-cache: false
- name: Record source and cache inputs
id: context
run: node scripts/ci-context.mjs
- name: Cache locked Yarn downloads
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 ref verified 2026-09-13; node24
with:
path: ${{ steps.context.outputs.yarn_cache }}
key: yarn-${{ runner.os }}-${{ runner.arch }}-node-${{ steps.context.outputs.node }}-yarn-${{ steps.context.outputs.yarn }}-${{ github.ref }}-${{ hashFiles('yarn.lock') }}
- name: Install the pinned package manager
run: npm install --global --force yarn@1.22.22 2>&1 | tee refactor/.cache/ci/toolchain-install.log
- name: Validate workflow syntax
run: |
curl --fail --silent --show-error --location https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_linux_amd64.tar.gz --output "$RUNNER_TEMP/actionlint.tar.gz"
printf '%s %s\n' '8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8' "$RUNNER_TEMP/actionlint.tar.gz" | sha256sum --check
tar -xzf "$RUNNER_TEMP/actionlint.tar.gz" -C "$RUNNER_TEMP" actionlint
"$RUNNER_TEMP/actionlint" -color
if: matrix.os == 'ubuntu-latest'
- name: Frozen install
run: |
mkdir -p refactor/.cache/ci
yarn install --frozen-lockfile --non-interactive 2>&1 | tee refactor/.cache/ci/install.log
- name: Read-only checks and tests
run: yarn ci:check 2>&1 | tee refactor/.cache/ci/check.log
- name: Build libraries and documentation
run: yarn ci:build 2>&1 | tee refactor/.cache/ci/build.log
- name: Validate and stage Pages paths
id: pages
if: inputs.pages-artifact && github.ref == 'refs/heads/master' && matrix.os == 'ubuntu-latest'
run: yarn prepare:pages 2>&1 | tee refactor/.cache/ci/pages.log
- name: Install staged Pages browser dependencies
if: inputs.pages-artifact && github.ref == 'refs/heads/master' && matrix.os == 'ubuntu-latest'
run: yarn test:browser:install --with-deps 2>&1 | tee refactor/.cache/ci/pages-browser-install.log
- name: Verify staged Pages entrypoints
if: inputs.pages-artifact && github.ref == 'refs/heads/master' && matrix.os == 'ubuntu-latest'
run: yarn test:pages:browser 2>&1 | tee refactor/.cache/ci/pages-browser.log
- name: Record source and tool versions
if: always()
run: |
mkdir -p refactor/.cache/ci
git rev-parse HEAD > refactor/.cache/ci/source.txt
node --version > refactor/.cache/ci/node.txt
yarn --version > refactor/.cache/ci/yarn.txt
sha256sum yarn.lock > refactor/.cache/ci/lock.sha256
git diff --stat > refactor/.cache/ci/generated-diff.txt
- name: Upload available logs
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: checks-${{ matrix.os }}-${{ github.run_id }}-${{ github.run_attempt }}
path: |
refactor/.cache/ci/
refactor/.cache/pages/run-*/report.json
refactor/.cache/pages/run-*/browser.json
include-hidden-files: true
retention-days: 14
if-no-files-found: warn
- name: Prepare Pages artifact
if: inputs.pages-artifact && github.ref == 'refs/heads/master' && matrix.os == 'ubuntu-latest'
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: ${{ steps.pages.outputs.site }}
include-hidden-files: true
strategy:
fail-fast: false
max-parallel: 2
matrix:
os:
- ubuntu-latest
- windows-latest
ci-result:
name: CI result
if: always()
needs:
- checks
- coverage
- browser-smoke
- browser-consumers
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
fetch-depth: 0
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: .node-version
package-manager-cache: false
- name: Require every matrix job to succeed
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ARTPLAYER_CI_NEEDS: ${{ toJSON(needs) }}
run: node scripts/ci-summary.mjs
- name: Upload final status
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ci-result-${{ github.run_id }}-${{ github.run_attempt }}
path: refactor/.cache/ci/
include-hidden-files: true
retention-days: 14
if-no-files-found: warn
+34
View File
@@ -0,0 +1,34 @@
name: Deploy Pages
on:
workflow_dispatch:
permissions:
contents: read
concurrency:
group: pages
cancel-in-progress: false
jobs:
validate:
if: github.ref == 'refs/heads/master' && vars.PAGES_DEPLOY_ENABLED == 'true'
uses: ./.github/workflows/nodejs.yml
with:
pages-artifact: true
deploy:
if: github.ref == 'refs/heads/master' && vars.PAGES_DEPLOY_ENABLED == 'true'
needs: validate
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy the validated artifact
id: deployment
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
+2 -2
View File
@@ -2,6 +2,6 @@
.vscode
.DS_Store
node_modules
package-lock.json
**/package-lock.json
lerna-debug.log
yarn.lock
refactor/.cache/
+1
View File
@@ -0,0 +1 @@
24.21.0
+362
View File
@@ -0,0 +1,362 @@
# AGENTS.md
## Compatibility Refactor
2026-09-16 user scope update: stop autonomous refactor implementation and hand off for
the user's extended self-testing. Read [refactor/self-test-handoff.md](refactor/self-test-handoff.md)
first. Remaining tasks are deferred, not passed; do not resume long tests, new fixes,
full matrices, release preparation, or formal reviews without a new user instruction.
Existing compatibility requirements and future publication gates remain in force.
The compatibility modernization plan is maintained in [refactor/README.md](refactor/README.md).
For refactor work, read its compatibility contract, task plan, and progress log before editing.
Use `refactor/tasks.json` as the task status source and regenerate the readable plan with
`node refactor/scripts/plan.mjs --write`; validate it with `node refactor/scripts/plan.mjs --check`.
Preserve existing public APIs, event behavior, types, DOM/CSS hooks, and distribution entrypoints.
The planned TypeScript migration permits incremental JS/TS coexistence; it does not authorize
changing consumer APIs or treating planned validation as completed validation.
Apply [refactor/quality-contract.md](refactor/quality-contract.md) to every implementation task:
the user authorizes improving unreasonable internals while preserving old public contracts.
Refactor responsibilities and dependencies alongside TypeScript migration, add meaningful
risk-based tests, and update package architecture/maintenance documentation in the same change.
The user requires one separate local Git commit for each completed refactor task.
Include the task ID in the commit subject and include its implementation, tests, documentation,
and status updates together. Verify the commit before starting the next task. Do not bundle
multiple newly completed tasks or include unrelated work. This does not authorize pushing or publishing.
Use Yarn Classic 1.22.22 as packageManager and maintain only the root yarn.lock.
Core public declarations are authored in packages/artplayer/public/ and generated
with yarn build:types into the existing types/ entrypoints. Do not hand-edit the
generated core declarations; yarn check:types is read-only and rejects drift.
Use Node from .node-version; frozen Yarn installs and strict toolchain checks are required.
Bun remains an isolated evaluation and must not replace Yarn without a new user decision.
The user also authorizes installing needed dependencies and adding or improving reasonable
project scripts for the refactor without asking again for routine tooling choices.
Record their purpose and versions, use the appropriate workspace/dependency category, update
the lockfile when applicable, and verify compatibility and reproducible execution.
After implementation and its necessary tests, hand off the results and wait for the
user to guide and start the review phase. Do not automatically begin REVIEW-01/02/03,
including an early first review. Follow [refactor/release-reviews.md](refactor/release-reviews.md):
the three review rounds and closure of blocking findings remain required before candidate publication.
Connected Chrome interaction checks complement committed automated browser tests; neither
connection availability nor mocks replace actual playback or required device evidence.
If Chrome is unavailable, use the Codex in-app browser for supported real-page tests.
The user explicitly authorizes this fallback; record the actual browser/version and limitations.
Do not block ordinary browser checks solely on the Chrome extension connection.
Each review fix remains a separate task and commit. Revalidate changed candidate contents.
The user explicitly includes GitHub CI/CD modernization in this refactor.
Follow [refactor/github-ci-cd.md](refactor/github-ci-cd.md) for PR checks, regression matrices,
artifacts, Pages and npm workflows. Distinguish local configuration from verified remote runs.
The user requires every workspace package to move to its own next major version for this
refactor (M.m.p -> (M+1).0.0). Follow refactor/version-policy.md; independent versions and
old API compatibility remain mandatory. This version policy is not publication authorization.
## Project Summary
ArtPlayer is a monorepo for a modern HTML5 video player and its ecosystem packages.
- Homepage: `https://artplayer.org`
- Local dev site: `http://localhost:8082`
- API docs: `https://artplayer.org/document`
- Packaging model: workspace monorepo with per-package versioning and per-package build output
The repository contains:
- `packages/artplayer`: the core player
- `packages/artplayer-plugin-*`: UI and playback plugins
- `packages/artplayer-proxy-*`: proxy renderers and playback adapters
- `packages/artplayer-tool-*`: helper tools
- `packages/artplayer-vitepress`: docs site package
- `docs/`: local demo site, examples, compiled assets, generated docs
- `scripts/`: custom build/dev/doc tooling
## Working Style For This Repo
- Verify the real implementation before editing docs or examples.
- Prefer changing the source package first, then regenerate build artifacts only when needed.
- Keep package APIs small and consistent with existing ArtPlayer plugin conventions.
- Preserve the existing visual and API style of sibling packages instead of inventing a new pattern.
- When touching demo examples, make sure the example still works in `http://localhost:8082`.
- Do not hand-edit `dist/`, `docs/compiled/`, or `docs/uncompiled/` unless a build step generated them.
- Desktop editor sources live in `packages/artplayer-vitepress/browser/`; `docs/assets/js/common.js`,
`bootstrap.js`, `loader.js`, `mobile.js` and `packages/artplayer-vitepress/docs/public/main.js`
are generated with `yarn build:site-assets`. `editor-libraries.ts` is generated by `yarn build:ts`.
## Primary Commands
Use the repo scripts rather than ad hoc bundler commands.
### Development
```bash
yarn dev
```
Starts the local dev site on port `8082` and interactively selects a package to watch. The selected package is built into:
- `docs/uncompiled/<package>/`
### Production Build
```bash
yarn build
```
Interactive build for one package. Outputs:
- `packages/<name>/dist/*.js|*.legacy.js|*.mjs`
- copied artifacts into `docs/compiled/`
Build all packages:
```bash
yarn build all
```
### Other Project Scripts
```bash
yarn build:i18n
yarn build:ts
yarn build:docs
yarn build:llm
yarn build:test
yarn lint
yarn build:all
```
Notes:
- `yarn lint` is read-only; `yarn lint:fix` explicitly fixes the same source/type/script range.
- `yarn ci:check` runs strict toolchain/plan/lint/tests; `yarn ci:build` generates outputs and checks imports.
- See `refactor/ci-setup.md` for CI and separate Pages deployment; remote activation is tracked separately.
- `yarn build:all` is expensive; use it when a change truly spans builds/docs/types/lint together.
## Useful Local URLs
- Root demo index: `http://localhost:8082`
- Demo by package/example:
- `http://localhost:8082/?libs=./uncompiled/<package>/index.js&example=<example>`
- Docs: `http://localhost:8082/document/`
For proxy/plugin work, prefer validating on the local demo page rather than reasoning only from source.
## Repository Layout
### Core package
- `packages/artplayer/src/index.ts`: player entry
- `packages/artplayer/src/player/`: playback mixins and player-facing behavior
- `packages/artplayer/src/control/`: bottom controls
- `packages/artplayer/src/setting/`: settings panel
- `packages/artplayer/src/contextmenu/`: context menu items
- `packages/artplayer/src/plugins/`: built-in plugins
- `packages/artplayer/src/utils/`: shared helpers, component base classes, DOM utilities
- `packages/artplayer/public/`: public TypeScript declaration sources
- `packages/artplayer/types/`: generated public declarations and compatibility documentation
### Ecosystem packages
Migrated ecosystem packages follow this pattern:
```text
packages/<package>/
src/index.ts
src/*.ts # internal modules; see the package maintenance map
src/*.less # optional
types/*.d.ts # public compatibility declarations
ARCHITECTURE.md # maintenance map, or a maintenance section in README.md
README.md
package.json
dist/*
```
Read the package maintenance map before changing module ownership. Some packages
also expose accurate types through `/runtime`, with `.d.mts`/`.d.cts` declarations.
Do not replace historical root declarations with internal implementation types;
follow [the approved type policy](refactor/type-compatibility-policy.md) and each
package's recorded compatibility decisions. Check package.json for exact exports.
### Demo and docs assets
- `docs/assets/example/*.js`: runnable browser examples
- `docs/assets/ts/*.js`: TypeScript demo assets targeted by lint/docs flows
- `docs/uncompiled/`: dev output
- `docs/compiled/`: production-copied output
- `docs/document/`: generated docs content
## Architecture Notes
### Core player
ArtPlayer composes many subsystems during construction. Common integration points:
- `art.template`
- `art.events`
- `art.controls`
- `art.setting`
- `art.contextmenu`
- `art.layers`
- `art.plugins`
- `art.player`
When extending behavior, prefer integrating with these existing systems rather than bypassing them.
### Control and setting components
Controls and setting entries are managed through component registries.
Relevant implementation:
- `packages/artplayer/src/control/index.ts`
- `packages/artplayer/src/setting/index.ts`
- `packages/artplayer/src/utils/component.ts`
Important behavior:
- `art.controls.update(...)` and `art.setting.update(...)` replace existing entries by `name`
- `art.controls.remove(name)` and `art.setting.remove(name)` are the correct cleanup APIs
- selector-style controls rely on `default` flags to determine highlighted items
If a plugin conditionally shows UI, it must also clean that UI up when the condition no longer holds.
### Plugin shape
Standard plugin/export shape:
```js
export default function somePlugin(option = {}) {
return (art) => {
return {
name: 'somePlugin',
}
}
}
```
Naming conventions:
- package: `artplayer-plugin-<name>`
- global: `artplayerPlugin<Name>`
- exported function name should match the global naming convention
### Proxy packages
Proxy packages usually return a non-video element or video-like shim and emulate media element behavior for ArtPlayer.
Examples:
- `packages/artplayer-proxy-canvas`
- `packages/artplayer-proxy-mediabunny`
When editing proxy packages:
- keep the HTMLMediaElement-like surface coherent
- keep event ordering stable
- treat `loadedmetadata`, `loadeddata`, `canplay`, `seeked`, `waiting`, and `pause/play` semantics carefully
- ensure UI state is updated and cleaned up when source topology changes
### HLS / adaptive playback controls
The reference implementation for adaptive selector UI is:
- `packages/artplayer-plugin-hls-control/src/index.ts`
- `packages/artplayer-plugin-dash-control/src/index.ts` (SDK 4.x/5.x capability adapter)
If adding HLS-like quality/audio selection elsewhere:
- follow the selector format used there
- derive highlighted items from actual current tracks, not only from mode flags
- avoid stale selectors when changing to streams without the same topology
## Build and Artifact Rules
- Always edit source first: core runtime in `src/`, core declarations in `public/`;
other packages retain `types/` until their own declaration source migration.
- Rebuild package artifacts after source changes that should ship.
- Do not treat `dist/` as source of truth.
- If a change affects demo behavior, also verify the matching file in `docs/assets/example/`.
For package-specific builds, the normal flow is:
1. `yarn dev` and pick the package for fast local iteration
2. validate in `http://localhost:8082`
3. `yarn build` and pick the package when ready to update shippable artifacts
## Documentation Expectations
If a public package API changes, check whether these also need updates:
- the package `README.md`
- `docs/assets/example/<name>.js`
- `types/<name>.d.ts`
- any generated compiled outputs if you built the package
Keep examples realistic and runnable. Prefer local demo URLs or stable public sample streams.
## Code Quality Expectations
- Follow the existing TypeScript style for migrated production modules and the
existing JavaScript style for tests, launchers and documented legacy exceptions.
- Use ASCII unless a file already requires otherwise.
- Match the minimal-comment style of neighboring files.
- Avoid unnecessary abstraction; this codebase generally prefers direct implementation.
- Respect current browser targets:
- modern build: `es2020`
- legacy build: `es2015`
## Validation Checklist
For most package changes, validate as many of these as apply:
- source file lint passes
- local demo page loads
- expected events fire once and in the correct order
- controls/settings render correctly
- cleanup works after restart, source switch, or destroy
- package build succeeds
For playback/proxy changes specifically:
- test initial load
- test play/pause
- test seek
- test switching source or track topology
- test whether UI reflects the actual selected track/quality
## Notes Specific To `artplayer-proxy-mediabunny`
This package now depends on modern `mediabunny` and supports HLS through `mediabunny` input handling.
Files to understand first:
- `packages/artplayer-proxy-mediabunny/ARCHITECTURE.md`
- `packages/artplayer-proxy-mediabunny/src/index.ts`
- `packages/artplayer-proxy-mediabunny/src/VideoShim.ts`
- `packages/artplayer-proxy-mediabunny/src/MediaBunnyEngine.ts`
- `packages/artplayer-proxy-mediabunny/src/input.ts`
- `packages/artplayer-proxy-mediabunny/src/m3u8.ts`
Key expectations:
- HLS source detection should happen in `input.ts`
- track selection should use actual pairable audio/video relationships
- selector UI should mirror the behavior of `artplayer-plugin-hls-control`
- selector cleanup is required when a later source no longer supports the same controls
- avoid duplicate readiness events during load and track switches
For sustained playback, use `yarn test:mediabunny-soak` with explicit artifacts and
media; see [the long-test procedure](refactor/changes/2026-09-16-PKG-MB-09-hour-soak.md).
It shares port 8084 with ordinary browser tests. Do not start another browser
server or change the measured source, artifacts or media during a live run.
Use its live process handle and per-case progress samples to check progress;
an old report or a start snapshot does not prove current execution or completion.
## When Unsure
Start with the nearest sibling implementation instead of inventing a new pattern:
- control/setting UI: `artplayer-plugin-hls-control`, `artplayer-plugin-dash-control`
- proxy behavior: `artplayer-proxy-canvas`, `artplayer-proxy-mediabunny`
- component lifecycle: `packages/artplayer/src/utils/component.ts`
If a change spans source, examples, and packaging, make all three consistent in the same pass.
+2
View File
@@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
## [Unreleased]
- Fix safe area issue when enter web fullscreen [#1033](https://github.com/zhw2590582/ArtPlayer/issues/1033)
## [5.4.0] - 2026-03-12
- Refactor `Parcel` to `Vite`
+202
View File
@@ -0,0 +1,202 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
ArtPlayer.js is a modern, full-featured HTML5 video player. It's organized as a monorepo using Lerna with independent versioning.
- **Homepage**: https://artplayer.org
- **Online Editor**: https://artplayer.org (for testing examples)
- **API Docs**: https://artplayer.org/document
## Repository Structure
```
packages/
artplayer/ # Core player package
artplayer-plugin-*/ # 17+ plugins (danmuku, ads, chromecast, etc.)
artplayer-proxy-*/ # Canvas, Mediabunny proxies
artplayer-tool-*/ # iframe, thumbnail tools
artplayer-vitepress/ # Documentation site
docs/ # Documentation and demo site
assets/ # Example assets and TypeScript demos
compiled/ # Built packages output
document/ # Generated API documentation
uncompiled/ # Development build output
test/ # Browser test files
scripts/ # Build tooling
build.js # Production build
dev.js # Development server
build-i18n.js # I18n bundle builder
build-docs.js # Documentation generator
build-llm.js # LLMs.txt generator
plugin/create.js # New plugin scaffolding
```
## Common Commands
### Development
```bash
# Start dev server on port 8082 with hot reload
npm run dev
# Build for production (interactive prompt to select package)
npm run build
# Build all packages
npm run build all
# Build everything (packages, i18n, types, docs) + lint
npm run build:all
```
### Code Quality
```bash
# Lint with auto-fix (covers packages, scripts, tests, docs assets)
npm run lint
```
### Plugin Development
```bash
# Create new plugin from template
npm run create:plugin <kebab-case-name>
# Example:
npm run create:plugin my-feature
```
### I18n
```bash
# Build i18n bundles for all languages
npm run build:i18n
```
### TypeScript
```bash
# Generate TypeScript declaration files
npm run build:ts
```
## Architecture
### Core Player (`packages/artplayer`)
The main `Artplayer` class extends `Emitter` and initializes sub-components:
```javascript
// Key components instantiated in constructor:
this.template = new Template(this) // DOM structure
this.events = new Events(this) // Event handling
this.player = new Player(this) // Video playback
this.controls = new Control(this) // Control bar
this.layers = new Layer(this) // Custom layers
this.contextmenu = new Contextmenu(this)
this.subtitle = new Subtitle(this)
this.setting = new Setting(this)
this.plugins = new Plugins(this) // Plugin manager
// ... and more
```
Source organization in `src/`:
- `config/` - Default configuration values
- `control/` - UI controls (play, progress, volume, etc.)
- `events/` - Event handling (click, hover, resize, etc.)
- `i18n/` - Localization files
- `icons/` - SVG icons
- `player/` - Video playback logic (hls, flv, dash, etc.)
- `plugins/` - Built-in plugins
- `setting/` - Settings panel components
- `style/` - LESS stylesheets
- `template.js` - HTML template generation
- `utils/` - Utility functions
### Plugin Architecture
Plugins are functions that receive the player instance and options:
```javascript
// Template from scripts/plugin/template/src/index.js
export default function artplayerPluginTemplate(option = {}) {
return (art) => {
// Plugin initialization
// Access: art.player, art.controls, art.template, etc.
return {
name: 'artplayerPluginTemplate',
// Expose methods to art.plugins['artplayerPluginTemplate']
}
}
}
```
Plugin naming convention:
- Package: `artplayer-plugin-<name>`
- Global variable: `artplayerPlugin<Name>` (camelCase)
- Exported function uses same name as global
### Styling
Uses LESS with inline imports:
```javascript
import style from './style/index.less?inline'
```
Styles are injected at runtime via `utils.setStyleText()`.
### Build System
Uses Vite via custom Node.js scripts:
**Development** (`scripts/dev.js`):
- Builds IIFE bundle to `docs/uncompiled/<package>/`
- Serves `docs/` directory on port 8082
- Watches source files for changes
**Production** (`scripts/build.js`):
- Builds 3 formats: UMD (`.js`), UMD legacy (`.legacy.js`), ESM (`.mjs`)
- Outputs to `packages/<name>/dist/`
- Copies to `docs/compiled/`
### I18n System
Language files in `packages/artplayer/src/i18n/`:
- Base language: `zh-cn.js`
- Additional languages: `en.js`, `fr.js`, etc.
- Built as separate UMD/ESM bundles via `build-i18n.js`
- Global naming: `artplayerI18n<Language>` (e.g., `artplayerI18nEn`)
### Creating New Plugins
The `npm run create:plugin <name>` command:
1. Copies `scripts/plugin/template/` to `packages/artplayer-plugin-<name>/`
2. Replaces placeholders in filenames and content
3. Creates example file at `docs/assets/example/<name>.js`
Plugin template structure:
```
src/
index.js # Main plugin code
style.less # Plugin styles
package.json
README.md
types/
<name>.d.ts # TypeScript declarations (optional)
```
### Utility Functions
Core utilities in `packages/artplayer/src/utils/`:
- `utils.js` - Common helpers (isMobile, isSafari, query, etc.)
- `emitter.js` - Event emitter base class
- `scheme.js` - Option validation schema
## Development Notes
- **Package manager**: Uses Yarn with Lerna
- **Node version**: >= 20.0.0
- **ESLint**: Uses @antfu/eslint-config
- **Browser support**: Last 1 Chrome version (ES2020), legacy builds target ES2015
- **UMD builds**: Always expose global even in AMD/RequireJS environments
+14 -2
View File
@@ -63,6 +63,18 @@ Or install with `yarn`:
$ yarn add artplayer
```
Or install with `pnpm`:
```bash
$ pnpm add artplayer
```
Or install with `bun`:
```bash
$ bun add artplayer
```
```js
import Artplayer from 'artplayer'
```
@@ -104,7 +116,7 @@ let art = new Artplayer({
| :--- | :--- | :--- |
| [artplayer-plugin-danmuku](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-danmuku/index.js&example=danmuku) | Danmuku (bullet comment) system | <img src="https://img.shields.io/npm/v/artplayer-plugin-danmuku.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-danmuku.svg?sanitize=true"> |
| [artplayer-plugin-hls-control](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.5.17/hls.min.js%0A./uncompiled/artplayer-plugin-hls-control/index.js&example=hls.control) | HLS quality control | <img src="https://img.shields.io/npm/v/artplayer-plugin-hls-control.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-hls-control.svg?sanitize=true"> |
| [artplayer-plugin-dash-control](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/dashjs/4.5.2/dash.all.min.js%0A./uncompiled/artplayer-plugin-dash-control/index.js&example=dash.control) | DASH quality control | <img src="https://img.shields.io/npm/v/artplayer-plugin-dash-control.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-dash-control.svg?sanitize=true"> |
| [artplayer-plugin-dash-control](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/dashjs/5.2.1/modern/umd/dash.all.min.js%0A./uncompiled/artplayer-plugin-dash-control/index.js&example=dash.control) | DASH quality control | <img src="https://img.shields.io/npm/v/artplayer-plugin-dash-control.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-dash-control.svg?sanitize=true"> |
| [artplayer-plugin-vtt-thumbnail](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-vtt-thumbnail/index.js&example=vtt.thumbnail) | VTT thumbnail preview | <img src="https://img.shields.io/npm/v/artplayer-plugin-vtt-thumbnail.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-vtt-thumbnail.svg?sanitize=true"> |
| [artplayer-plugin-multiple-subtitles](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-multiple-subtitles/index.js&example=multiple.subtitles) | Multiple subtitles support | <img src="https://img.shields.io/npm/v/artplayer-plugin-multiple-subtitles.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-multiple-subtitles.svg?sanitize=true"> |
| [artplayer-plugin-chromecast](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-chromecast/index.js&example=chromecast) | Google Chromecast support | <img src="https://img.shields.io/npm/v/artplayer-plugin-chromecast.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-chromecast.svg?sanitize=true"> |
@@ -124,7 +136,7 @@ let art = new Artplayer({
| Name | Describe | State |
| :--- | :--- | :--- |
| [hls.js](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.5.17/hls.min.js&example=hls) | HLS client | <img src="https://img.shields.io/npm/v/hls.js.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/hls.js.svg?sanitize=true"> |
| [dash.js](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/dashjs/4.5.2/dash.all.min.js&example=dash) | MPEG DASH player | <img src="https://img.shields.io/npm/v/dashjs.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/dashjs.svg?sanitize=true"> |
| [dash.js](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/dashjs/5.2.1/modern/umd/dash.all.min.js&example=dash) | MPEG DASH player | <img src="https://img.shields.io/npm/v/dashjs.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/dashjs.svg?sanitize=true"> |
| [flv.js](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/flv.js/1.6.2/flv.min.js&example=flv) | HTML5 FLV Player | <img src="https://img.shields.io/npm/v/flv.js.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/flv.js.svg?sanitize=true"> |
| [mpegts.js](https://artplayer.org/?libs=https://cdn.jsdelivr.net/npm/mpegts.js@1.7.3/dist/mpegts.min.js&example=mpegts) | MPEG-TS/FLV Player | <img src="https://img.shields.io/npm/v/mpegts.js.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/mpegts.js.svg?sanitize=true"> |
| [webtorrent.js](https://artplayer.org/?libs=https://cdn.jsdelivr.net/npm/webtorrent@1/webtorrent.min.js&example=webtorrent) | Streaming torrent client | <img src="https://img.shields.io/npm/v/webtorrent.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/webtorrent.svg?sanitize=true"> |
+1 -1
View File
@@ -1 +1 @@
artplayer.org
github.artplayer.org
+420
View File
@@ -0,0 +1,420 @@
# Verified site component notices
Frozen source identities and complete upstream notice texts for selected site components and font references. Unresolved font/media and embedded provenance gates remain open; this inventory is not publication clearance.
Generated by yarn build:site-notices. Runtime asset URLs are retained; reviewed local patches are identified below.
## vconsole 3.15.0
Source: https://registry.npmjs.org/vconsole/-/vconsole-3.15.0.tgz
The original 3.15.0 LICENSE is preserved unchanged; its missing MIT body is supplemented separately using the MIT text explicitly referenced by upstream. Exact reconstruction from the pinned source and lockfile establishes eight bundled package dependencies and webpack bootstrap; their complete notices and attribution are distributed below. ArtPlayer retains its reproducible lifecycle patch and the original script URL/UMD/CSS contracts.
Included component: @babel/runtime 7.17.9
Source: https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz
Included component: core-js 3.21.1
Source: https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz
Included component: copy-text-to-clipboard 3.0.1
Source: https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.0.1.tgz
Included component: mutation-observer 1.0.3
Source: https://registry.npmjs.org/mutation-observer/-/mutation-observer-1.0.3.tgz
Included component: svelte 3.47.0
Source: https://registry.npmjs.org/svelte/-/svelte-3.47.0.tgz
Included component: regenerator-runtime 0.13.9
Source: https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz
Included component: style-loader 3.3.1
Source: https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz
Included component: css-loader 6.7.1
Source: https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz
Included component: webpack 5.72.0
Source: https://registry.npmjs.org/webpack/-/webpack-5.72.0.tgz
- licenses/vconsole/LICENSE
- licenses/vconsole/babel-runtime/LICENSE
- licenses/vconsole/core-js/LICENSE
- licenses/vconsole/copy-text-to-clipboard/LICENSE
- licenses/vconsole/mutation-observer/LICENSE
- licenses/vconsole/svelte/LICENSE
- licenses/vconsole/regenerator-runtime/LICENSE
- licenses/vconsole/style-loader/LICENSE
- licenses/vconsole/css-loader/LICENSE
- licenses/vconsole/webpack/LICENSE
- licenses/vconsole/MIT-LICENSE
- licenses/vconsole/ATTRIBUTION.md
## monaco-editor 0.30.1
Source: https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.30.1.tgz
The complete upstream Monaco LICENSE/ThirdPartyNotices are retained. The unmodified bundled Codicons font exactly matches @vscode/codicons 0.0.26; its historical README, CC BY 4.0 content license, MIT code license and added attribution are distributed below. Other site assets remain subject to their separate provenance reviews.
Included component: @vscode/codicons 0.0.26
Source: https://registry.npmjs.org/@vscode/codicons/-/codicons-0.0.26.tgz
Included component: typescript (Monaco worker) 4.4.4
Source: https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz
Included component: jsonc-parser 3.0.0
Source: https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz
Included component: vscode-css-languageservice 5.1.8
Source: https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-5.1.8.tgz
Included component: vscode-html-languageservice 4.1.1
Source: https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-4.1.1.tgz
Included component: vscode-json-languageservice 4.1.9
Source: https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.1.9.tgz
Included component: vscode-languageserver-textdocument 1.0.2
Source: https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.2.tgz
Included component: vscode-languageserver-types 3.16.0
Source: https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz
Included component: vscode-uri 3.0.2
Source: https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.2.tgz
Included component: js-beautify (Monaco HTML embedded) embedded sources in vscode-html-languageservice 4.1.1
Source: https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-4.1.1.tgz
Included component: glob-to-regexp (Monaco JSON fork) embedded source in vscode-json-languageservice 4.1.9
Source: https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.1.9.tgz
Included component: dompurify (Monaco core) 2.3.1
Source: https://registry.npmjs.org/dompurify/-/dompurify-2.3.1.tgz
Included component: marked (Monaco core) 3.0.2
Source: https://registry.npmjs.org/marked/-/marked-3.0.2.tgz
Included component: nodejs path (Monaco core) 14.16.0
Source: https://github.com/nodejs/node/blob/bd60e93357a118204ea238d94e7a9e4209d93062/lib/path.js
Included component: WinJS-derived DOM helpers (Monaco core) unversioned adaptation; reference WinJS 4.4.5
Source: https://github.com/winjs/winjs/tree/4329b1133b243d9ded3b5a1f98d096ee8e80e889
Included component: Unicode data (Monaco core) mixed historical inputs: 10.0.0d5, 13.0 drafts, Emoji 13.1
Source: https://github.com/alexdima/unicode-utils
- licenses/monaco-editor/LICENSE
- licenses/monaco-editor/ThirdPartyNotices.txt
- licenses/monaco-editor/codicons/LICENSE
- licenses/monaco-editor/codicons/LICENSE-CODE
- licenses/monaco-editor/codicons/README.md
- licenses/monaco-editor/codicons/ATTRIBUTION.md
- licenses/monaco-editor/typescript/LICENSE.txt
- licenses/monaco-editor/typescript/CopyrightNotice.txt
- licenses/monaco-editor/typescript/ThirdPartyNoticeText.txt
- licenses/monaco-editor/typescript/ATTRIBUTION.md
- licenses/monaco-editor/language-services/jsonc-parser/LICENSE.md
- licenses/monaco-editor/language-services/vscode-css-languageservice/LICENSE.md
- licenses/monaco-editor/language-services/vscode-html-languageservice/LICENSE.md
- licenses/monaco-editor/language-services/vscode-html-languageservice/thirdpartynotices.txt
- licenses/monaco-editor/language-services/vscode-json-languageservice/LICENSE.md
- licenses/monaco-editor/language-services/vscode-languageserver-textdocument/License.txt
- licenses/monaco-editor/language-services/vscode-languageserver-textdocument/thirdpartynotices.txt
- licenses/monaco-editor/language-services/vscode-languageserver-types/License.txt
- licenses/monaco-editor/language-services/vscode-uri/LICENSE.md
- licenses/monaco-editor/language-services/beautify-css-NOTICE.txt
- licenses/monaco-editor/language-services/beautify-html-NOTICE.txt
- licenses/monaco-editor/language-services/ATTRIBUTION.md
- licenses/monaco-editor/core-origins/DOMPurify-LICENSE
- licenses/monaco-editor/core-origins/marked-LICENSE
- licenses/monaco-editor/core-origins/marked-vscode-license.txt
- licenses/monaco-editor/core-origins/ATTRIBUTION.md
- licenses/monaco-editor/core-path/ATTRIBUTION.md
- licenses/monaco-editor/core-dom/LICENSE.txt
- licenses/monaco-editor/core-dom/ATTRIBUTION.md
- licenses/monaco-editor/core-unicode/LICENSE.txt
- licenses/monaco-editor/core-unicode/ATTRIBUTION.md
## console legacy-vendor-with-TS-adapter
Source: https://github.com/zhw2590582/ArtPlayer/blob/5d6b2f22bc75213ac97cff0bcffa4a1ce2bc786c/docs/assets/js/console.js
The 100 third-party Parcel modules and loader have exact source reproduction. The two owned adapter modules are built from TypeScript. Preserved notices also cover two embedded license headers, all 17 react-inspector external source-map members, and all seven HTML tokenizer sources from its fixed Git dependency. The identified embedded-source and attribution review is complete for this frozen vendor boundary. Source records bind each component to its original notices; this inventory is not publication clearance. The original full lockfile and historical online Closure service are not recovered. Modified replicator and Emotion/Stylis copies retain upstream author licenses; the original Emotion online Closure stage is not claimed to be reproducible. MurmurHash credits include Gary Court and Austin Appleby. The customStringify snippet matches Stack Overflow answer revision 5 under CC BY-SA 4.0; its separate attribution, source and full license are supplied. This is a mixed-license bundle, not MIT-only.
Included component: console-feed 3.2.2
Source: https://registry.npmjs.org/console-feed/-/console-feed-3.2.2.tgz
Included component: react 17.0.2
Source: https://registry.npmjs.org/react/-/react-17.0.2.tgz
Included component: react-dom 17.0.2
Source: https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz
Included component: scheduler 0.20.2
Source: https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz
Included component: object-assign 4.1.1
Source: https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz
Included component: react-is 16.13.1
Source: https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz
Included component: prop-types 15.7.2
Source: https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz
Included component: shallowequal 1.1.0
Source: https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz
Included component: process 0.11.10
Source: https://registry.npmjs.org/process/-/process-0.11.10.tgz
Included component: hoist-non-react-statics 3.3.2
Source: https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz
Included component: is-dom 1.1.0
Source: https://registry.npmjs.org/is-dom/-/is-dom-1.1.0.tgz
Included component: is-object 1.0.2
Source: https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz
Included component: is-window 1.0.2
Source: https://registry.npmjs.org/is-window/-/is-window-1.0.2.tgz
Included component: linkifyjs 2.1.9
Source: https://registry.npmjs.org/linkifyjs/-/linkifyjs-2.1.9.tgz
Included component: @emotion/core 10.3.0
Source: https://registry.npmjs.org/@emotion/core/-/core-10.3.0.tgz
Included component: @emotion/css 10.0.27
Source: https://registry.npmjs.org/@emotion/css/-/css-10.0.27.tgz
Included component: @emotion/cache 10.0.29
Source: https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz
Included component: @emotion/styled 10.0.27
Source: https://registry.npmjs.org/@emotion/styled/-/styled-10.0.27.tgz
Included component: @emotion/styled-base 10.3.0
Source: https://registry.npmjs.org/@emotion/styled-base/-/styled-base-10.3.0.tgz
Included component: emotion-theming 10.3.0
Source: https://registry.npmjs.org/emotion-theming/-/emotion-theming-10.3.0.tgz
Included component: styled-components 5.3.3
Source: https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz
Included component: @babel/runtime 7.16.3
Source: https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz
Included component: @emotion/sheet 0.9.4
Source: https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz
Included component: @emotion/stylis 0.8.5
Source: https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz
Included component: @emotion/weak-memoize 0.2.5
Source: https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz
Included component: @emotion/utils 0.11.3
Source: https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz
Included component: @emotion/hash 0.8.0
Source: https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz
Included component: @emotion/unitless 0.7.5
Source: https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz
Included component: @emotion/memoize 0.7.4
Source: https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz
Included component: @emotion/serialize 0.11.16
Source: https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz
Included component: @emotion/is-prop-valid 0.8.8
Source: https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz
Included component: react-inspector 5.1.1
Source: https://registry.npmjs.org/react-inspector/-/react-inspector-5.1.1.tgz
Included component: parcel-bundler 1.12.5
Source: https://registry.npmjs.org/parcel-bundler/-/parcel-bundler-1.12.5.tgz
Included component: chromium-string-utils embedded in console-feed-3.2.2
Source: https://registry.npmjs.org/console-feed/-/console-feed-3.2.2.tgz
Included component: stylis-rule-sheet embedded in styled-components-5.3.3
Source: https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz
Included component: @babel/runtime (react-inspector embedded) 7.13.10
Source: https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz
Included component: regenerator-runtime 0.13.7
Source: https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz
Included component: simple-html-tokenizer git-04799f4638ec5ed903a4e5aa6e832269fa59be6b
Source: https://api.github.com/repos/nfrasser/simple-html-tokenizer/tarball/04799f4638ec5ed903a4e5aa6e832269fa59be6b
Included component: replicator (console-feed fork) modified; upstream 1.0.x license
Source: https://registry.npmjs.org/replicator/-/replicator-1.0.1.tgz
Included component: stylis (Emotion fork) 3.5.4-derived
Source: https://registry.npmjs.org/stylis/-/stylis-3.5.4.tgz
Included component: murmurhash-js (Gary Court) license commit 23dc2e7
Source: https://github.com/garycourt/murmurhash-js/blob/23dc2e7008582ca3ef69d8623f02bba4c8dd05e5/README.md
Included component: murmurhash2 (Austin Appleby) 61a0530
Source: https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash2.cpp
Included component: stackoverflow-custom-stringify answer 48254637 revision 5 (CC BY-SA 4.0)
Source: https://api.stackexchange.com/2.3/revisions/8FD5F52A-B16F-4C66-AB48-830EABB36CC0?site=stackoverflow&filter=withbody
Included component: react-pure-render (shallowequal origin) source commit 729cdbd
Source: https://github.com/gaearon/react-pure-render/blob/729cdbd51df00068816376544738cc1fc4720cf2/LICENSE
- licenses/console/console-feed/console-feed-3.2.2-LICENSE
- licenses/console/react/react-17.0.2-LICENSE
- licenses/console/react-dom/react-dom-17.0.2-LICENSE
- licenses/console/scheduler/scheduler-0.20.2-LICENSE
- licenses/console/object-assign/object-assign-4.1.1-license
- licenses/console/react-is/react-is-16.13.1-LICENSE
- licenses/console/prop-types/prop-types-15.7.2-LICENSE
- licenses/console/shallowequal/shallowequal-1.1.0-LICENSE
- licenses/console/process/process-0.11.10-LICENSE
- licenses/console/hoist-non-react-statics/hoist-non-react-statics-3.3.2-LICENSE.md
- licenses/console/is-dom/is-dom-1.1.0-LICENSE
- licenses/console/is-object/is-object-1.0.2-LICENSE
- licenses/console/is-window/is-window-1.0.2-LICENSE
- licenses/console/linkifyjs/linkifyjs-2.1.9-LICENSE
- licenses/console/emotion-core/emotion-core-10.3.0-LICENSE
- licenses/console/emotion-css/emotion-css-10.0.27-LICENSE
- licenses/console/emotion-cache/emotion-cache-10.0.29-LICENSE
- licenses/console/emotion-styled/emotion-styled-10.0.27-LICENSE
- licenses/console/emotion-styled-base/emotion-styled-base-10.3.0-LICENSE
- licenses/console/emotion-theming/emotion-theming-10.3.0-LICENSE
- licenses/console/styled-components/styled-components-5.3.3-UPSTREAM-LICENSE
- licenses/console/babel-runtime/babel-runtime-7.16.3-LICENSE
- licenses/console/emotion-sheet/emotion-sheet-0.9.4-LICENSE
- licenses/console/emotion-stylis/emotion-stylis-0.8.5-LICENSE
- licenses/console/emotion-weak-memoize/emotion-weak-memoize-0.2.5-LICENSE
- licenses/console/emotion-utils/emotion-utils-0.11.3-LICENSE
- licenses/console/emotion-hash/emotion-hash-0.8.0-LICENSE
- licenses/console/emotion-unitless/emotion-unitless-0.7.5-LICENSE
- licenses/console/emotion-memoize/emotion-memoize-0.7.4-LICENSE
- licenses/console/emotion-serialize/emotion-serialize-0.11.16-LICENSE
- licenses/console/emotion-is-prop-valid/emotion-is-prop-valid-0.8.8-LICENSE
- licenses/console/react-inspector/react-inspector-5.1.1-LICENSE
- licenses/console/parcel-bundler/parcel-bundler-1.12.5-LICENSE
- licenses/console/chromium-string-utils/LICENSE
- licenses/console/stylis-rule-sheet/LICENSE
- licenses/console/react-inspector-babel/LICENSE
- licenses/console/regenerator-runtime/LICENSE
- licenses/console/simple-html-tokenizer/LICENSE
- licenses/console/replicator/LICENSE
- licenses/console/stylis/LICENSE
- licenses/console/murmurhash-js/README.md
- licenses/console/murmurhash2/PUBLIC-DOMAIN.txt
- licenses/console/stackoverflow/LICENSE
- licenses/console/stackoverflow/SOURCE.js
- licenses/console/stackoverflow/ATTRIBUTION.md
- licenses/console/react-pure-render/LICENSE
- licenses/console/react-pure-render/ATTRIBUTION.md
## jassub-fonts selected historical references
Source: https://github.com/ThaUnknown/jassub/tree/25d1ea7ca1f827dbed2c8ea539c9bc917ccbfab1
Four selected font families only. CHAWP matches author bytes; other full notice references have explicit font-table differences. Other fonts and complete redistribution provenance remain open under SITE-07/VENDOR-05.
Included component: Liberation Sans 2.00.5 reference
Source: https://github.com/liberationfonts/liberation-fonts/files/2926169/liberation-fonts-ttf-2.00.5.tar.gz
Included component: Averia Sans Libre Light 1.002 reference
Source: https://github.com/google/fonts/blob/0f81bc90462b862dbfe3d16403ff284a68473833/ofl/averiasanslibre/AveriaSansLibre-Light.ttf
Included component: Lato Regular 2.015 reference
Source: https://github.com/google/fonts/blob/f3b885d5590e307e02542f1a724cec55d567fdaa/ofl/lato/Lato-Regular.ttf
Included component: CHAWP 1.000 exact bytes
Source: https://github.com/awp/chawp/blob/3c4f6317bebd6783c8d0db3bc9206aa62d602f90/chawp.otf
- licenses/jassub-fonts/liberation/OFL.txt
- licenses/jassub-fonts/averia-sans/OFL.txt
- licenses/jassub-fonts/lato/OFL.txt
- licenses/jassub-fonts/chawp/OFL.txt
- licenses/jassub-fonts/ATTRIBUTION.md
+68
View File
@@ -0,0 +1,68 @@
/* global Artplayer, artplayerPluginAsr */
// Local audio capture demo. The subtitles below are simulated, not recognized speech.
// No audio is uploaded; only the sample media is loaded from this local site.
const statistics = document.createElement('div')
statistics.textContent = 'Local ASR demo: press play. No recognition service is used.'
let chunks = 0
let pcmBytes = 0
let wavBytes = 0
const art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/steve-jobs.mp4',
autoSize: true,
fullscreen: true,
fullscreenWeb: true,
layers: [{
name: 'asr-local-statistics',
html: statistics,
style: {
position: 'absolute',
top: '12px',
left: '12px',
right: '12px',
padding: '8px 12px',
background: 'rgba(0, 0, 0, 0.65)',
color: '#fff',
fontSize: '12px',
whiteSpace: 'pre-line',
pointerEvents: 'none',
},
}],
controls: [{
name: 'asr-local-stop',
position: 'right',
html: 'Stop ASR',
tooltip: 'Stop capture; pause and play to restart',
async click() {
await art.plugins.artplayerPluginAsr.stop()
if (!art.isDestroy)
statistics.textContent = 'Local capture stopped. Pause and play to restart. Nothing was uploaded.'
},
}],
plugins: [artplayerPluginAsr({
length: 2,
interval: 250,
sampleRate: 16000,
autoHideTimeout: 5000,
onAudioChunk({ pcm, wav }) {
if (art.isDestroy)
return
chunks++
pcmBytes += pcm.byteLength
wavBytes += wav.byteLength
const sampleRate = new DataView(wav).getUint32(24, true)
const samples = new DataView(pcm)
let peak = 0
for (let offset = 0; offset < pcm.byteLength; offset += 2)
peak = Math.max(peak, Math.abs(samples.getInt16(offset, true)))
const duration = (pcmBytes / 2 / sampleRate).toFixed(2)
statistics.textContent = [
'Local capture only - simulated subtitles, no speech recognition',
`Chunks: ${chunks} | ${sampleRate} Hz mono PCM16 | ${duration} seconds captured`,
`PCM: ${pcmBytes} bytes | WAV: ${wavBytes} bytes | Current peak: ${peak}`,
].join('\n')
return `Simulated local subtitle: audio chunk ${chunks} received.`
},
})],
})
+3
View File
@@ -20,6 +20,9 @@ const art = new Artplayer({
miniProgressBar: true,
autoPlayback: true,
autoOrientation: true,
subtitle: {
url: '/assets/sample/subtitle.srt',
},
thumbnails: {
url: '/assets/sample/thumbnails.png',
number: 60,
+44 -32
View File
@@ -4,45 +4,55 @@
// import dashjs from 'dashjs';
// import artplayerPluginDashControl from 'artplayer-plugin-dash-control';
const useDash = dashjs.supportsMediaSource()
let dash
function destroyDash() {
const previous = dash
dash = undefined
if (previous)
previous.destroy()
}
const art = new Artplayer({
container: '.artplayer-app',
url: 'https://media.axprod.net/TestVectors/v7-Clear/Manifest_1080p.mpd',
setting: true,
plugins: [
artplayerPluginDashControl({
quality: {
// Show qualitys in control
control: true,
// Show qualitys in setting
setting: true,
// Get the quality name from level
getName: level => `${level.height}P`,
// I18n
title: 'Quality',
auto: 'Auto',
},
audio: {
// Show audios in control
control: true,
// Show audios in setting
setting: true,
// Get the audio name from track
getName: track => track.lang.toUpperCase(),
// I18n
title: 'Audio',
auto: 'Auto',
},
}),
],
plugins: useDash
? [
artplayerPluginDashControl({
quality: {
// Show quality choices in the controls
control: true,
// Show quality choices in settings
setting: true,
// Get the quality name from level
getName: level => `${level.height}P`,
// I18n
title: 'Quality',
auto: 'Auto',
},
audio: {
// Show audios in control
control: true,
// Show audios in setting
setting: true,
// Get the audio name from track
getName: track => track.lang?.toUpperCase() || String(track.id ?? 'Audio'),
// I18n
title: 'Audio',
auto: 'Auto',
},
}),
]
: [],
customType: {
mpd: function playMpd(video, url, art) {
if (dashjs.supportsMediaSource()) {
if (art.dash)
art.dash.destroy()
const dash = dashjs.MediaPlayer().create()
dash.initialize(video, url, art.option.autoplay)
destroyDash()
if (useDash) {
dash = dashjs.MediaPlayer().create()
art.dash = dash
art.on('destroy', () => dash.destroy())
dash.initialize(video, url, art.option.autoplay)
}
else {
art.notice.show = 'Unsupported playback format: mpd'
@@ -50,3 +60,5 @@ const art = new Artplayer({
},
},
})
art.on('destroy', destroyDash)
+44 -32
View File
@@ -4,46 +4,56 @@
// import Hls from 'hls.js';
// import artplayerPluginHlsControl from 'artplayer-plugin-hls-control';
const useHls = Hls.isSupported()
let hls
function destroyHls() {
const previous = hls
hls = undefined
if (previous)
previous.destroy()
}
const art = new Artplayer({
container: '.artplayer-app',
url: 'https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8',
setting: true,
plugins: [
artplayerPluginHlsControl({
quality: {
// Show qualitys in control
control: true,
// Show qualitys in setting
setting: true,
// Get the quality name from level
getName: level => `${level.height}P`,
// I18n
title: 'Quality',
auto: 'Auto',
},
audio: {
// Show audios in control
control: true,
// Show audios in setting
setting: true,
// Get the audio name from track
getName: track => track.name,
// I18n
title: 'Audio',
auto: 'Auto',
},
}),
],
plugins: useHls
? [
artplayerPluginHlsControl({
quality: {
// Show quality choices in the controls
control: true,
// Show quality choices in settings
setting: true,
// Get the quality name from level
getName: level => `${level.height}P`,
// I18n
title: 'Quality',
auto: 'Auto',
},
audio: {
// Show audios in control
control: true,
// Show audios in setting
setting: true,
// Get the audio name from track
getName: track => track.name || track.lang || 'Audio',
// I18n
title: 'Audio',
auto: 'Auto',
},
}),
]
: [],
customType: {
m3u8: function playM3u8(video, url, art) {
if (Hls.isSupported()) {
if (art.hls)
art.hls.destroy()
const hls = new Hls()
destroyHls()
if (useHls) {
hls = new Hls()
art.hls = hls
hls.loadSource(url)
hls.attachMedia(video)
art.hls = hls
art.on('destroy', () => hls.destroy())
}
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = url
@@ -54,3 +64,5 @@ const art = new Artplayer({
},
},
})
art.on('destroy', destroyHls)
+8
View File
@@ -15,6 +15,11 @@ const iframe = new ArtplayerToolIframe({
url: '/iframe.html',
})
window.addEventListener('artplayer:example:cleanup', () => {
iframe.destroy()
$iframe.remove()
}, { once: true })
iframe.message(({ type, data }) => {
switch (type) {
case 'fullscreenWeb':
@@ -44,4 +49,7 @@ iframe.commit(() => {
data: state,
})
})
}).catch((error) => {
if (!iframe.destroyed)
console.error(error)
})
+30 -20
View File
@@ -2,24 +2,34 @@
// import artplayerProxyMediabunny from 'artplayer-proxy-mediabunny';
const art = new Artplayer({
container: '.artplayer-app',
url: 'https://artplayer.org/assets/sample/frag_bunny.mp4',
autoSize: true,
screenshot: true,
setting: true,
loop: true,
flip: true,
playbackRate: true,
fullscreen: true,
fullscreenWeb: true,
miniProgressBar: true,
autoPlayback: true,
autoOrientation: true,
thumbnails: {
url: '/assets/sample/frag_bunny.png',
number: 60,
column: 10,
scale: 0.85,
container: '.artplayer-app',
url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
autoSize: true,
setting: true,
loop: true,
flip: true,
playbackRate: true,
fullscreen: true,
fullscreenWeb: true,
miniProgressBar: true,
autoPlayback: true,
autoOrientation: true,
proxy: artplayerProxyMediabunny({
m3u8: {
quality: {
control: true,
setting: true,
getName: level => level.height ? `${level.height}P` : level.name,
title: 'Quality',
auto: 'Auto',
},
audio: {
control: true,
setting: true,
getName: track => track.name || track.language,
title: 'Audio',
auto: 'Auto',
},
},
proxy: artplayerProxyMediabunny(),
})
}),
})
+42
View File
@@ -0,0 +1,42 @@
// Generated by yarn build:site-assets. Do not edit.
"use strict";
(() => {
// packages/artplayer-vitepress/browser/editor-preferences.ts
function readPreference(key, storage = () => localStorage) {
try {
return storage().getItem(key) === "true";
} catch {
return false;
}
}
// packages/artplayer-vitepress/browser/bootstrap.ts
function loadScript(url) {
return new Promise((resolve, reject) => {
const script = document.createElement("script");
const clear = () => {
script.onload = null;
script.onerror = null;
};
script.onload = () => {
clear();
resolve();
};
script.onerror = () => {
clear();
script.remove();
reject(new Error(`Editor bootstrap failed: ${url}`));
};
script.src = url;
document.body.appendChild(script);
});
}
async function bootstrap() {
await loadScript(
readPreference("prod") ? "./compiled/artplayer.js" : "./uncompiled/artplayer/index.js"
);
await loadScript("./assets/js/vs/loader.js");
await loadScript("./assets/js/common.js");
}
void bootstrap().catch((error) => console.error(error));
})();
+402 -295
View File
@@ -1,312 +1,419 @@
(function () {
Artplayer.DEBUG = true
if (Artplayer.utils.isMobile) {
window.location.href = `./mobile.html${location.search}`
// Generated by yarn build:site-assets. Do not edit.
"use strict";
(() => {
// packages/artplayer-vitepress/browser/editor-files.ts
function readEditorFile(file, signal, createReader = () => new FileReader()) {
return new Promise((resolve, reject) => {
const reader = createReader();
function clear() {
reader.onload = null;
reader.onerror = null;
reader.onabort = null;
signal.removeEventListener("abort", cancel);
}
function fail(error) {
clear();
reject(error);
}
function cancel() {
reader.abort();
fail(new Error(`File import cancelled: ${file.name}`));
}
reader.onload = () => {
if (typeof reader.result !== "string") {
fail(new Error(`File is not text: ${file.name}`));
return;
}
const value = reader.result;
clear();
resolve(value);
};
reader.onerror = () => fail(reader.error || new Error(`Reading file failed: ${file.name}`));
reader.onabort = () => fail(new Error(`File import cancelled: ${file.name}`));
signal.addEventListener("abort", cancel, { once: true });
try {
if (signal.aborted)
cancel();
else reader.readAsText(file);
} catch (error) {
fail(error);
}
});
}
let $codeMirror = document.querySelector('.codeMirrorWrap')
let $lib = document.querySelector('.libsInput')
let $run = document.querySelector('.run')
let $popups = document.querySelector('.popups')
let $console = document.querySelector('.console')
let $prod = document.querySelector('#prod')
let $ts = document.querySelector('#ts')
let $code = document.querySelector('#code')
let $log = document.querySelector('#log')
let $file = document.querySelector('#file')
let $editor = document.querySelector('#editor')
window.consoleLog($console)
// Helper functions for localStorage
const getStorageBoolean = (key) => localStorage.getItem(key) === 'true'
const setStorageBoolean = (key, value) => localStorage.setItem(key, value ? 'true' : 'false')
$prod.checked = getStorageBoolean('prod')
$ts.checked = getStorageBoolean('ts')
$code.checked = getStorageBoolean('code')
$log.checked = getStorageBoolean('log')
if ($code.checked) {
$editor.style.display = 'none'
}
if ($log.checked) {
$console.style.display = 'none'
}
let editor = null
let loadedLibs = []
require.config({ paths: { vs: './assets/js/vs' } })
require(['vs/editor/editor.main'], async () => {
monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
noSemanticValidation: true,
noSyntaxValidation: false,
})
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
target: monaco.languages.typescript.ScriptTarget.ES6,
allowNonTsExtensions: true,
})
let libUris = [
'./assets/ts/artplayer-plugin-ads.d.ts',
'./assets/ts/artplayer-plugin-ambilight.d.ts',
'./assets/ts/artplayer-plugin-asr.d.ts',
'./assets/ts/artplayer-plugin-audio-track.d.ts',
'./assets/ts/artplayer-plugin-auto-thumbnail.d.ts',
'./assets/ts/artplayer-plugin-chapter.d.ts',
'./assets/ts/artplayer-plugin-chromecast.d.ts',
'./assets/ts/artplayer-plugin-danmuku-mask.d.ts',
'./assets/ts/artplayer-plugin-danmuku.d.ts',
'./assets/ts/artplayer-plugin-dash-control.d.ts',
'./assets/ts/artplayer-plugin-document-pip.d.ts',
'./assets/ts/artplayer-plugin-hls-control.d.ts',
'./assets/ts/artplayer-plugin-jassub.d.ts',
'./assets/ts/artplayer-plugin-multiple-subtitles.d.ts',
'./assets/ts/artplayer-plugin-vast.d.ts',
'./assets/ts/artplayer-plugin-vtt-thumbnail.d.ts',
'./assets/ts/artplayer-proxy-canvas.d.ts',
'./assets/ts/artplayer-proxy-mediabunny.d.ts',
'./assets/ts/artplayer-tool-iframe.d.ts',
'./assets/ts/artplayer.d.ts',
]
for (let index = 0; index < libUris.length; index++) {
let libUri = libUris[index]
let libSource = await (await fetch(libUri)).text()
monaco.languages.typescript.javascriptDefaults.addExtraLib(libSource, libUri)
monaco.editor.createModel(libSource, 'typescript', monaco.Uri.parse(libUri))
}
const disposable = monaco.editor.onDidCreateEditor(() => {
disposable.dispose()
setTimeout(initApp, 1000)
})
editor = monaco.editor.create($codeMirror, {
theme: 'vs-dark',
folding: true,
automaticLayout: true,
quickSuggestions: {
other: true,
comments: true,
strings: true,
function createFileImports(document, label) {
const controller = new AbortController();
const elements = [];
let queue = Promise.resolve();
return {
add(files) {
const work = queue.then(async () => {
for (const file of files) {
const name = file.name.toLowerCase().trim();
if (!name.endsWith(".js") && !name.endsWith(".css"))
continue;
const text = await readEditorFile(file, controller.signal);
if (controller.signal.aborted)
return;
const element = document.createElement(
name.endsWith(".css") ? "style" : "script"
);
element.textContent = text;
document.body.appendChild(element);
elements.push(element);
label(name);
}
});
queue = work.catch(() => {
});
return work;
},
model: monaco.editor.createModel(
dispose() {
controller.abort();
for (const element of elements) element.remove();
elements.length = 0;
}
};
}
// packages/artplayer-vitepress/browser/editor-libraries.ts
var libUris = [
"./assets/ts/artplayer-plugin-ads.d.ts",
"./assets/ts/artplayer-plugin-ambilight.d.ts",
"./assets/ts/artplayer-plugin-asr.d.ts",
"./assets/ts/artplayer-plugin-audio-track.d.ts",
"./assets/ts/artplayer-plugin-auto-thumbnail.d.ts",
"./assets/ts/artplayer-plugin-chapter.d.ts",
"./assets/ts/artplayer-plugin-chromecast.d.ts",
"./assets/ts/artplayer-plugin-danmuku-mask.d.ts",
"./assets/ts/artplayer-plugin-danmuku.d.ts",
"./assets/ts/artplayer-plugin-dash-control.d.ts",
"./assets/ts/artplayer-plugin-document-pip.d.ts",
"./assets/ts/artplayer-plugin-hls-control.d.ts",
"./assets/ts/artplayer-plugin-jassub.d.ts",
"./assets/ts/artplayer-plugin-multiple-subtitles.d.ts",
"./assets/ts/artplayer-plugin-vast.d.ts",
"./assets/ts/artplayer-plugin-vtt-thumbnail.d.ts",
"./assets/ts/artplayer-proxy-canvas.d.ts",
"./assets/ts/artplayer-proxy-mediabunny.d.ts",
"./assets/ts/artplayer-tool-iframe.d.ts",
"./assets/ts/artplayer-tool-thumbnail.d.ts",
"./assets/ts/artplayer.d.ts",
"./assets/ts/artplayer-i18n.d.ts"
];
// packages/artplayer-vitepress/browser/editor-monaco.ts
async function createMonaco(host, container, typescript, signal) {
host.require.config({ paths: { vs: "./assets/js/vs" } });
await new Promise(
(resolve, reject) => host.require(["vs/editor/editor.main"], resolve, reject)
);
await new Promise(
(resolve, reject) => host.require(
[
'var art = new Artplayer({',
'\tcontainer: \'.artplayer-app\',',
'\turl: \'/assets/sample/video.mp4\',',
'});',
].join('\n'),
$ts.checked ? 'typescript' : 'javascript',
),
})
})
function getURLParameters(url) {
return (url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce((params, pair) => {
const index = pair.indexOf('=')
params[pair.slice(0, index)] = pair.slice(index + 1)
return params
}, {})
}
function getExt(url) {
if (url.includes('?')) {
return getExt(url.split('?')[0])
}
if (url.includes('#')) {
return getExt(url.split('#')[0])
}
return url.trim().toLowerCase().split('.').pop()
}
function loadScript(url) {
return new Promise((resolve, reject) => {
const originalDefine = window.define
window.define = undefined
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = url
script.onload = () => {
window.define = originalDefine
resolve(url)
"vs/basic-languages/typescript/typescript",
"vs/basic-languages/javascript/javascript",
"vs/language/typescript/tsMode"
],
resolve,
reject
)
);
if (signal.aborted)
throw new Error("Editor initialization cancelled");
const api = host.monaco;
const types = api.languages.typescript;
const resources = [];
const temporary = /* @__PURE__ */ new Set();
let editor;
let disposed = false;
const dispose = () => {
if (disposed)
return;
disposed = true;
signal.removeEventListener("abort", dispose);
editor?.dispose();
editor = void 0;
for (const model of temporary) model.dispose();
temporary.clear();
for (const resource of resources.splice(0).reverse()) resource.dispose();
};
signal.addEventListener("abort", dispose, { once: true });
try {
for (const defaults of [
types.javascriptDefaults,
types.typescriptDefaults
]) {
defaults.setDiagnosticsOptions({
noSemanticValidation: defaults === types.javascriptDefaults,
noSyntaxValidation: false
});
defaults.setCompilerOptions({
target: types.ScriptTarget.ES2015,
module: types.ModuleKind.None,
allowNonTsExtensions: true,
noEmit: false
});
}
script.onerror = () => {
window.define = originalDefine
reject(new Error(`Loading script failed: ${url}`))
for (const uri of libUris) {
const response = await host.fetch(uri, { signal });
if (!response.ok) {
throw new Error(
`Loading editor declaration failed: ${uri} (${response.status})`
);
}
const source = await response.text();
if (signal.aborted)
throw new Error("Editor initialization cancelled");
resources.push(
types.javascriptDefaults.addExtraLib(source, uri),
types.typescriptDefaults.addExtraLib(source, uri)
);
resources.push(
api.editor.createModel(source, "typescript", api.Uri.parse(uri))
);
}
document.head.appendChild(script)
})
const model = api.editor.createModel(
"var art = new Artplayer({\n container: '.artplayer-app',\n url: '/assets/sample/video.mp4',\n});",
typescript ? "typescript" : "javascript"
);
resources.push(model);
editor = api.editor.create(container, {
theme: "vs-dark",
folding: true,
automaticLayout: true,
quickSuggestions: { other: true, comments: true, strings: true },
model
});
return {
editor,
async compile(source) {
if (disposed)
throw new Error("Editor was disposed");
if (!typescript)
return source;
const model2 = api.editor.createModel(source, "typescript");
temporary.add(model2);
try {
const worker = await (await types.getTypeScriptWorker())(model2.uri);
const file = model2.uri.toString();
const syntax = await worker.getSyntacticDiagnostics(file);
if (syntax.length) {
throw new Error(
`TypeScript syntax error: ${syntax.map((item) => typeof item.messageText === "string" ? item.messageText : item.messageText.messageText).join("; ")}`
);
}
const output = await worker.getEmitOutput(file);
const script = output.outputFiles.find(
(file2) => file2.name.endsWith(".js")
);
if (output.emitSkipped || !script)
throw new Error("TypeScript worker did not emit JavaScript");
return script.text;
} finally {
temporary.delete(model2);
if (!model2.isDisposed())
model2.dispose();
}
},
dispose
};
} catch (error) {
dispose();
throw error;
}
}
function loadStyle(url) {
return new Promise((resolve, reject) => {
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = url
link.onload = () => resolve(url)
link.onerror = () => reject(new Error(`Loading style failed: ${url}`))
document.head.appendChild(link)
})
// packages/artplayer-vitepress/browser/editor-preferences.ts
function readPreference(key, storage = () => localStorage) {
try {
return storage().getItem(key) === "true";
} catch {
return false;
}
}
function writePreference(key, value, storage = () => localStorage) {
try {
storage().setItem(key, value ? "true" : "false");
return true;
} catch {
return false;
}
}
function loadLib(libs) {
const libPromises = []
const libsDecoded = decodeURIComponent(libs || '')
const urls = libsDecoded
.split(/\r?\n/)
.filter((url) => url.trim() && !loadedLibs.includes(url))
urls.forEach((url) => {
const ext = getExt(url)
if (ext === 'js') {
libPromises.push(loadScript(url))
} else if (ext === 'css') {
libPromises.push(loadStyle(url))
// packages/artplayer-vitepress/browser/editor-session.ts
function createEditorSession(options) {
let generation = 0;
let disposed = false;
return {
async run({
libs = "",
code,
example
}) {
const current = ++generation;
const active = () => !disposed && current === generation;
if (!active())
return;
await options.loadLibraries(libs);
if (!active())
return;
const source = example ? await options.exampleSource(example) : code ? decodeURIComponent(code).trim() : await options.exampleSource("index");
if (!active())
return;
options.writeCode(source);
const executable = await options.compile(source);
if (active())
options.execute(executable);
},
dispose() {
disposed = true;
generation++;
}
})
$lib.value = libsDecoded
return Promise.all(libPromises)
};
}
function executeClassic(code) {
new Function(code)();
}
function runExample(name) {
fetch(`./assets/example/${name}.js`)
.then((response) => {
return response.text()
})
.then((text) => {
editor.setValue(text)
runCode()
})
.catch((err) => {
console.error(err)
})
}
function loadCode(code, example) {
if (example) {
runExample(example)
// packages/artplayer-vitepress/browser/editor.ts
async function installEditor(host) {
const document = host.document;
const element = (selector) => {
const node = document.querySelector(selector);
if (!node)
throw new Error(`Missing editor element: ${selector}`);
return node;
};
host.Artplayer.DEBUG = true;
if (host.Artplayer.utils.isMobile) {
host.location.href = `./mobile.html${host.location.search}`;
return;
}
else if (code) {
editor.setValue(decodeURIComponent(code).trim())
runCode()
const run = element(".run");
const libs = element(".libsInput");
const file = element("#file");
const popup = element(".popups");
const output = element(".console");
host.consoleLog(output);
const controller = new AbortController();
const cleanups = [];
cleanups.push(() => {
host.consoleLog.unmount?.(output);
});
const listen = (target, type, callback) => {
target.addEventListener(type, callback);
cleanups.push(() => target.removeEventListener(type, callback));
};
const report = (error) => {
if (!controller.signal.aborted)
host.console.error(error);
};
listen(host, "error", (event) => host.console.error(event));
listen(host, "unhandledrejection", (event) => host.console.error(event));
for (const key of ["prod", "ts", "code", "log"]) {
const checkbox = element(`#${key}`);
checkbox.checked = readPreference(key, () => host.localStorage);
listen(checkbox, "change", () => {
if (writePreference(key, checkbox.checked, () => host.localStorage)) {
host.location.reload();
} else {
checkbox.checked = readPreference(key, () => host.localStorage);
report(
new Error("Browser storage is unavailable; preference was not saved")
);
}
});
}
else {
runExample('index')
}
}
function runCode() {
// Destroy all existing instances
Artplayer.instances.forEach((art) => art.destroy(true))
const value = editor.getValue()
eval(value)
window.art = Artplayer.instances[0]
}
function initApp() {
const urlParams = getURLParameters(window.location.href)
const { code, libs, example } = urlParams
loadLib(libs)
.then((result) => {
loadedLibs.push(...result)
loadCode(code, example)
})
.catch((err) => {
console.error('Failed to initialize app:', err)
})
}
function restart() {
const libs = encodeURIComponent($lib.value)
const code = encodeURIComponent(editor.getValue())
const url = `${window.location.origin}${window.location.pathname}?libs=${libs}&code=${code}`
history.pushState(null, null, url)
initApp()
}
function readFile(file) {
return new Promise((resolve) => {
const reader = new FileReader()
reader.onload = () => resolve(reader.result)
reader.readAsText(file)
})
}
$run.addEventListener('click', () => {
restart()
})
$popups.addEventListener('click', function (event) {
if (event.target === this) {
this.style.display = 'none'
}
})
$prod.addEventListener('change', () => {
setStorageBoolean('prod', $prod.checked)
window.location.reload()
})
$ts.addEventListener('change', () => {
setStorageBoolean('ts', $ts.checked)
window.location.reload()
})
$code.addEventListener('change', () => {
setStorageBoolean('code', $code.checked)
window.location.reload()
})
$log.addEventListener('change', () => {
setStorageBoolean('log', $log.checked)
window.location.reload()
})
$file.addEventListener('change', async () => {
for (let index = 0; index < $file.files.length; index++) {
const file = $file.files[index]
const name = file.name.toLowerCase().trim()
if (name.endsWith('.css')) {
const text = await readFile(file)
const $style = document.createElement('style')
$style.textContent = text
document.body.appendChild($style)
$lib.value = `\n[${name}]`
$lib.value = $lib.value.trim()
if (element("#code").checked)
element("#editor").style.display = "none";
if (element("#log").checked)
output.style.display = "none";
const imports = createFileImports(document, (name) => {
libs.value = `[${name}]`;
});
cleanups.push(() => imports.dispose());
cleanups.push(() => {
host.dispatchEvent(new Event("artplayer:example:cleanup"));
for (const art of host.Artplayer.instances.slice()) {
try {
art.destroy(true);
} catch (error) {
host.console.error(error);
}
}
if (name.endsWith('.js')) {
const text = await readFile(file)
const $script = document.createElement('script')
$script.textContent = text
document.body.appendChild($script)
$lib.value = `\n[${name}]`
$lib.value = $lib.value.trim()
host.art = void 0;
});
listen(file, "change", () => {
void imports.add(Array.from(file.files || [])).catch(report);
});
listen(popup, "click", (event) => {
if (event.target === popup)
popup.style.display = "none";
});
const onPageHide = (event) => {
if (event.persisted)
return;
controller.abort();
for (const cleanup of cleanups.reverse()) {
try {
cleanup();
} catch (error) {
host.console.error(error);
}
}
};
host.addEventListener("pagehide", onPageHide);
cleanups.push(() => host.removeEventListener("pagehide", onPageHide));
run.setAttribute("aria-disabled", "true");
try {
let restart2 = function() {
const code = encodeURIComponent(monaco.editor.getValue());
const dependencies = encodeURIComponent(libs.value);
host.history.pushState(
null,
"",
`${host.location.origin}${host.location.pathname}?libs=${dependencies}&code=${code}`
);
void session.run({ libs: dependencies, code }).catch(report);
};
var restart = restart2;
const monaco = await createMonaco(
host,
element(".codeMirrorWrap"),
element("#ts").checked,
controller.signal
);
const session = createEditorSession({
loadLibraries: (encoded) => {
libs.value = decodeURIComponent(encoded);
return host.ArtplayerDocsLoader.loadLibraries(encoded);
},
exampleSource: (name) => host.ArtplayerDocsLoader.exampleSource(name),
writeCode: (code) => monaco.editor.setValue(code),
compile: monaco.compile,
execute: (code) => {
host.dispatchEvent(new Event("artplayer:example:cleanup"));
for (const art of host.Artplayer.instances.slice()) art.destroy(true);
executeClassic(code);
host.art = host.Artplayer.instances[0];
}
});
cleanups.push(() => session.dispose(), monaco.dispose);
listen(run, "click", restart2);
listen(document, "keydown", (event) => {
const key = event;
if ((key.ctrlKey || key.metaKey) && key.key === "s") {
key.preventDefault();
restart2();
}
});
run.removeAttribute("aria-disabled");
await session.run(host.ArtplayerDocsLoader.parameters(host.location.href));
} catch (error) {
report(error);
}
})
window.addEventListener('error', (err) => {
console.error(err)
})
window.addEventListener('unhandledrejection', (err) => {
console.error(err)
})
document.addEventListener('keydown', (event) => {
if ((event.ctrlKey || event.metaKey) && event.key === 's') {
event.preventDefault()
restart()
}
})
})()
}
void installEditor(window).catch(
(error) => console.error(error)
);
})();
+42 -3
View File
@@ -202,8 +202,47 @@ var t,e,n=module.exports={};function r(){throw new Error("setTimeout has not bee
var process = require("process");
var e=require("process");Object.defineProperty(exports,"__esModule",{value:!0}),exports.StyleSheetContext=exports.StyleSheetConsumer=exports.ServerStyleSheet=void 0,exports.StyleSheetManager=fe,exports.ThemeContext=exports.ThemeConsumer=void 0,exports.ThemeProvider=Fe,exports.__PRIVATE__=void 0,exports.createGlobalStyle=We,exports.css=we,exports.default=void 0,exports.isStyledComponent=S,exports.keyframes=$e,exports.withTheme=exports.version=exports.useTheme=void 0;var t=require("react-is"),r=c(require("react")),n=u(require("shallowequal")),o=u(require("@emotion/stylis")),i=u(require("@emotion/unitless")),s=u(require("@emotion/is-prop-valid")),a=u(require("hoist-non-react-statics"));function u(e){return e&&e.__esModule?e:{default:e}}function l(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,r=new WeakMap;return(l=function(e){return e?r:t})(e)}function c(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var r=l(t);if(r&&r.has(e))return r.get(e);var n={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if("default"!==i&&Object.prototype.hasOwnProperty.call(e,i)){var s=o?Object.getOwnPropertyDescriptor(e,i):null;s&&(s.get||s.set)?Object.defineProperty(n,i,s):n[i]=e[i]}return n.default=e,r&&r.set(e,n),n}function f(e){return(f="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function h(){return(h=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e}).apply(this,arguments)}var d=function(e,t){for(var r=[e[0]],n=0,o=t.length;n<o;n+=1)r.push(t[n],e[n+1]);return r},p=function(e){return null!==e&&"object"==f(e)&&"[object Object]"===(e.toString?e.toString():Object.prototype.toString.call(e))&&!(0,t.typeOf)(e)},v=Object.freeze([]),g=Object.freeze({});function m(e){return"function"==typeof e}function y(e){return e.displayName||e.name||"Component"}function S(e){return e&&"string"==typeof e.styledComponentId}var b="data-styled",w="5.3.3",x="undefined"!=typeof window&&"HTMLElement"in window,C=Boolean("boolean"==typeof SC_DISABLE_SPEEDY&&SC_DISABLE_SPEEDY),I={},A={};function P(){for(var e=arguments.length<=0?void 0:arguments[0],t=[],r=1,n=arguments.length;r<n;r+=1)t.push(r<0||arguments.length<=r?void 0:arguments[r]);return t.forEach(function(t){e=e.replace(/%[a-z]/,t)}),e}function j(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n<t;n++)r[n-1]=arguments[n];throw new Error("An error occurred. See https://git.io/JUIaE#"+e+" for more information."+(r.length>0?" Args: "+r.join(", "):""))}exports.version=w;var R=function(){function e(e){this.groupSizes=new Uint32Array(512),this.length=512,this.tag=e}var t=e.prototype;return t.indexOfGroup=function(e){for(var t=0,r=0;r<e;r++)t+=this.groupSizes[r];return t},t.insertRules=function(e,t){if(e>=this.groupSizes.length){for(var r=this.groupSizes,n=r.length,o=n;e>=o;)(o<<=1)<0&&j(16,""+e);this.groupSizes=new Uint32Array(o),this.groupSizes.set(r),this.length=o;for(var i=n;i<o;i++)this.groupSizes[i]=0}for(var s=this.indexOfGroup(e+1),a=0,u=t.length;a<u;a++)this.tag.insertRule(s,t[a])&&(this.groupSizes[e]++,s++)},t.clearGroup=function(e){if(e<this.length){var t=this.groupSizes[e],r=this.indexOfGroup(e),n=r+t;this.groupSizes[e]=0;for(var o=r;o<n;o++)this.tag.deleteRule(r)}},t.getGroup=function(e){var t="";if(e>=this.length||0===this.groupSizes[e])return t;for(var r=this.groupSizes[e],n=this.indexOfGroup(e),o=n+r,i=n;i<o;i++)t+=this.tag.getRule(i)+"/*!sc*/\n";return t},e}(),_=new Map,O=new Map,N=1,E=function(e){if(_.has(e))return _.get(e);for(;O.has(N);)N++;var t=N++;return _.set(e,t),O.set(t,e),t},T=function(e){return O.get(e)},k=function(e,t){t>=N&&(N=t+1),_.set(e,t),O.set(t,e)},M="style["+b+'][data-styled-version="5.3.3"]',z=new RegExp("^"+b+'\\.g(\\d+)\\[id="([\\w\\d-]+)"\\].*?"([^"]*)'),F=function(e,t,r){for(var n,o=r.split(","),i=0,s=o.length;i<s;i++)(n=o[i])&&e.registerName(t,n)},q=function(e,t){for(var r=(t.textContent||"").split("/*!sc*/\n"),n=[],o=0,i=r.length;o<i;o++){var s=r[o].trim();if(s){var a=s.match(z);if(a){var u=0|parseInt(a[1],10),l=a[2];0!==u&&(k(l,u),F(e,l,a[3]),e.getTag().insertRules(u,n)),n.length=0}else n.push(s)}}},G=function(){return"undefined"!=typeof window&&void 0!==window.__webpack_nonce__?window.__webpack_nonce__:null},B=function(e){var t=document.head,r=e||t,n=document.createElement("style"),o=function(e){for(var t=e.childNodes,r=t.length;r>=0;r--){var n=t[r];if(n&&1===n.nodeType&&n.hasAttribute(b))return n}}(r),i=void 0!==o?o.nextSibling:null;n.setAttribute(b,"active"),n.setAttribute("data-styled-version","5.3.3");var s=G();return s&&n.setAttribute("nonce",s),r.insertBefore(n,i),n},D=function(){function e(e){var t=this.element=B(e);t.appendChild(document.createTextNode("")),this.sheet=functionLine truncated
},{"react-is":"H1RQ","react":"n8MK","shallowequal":"NKxe","@emotion/stylis":"uxSu","@emotion/unitless":"qy56","@emotion/is-prop-valid":"m5O0","hoist-non-react-statics":"LCQI","process":"KIG8"}],"W5CS":[function(require,module,exports) {
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var e,t=r(require("react")),n=require("console-feed"),o=r(require("styled-components"));function r(e){return e&&e.__esModule?e:{default:e}}function l(e){return(l="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e){return s(e)||u(e)||a(e)||c()}function c(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function a(e,t){if(e){if("string"==typeof e)return f(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?f(e,t):void 0}}function u(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}function s(e){if(Array.isArray(e))return f(e)}function f(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,o=new Array(t);n<t;n++)o[n]=e[n];return o}function d(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function p(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}function y(e,t,n){return t&&p(e.prototype,t),n&&p(e,n),e}function h(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&m(e,t)}function m(e,t){return(m=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}function v(e){var t=w();return function(){var n,o=E(e);if(t){var r=E(this).constructor;n=Reflect.construct(o,arguments,r)}else n=o.apply(this,arguments);return b(this,n)}}function b(e,t){if(t&&("object"===l(t)||"function"==typeof t))return t;if(void 0!==t)throw new TypeError("Derived constructors may only return object or undefined");return g(e)}function g(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function w(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}function E(e){return(E=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function O(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}var j=o.default.div(e||(e=O(["\n position: relative;\n height: 100%;\n display: flex;\n flex-direction: column;\n background-color: #242424;\n .console-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n color: #eee;\n padding: 7px 10px;\n font-size: 12px;\n background-color: #111;\n border-bottom: 1px solid rgb(255 255 255 / 10%);\n user-select: none;\n .console-header-left {\n display: flex;\n align-items: center;\n .console-header-number {\n margin-left: 5px;\n color: rgba(255, 255, 255, 0.4);\n }\n }\n .console-header-right {\n cursor: pointer;\n }\n }\n .console-component {\n scroll-behavior: smooth;\n position: relative;\n overflow: auto;\n height: 200px;\n flex: 1;\n }\n"]))),x=function(e){h(r,t.default.Component);var o=v(r);function r(e){var n;return d(this,r),(n=o.call(this,e)).scrollTimer=null,n.consoleRef=t.default.createRef(),n.onClear=n.onClear.bind(g(n)),n.onMouseEnter=n.onMouseEnter.bind(g(n)),n.onMouseLeave=n.onMouseLeave.bind(g(n)),n.state={logs:[],hover:!1},n}return y(r,[{key:"componentDidMount",value:function(){var e=this;(0,n.Hook)(window.console,function(t){return e.add(t)},!1)}},{key:"add",value:function(e){this.setState({logs:[].concat(i(this.state.logs),[e])});var t=this.consoleRef.current;!this.state.hover&&t&&(clearTimeout(this.scrollTimer),this.scrollTimer=setTimeout(function(){t.scrollTop=t.scrollHeight},200))}},{key:"onClear",value:function(){this.setState({logs:[]})}},{key:"onMouseEnter",value:function(){this.setState({hover:!0})}},{key:"onMouseLeave",value:function(){this.setState({hover:!1})}},{key:"componentWillUnmount",value:function(){(0,n.Unhook)(window.console)}},{key:"render",value:function(){return t.default.createElement(j,null,t.default.createElement("div",{className:"console-header"},t.default.createElement("div",{className:"console-header-left"},"Console"," ",t.default.createElement("span",{className:"console-header-number"},this.state.logs.length)),t.default.createElement("div",{className:"console-header-right",onClick:this.onClear},"Clear")),t.default.createLine truncated
"use strict";"use strict";var __consoleOwned=(()=>{var v=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var O=(e,o)=>{for(var s in o)v(e,s,{get:o[s],enumerable:!0})},j=(e,o,s,i)=>{if(o&&typeof o=="object"||typeof o=="function")for(let n of E(o))!L.call(e,n)&&n!==s&&v(e,n,{get:()=>o[n],enumerable:!(i=C(o,n))||i.enumerable});return e};var P=e=>j(v({},"__esModule",{value:!0}),e);var D={};O(D,{createView:()=>N});var w=`
position: relative;
height: 100%;
display: flex;
flex-direction: column;
background-color: #242424;
.console-header {
display: flex;
justify-content: space-between;
align-items: center;
color: #eee;
padding: 7px 10px;
font-size: 12px;
background-color: #111;
border-bottom: 1px solid rgb(255 255 255 / 10%);
user-select: none;
.console-header-left {
display: flex;
align-items: center;
.console-header-number {
margin-left: 5px;
color: rgba(255, 255, 255, 0.4);
}
}
.console-header-right {
cursor: pointer;
}
}
.console-component {
scroll-behavior: smooth;
position: relative;
overflow: auto;
height: 200px;
flex: 1;
}
`;function k(e){try{if(Object.prototype.toString.call(e)!=="[object Error]")return e;let o=e,s=o.stack,i=o.message;if(typeof s!="string"||!i)return e;let n=o.name?`${o.name}: ${i}`:i;return s.startsWith(n)?e:`${n}
${s}`}catch(o){return e}}function x(e,o,s,i){let n;function p(l){for(let r of l.pending)i.clearTimeout(r);l.pending.clear();for(let r of l.saved)e[r.name]===r.wrapper&&(r.descriptor?Object.defineProperty(e,r.name,r.descriptor):delete e[r.name]);e.feed===l.feed&&(l.previousFeed?Object.defineProperty(e,"feed",l.previousFeed):delete e.feed)}return l=>{if(!n){let c={listeners:new Set,pending:new Set,saved:[],previousFeed:Object.getOwnPropertyDescriptor(e,"feed"),feed:{pointers:{},src:{npm:"https://npmjs.com/package/console-feed",github:"https://github.com/samdenty99/console-feed"}}};n=c;try{for(let t of o){let a=e[t],d=function(...u){Reflect.apply(a,this,u);let h=[...c.listeners];if(!h.length)return;let m=i.setTimeout(()=>{var T;c.pending.delete(m);let y=s(t,t==="error"?u.map(k):u);if(y){let g=!1,M;for(let b of h)try{(T=b.callback)==null||T.call(b,y)}catch(S){g?i.setTimeout(()=>{throw S},0):(g=!0,M=S)}if(g)throw M}},0);c.pending.add(m)};c.feed.pointers[t]=a,c.saved.push({name:t,descriptor:Object.getOwnPropertyDescriptor(e,t),wrapper:d}),e[t]=d}e.feed=c.feed}catch(t){throw p(c),n=void 0,t}}let r=n,f={callback:l};return r.listeners.add(f),()=>{f.callback=void 0,r.listeners.delete(f),!r.listeners.size&&n===r&&(n=void 0,p(r))}}}function N(e,o,s,i,n){let p=Object.freeze(Object.defineProperty([w],"raw",{value:Object.freeze([w])})),l=s.div(p),r=x(window.console,n,i,window);return class extends e.Component{constructor(t){super(t);this.scrollTimer=null;this.consoleRef=e.createRef();this.mounted=!1;this.onClear=this.onClear.bind(this),this.onMouseEnter=this.onMouseEnter.bind(this),this.onMouseLeave=this.onMouseLeave.bind(this),this.state={logs:[],hover:!1}}componentDidMount(){this.mounted=!0,this.unsubscribe=r(t=>this.add(t))}add(t){if(!this.mounted)return;this.setState(d=>({logs:[...d.logs,t]}));let a=this.consoleRef.current;!this.state.hover&&a&&(this.scrollTimer!==null&&window.clearTimeout(this.scrollTimer),this.scrollTimer=window.setTimeout(()=>{this.scrollTimer=null,this.mounted&&this.consoleRef.current===a&&(a.scrollTop=a.scrollHeight)},200))}onClear(){this.setState({logs:[]})}onMouseEnter(){this.setState({hover:!0})}onMouseLeave(){this.setState({hover:!1})}componentWillUnmount(){var t;this.mounted=!1,(t=this.unsubscribe)==null||t.call(this),this.unsubscribe=void 0,this.scrollTimer!==null&&window.clearTimeout(this.scrollTimer),this.scrollTimer=null}render(){let t=e.createElement("span",{className:"console-header-number"},this.state.logs.length),a=e.createElement("div",{className:"console-header-left"},"Console"," ",t),d=e.createElement("div",{className:"console-header-right",onClick:this.onClear},"Clear"),u=e.createElement("div",{className:"console-header"},a,d),h=e.createElement(o.Console,{logs:this.state.logs,variant:"dark"}),m=e.createElement("div",{ref:this.consoleRef,className:"console-component",onMouseEnter:this.onMouseEnter,onMouseLeave:this.onMouseLeave},h);return e.createElement(l,null,u,m)}}}return P(D);})();
Object.defineProperty(exports,"__esModule",{value:true});exports.default=__consoleOwned.createView(require("react"),require("console-feed"),require("styled-components").default,require("RxPG").default,require("V2JG").default);
},{"react":"n8MK","console-feed":"m6b6","styled-components":"tFSs"}],"Focm":[function(require,module,exports) {
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var e=u(require("react")),t=u(require("react-dom")),r=u(require("./Console"));function u(e){return e&&e.__esModule?e:{default:e}}var o=function(u){return t.default.render(e.default.createElement(r.default,null),u)};window.React=e.default,window.ReactDOM=t.default,window.consoleLog=o;var a=o;exports.default=a;
"use strict";"use strict";var __consoleOwned=(()=>{var r=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var R=Object.prototype.hasOwnProperty;var l=(e,n)=>{for(var o in n)r(e,o,{get:n[o],enumerable:!0})},p=(e,n,o,m)=>{if(n&&typeof n=="object"||typeof n=="function")for(let t of c(n))!R.call(e,t)&&t!==o&&r(e,t,{get:()=>n[t],enumerable:!(m=i(n,t))||m.enumerable});return e};var s=e=>p(r({},"__esModule",{value:!0}),e);var d={};l(d,{install:()=>a});function a(e,n,o,m){let t=u=>n.render(e.createElement(o),u);return t.unmount=u=>n.unmountComponentAtNode(u),m.React=e,m.ReactDOM=n,m.consoleLog=t,t}return s(d);})();
Object.defineProperty(exports,"__esModule",{value:true});exports.default=__consoleOwned.install(require("react"),require("react-dom"),require("./Console").default,window);
},{"react":"n8MK","react-dom":"NKHc","./Console":"W5CS"}]},{},["Focm"], null)
//# sourceMappingURL=/index.js.map
/*! customStringify: Alexander Mills, with credit to Rob W. CC BY-SA 4.0: https://creativecommons.org/licenses/by-sa/4.0/ . Source revision: https://api.stackexchange.com/2.3/revisions/8FD5F52A-B16F-4C66-AB48-830EABB36CC0?site=stackoverflow&filter=withbody . ES3 compilation and minification; notices and source: /licenses/console/stackoverflow/ATTRIBUTION.md . Other component notices: /THIRD_PARTY_NOTICES.md */
+135
View File
@@ -0,0 +1,135 @@
// Generated by yarn build:site-assets. Do not edit.
"use strict";
(() => {
// packages/artplayer-vitepress/browser/loader.ts
function parameters(url) {
const result = {};
for (const part of new URL(url).search.slice(1).split("&")) {
const index = part.indexOf("=");
if (index >= 0)
result[part.slice(0, index)] = part.slice(index + 1);
}
return result;
}
function suspendDefine(host) {
const descriptor = Object.getOwnPropertyDescriptor(host, "define");
if (descriptor?.configurable === false) {
if (!("value" in descriptor) || !descriptor.writable)
throw new Error("Cannot temporarily suspend the AMD loader");
Object.defineProperty(host, "define", { value: void 0 });
} else {
Object.defineProperty(host, "define", { value: void 0, configurable: true, writable: true, enumerable: descriptor?.enumerable ?? true });
}
return () => {
if (descriptor)
Object.defineProperty(host, "define", descriptor);
else Reflect.deleteProperty(host, "define");
};
}
function createLibraryLoader(host = window) {
const loaded = /* @__PURE__ */ new Set();
let queue = Promise.resolve();
let cancel;
let disposed = false;
const ensureActive = () => {
if (disposed)
throw new Error("Documentation loader was disposed");
};
function load(url, script) {
return new Promise((resolve, reject) => {
const element = host.document.createElement(script ? "script" : "link");
let restore;
let settled = false;
function finish(error) {
if (settled)
return;
settled = true;
element.removeEventListener("load", success);
element.removeEventListener("error", failure);
cancel = void 0;
try {
restore?.();
} catch (cause) {
error = new Error(`Failed to restore AMD loader: ${String(cause)}`);
}
if (error) {
element.remove();
reject(error);
} else {
resolve();
}
}
function success() {
finish();
}
function failure() {
finish(new Error(`Loading ${script ? "script" : "style"} failed: ${url}`));
}
element.addEventListener("load", success);
element.addEventListener("error", failure);
cancel = () => finish(new Error(`Cancelled documentation dependency: ${url}`));
try {
ensureActive();
if (script) {
restore = suspendDefine(host);
const node = element;
node.type = "text/javascript";
node.src = url;
node.async = false;
} else {
const node = element;
node.rel = "stylesheet";
node.href = url;
}
host.document.head.appendChild(element);
} catch (cause) {
finish(cause instanceof Error ? cause : new Error(String(cause)));
}
});
}
return {
loadLibraries(encoded = "") {
const work = queue.then(async () => {
ensureActive();
const urls = decodeURIComponent(encoded).split(/\r?\n/).map((url) => url.trim()).filter(Boolean);
const result = [];
for (const url of urls) {
ensureActive();
const absolute = new URL(url, host.location.href);
const extension = absolute.pathname.toLowerCase().split(".").pop();
if (extension !== "js" && extension !== "css")
continue;
if (!loaded.has(absolute.href)) {
await load(absolute.href, extension === "js");
loaded.add(absolute.href);
}
result.push(url);
}
return result;
});
queue = work.catch(() => {
});
return work;
},
dispose() {
disposed = true;
cancel?.();
loaded.clear();
}
};
}
async function exampleSource(name, request = fetch) {
const response = await request(`./assets/example/${name}.js`);
if (!response.ok)
throw new Error(`Loading example failed: ${name} (${response.status})`);
return response.text();
}
// packages/artplayer-vitepress/browser/editor-loader.ts
var loader = createLibraryLoader();
Object.assign(window, { ArtplayerDocsLoader: { ...loader, exampleSource, parameters } });
window.addEventListener("pagehide", (event) => {
if (!event.persisted)
loader.dispose();
});
})();
+137 -95
View File
@@ -1,100 +1,142 @@
(function () {
Artplayer.DEBUG = true;
function getURLParameters(url) {
return (url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce(function (a, v) {
return (a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1)), a;
}, {});
// Generated by yarn build:site-assets. Do not edit.
"use strict";
(() => {
// packages/artplayer-vitepress/browser/loader.ts
function parameters(url) {
const result = {};
for (const part of new URL(url).search.slice(1).split("&")) {
const index = part.indexOf("=");
if (index >= 0)
result[part.slice(0, index)] = part.slice(index + 1);
}
function getExt(url) {
if (url.includes('?')) {
return getExt(url.split('?')[0]);
}
if (url.includes('#')) {
return getExt(url.split('#')[0]);
}
return url.trim().toLowerCase().split('.').pop();
return result;
}
function suspendDefine(host) {
const descriptor = Object.getOwnPropertyDescriptor(host, "define");
if (descriptor?.configurable === false) {
if (!("value" in descriptor) || !descriptor.writable)
throw new Error("Cannot temporarily suspend the AMD loader");
Object.defineProperty(host, "define", { value: void 0 });
} else {
Object.defineProperty(host, "define", { value: void 0, configurable: true, writable: true, enumerable: descriptor?.enumerable ?? true });
}
function loadScript(url) {
return new Promise(function (resolve, reject) {
var define2 = window.define;
window.define = undefined;
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
script.onload = function () {
window.define = define2;
resolve(url);
};
script.onerror = function () {
reject(new Error('Loading script failed:' + url));
};
document.querySelector('head').appendChild(script);
return () => {
if (descriptor)
Object.defineProperty(host, "define", descriptor);
else Reflect.deleteProperty(host, "define");
};
}
function createLibraryLoader(host = window) {
const loaded = /* @__PURE__ */ new Set();
let queue = Promise.resolve();
let cancel;
let disposed = false;
const ensureActive = () => {
if (disposed)
throw new Error("Documentation loader was disposed");
};
function load(url, script) {
return new Promise((resolve, reject) => {
const element = host.document.createElement(script ? "script" : "link");
let restore;
let settled = false;
function finish(error) {
if (settled)
return;
settled = true;
element.removeEventListener("load", success);
element.removeEventListener("error", failure);
cancel = void 0;
try {
restore?.();
} catch (cause) {
error = new Error(`Failed to restore AMD loader: ${String(cause)}`);
}
if (error) {
element.remove();
reject(error);
} else {
resolve();
}
}
function success() {
finish();
}
function failure() {
finish(new Error(`Loading ${script ? "script" : "style"} failed: ${url}`));
}
element.addEventListener("load", success);
element.addEventListener("error", failure);
cancel = () => finish(new Error(`Cancelled documentation dependency: ${url}`));
try {
ensureActive();
if (script) {
restore = suspendDefine(host);
const node = element;
node.type = "text/javascript";
node.src = url;
node.async = false;
} else {
const node = element;
node.rel = "stylesheet";
node.href = url;
}
host.document.head.appendChild(element);
} catch (cause) {
finish(cause instanceof Error ? cause : new Error(String(cause)));
}
});
}
return {
loadLibraries(encoded = "") {
const work = queue.then(async () => {
ensureActive();
const urls = decodeURIComponent(encoded).split(/\r?\n/).map((url) => url.trim()).filter(Boolean);
const result = [];
for (const url of urls) {
ensureActive();
const absolute = new URL(url, host.location.href);
const extension = absolute.pathname.toLowerCase().split(".").pop();
if (extension !== "js" && extension !== "css")
continue;
if (!loaded.has(absolute.href)) {
await load(absolute.href, extension === "js");
loaded.add(absolute.href);
}
result.push(url);
}
return result;
});
}
function loadStyle(url) {
return new Promise(function (resolve, reject) {
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = url;
link.onload = function () {
resolve(url);
};
link.onerror = function () {
reject(new Error('Loading style failed:' + url));
};
document.querySelector('head').appendChild(link);
queue = work.catch(() => {
});
}
return work;
},
dispose() {
disposed = true;
cancel?.();
loaded.clear();
}
};
}
async function exampleSource(name, request = fetch) {
const response = await request(`./assets/example/${name}.js`);
if (!response.ok)
throw new Error(`Loading example failed: ${name} (${response.status})`);
return response.text();
}
function loadLib(libs) {
var libPromise = [];
var libsDecode = decodeURIComponent(libs || '');
libsDecode
.split(/\r?\n/)
.forEach(function (url) {
var ext = getExt(url);
if (ext === 'js') {
libPromise.push(loadScript(url));
} else if (ext === 'css') {
libPromise.push(loadStyle(url));
}
});
return Promise.all(libPromise);
}
function runExample(name) {
fetch('./assets/example/' + name + '.js')
.then(function (response) {
return response.text();
})
.then(function (text) {
eval(text);
})
}
function loadCode(code, example) {
if (example) {
runExample(example);
} else if (code) {
eval(decodeURIComponent(code).trim());
} else {
runExample('mobile');
}
}
var _getURLParameters = getURLParameters(window.location.href),
code = _getURLParameters.code,
libs = _getURLParameters.libs;
example = _getURLParameters.example;
loadLib(libs)
.then(function () {
loadCode(code, example);
})
})();
// packages/artplayer-vitepress/browser/mobile.ts
window.Artplayer.DEBUG = true;
var loader = createLibraryLoader();
window.addEventListener("pagehide", (event) => {
if (!event.persisted)
loader.dispose();
});
async function start() {
const { code, libs, example } = parameters(location.href);
await loader.loadLibraries(libs);
const source = example ? await exampleSource(example) : code ? decodeURIComponent(code).trim() : await exampleSource("mobile");
new Function(source)();
}
start().catch((error) => console.error("Failed to initialize mobile example:", error));
})();
+1 -1
View File
@@ -7,4 +7,4 @@
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/
!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define("VConsole",[],n):"object"==typeof exports?exports.VConsole=n():t.VConsole=n()}(this||self,(function(){return function(){var __webpack_modules__={4264:function(t,n,e){t.exports=e(7588)},5036:function(t,n,e){e(1719),e(5677),e(6394),e(5334),e(6969),e(2021),e(8328),e(2129);var o=e(1287);t.exports=o.Promise},2582:function(t,n,e){e(1646),e(6394),e(2004),e(462),e(8407),e(2429),e(1172),e(8288),e(1274),e(8201),e(6626),e(3211),e(9952),e(15),e(9831),e(7521),e(2972),e(6956),e(5222),e(2257);var o=e(1287);t.exports=o.Symbol},8257:function(t,n,e){var o=e(7583),r=e(9212),i=e(5637),a=o.TypeError;t.exports=function(t){if(r(t))return t;throw a(i(t)+" is not a function")}},1186:function(t,n,e){var o=e(7583),r=e(2097),i=e(5637),a=o.TypeError;t.exports=function(t){if(r(t))return t;throw a(i(t)+" is not a constructor")}},9882:function(t,n,e){var o=e(7583),r=e(9212),i=o.String,a=o.TypeError;t.exports=function(t){if("object"==typeof t||r(t))return t;throw a("Can't set "+i(t)+" as a prototype")}},6288:function(t,n,e){var o=e(3649),r=e(3590),i=e(4615),a=o("unscopables"),c=Array.prototype;null==c[a]&&i.f(c,a,{configurable:!0,value:r(null)}),t.exports=function(t){c[a][t]=!0}},4761:function(t,n,e){var o=e(7583),r=e(2447),i=o.TypeError;t.exports=function(t,n){if(r(n,t))return t;throw i("Incorrect invocation")}},2569:function(t,n,e){var o=e(7583),r=e(794),i=o.String,a=o.TypeError;t.exports=function(t){if(r(t))return t;throw a(i(t)+" is not an object")}},5766:function(t,n,e){var o=e(2977),r=e(6782),i=e(1825),a=function(t){return function(n,e,a){var c,u=o(n),s=i(u),l=r(a,s);if(t&&e!=e){for(;s>l;)if((c=u[l++])!=c)return!0}else for(;s>l;l++)if((t||l in u)&&u[l]===e)return t||l||0;return!t&&-1}};t.exports={includes:a(!0),indexOf:a(!1)}},4805:function(t,n,e){var o=e(2938),r=e(7386),i=e(5044),a=e(1324),c=e(1825),u=e(4822),s=r([].push),l=function(t){var n=1==t,e=2==t,r=3==t,l=4==t,f=6==t,d=7==t,v=5==t||f;return function(h,p,g,m){for(var _,b,y=a(h),w=i(y),E=o(p,g),L=c(w),T=0,x=m||u,C=n?x(h,L):e||d?x(h,0):void 0;L>T;T++)if((v||T in w)&&(b=E(_=w[T],T,y),t))if(n)C[T]=b;else if(b)switch(t){case 3:return!0;case 5:return _;case 6:return T;case 2:s(C,_)}else switch(t){case 4:return!1;case 7:s(C,_)}return f?-1:r||l?l:C}};t.exports={forEach:l(0),map:l(1),filter:l(2),some:l(3),every:l(4),find:l(5),findIndex:l(6),filterReject:l(7)}},9269:function(t,n,e){var o=e(6544),r=e(3649),i=e(4061),a=r("species");t.exports=function(t){return i>=51||!o((function(){var n=[];return(n.constructor={})[a]=function(){return{foo:1}},1!==n[t](Boolean).foo}))}},4546:function(t,n,e){var o=e(7583),r=e(6782),i=e(1825),a=e(5999),c=o.Array,u=Math.max;t.exports=function(t,n,e){for(var o=i(t),s=r(n,o),l=r(void 0===e?o:e,o),f=c(u(l-s,0)),d=0;s<l;s++,d++)a(f,d,t[s]);return f.length=d,f}},6917:function(t,n,e){var o=e(7386);t.exports=o([].slice)},5289:function(t,n,e){var o=e(7583),r=e(4521),i=e(2097),a=e(794),c=e(3649)("species"),u=o.Array;t.exports=function(t){var n;return r(t)&&(n=t.constructor,(i(n)&&(n===u||r(n.prototype))||a(n)&&null===(n=n[c]))&&(n=void 0)),void 0===n?u:n}},4822:function(t,n,e){var o=e(5289);t.exports=function(t,n){return new(o(t))(0===n?0:n)}},3616:function(t,n,e){var o=e(3649)("iterator"),r=!1;try{var i=0,a={next:function(){return{done:!!i++}},return:function(){r=!0}};a[o]=function(){return this},Array.from(a,(function(){throw 2}))}catch(t){}t.exports=function(t,n){if(!n&&!r)return!1;var e=!1;try{var i={};i[o]=function(){return{next:function(){return{done:e=!0}}}},t(i)}catch(t){}return e}},9624:function(t,n,e){var o=e(7386),r=o({}.toString),i=o("".slice);t.exports=function(t){return i(r(t),8,-1)}},3058:function(t,n,e){var o=e(7583),r=e(8191),i=e(9212),a=e(9624),c=e(3649)("toStringTag"),u=o.Object,s="Arguments"==a(function(){return arguments}());t.exports=r?a:function(t){var n,e,o;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(e=function(t,n){try{return t[n]}catch(t){}}(n=u(t),c))?e:s?a(n):"Object"==(o=a(n))&&i(n.callee)?"Arguments":o}},1509:function(t,n,e){var o=e(7386)("".replace),r=String(Error("zxcasd").stack),i=/\n\s*at [^:]*:[^\n]*/,a=i.test(r);t.exports=function(t,n){if(a&&"string"==typeof t)for(;n--;)t=o(t,i,"");return t}},3478:function(t,n,e){var o=e(2870),r=e(929),i=e(6683),a=e(4615);t.exports=function(t,n,e){for(var c=r(n),u=a.f,s=i.f,l=0;l<c.length;l++){var f=c[l];o(t,f)||e&&o(e,f)||u(t,f,s(n,f))}}},926:function(t,n,e){var o=e(6544);t.exports=!o((function(){function t(){}return t.prototype.constructor=null,Object.getPrototypeOf(new t)!==t.prototype}))},4683:function(t,n,e){"use strict";var o=e(2365).IteratorPrototype,r=e(3590),i=e(4677),a=e(8821),c=e(339),u=function(){return this};t.exports=function(t,n,e,s){var l=n+" Iterator";return t.prototype=r(o,{next:i(+!s,e)}),a(t,l,!1,!0),c[l]=u,t}},57:function(t,n,e){var o=e(8494),r=e(4615),i=e(4677);t.exports=o?function(t,n,e){return r.f(t,n,i(1,e))}:function(t,n,e){reLine truncated
!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define("VConsole",[],n):"object"==typeof exports?exports.VConsole=n():t.VConsole=n()}(this||self,(function(){var __artplayerVConsoleLogLifecycle=(function(){var o=Object.defineProperty;var t=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var p=Object.prototype.hasOwnProperty;var s=function(e,n){for(var u in n)o(e,u,{get:n[u],enumerable:!0})},L=function(e,n,u,i){if(n&&typeof n=="object"||typeof n=="function")for(var r=g(n),a=0,c=r.length,l;a<c;a++)l=r[a],!p.call(e,l)&&l!==u&&o(e,l,{get:function(d){return n[d]}.bind(null,l),enumerable:!(i=t(n,l))||i.enumerable});return e};var m=function(e){return L(o({},"__esModule",{value:!0}),e)};var D={};s(D,{enqueue:function(){return v},renderTab:function(){return h},unbind:function(){return A}});var f=[];function h(e,n,u){setTimeout(function(){e.isInited&&e.pluginList[n.id]===n&&u()},0)}function v(e,n,u){if(e.ADDED_LOG_PLUGIN_ID.length!==0){if(!e.flushLogScheduled){var i={host:e,id:0};f.push(i),e.flushLogScheduled=!0,i.id=u.requestAnimationFrame(function(){var r=f.indexOf(i);r!==-1&&(f.splice(r,1),e.flushLogScheduled=!1,e._flushLogs())})}e.logQueue.push(n)}}function A(e,n){for(var u,i=0;i<f.length;i++)if(f[i].host===e){u=f[i],f.splice(i,1);break}e.logQueue=[],e.flushLogScheduled=!1;try{u&&typeof n.cancelAnimationFrame=="function"&&n.cancelAnimationFrame(u.id)}finally{e.unmockConsole()}}return m(D);})();return function(){var __webpack_modules__={4264:function(t,n,e){t.exports=e(7588)},5036:function(t,n,e){e(1719),e(5677),e(6394),e(5334),e(6969),e(2021),e(8328),e(2129);var o=e(1287);t.exports=o.Promise},2582:function(t,n,e){e(1646),e(6394),e(2004),e(462),e(8407),e(2429),e(1172),e(8288),e(1274),e(8201),e(6626),e(3211),e(9952),e(15),e(9831),e(7521),e(2972),e(6956),e(5222),e(2257);var o=e(1287);t.exports=o.Symbol},8257:function(t,n,e){var o=e(7583),r=e(9212),i=e(5637),a=o.TypeError;t.exports=function(t){if(r(t))return t;throw a(i(t)+" is not a function")}},1186:function(t,n,e){var o=e(7583),r=e(2097),i=e(5637),a=o.TypeError;t.exports=function(t){if(r(t))return t;throw a(i(t)+" is not a constructor")}},9882:function(t,n,e){var o=e(7583),r=e(9212),i=o.String,a=o.TypeError;t.exports=function(t){if("object"==typeof t||r(t))return t;throw a("Can't set "+i(t)+" as a prototype")}},6288:function(t,n,e){var o=e(3649),r=e(3590),i=e(4615),a=o("unscopables"),c=Array.prototype;null==c[a]&&i.f(c,a,{configurable:!0,value:r(null)}),t.exports=function(t){c[a][t]=!0}},4761:function(t,n,e){var o=e(7583),r=e(2447),i=o.TypeError;t.exports=function(t,n){if(r(n,t))return t;throw i("Incorrect invocation")}},2569:function(t,n,e){var o=e(7583),r=e(794),i=o.String,a=o.TypeError;t.exports=function(t){if(r(t))return t;throw a(i(t)+" is not an object")}},5766:function(t,n,e){var o=e(2977),r=e(6782),i=e(1825),a=function(t){return function(n,e,a){var c,u=o(n),s=i(u),l=r(a,s);if(t&&e!=e){for(;s>l;)if((c=u[l++])!=c)return!0}else for(;s>l;l++)if((t||l in u)&&u[l]===e)return t||l||0;return!t&&-1}};t.exports={includes:a(!0),indexOf:a(!1)}},4805:function(t,n,e){var o=e(2938),r=e(7386),i=e(5044),a=e(1324),c=e(1825),u=e(4822),s=r([].push),l=function(t){var n=1==t,e=2==t,r=3==t,l=4==t,f=6==t,d=7==t,v=5==t||f;return function(h,p,g,m){for(var _,b,y=a(h),w=i(y),E=o(p,g),L=c(w),T=0,x=m||u,C=n?x(h,L):e||d?x(h,0):void 0;L>T;T++)if((v||T in w)&&(b=E(_=w[T],T,y),t))if(n)C[T]=b;else if(b)switch(t){case 3:return!0;case 5:return _;case 6:return T;case 2:s(C,_)}else switch(t){case 4:return!1;case 7:s(C,_)}return f?-1:r||l?l:C}};t.exports={forEach:l(0),map:l(1),filter:l(2),some:l(3),every:l(4),find:l(5),findIndex:l(6),filterReject:l(7)}},9269:function(t,n,e){var o=e(6544),r=e(3649),i=e(4061),a=r("species");t.exports=function(t){return i>=51||!o((function(){var n=[];return(n.constructor={})[a]=function(){return{foo:1}},1!==n[t](Boolean).foo}))}},4546:function(t,n,e){var o=e(7583),r=e(6782),i=e(1825),a=e(5999),c=o.Array,u=Math.max;t.exports=function(t,n,e){for(var o=i(t),s=r(n,o),l=r(void 0===e?o:e,o),f=c(u(l-s,0)),d=0;s<l;s++,d++)a(f,d,t[s]);return f.length=d,f}},6917:function(t,n,e){var o=e(7386);t.exports=o([].slice)},5289:function(t,n,e){var o=e(7583),r=e(4521),i=e(2097),a=e(794),c=e(3649)("species"),u=o.Array;t.exports=function(t){var n;return r(t)&&(n=t.constructor,(i(n)&&(n===u||r(n.prototype))||a(n)&&null===(n=n[c]))&&(n=void 0)),void 0===n?u:n}},4822:function(t,n,e){var o=e(5289);t.exports=function(t,n){return new(o(t))(0===n?0:n)}},3616:function(t,n,e){var o=e(3649)("iterator"),r=!1;try{var i=0,a={next:function(){return{done:!!i++}},return:function(){r=!0}};a[o]=function(){return this},Array.from(a,(function(){throw 2}))}catch(t){}t.exports=function(t,n){if(!n&&!r)return!1;var e=!1;try{var i={};i[o]=function(){return{next:function(){return{done:e=!0}}}},t(i)}catch(t){}return e}},9624:function(t,n,e){var o=e(7386),r=o({}.toString),i=o("".slice);t.exports=function(t){return i(r(t),8,-Line truncated
+4
View File
@@ -0,0 +1,4 @@
declare module 'artplayer/i18n/*' {
const language: NonNullable<Artplayer.I18n['en']>
export default language
}
+75 -49
View File
@@ -1,52 +1,78 @@
interface Option {
/**
* 广告源文本,支持视频链接、图片链接、HTML文本
*/
source: string
/**
* 知名广告的类型:'video' | 'image' | 'html'
*/
type: 'video' | 'image' | 'html'
/**
* 广告必看的时长,单位为秒
*/
playDuration?: number
/**
* 广告总的时长,单位为秒
*/
totalDuration?: number
/**
* 视频广告是否默认静音
*/
muted?: boolean
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
declare namespace artplayerPluginAds {
interface Translations {
close: string
countdown: string
detail: string
canBeClosed: string
}
/** Implemented options. Video takes precedence over HTML. */
interface Option {
html?: string
video?: string
url?: string
/** Seconds before the close button becomes available. @default 5 */
playDuration?: number
/** Total advertisement duration in seconds. @default 10 */
totalDuration?: number
/** Initial ad-video mute state. @default false */
muted?: boolean
/** All four fields replace the default translation object together. */
i18n?: Translations
}
/** Historical published declaration. String durations still fail runtime validation. */
interface LegacyOption extends Omit<Option, 'totalDuration'> {
/** @deprecated Incorrect in the old declaration; use a numeric duration. */
totalDuration?: string
}
/** Historical unpublished workspace declaration; these fields are not runtime aliases. */
interface WorkspaceOption extends Option {
/** @deprecated Ignored by the runtime. Use html or video instead. */
source: string
/** @deprecated Ignored by the runtime. Images are supplied through html. */
type: 'video' | 'image' | 'html'
}
/** Input acceptance for both historical declaration families. */
interface CompatOption extends Omit<Option, 'totalDuration'> {
/** @deprecated The string branch exists for old types only and is rejected at runtime. */
totalDuration?: number | string
/** @deprecated Ignored by the runtime. Use html or video instead. */
source?: string
/** @deprecated Ignored by the runtime. Images are supplied through html. */
type?: 'video' | 'image' | 'html'
}
interface Result {
name: 'artplayerPluginAds'
/** Complete once; before initialization this cancels the pending preroll. */
skip: () => void
/** Pause only the countdown, leaving ad video playback unchanged. */
pause: () => void
/** Resume only the countdown without adding extra timers. */
play: () => void
}
interface Callable {
(option?: Option): (art: Artplayer) => Result
/** @deprecated Compatibility with erroneous old string-duration declarations only. */
(option: LegacyOption): (art: Artplayer) => Result
(option: WorkspaceOption): (art: Artplayer) => Result
(option?: CompatOption): (art: Artplayer) => Result
/** Required final signature keeps Parameters extraction free of top-level undefined. */
(option: CompatOption): (art: Artplayer) => Result
}
interface Factory extends Callable {
/** Same function; supports historical require(package).default calls. */
readonly default: Callable
}
interface RuntimeCallable {
(option?: Option): (art: Artplayer) => Result
(option: Option): (art: Artplayer) => Result
}
/** Accurate typing for the identical implementation at /runtime. */
interface RuntimeFactory extends RuntimeCallable {
readonly default: RuntimeCallable
}
}
interface Ads {
name: 'artplayerPluginAds'
/**
* 跳过广告
*/
skip: () => void
/**
* 暂停广告
*/
pause: () => void
/**
* 播放广告
*/
play: () => void
}
declare const artplayerPluginAds: (option: Option) => (art: Artplayer) => Ads
export default artplayerPluginAds
declare const artplayerPluginAds: artplayerPluginAds.Factory
export = artplayerPluginAds
export as namespace artplayerPluginAds;
+38 -16
View File
@@ -1,20 +1,42 @@
interface Option {
blur?: string
opacity?: number
frequency?: number
zIndex?: number
duration?: number
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
declare namespace artplayerPluginAmbilightDefinitions {
export interface Option {
/** CSS blur radius. @default '50px' */
blur?: string
/** Grid cell opacity. @default 0.5 */
opacity?: number
/** Maximum sampling frequency in frames per second. @default 10 */
frequency?: number
/** Historical input retained for compatibility; runtime uses a fixed z-index of 9. */
zIndex?: number
/** Background color transition duration in seconds. @default 0.3 */
duration?: number
}
export interface Result {
name: 'artplayerPluginAmbilight'
/** Start sampling; does nothing after the player is destroyed. */
start: () => void
/** Stop sampling while retaining the last colors. */
stop: () => void
}
/** Published 1.1.0 factory shape; the options argument remains required. */
export type Callable = (option: Option) => (art: Artplayer) => Result
export type Factory = Callable
/** Accurate optional invocation and CommonJS self alias, exposed by /runtime. */
export interface RuntimeFactory {
(option?: Option): (art: Artplayer) => Result
readonly default: RuntimeFactory
}
export const artplayerPluginAmbilight: (option: Option) => (art: Artplayer) => Result
}
interface Result {
name: 'artplayerPluginAmbilight'
start: () => void
stop: () => void
declare const artplayerPluginAmbilight: typeof artplayerPluginAmbilightDefinitions.artplayerPluginAmbilight
declare namespace artplayerPluginAmbilight {
export type Option = artplayerPluginAmbilightDefinitions.Option
export type Result = artplayerPluginAmbilightDefinitions.Result
export type Callable = artplayerPluginAmbilightDefinitions.Callable
export type Factory = artplayerPluginAmbilightDefinitions.Factory
export type RuntimeFactory = artplayerPluginAmbilightDefinitions.RuntimeFactory
}
declare const artplayerPluginAmbilight: (option: Option) => (art: Artplayer) => Result
export default artplayerPluginAmbilight
export = artplayerPluginAmbilight
export as namespace artplayerPluginAmbilight;
+47 -22
View File
@@ -1,26 +1,51 @@
interface AudioChunk {
pcm: ArrayBuffer
wav: ArrayBuffer
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
declare namespace artplayerPluginAsrDefinitions {
export interface AudioChunk {
pcm: ArrayBuffer
wav: ArrayBuffer
}
export interface AsrPluginOption {
length?: number
interval?: number
sampleRate?: number
autoHideTimeout?: number
onAudioChunk?: (chunk: AudioChunk) => void | Promise<void>
}
export interface AsrPluginInstance {
name: 'artplayerPluginAsr'
stop: () => void
hide: () => void
append: (subtitle: string) => void
}
/** Historical factory shape, including void stop and callback results. */
export type Factory = (option?: AsrPluginOption) => (art: Artplayer) => AsrPluginInstance
/** Accurate asynchronous view available through the /runtime entry. */
export interface RuntimeOption extends Omit<AsrPluginOption, 'onAudioChunk'> {
/** Capture the media stream without taking ownership of its playback route. */
audioInput?: {
type: 'capture'
}
onAudioChunk?: (chunk: AudioChunk) => string | void | null | Promise<string | void | null>
}
export interface RuntimeResult extends Omit<AsrPluginInstance, 'stop'> {
stop: () => Promise<void>
}
export interface RuntimeFactory {
(option?: RuntimeOption): (art: Artplayer) => RuntimeResult
readonly default: RuntimeFactory
}
export function artplayerPluginAsr(option?: AsrPluginOption): (art: Artplayer) => AsrPluginInstance
}
interface AsrPluginOption {
length?: number
interval?: number
sampleRate?: number
autoHideTimeout?: number
onAudioChunk?: (chunk: AudioChunk) => void | Promise<void>
declare const artplayerPluginAsr: typeof artplayerPluginAsrDefinitions.artplayerPluginAsr
declare namespace artplayerPluginAsr {
export type AudioChunk = artplayerPluginAsrDefinitions.AudioChunk
export type AsrPluginOption = artplayerPluginAsrDefinitions.AsrPluginOption
export type AsrPluginInstance = artplayerPluginAsrDefinitions.AsrPluginInstance
export type Factory = artplayerPluginAsrDefinitions.Factory
export type RuntimeOption = artplayerPluginAsrDefinitions.RuntimeOption
export type RuntimeResult = artplayerPluginAsrDefinitions.RuntimeResult
export type RuntimeFactory = artplayerPluginAsrDefinitions.RuntimeFactory
}
interface AsrPluginInstance {
name: 'artplayerPluginAsr'
stop: () => void
hide: () => void
append: (subtitle: string) => void
}
declare function artplayerPluginAsr(option?: AsrPluginOption): (art: Artplayer) => AsrPluginInstance
export default artplayerPluginAsr
export = artplayerPluginAsr
export as namespace artplayerPluginAsr;
+48 -36
View File
@@ -1,40 +1,52 @@
interface Option {
/**
* Audio track URL
*/
url: string
/**
* Time offset in seconds between video and audio
* Positive value means audio plays ahead of video
* Negative value means audio plays behind video
* @default 0
*/
offset?: number
/**
* Synchronization threshold in seconds
* @default 0.3
*/
sync?: number
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
declare namespace artplayerPluginAudioTrackDefinitions {
export interface Option {
/**
* Audio track URL
*/
url: string
/**
* Time offset in seconds between video and audio
* Positive value means audio plays ahead of video
* Negative value means audio plays behind video
* @default 0
*/
offset?: number
/**
* Synchronization threshold in seconds
* @default 0.3
*/
sync?: number
}
export type UpdateOption = Partial<Option>
export interface Result {
name: 'artplayerPluginAudioTrack'
/**
* The audio element
*/
audio: HTMLAudioElement
/**
* Historical update signature. Runtime also accepts partial options.
* Import the /runtime entry for the precise partial-update signature.
*/
update: (option: Option) => void
}
export interface RuntimeResult extends Result {
/** Update selected fields without replacing the audio element. */
update: (option: UpdateOption) => void
}
/** Precise typing for the same runtime factory, without changing legacy inference. */
export type RuntimeFactory = (option: Option) => (art: Artplayer) => RuntimeResult
export function artplayerPluginAudioTrack(option: Option): (art: Artplayer) => Result
}
interface Result {
name: 'artplayerPluginAudioTrack'
/**
* The audio element
*/
audio: HTMLAudioElement
/**
* Update option
*/
update: (option: Option) => void
declare const artplayerPluginAudioTrack: typeof artplayerPluginAudioTrackDefinitions.artplayerPluginAudioTrack
declare namespace artplayerPluginAudioTrack {
export type Option = artplayerPluginAudioTrackDefinitions.Option
export type UpdateOption = artplayerPluginAudioTrackDefinitions.UpdateOption
export type Result = artplayerPluginAudioTrackDefinitions.Result
export type RuntimeResult = artplayerPluginAudioTrackDefinitions.RuntimeResult
export type RuntimeFactory = artplayerPluginAudioTrackDefinitions.RuntimeFactory
}
declare const artplayerPluginAudioTrack: (option: Option) => (art: Artplayer) => Result
export default artplayerPluginAudioTrack
export = artplayerPluginAudioTrack
export as namespace artplayerPluginAudioTrack;
+15 -14
View File
@@ -1,17 +1,18 @@
interface Option {
url?: string
width?: number
number?: number
scale?: number
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
declare namespace artplayerPluginAutoThumbnailDefinitions {
export interface Option {
url?: string
width?: number
number?: number
scale?: number
}
export interface Result {
name: 'artplayerPluginAutoThumbnail'
}
export const artplayerPluginAutoThumbnail: (option: Option) => (art: Artplayer) => Result
}
interface Result {
name: 'artplayerPluginAutoThumbnail'
}
declare const artplayerPluginAutoThumbnail: (option: Option) => (art: Artplayer) => Result
export default artplayerPluginAutoThumbnail
declare const artplayerPluginAutoThumbnail: typeof artplayerPluginAutoThumbnailDefinitions.artplayerPluginAutoThumbnail
declare namespace artplayerPluginAutoThumbnail { }
export = artplayerPluginAutoThumbnail
export as namespace artplayerPluginAutoThumbnail;
+21 -17
View File
@@ -1,21 +1,25 @@
type Chapters = {
start: number
end: number
title: string
}[]
interface Option {
chapters?: Chapters
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
declare namespace artplayerPluginChapterDefinitions {
export type Chapters = {
start: number
end: number
title: string
}[]
export interface Option {
chapters?: Chapters
}
export interface Result {
name: 'artplayerPluginChapter'
update: (option: Option) => void
}
export const artplayerPluginChapter: (option?: Option) => (art: Artplayer) => Result
}
interface Result {
name: 'artplayerPluginChapter'
update: (option: Option) => void
declare const artplayerPluginChapter: typeof artplayerPluginChapterDefinitions.artplayerPluginChapter
declare namespace artplayerPluginChapter {
export type Chapters = artplayerPluginChapterDefinitions.Chapters
export type Option = artplayerPluginChapterDefinitions.Option
export type Result = artplayerPluginChapterDefinitions.Result
}
declare const artplayerPluginChapter: (option: Option) => (art: Artplayer) => Result
export default artplayerPluginChapter
export = artplayerPluginChapter
export as namespace artplayerPluginChapter;
+43 -13
View File
@@ -1,17 +1,47 @@
interface Option {
url?: string
sdk?: string
icon?: string
mimeType?: string
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
declare namespace artplayerPluginChromecastDefinitions {
export interface Option {
url?: string
sdk?: string
icon?: string
mimeType?: string
}
export interface Chromecast {
name: 'artplayerPluginChromecast'
}
/** Published 1.1.0 result; actual registration is asynchronous. */
export type Result = Chromecast
export type Factory = (option: Option) => (art: Artplayer) => Chromecast
export type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'disconnecting'
export interface RuntimeOption extends Option {
onStateChange?: (this: RuntimeOption, state: ConnectionState) => void
onCastAvailable?: (this: RuntimeOption, available: boolean) => void
onCastStart?: (this: RuntimeOption) => void
onError?: (this: RuntimeOption, error: unknown) => void
}
export interface RuntimeResult extends Chromecast {
/** Last raw SDK SessionState, initially null; not the normalized callback state. */
getCastState: () => string | null
/** Whether this controller retains a session; does not prove receiver playback. */
isCasting: () => boolean
}
export interface RuntimeFactory {
(option: RuntimeOption): (art: Artplayer) => Promise<RuntimeResult>
default: RuntimeFactory
}
export const artplayerPluginChromecast: (option: Option) => (art: Artplayer) => Chromecast
}
interface Chromecast {
name: 'artplayerPluginChromecast'
declare const artplayerPluginChromecast: typeof artplayerPluginChromecastDefinitions.artplayerPluginChromecast
declare namespace artplayerPluginChromecast {
export type Option = artplayerPluginChromecastDefinitions.Option
export type Chromecast = artplayerPluginChromecastDefinitions.Chromecast
export type Result = artplayerPluginChromecastDefinitions.Result
export type Factory = artplayerPluginChromecastDefinitions.Factory
export type ConnectionState = artplayerPluginChromecastDefinitions.ConnectionState
export type RuntimeOption = artplayerPluginChromecastDefinitions.RuntimeOption
export type RuntimeResult = artplayerPluginChromecastDefinitions.RuntimeResult
export type RuntimeFactory = artplayerPluginChromecastDefinitions.RuntimeFactory
}
declare const artplayerPluginChromecast: (option: Option) => (art: Artplayer) => Chromecast
export default artplayerPluginChromecast
export = artplayerPluginChromecast
export as namespace artplayerPluginChromecast;
+23 -22
View File
@@ -1,25 +1,26 @@
interface Option {
solutionPath?: string
modelSelection?: number
smoothSegmentation?: boolean
minDetectionConfidence?: number
minTrackingConfidence?: number
selfieMode?: boolean
drawContour?: boolean
foregroundThreshold?: number
opacity?: number
maskBlurAmount?: number
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
declare namespace artplayerPluginDanmukuMaskDefinitions {
export interface Option {
solutionPath?: string
modelSelection?: number
smoothSegmentation?: boolean
minDetectionConfidence?: number
minTrackingConfidence?: number
selfieMode?: boolean
drawContour?: boolean
foregroundThreshold?: number
opacity?: number
maskBlurAmount?: number
}
export interface Result {
name: 'artplayerPluginDanmukuMask'
start: () => Promise<void>
stop: () => void
}
export const artplayerPluginDanmukuMask: (option?: Option) => (art: Artplayer) => Result
}
interface Result {
name: 'artplayerPluginDanmukuMask'
start: () => Promise<void>
stop: () => void
}
declare const artplayerPluginDanmukuMask: (option?: Option) => (art: Artplayer) => Result
export default artplayerPluginDanmukuMask
declare const artplayerPluginDanmukuMask: typeof artplayerPluginDanmukuMaskDefinitions.artplayerPluginDanmukuMask
declare namespace artplayerPluginDanmukuMask { }
export = artplayerPluginDanmukuMask
export as namespace artplayerPluginDanmukuMask;
+209 -244
View File
@@ -1,114 +1,96 @@
export type Mode = 0 | 1 | 2
export type Danmuku
= | Danmu[]
| string // URL
| (() => Promise<Danmu[]>)
| Promise<Danmu[]>
export interface Slider {
min?: number
max?: number
steps?: {
name?: string
value?: number | string
show?: boolean
}[]
}
export interface Danmu {
/**
* 弹幕文本
*/
text: string
/**
* 弹幕发送模式: 0: 滚动,1: 顶部,2: 底部
*/
mode?: Mode
/**
* 弹幕颜色
*/
color?: string
/**
* 弹幕出现的时间,单位为秒
*/
time?: number
/**
* 弹幕是否有描边, 默认为 false
*/
border?: boolean
/**
* 弹幕自定义样式
*/
style?: Partial<CSSStyleDeclaration>
}
export interface Option {
/**
* 弹幕数据: 函数,数组,Promise,URL
*/
danmuku: Danmuku
/**
* 弹幕持续时间,范围在[1 ~ 10]
*/
speed?: number
/**
* 弹幕上下边距,支持像素数字和百分比
*/
margin?: [number | `${number}%`, number | `${number}%`]
/**
* 弹幕透明度,范围在[0 ~ 1]
*/
opacity?: number
/**
* 默认弹幕颜色,可以被单独弹幕项覆盖
*/
color?: string
/**
* 弹幕模式: 0: 滚动,1: 顶部,2: 底部
*/
mode?: Mode
/**
* 弹幕可见的模式
*/
modes?: Mode[]
/**
* 弹幕字体大小,支持像素数字和百分比
*/
fontSize?: number | `${number}%`
/**
* 弹幕是否防重叠
*/
antiOverlap?: boolean
/**
* 是否同步播放速度
*/
synchronousPlayback?: boolean
/**
* 弹幕发射器挂载点, 默认为播放器控制栏中部
*/
mount?: HTMLDivElement | string
/**
* 是否开启弹幕热度图
*/
heatmap?:
| boolean
| {
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
declare namespace artplayerPluginDanmukuDefinitions {
export type Mode = 0 | 1 | 2
export type Danmuku = Danmu[] | string // URL
| (() => Promise<Danmu[]>) | Promise<Danmu[]>
export interface Slider {
min?: number
max?: number
steps?: {
name?: string
value?: number | string
show?: boolean
}[]
}
export interface Danmu {
/**
* 弹幕文本
*/
text: string
/**
* 弹幕发送模式: 0: 滚动,1: 顶部,2: 底部
*/
mode?: Mode
/**
* 弹幕颜色
*/
color?: string
/**
* 弹幕出现的时间,单位为秒
*/
time?: number
/**
* 弹幕是否有描边, 默认为 false
*/
border?: boolean
/**
* 弹幕自定义样式
*/
style?: Partial<CSSStyleDeclaration>
}
export interface Option {
/**
* 弹幕数据: 函数,数组,Promise,URL
*/
danmuku: Danmuku
/**
* 弹幕持续时间,范围在[1 ~ 10]
*/
speed?: number
/**
* 弹幕上下边距,支持像素数字和百分比
*/
margin?: [
number | `${number}%`,
number | `${number}%`,
]
/**
* 弹幕透明度,范围在[0 ~ 1]
*/
opacity?: number
/**
* 默认弹幕颜色,可以被单独弹幕项覆盖
*/
color?: string
/**
* 弹幕模式: 0: 滚动,1: 顶部,2: 底部
*/
mode?: Mode
/**
* 弹幕可见的模式
*/
modes?: Mode[]
/**
* 弹幕字体大小,支持像素数字和百分比
*/
fontSize?: number | `${number}%`
/**
* 弹幕是否防重叠
*/
antiOverlap?: boolean
/**
* 是否同步播放速度
*/
synchronousPlayback?: boolean
/**
* 弹幕发射器挂载点, 默认为播放器控制栏中部
*/
mount?: HTMLDivElement | string
/**
* 是否开启弹幕热度图
*/
heatmap?: boolean | {
xMin?: number
xMax?: number
yMin?: number
@@ -120,140 +102,123 @@ export interface Option {
smoothing?: number
flattening?: number
}
/**
* 当播放器宽度小于此值时,弹幕发射器置于播放器底部
*/
width?: number
/**
* 热力图数据
*/
points?: { time: number, value: number }[]
/**
* 弹幕载入前的过滤器,只支持返回布尔值
*/
filter?: (danmu: Danmu) => boolean
/**
* 弹幕发送前的过滤器,支持返回 Promise
*/
beforeEmit?: (danmu: Danmu) => boolean | Promise<boolean>
/**
* 弹幕显示前的过滤器,支持返回 Promise
*/
beforeVisible?: (danmu: Danmu) => boolean | Promise<boolean>
/**
* 弹幕是否可见
*/
visible?: boolean
/**
* 是否开启弹幕发射器
*/
emitter?: boolean
/**
* 弹幕输入框最大长度, 范围在[1 ~ 1000]
*/
maxLength?: number
/**
* 输入框锁定时间,范围在[1 ~ 60]
*/
lockTime?: number
/**
* 弹幕主题,只在自定义挂载时生效
*/
theme?: 'light' | 'dark'
/**
* 不透明度配置项
*/
OPACITY?: Slider
/**
* 弹幕速度配置项
*/
SPEED?: Slider
/**
* 显示区域配置项
*/
MARGIN?: Slider
/**
* 弹幕字号配置项
*/
FONT_SIZE?: Slider
/**
* 颜色列表配置项
*/
COLOR?: string[]
/**
* 当播放器宽度小于此值时,弹幕发射器置于播放器底部
*/
width?: number
/**
* 热力图数据
*/
points?: {
time: number
value: number
}[]
/**
* 弹幕载入前的过滤器,只支持返回布尔值
*/
filter?: (danmu: Danmu) => boolean
/**
* 弹幕发送前的过滤器,支持返回 Promise
*/
beforeEmit?: (danmu: Danmu) => boolean | Promise<boolean>
/**
* 弹幕显示前的过滤器,支持返回 Promise
*/
beforeVisible?: (danmu: Danmu) => boolean | Promise<boolean>
/**
* 弹幕是否可见
*/
visible?: boolean
/**
* 是否开启弹幕发射器
*/
emitter?: boolean
/**
* 弹幕输入框最大长度, 范围在[1 ~ 1000]
*/
maxLength?: number
/**
* 输入框锁定时间,范围在[1 ~ 60]
*/
lockTime?: number
/**
* 弹幕主题,只在自定义挂载时生效
*/
theme?: 'light' | 'dark'
/**
* 不透明度配置项
*/
OPACITY?: Slider
/**
* 弹幕速度配置项
*/
SPEED?: Slider
/**
* 显示区域配置项
*/
MARGIN?: Slider
/**
* 弹幕字号配置项
*/
FONT_SIZE?: Slider
/**
* 颜色列表配置项
*/
COLOR?: string[]
}
export interface Result {
name: 'artplayerPluginDanmuku'
/**
* 发送一条实时弹幕
*/
emit: (danmu: Danmu) => Result
/**
* 重载弹幕源,或者切换新弹幕
*/
load: (danmuku?: Danmuku) => Promise<Result>
/**
* 实时改变弹幕配置
*/
config: (option: Option) => Result
/**
* 隐藏弹幕层
*/
hide: () => Result
/**
* 显示弹幕层
*/
show: () => Result
/**
* 挂载弹幕输入框
*/
mount: (el?: HTMLDivElement | string) => void
/**
* 重置弹幕
*/
reset: () => Result
/**
* 弹幕配置
*/
option: Option
/**
* 是否隐藏弹幕层
*/
isHide: boolean
/**
* 是否弹幕层停止状态
*/
isStop: boolean
}
export const artplayerPluginDanmuku: (option: Option) => (art: Artplayer) => Result
}
export interface Result {
name: 'artplayerPluginDanmuku'
/**
* 发送一条实时弹幕
*/
emit: (danmu: Danmu) => Result
/**
* 重载弹幕源,或者切换新弹幕
*/
load: (danmuku?: Danmuku) => Promise<Result>
/**
* 实时改变弹幕配置
*/
config: (option: Option) => Result
/**
* 隐藏弹幕层
*/
hide: () => Result
/**
* 显示弹幕层
*/
show: () => Result
/**
* 挂载弹幕输入框
*/
mount: (el?: HTMLDivElement | string) => void
/**
* 重置弹幕
*/
reset: () => Result
/**
* 弹幕配置
*/
option: Option
/**
* 是否隐藏弹幕层
*/
isHide: boolean
/**
* 是否弹幕层停止状态
*/
isStop: boolean
declare const artplayerPluginDanmuku: typeof artplayerPluginDanmukuDefinitions.artplayerPluginDanmuku
declare namespace artplayerPluginDanmuku {
export type Mode = artplayerPluginDanmukuDefinitions.Mode
export type Danmuku = artplayerPluginDanmukuDefinitions.Danmuku
export type Slider = artplayerPluginDanmukuDefinitions.Slider
export type Danmu = artplayerPluginDanmukuDefinitions.Danmu
export type Option = artplayerPluginDanmukuDefinitions.Option
export type Result = artplayerPluginDanmukuDefinitions.Result
}
declare const artplayerPluginDanmuku: (option: Option) => (art: Artplayer) => Result
export default artplayerPluginDanmuku
export = artplayerPluginDanmuku
export as namespace artplayerPluginDanmuku;
+42 -13
View File
@@ -1,17 +1,46 @@
interface Config {
control?: boolean
setting?: boolean
title?: string
auto?: string
getName?: (level: object) => string
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
declare namespace artplayerPluginDashControlDefinitions {
export interface QualityLevel {
height: number
width?: number
id?: string | number
qualityIndex?: number
bitrate?: number
bitrateInKbit?: number
}
export interface AudioTrack {
id?: string | number | null
index?: number | null
lang?: string | null
}
export interface Config<Item extends object = object> {
control?: boolean
setting?: boolean
title?: string
auto?: string
/** Called without a receiver or index, with the original SDK object. */
getName?: (item: Item) => string
}
export interface Option<Level extends object = QualityLevel, Track extends object = AudioTrack> {
quality?: Config<Level>
audio?: Config<Track>
}
export interface Result {
name: 'artplayerPluginDashControl'
update: () => void
}
export function artplayerPluginDashControl<Level extends object = QualityLevel, Track extends object = AudioTrack>(option?: Option<Level, Track>): (art: Artplayer) => Result
// Preserve the required last signature for historical Parameters<typeof factory>[0] consumers.
export function artplayerPluginDashControl<Level extends object = QualityLevel, Track extends object = AudioTrack>(option: Option<Level, Track>): (art: Artplayer) => Result
}
declare const artplayerPluginDashControl: (option: { quality?: Config, audio?: Config }) => (art: Artplayer) => {
name: 'artplayerPluginDashControl'
update: () => void
declare const artplayerPluginDashControl: typeof artplayerPluginDashControlDefinitions.artplayerPluginDashControl
declare namespace artplayerPluginDashControl {
export type QualityLevel = artplayerPluginDashControlDefinitions.QualityLevel
export type AudioTrack = artplayerPluginDashControlDefinitions.AudioTrack
export type Config<Item extends object = object> = artplayerPluginDashControlDefinitions.Config<Item>
export type Option<Level extends object = QualityLevel, Track extends object = AudioTrack> = artplayerPluginDashControlDefinitions.Option<Level, Track>
export type Result = artplayerPluginDashControlDefinitions.Result
}
export default artplayerPluginDashControl
export = artplayerPluginDashControl
export as namespace artplayerPluginDashControl;
+49 -18
View File
@@ -1,22 +1,53 @@
interface Option {
width?: number
height?: number
placeholder?: string
fallbackToVideoPiP?: boolean
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
declare namespace artplayerPluginDocumentPipDefinitions {
export interface Option {
/** Requested window width. @default 480 */
width?: number
/** Requested window height. @default 270 */
height?: number
/** Text displayed in the original player container while the window is active. */
placeholder?: string
/** Use the core video PiP property when Document PiP is unavailable. @default true */
fallbackToVideoPiP?: boolean
}
/** Historical assignable result; preserved for direct and extracted return types. */
export interface Result {
name: 'artplayerPluginDocumentPip'
/** Runtime is a readonly capability snapshot; the published field stays assignable. */
isSupported: boolean
/** Runtime is a readonly live getter; the published field stays assignable. */
isActive: boolean
/** Runtime returns Promise<void>; the published void action remains assignable here. */
open: () => void
/** Runtime returns Promise<void>; the published void action remains assignable here. */
close: () => void
toggle: () => void
}
/** Exact view of an unmodified runtime result. */
export interface AsyncResult extends Omit<Result, 'isSupported' | 'isActive' | 'open' | 'close'> {
readonly isSupported: boolean
readonly isActive: boolean
open: () => Promise<void>
close: () => Promise<void>
}
/** Exact published factory signature, including compatibility with replacement functions. */
export type Factory = (option: Option) => (art: Artplayer) => Result
/** Opt-in runtime view with omitted options, self default and precise async actions. */
export interface RuntimeFactory {
(option?: Option): (art: Artplayer) => AsyncResult
readonly default: RuntimeFactory
}
/** Keep the published callable type; use RuntimeFactory explicitly for its broader runtime shape. */
export function artplayerPluginDocumentPip(option: Option): (art: Artplayer) => Result
}
interface Result {
name: 'artplayerPluginDocumentPip'
isSupported: boolean
isActive: boolean
open: () => void
close: () => void
toggle: () => void
declare const artplayerPluginDocumentPip: typeof artplayerPluginDocumentPipDefinitions.artplayerPluginDocumentPip
declare namespace artplayerPluginDocumentPip {
export type Option = artplayerPluginDocumentPipDefinitions.Option
export type Result = artplayerPluginDocumentPipDefinitions.Result
export type AsyncResult = artplayerPluginDocumentPipDefinitions.AsyncResult
export type Factory = artplayerPluginDocumentPipDefinitions.Factory
export type RuntimeFactory = artplayerPluginDocumentPipDefinitions.RuntimeFactory
}
declare const artplayerPluginDocumentPip: (option: Option) => (art: Artplayer) => Result
export default artplayerPluginDocumentPip
export = artplayerPluginDocumentPip
export as namespace artplayerPluginDocumentPip;
+39 -13
View File
@@ -1,17 +1,43 @@
interface Config {
control?: boolean
setting?: boolean
title?: string
auto?: string
getName?: (level: object) => string
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
declare namespace artplayerPluginHlsControlDefinitions {
export interface QualityLevel {
height: number
name?: string
}
export interface AudioTrack {
id: number
name: string
lang?: string
language?: string
}
export interface Config<Item extends object = object> {
control?: boolean
setting?: boolean
title?: string
auto?: string
/** Plain callback; current-label calls omit index. SDK objects retain their identity. */
getName?: (item: Item, index?: number) => string
}
export interface Option<Level extends object = QualityLevel, Track extends object = AudioTrack> {
quality?: Config<Level>
audio?: Config<Track>
}
export interface Result {
name: 'artplayerPluginHlsControl'
update: () => void
}
export function artplayerPluginHlsControl<Level extends object = QualityLevel, Track extends object = AudioTrack>(option?: Option<Level, Track>): (art: Artplayer) => Result
// Keep the required last signature for historical Parameters<typeof factory>[0] consumers.
export function artplayerPluginHlsControl<Level extends object = QualityLevel, Track extends object = AudioTrack>(option: Option<Level, Track>): (art: Artplayer) => Result
}
declare const artplayerPluginHlsControl: (option: { quality?: Config, audio?: Config }) => (art: Artplayer) => {
name: 'artplayerPluginHlsControl'
update: () => void
declare const artplayerPluginHlsControl: typeof artplayerPluginHlsControlDefinitions.artplayerPluginHlsControl
declare namespace artplayerPluginHlsControl {
export type QualityLevel = artplayerPluginHlsControlDefinitions.QualityLevel
export type AudioTrack = artplayerPluginHlsControlDefinitions.AudioTrack
export type Config<Item extends object = object> = artplayerPluginHlsControlDefinitions.Config<Item>
export type Option<Level extends object = QualityLevel, Track extends object = AudioTrack> = artplayerPluginHlsControlDefinitions.Option<Level, Track>
export type Result = artplayerPluginHlsControlDefinitions.Result
}
export default artplayerPluginHlsControl
export = artplayerPluginHlsControl
export as namespace artplayerPluginHlsControl;
+37 -34
View File
@@ -1,38 +1,41 @@
export interface JassubOption {
workerUrl: string
wasmUrl: string
modernWasmUrl: string
subUrl?: string
subContent?: string
timeOffset?: number
debug?: boolean
prescaleFactor?: number
prescaleHeightLimit?: number
maxRenderHeight?: number
fonts?: string[] | Uint8Array[]
availableFonts?: Record<string, Uint8Array | string>
fallbackFont?: string
useLocalFonts?: boolean
libassMemoryLimit?: number
libassGlyphLimit?: number
[key: string]: any
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
declare namespace artplayerPluginJassubDefinitions {
export interface JassubOption {
workerUrl: string
wasmUrl: string
modernWasmUrl: string
subUrl?: string
subContent?: string
timeOffset?: number
debug?: boolean
prescaleFactor?: number
prescaleHeightLimit?: number
maxRenderHeight?: number
fonts?: string[] | Uint8Array[]
availableFonts?: Record<string, Uint8Array | string>
fallbackFont?: string
useLocalFonts?: boolean
libassMemoryLimit?: number
libassGlyphLimit?: number
[key: string]: any
}
export interface JassubInstance {
resize: (force?: boolean, width?: number, height?: number, top?: number, left?: number) => Promise<void>
setVideo: (video: HTMLVideoElement) => Promise<void>
destroy: () => Promise<void>
[key: string]: any
}
export interface Result {
name: 'artplayerPluginJassub'
instance: JassubInstance
}
export const artplayerPluginJassub: (option: JassubOption) => (art: Artplayer) => Result
}
export interface JassubInstance {
resize: (force?: boolean, width?: number, height?: number, top?: number, left?: number) => Promise<void>
setVideo: (video: HTMLVideoElement) => Promise<void>
destroy: () => Promise<void>
[key: string]: any
declare const artplayerPluginJassub: typeof artplayerPluginJassubDefinitions.artplayerPluginJassub
declare namespace artplayerPluginJassub {
export type JassubOption = artplayerPluginJassubDefinitions.JassubOption
export type JassubInstance = artplayerPluginJassubDefinitions.JassubInstance
}
interface Result {
name: 'artplayerPluginJassub'
instance: JassubInstance
}
declare const artplayerPluginJassub: (option: JassubOption) => (art: Artplayer) => Result
export default artplayerPluginJassub
export = artplayerPluginJassub
export as namespace artplayerPluginJassub;
+37 -8
View File
@@ -1,16 +1,45 @@
declare const artplayerPluginMultipleSubtitles: (option: {
subtitles: {
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
declare namespace artplayerPluginMultipleSubtitlesDefinitions {
export interface TrackOption {
url?: string
name?: string
type?: 'vtt' | 'srt' | 'ass'
encoding?: string
onParser?: (...args: object[]) => object
}[]
}) => (art: Artplayer) => {
name: 'multipleSubtitles'
}
export interface Option {
subtitles: TrackOption[]
}
export interface RuntimeOption {
subtitles?: TrackOption[]
}
export interface LegacyResult {
name: 'multipleSubtitles'
}
export interface Result extends LegacyResult {
tracks: (names?: string[]) => void
reset: () => void
}
/** Historical synchronous extraction; actual registration is asynchronous. */
export type Factory = (option: Option) => (art: Artplayer) => LegacyResult
/** Accurate runtime view available through the /runtime entry. */
export interface RuntimeFactory {
(option: RuntimeOption): (art: Artplayer) => Promise<Result>
default: RuntimeFactory
}
/** Preserve existing parameter extraction and replacement-function compatibility. */
export function artplayerPluginMultipleSubtitles(option: Option): (art: Artplayer) => LegacyResult
}
declare const artplayerPluginMultipleSubtitles: typeof artplayerPluginMultipleSubtitlesDefinitions.artplayerPluginMultipleSubtitles
declare namespace artplayerPluginMultipleSubtitles {
export type TrackOption = artplayerPluginMultipleSubtitlesDefinitions.TrackOption
export type Option = artplayerPluginMultipleSubtitlesDefinitions.Option
export type RuntimeOption = artplayerPluginMultipleSubtitlesDefinitions.RuntimeOption
export type LegacyResult = artplayerPluginMultipleSubtitlesDefinitions.LegacyResult
export type Result = artplayerPluginMultipleSubtitlesDefinitions.Result
export type Factory = artplayerPluginMultipleSubtitlesDefinitions.Factory
export type RuntimeFactory = artplayerPluginMultipleSubtitlesDefinitions.RuntimeFactory
}
export default artplayerPluginMultipleSubtitles
export = artplayerPluginMultipleSubtitles
export as namespace artplayerPluginMultipleSubtitles;
@@ -0,0 +1,224 @@
@glomex/vast-ima-player
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2020 glomex GmbH
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@alugha/ima
# The MIT License (MIT)
**Copyright 2020 Alugha GmbH**
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+15 -34
View File
@@ -1,36 +1,17 @@
declare global {
interface Window {
artplayerPluginVast?: typeof artplayerPluginVast
}
}
type PlayUrlFn = (url: string, config?: any) => void
type PlayResFn = (res: string, config?: any) => void
interface VastPluginContext {
art: Artplayer
ima: any
imaPlayer: Player | null
playUrl: PlayUrlFn
playRes: PlayResFn
init: () => Player
adsRenderingSettings: any
playerOptions: PlayerOptions
container: HTMLDivElement | null
}
export type ArtplayerPluginVastOption = (params: VastPluginContext) => void | Promise<void>
export interface ArtplayerPluginVastInstance {
name: 'artplayerPluginVast'
destroy?: () => void
}
declare function artplayerPluginVast(
option: ArtplayerPluginVastOption,
): (art: Artplayer) => ArtplayerPluginVastInstance
export default artplayerPluginVast
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-use-before-define, ts/consistent-type-definitions -- Preserve historical export ordering and private aliases. */
export = artplayerPluginVast
export as namespace artplayerPluginVast;
type Option = (params: {
art: Artplayer
id: string
ima: any
imaPlayer: any
$container: HTMLDivElement
playUrl: (url: string) => void
playRes: (res: string) => void
}) => void
type Result = {
name: 'artplayerPluginVast'
}
declare const artplayerPluginVast: (option: Option) => (art: Artplayer) => Result
+26 -7
View File
@@ -1,10 +1,29 @@
declare const artplayerPluginVttThumbnail: (option: { vtt?: string, style?: Partial<CSSStyleDeclaration> }) => (
art: Artplayer,
) => {
name: 'artplayerPluginVttThumbnail'
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
declare namespace artplayerPluginVttThumbnailDefinitions {
export interface Option {
vtt?: string
style?: Partial<CSSStyleDeclaration>
}
export interface Result {
name: 'artplayerPluginVttThumbnail'
}
/** Historical factory type. Actual registration is asynchronous. */
export type Factory = (option: Option) => (art: Artplayer) => Result
/** Accurate runtime view available without casts through the /runtime entry. */
export interface RuntimeFactory {
(option: Option): (art: Artplayer) => Promise<Result>
default: RuntimeFactory
}
/** Preserve historical extraction and replacement-function compatibility. */
export function artplayerPluginVttThumbnail(option: Option): (art: Artplayer) => Result
}
declare const artplayerPluginVttThumbnail: typeof artplayerPluginVttThumbnailDefinitions.artplayerPluginVttThumbnail
declare namespace artplayerPluginVttThumbnail {
export type Option = artplayerPluginVttThumbnailDefinitions.Option
export type Result = artplayerPluginVttThumbnailDefinitions.Result
export type Factory = artplayerPluginVttThumbnailDefinitions.Factory
export type RuntimeFactory = artplayerPluginVttThumbnailDefinitions.RuntimeFactory
}
export default artplayerPluginVttThumbnail
export = artplayerPluginVttThumbnail
export as namespace artplayerPluginVttThumbnail;
+26 -8
View File
@@ -1,10 +1,28 @@
type Option = (ctx: CanvasRenderingContext2D, video: HTMLVideoElement) => void
type Result = HTMLCanvasElement
declare const artplayerProxyCanvas: (option?: Option) => (art: Artplayer) => Result
export default artplayerProxyCanvas
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
declare namespace artplayerProxyCanvasDefinitions {
/** Runs after drawing and bitmap release, before the draw event. */
export type Option = (ctx: CanvasRenderingContext2D, video: HTMLVideoElement) => void
/** Preserve the exact published 1.1.0 return type and its assignability. */
export type Result = HTMLCanvasElement
export type Factory = (option?: Option) => (art: Artplayer) => Result
export type Callable = Factory
/** Explicit view of forwarded media members; native Canvas members win. */
export type MediaCanvas = HTMLCanvasElement & Pick<HTMLVideoElement, Exclude<keyof HTMLVideoElement, keyof HTMLCanvasElement>>
/** Opt-in runtime identity; the historical root factory has no required properties. */
export interface RuntimeFactory extends Factory {
readonly default: RuntimeFactory
}
export const artplayerProxyCanvas: (option?: Option) => (art: Artplayer) => Result
}
declare const artplayerProxyCanvas: typeof artplayerProxyCanvasDefinitions.artplayerProxyCanvas
declare namespace artplayerProxyCanvas {
export type Option = artplayerProxyCanvasDefinitions.Option
export type Result = artplayerProxyCanvasDefinitions.Result
export type Factory = artplayerProxyCanvasDefinitions.Factory
export type Callable = artplayerProxyCanvasDefinitions.Callable
export type MediaCanvas = artplayerProxyCanvasDefinitions.MediaCanvas
export type RuntimeFactory = artplayerProxyCanvasDefinitions.RuntimeFactory
}
export = artplayerProxyCanvas
export as namespace artplayerProxyCanvas;
+212 -76
View File
@@ -1,79 +1,215 @@
interface Option {
/**
* Timeout for loading media in milliseconds
* @default 0
*/
loadTimeout?: number
/**
* Interval for timeupdate events in milliseconds
* @default 250
*/
timeupdateInterval?: number
/**
* Audio-video synchronization tolerance in seconds
* @default 0.12
*/
avSyncTolerance?: number
/**
* Whether to drop late video frames
* @default false
*/
dropLateFrames?: boolean
/**
* Poster image URL
*/
poster?: string
/**
* Media source (URL, Blob, or ReadableStream)
*/
source?: string | Blob | ReadableStream<Uint8Array>
/**
* Check if server supports range requests before loading
* @default false
*/
preflightRange?: boolean
/**
* Initial volume (0-1)
* @default 0.7
*/
volume?: number
/**
* Initial muted state
* @default false
*/
muted?: boolean
/**
* Autoplay
* @default false
*/
autoplay?: boolean
/**
* Loop playback
* @default false
*/
loop?: boolean
/**
* Cross-origin setting
*/
crossOrigin?: string
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
declare namespace artplayerProxyMediabunnyDefinitions {
export interface Option {
m3u8?: {
quality?: {
control?: boolean
setting?: boolean
title?: string
auto?: string
getName?: (level: {
id: number
index: number
name: null | string
height: number
bitrate: number
}) => string
}
audio?: {
control?: boolean
setting?: boolean
title?: string
auto?: string
getName?: (track: {
id: number
index: number
name: null | string
lang: string
language: string
bitrate: number
}) => string
}
}
/**
* Timeout for loading media in milliseconds
* @default 0
*/
loadTimeout?: number
/**
* Interval for timeupdate events in milliseconds
* @default 250
*/
timeupdateInterval?: number
/**
* Audio-video synchronization tolerance in seconds
* @default 0.12
*/
avSyncTolerance?: number
/**
* Whether to drop late video frames
* @default false
*/
dropLateFrames?: boolean
/**
* Poster image URL
*/
poster?: string
/**
* Media source (URL, Blob, or ReadableStream)
*/
source?: string | Blob | ReadableStream<Uint8Array>
/**
* Check if server supports range requests before loading
* @default false
*/
preflightRange?: boolean
/**
* Initial volume (0-1)
* @default 0.7
*/
volume?: number
/**
* Initial muted state
* @default false
*/
muted?: boolean
/**
* Autoplay
* @default false
*/
autoplay?: boolean
/**
* Loop playback
* @default false
*/
loop?: boolean
/**
* Cross-origin setting
*/
crossOrigin?: string
}
export type Result = HTMLCanvasElement
export interface HlsLevel {
id: number
index: number
name: string | null
height: number
bitrate: number
/** SDK object; narrow with the SDK version used by your application. */
track: unknown
}
export interface HlsAudio {
id: number
index: number
name: string | null
lang: string
language: string
bitrate: number
/** SDK object; narrow with the SDK version used by your application. */
track: unknown
}
export interface HlsState {
levels: HlsLevel[]
audios: HlsAudio[]
currentLevel: HlsLevel | null
currentAudio: HlsAudio | null
videoMode: 'auto' | 'manual'
audioMode: 'auto' | 'manual'
}
/** Historical RAF estimates, not decoded-frame or network timing measurements. */
export interface SyntheticFrameMetadata {
/** Historical media time in seconds, unlike the native video API. */
presentationTime: number
expectedDisplayTime: number
width: number
height: number
mediaTime: number
presentedFrames: number
processingDuration: number
captureTime: number
receiveTime: number
rtpTimestamp: number
}
export type SyntheticFrameCallback = (now: number, metadata: SyntheticFrameMetadata) => void
export type MediaListener = (event: Event & {
detail: unknown
}) => unknown
/** Opt-in media surface of art.mediabunny; decoder internals are not part of this view. */
export interface MediaBunnyShim {
canvas: HTMLCanvasElement
/** Runtime also accepts SDK sources; the default Option keeps its historical input union. */
src: unknown
readonly currentSrc: unknown
currentTime: number
readonly duration: number
/** Synthetic full-duration/current-time ranges, not measured network buffers. */
readonly buffered: TimeRanges
readonly played: TimeRanges
readonly seekable: TimeRanges
readonly paused: boolean
readonly playing: boolean
readonly ended: boolean
readonly seeking: boolean
readonly readyState: number
readonly networkState: number
readonly error: {
code: number
message: string
} | null
volume: number
muted: boolean
playbackRate: number
readonly videoWidth: number
readonly videoHeight: number
poster: string
/** The following setters are inert; use Option for autoplay/loop/crossOrigin. */
autoplay: boolean
loop: boolean
controls: boolean
playsInline: boolean
crossOrigin: string
preload: string
defaultMuted: boolean
defaultPlaybackRate: number
play: () => Promise<void>
pause: () => void
load: () => void
/** Always returns "maybe"; it does not probe codec/browser support. */
canPlayType: (type: string) => 'maybe'
getM3u8State: () => Promise<HlsState | null>
switchM3u8Quality: (value: unknown) => Promise<void>
switchM3u8Audio: (value: unknown) => Promise<void>
createTimeRanges: (start: number, end: number) => TimeRanges
requestVideoFrameCallback: (callback: SyntheticFrameCallback) => number
cancelVideoFrameCallback: (id: number) => void
addEventListener: (type: string, listener: MediaListener) => void
removeEventListener: (type: string, listener: MediaListener) => void
getBoundingClientRect: () => DOMRect
setAttribute: (name: string, value: unknown) => void
destroy: () => void
}
/** Native Canvas methods win collisions, including DOM event and attribute methods. */
export type MediaBunnyCanvas = HTMLCanvasElement & Omit<MediaBunnyShim, keyof HTMLCanvasElement>
/** The alias is installed by the proxy and removed on player destruction. */
export type MediaBunnyPlayer = Artplayer & {
mediabunny?: MediaBunnyShim
}
export const artplayerProxyMediabunny: (option?: Option) => (art: Artplayer) => Result
}
declare const artplayerProxyMediabunny: typeof artplayerProxyMediabunnyDefinitions.artplayerProxyMediabunny
declare namespace artplayerProxyMediabunny {
export type Option = artplayerProxyMediabunnyDefinitions.Option
export type Result = artplayerProxyMediabunnyDefinitions.Result
export type HlsLevel = artplayerProxyMediabunnyDefinitions.HlsLevel
export type HlsAudio = artplayerProxyMediabunnyDefinitions.HlsAudio
export type HlsState = artplayerProxyMediabunnyDefinitions.HlsState
export type SyntheticFrameMetadata = artplayerProxyMediabunnyDefinitions.SyntheticFrameMetadata
export type SyntheticFrameCallback = artplayerProxyMediabunnyDefinitions.SyntheticFrameCallback
export type MediaListener = artplayerProxyMediabunnyDefinitions.MediaListener
export type MediaBunnyShim = artplayerProxyMediabunnyDefinitions.MediaBunnyShim
export type MediaBunnyCanvas = artplayerProxyMediabunnyDefinitions.MediaBunnyCanvas
export type MediaBunnyPlayer = artplayerProxyMediabunnyDefinitions.MediaBunnyPlayer
}
type Result = HTMLCanvasElement
declare const artplayerProxyMediabunny: (option?: Option) => (art: Artplayer) => Result
export default artplayerProxyMediabunny
export = artplayerProxyMediabunny
export as namespace artplayerProxyMediabunny;
+107 -30
View File
@@ -1,32 +1,109 @@
interface Message {
type: string
data: any
id?: number
// Generated from the package public declaration by yarn build:ts. Do not edit.
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
declare namespace ArtplayerToolIframeDefinitions {
export interface Option {
iframe: HTMLIFrameElement
url: string
}
/** Historical open envelope. data remains required in the default class API. */
export interface Message<T = any> {
type: string
data: T
id?: number
}
export interface Callbacks {
resove: (...args: any[]) => any
reject: (...args: any[]) => any
}
/** Public notifications omit the request id and all private session metadata. */
export interface Notification<T = unknown> {
type: string
data: T
}
export type MessageCallback = (this: ArtplayerToolIframe, message: Notification) => void
/** Actual outgoing calls allow an omitted data field. Custom message types remain valid. */
export interface OutboundMessage<T = unknown> {
type: string
data?: T
id?: number
}
/** Known built-in envelopes; use Message/OutboundMessage for application protocols. */
export type ProtocolMessage<T = unknown> = {
type: 'inject'
data?: undefined
id?: number
} | {
type: 'commit'
data: string
id: number
} | {
type: 'response'
data: T
id: number
} | {
type: 'error'
data: unknown
id: number
}
export type Resolve<T> = (value: T | PromiseLike<T>) => void
export type ResolverCallback<T> = (resolve: Resolve<T>) => void
/** Opt-in view. Response T is supplied by the application's protocol, not validated at runtime. */
export interface RuntimeInstance extends Omit<ArtplayerToolIframe, 'messageCallback' | 'postMessage' | 'message'> {
messageCallback: MessageCallback | null
postMessage: <T = unknown>(message: OutboundMessage) => Promise<T>
message: (callback: MessageCallback) => void
}
/** For the existing serialized resolve(...) protocol; callback bodies must use that exact name. */
export interface ResolverInstance extends Omit<RuntimeInstance, 'commit'> {
commit: <T>(callback: ResolverCallback<T>) => Promise<T>
}
/** Opt-in static async/optional-data view. There is no runtime self-default property. */
export interface RuntimeConstructor {
new (option: Option): RuntimeInstance
readonly prototype: RuntimeInstance
readonly iframe: boolean
postMessage: (message: OutboundMessage) => void
onMessage: (event: MessageEvent<OutboundMessage>) => Promise<void>
inject: () => void
}
export class ArtplayerToolIframe {
constructor(option: Option)
static iframe: boolean
static postMessage(message: Message): void
static onMessage(event: MessageEvent & {
data: Message
}): void
static inject(): void
readonly promises: Record<number, Callbacks>
readonly injected: boolean
readonly destroyed: boolean
readonly $iframe: HTMLIFrameElement
readonly url: string
readonly messageCallback: (...args: any[]) => any
onMessage(event: MessageEvent & {
data: Message
}): void
postMessage(message: Message): Promise<any>
commit<T extends (...args: any[]) => any>(callback: T): Promise<ReturnType<T>>
message(callback: (...args: any[]) => any): void
destroy(): void
}
}
declare class ArtplayerToolIframe {
constructor(option: { iframe: HTMLIFrameElement, url: string })
static iframe: boolean
static postMessage(message: Message): void
static onMessage(event: MessageEvent & { data: Message }): void
static inject(): void
readonly promises: Record<number, { resove: (...args: any[]) => any, reject: (...args: any[]) => any }>
readonly injected: boolean
readonly destroyed: boolean
readonly $iframe: HTMLIFrameElement
readonly url: string
readonly messageCallback: (...args: any[]) => any
onMessage(event: MessageEvent & { data: Message }): void
postMessage(message: Message): Promise<any>
commit<T extends (...args: any[]) => any>(callback: T): Promise<ReturnType<T>>
message(callback: (...args: any[]) => any): void
destroy(): void
declare const ArtplayerToolIframe: typeof ArtplayerToolIframeDefinitions.ArtplayerToolIframe
type ArtplayerToolIframe = ArtplayerToolIframeDefinitions.ArtplayerToolIframe
declare namespace ArtplayerToolIframe {
export type Option = ArtplayerToolIframeDefinitions.Option
export type Message<T = any> = ArtplayerToolIframeDefinitions.Message<T>
export type Callbacks = ArtplayerToolIframeDefinitions.Callbacks
export type Notification<T = unknown> = ArtplayerToolIframeDefinitions.Notification<T>
export type MessageCallback = ArtplayerToolIframeDefinitions.MessageCallback
export type OutboundMessage<T = unknown> = ArtplayerToolIframeDefinitions.OutboundMessage<T>
export type ProtocolMessage<T = unknown> = ArtplayerToolIframeDefinitions.ProtocolMessage<T>
export type Resolve<T> = ArtplayerToolIframeDefinitions.Resolve<T>
export type ResolverCallback<T> = ArtplayerToolIframeDefinitions.ResolverCallback<T>
export type RuntimeInstance = ArtplayerToolIframeDefinitions.RuntimeInstance
export type ResolverInstance = ArtplayerToolIframeDefinitions.ResolverInstance
export type RuntimeConstructor = ArtplayerToolIframeDefinitions.RuntimeConstructor
}
export default ArtplayerToolIframe
export = artplayerToolIframe
export as namespace artplayerToolIframe;
export = ArtplayerToolIframe
export as namespace ArtplayerToolIframe;
+104
View File
@@ -0,0 +1,104 @@
// Generated from the package public declaration by yarn build:ts. Do not edit.
/** Extract PNG thumbnail sheets from a locally selected video file. */
declare class ArtplayerToolThumbnail {
constructor(option?: ArtplayerToolThumbnail.Option)
static readonly DEFAULTS: ArtplayerToolThumbnail.DefaultOptions
static ondragover(event: DragEvent): void
static creatVideo(): HTMLVideoElement
processing: boolean
option: ArtplayerToolThumbnail.ResolvedOption
video: HTMLVideoElement
duration: number
density: number | undefined
file: File | undefined
videoUrl: string | undefined
thumbnailUrl: string | undefined
e?: ArtplayerToolThumbnail.EventRegistry
setup(option?: ArtplayerToolThumbnail.Option): this
inputChange(event: Event): void
ondrop(event: DragEvent): void
loadVideo(file?: File | null): void
/** Ready-metadata preflight may throw synchronously. Cancellation rejects with AbortError. */
start(): Promise<void>
creatScreenshotDate(): ArtplayerToolThumbnail.ScreenshotPoint[]
creatCanvas(): HTMLCanvasElement
download(): this
errorHandle(condition: unknown, message: string): void
destroy(): void
on<Name extends PropertyKey, Custom extends unknown[], Context>(name: Name, callback: (this: Context, ...args: ArtplayerToolThumbnail.EventArgs<Name, Custom>) => unknown, ctx?: Context): this
once<Name extends PropertyKey, Custom extends unknown[], Context>(name: Name, callback: (this: Context, ...args: ArtplayerToolThumbnail.EventArgs<Name, Custom>) => unknown, ctx?: Context): this
emit<Name extends PropertyKey, Custom extends unknown[]>(name: Name, ...args: ArtplayerToolThumbnail.EventArgs<Name, Custom>): this
off<Name extends PropertyKey, Custom extends unknown[]>(name: Name, callback?: ArtplayerToolThumbnail.Listener<ArtplayerToolThumbnail.EventArgs<Name, Custom>>): this
}
declare namespace ArtplayerToolThumbnail {
interface SheetOptions {
number: number
width: number
height: number
column: number
begin: number
end: number
}
type Compatibility = 'published-3.5' | 'workspace-4.4'
interface DefaultOptions extends SheetOptions {
delay: number
}
/** fileInput must be a file input or an Element wrapper when constructing. */
interface Option extends Partial<SheetOptions> {
fileInput?: Element
compatibility?: Compatibility
/** Published mode delay in milliseconds, clamped to 10-1000. */
delay?: number
[name: string]: unknown
}
interface ResolvedOption extends SheetOptions {
fileInput: HTMLInputElement
compatibility?: Compatibility
delay?: number
[name: string]: unknown
}
interface ScreenshotPoint {
time: number
x: number
y: number
}
interface Events {
file: [
file: File,
]
video: [
video: HTMLVideoElement,
]
canvas: [
canvas: HTMLCanvasElement,
]
update: [
url: string,
progress: number,
]
done: [
]
download: [
name: string,
]
/** Built-in failures are strings; user callbacks may throw any message value. */
error: [
message: unknown,
]
destroy: [
]
}
type EventArgs<Name extends PropertyKey, Custom extends unknown[] = unknown[]> = Name extends keyof Events ? [
...Events[Name],
] : Custom
type Listener<Args extends unknown[]> = ((...args: Args) => unknown) & {
_?: (...args: Args) => unknown
}
/** Heterogeneous listener storage; dispatch through emit to retain event argument checks. */
type EventRegistry = Partial<Record<PropertyKey, {
fn: Listener<never[]>
ctx: unknown
}[]>>
}
export = ArtplayerToolThumbnail
export as namespace ArtplayerToolThumbnail;
+1365 -1284
View File
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-ads.js v2.1.0
* artplayer-plugin-ads.js v3.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,l){"object"===typeof exports&&"undefined"!==typeof module?module.exports=l():"function"==typeof define&&define.amd?(t.artplayerPluginAds=l(),define(function(){return t.artplayerPluginAds})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAds=l()}(this,function(){"use strict";function e(l){return n=>{!function(l){const{version:n,utils:{errorHandle:i}}=l.constructor,a=n.split(".").map(Number);i(a[0]+a[1]/100>=5,`Artplayer.js@${n} is not compatible the artplayerPluginAds@${e.version}. Please update it to version Artplayer.js@5.x.x`)}(n);const{template:{$player:i},icons:{volume:a,volumeClose:t,fullscreenOn:r,fullscreenOff:o,loading:d},constructor:{validator:s,utils:{query:p,append:u,setStyle:c}}}=n;l=s({html:"",video:"",url:"",playDuration:5,totalDuration:10,muted:!1,i18n:{close:"\u5173\u95ed\u5e7f\u544a",countdown:"%s\u79d2",detail:"\u67e5\u770b\u8be6\u60c5",canBeClosed:"%s\u79d2\u540e\u53ef\u5173\u95ed\u5e7f\u544a"},...l},{html:"?string",video:"?string",url:"?string",playDuration:"number",totalDuration:"number",muted:"?boolean",i18n:{close:"string",countdown:"string",detail:"string",canBeClosed:"string"}});let y=null,g=null,f=null,m=null,v=null,x=null,h=0,b=null,w=!1,$=!1,k=!1;function D(e,l){return l.replace("%s",e)}function A(){w=!0,n.play(),l.video&&y.pause(),c(n.template.$ads,"display","none"),n.emit("artplayerPluginAds:skip",l)}function C(){w||(b=setTimeout(()=>{h+=1;const e=l.playDuration-h;e>=1?f.innerHTML=D(e,l.i18n.canBeClosed):(f.innerHTML=l.i18n.close,k||(k=!0)),m.innerHTML=D(l.totalDuration-h,l.i18n.countdown),h>=l.totalDuration?A():C()},1e3))}function P(){w||clearTimeout(b)}function T(){$||($=!0,function(){n.template.$ads=u(i,'<div class="artplayer-plugin-ads"></div>'),y=u(n.template.$ads,l.video?`<video class="artplayer-plugin-ads-video" src="${l.video}" loop playsInline></video>`:`<div class="artplayer-plugin-ads-html">${l.html}</div>`),x=u(n.template.$ads,'<div class="artplayer-plugin-ads-loading"></div>'),u(x,d),g=u(n.template.$ads,`<div class="artplayer-plugin-ads-timer">\n <div class="artplayer-plugin-ads-close">${l.playDuration<=0?l.i18n.close:D(l.playDuration,l.i18n.canBeClosed)}</div>\n <div class="artplayer-plugin-ads-countdown">${D(l.totalDuration,l.i18n.countdown)}</div>\n </div>`),f=p(".artplayer-plugin-ads-close",g),m=p(".artplayer-plugin-ads-countdown",g),l.playDuration>=l.totalDuration&&c(f,"display","none"),n.proxy(f,"click",()=>{k&&A()}),v=u(n.template.$ads,`<div class="artplayer-plugin-ads-control">\n <div class="artplayer-plugin-ads-detail">${l.i18n.detail}</div>\n <div class="artplayer-plugin-ads-muted"></div>\n <div class="artplayer-plugin-ads-fullscreen"></div>\n </div>`);const e=p(".artplayer-plugin-ads-detail",v),s=p(".artplayer-plugin-ads-muted",v),h=p(".artplayer-plugin-ads-fullscreen",v);if(l.url?n.proxy(e,"click",()=>{window.open(l.url),n.emit("artplayerPluginAds:click",l)}):c(e,"display","none"),l.video){const e=u(s,a),i=u(s,t);c(i,"display","none"),l.muted&&(y.muted=!0,c(e,"display","none"),c(i,"display","inline-flex")),n.proxy(s,"click",()=>{y.muted=!y.muted,y.muted?(c(e,"display","none"),c(i,"display","inline-flex")):(c(e,"display","inline-flex"),c(i,"display","none"))})}else c(s,"display","none");const b=u(h,r),w=u(h,o);c(w,"display","none"),n.proxy(h,"click",()=>{n.fullscreen=!n.fullscreen,n.fullscreen?(c(b,"display","inline-flex"),c(w,"display","none")):(c(b,"display","none"),c(w,"display","inline-flex"))}),n.proxy(y,"click",()=>{l.url&&window.open(l.url),n.emit("artplayerPluginAds:click",l)})}(),n.pause(),l.video?(n.proxy(y,"error",A),n.proxy(y,"loadedmetadata",()=>{C(),y.play(),c(g,"display","flex"),c(v,"display","flex"),c(x,"display","none")})):(C(),c(g,"display","flex"),c(v,"display","flex"),c(x,"display","none")),n.on("document:visibilitychange",()=>{document.hidden?P():C()}))}return n.on("ready",()=>{n.once("play",T),n.once("video:playing",T)}),{name:"artplayerPluginAds",skip:A,pause:P,play:C}}}if("undefined"!==typeof document&&!document.getElementById("artplayer-plugin-ads")){const e=document.createElement("style");e.id="artplayer-plugin-ads",e.textContent=".artplayer-plugin-ads{position:absolute;z-index:150;inset:0;width:100%;height:100%;overflow:hidden;font-size:13px;line-height:1;color:#fff;background-color:#000}.artplayer-plugin-ads .artplayer-plugin-ads-html{display:flex;align-items:center;justify-content:center;width:100%;height:100%}.artplayer-plugin-ads .artplayer-plugin-ads-video{width:100%;height:100%}.artplayer-plugin-ads .artplayer-plugin-ads-timer{display:none;position:absolute;top:10px;right:10px}.artplayer-plugin-ads .artplayer-plugin-ads-timer>div{display:flex;align-items:center;background-color:#00000080;border-radius:15px;margin-left:5px;padding:5px 10px;cursor:pointer}.artplayer-plugin-ads .artplayer-plugin-ads-control{display:none;position:absolute;bottom:10px;right:10px}.artplLine truncated
!function(e,n){"object"===typeof exports&&"undefined"!==typeof module?module.exports=n():"function"==typeof define&&define.amd?(e.artplayerPluginAds=n(),define(function(){return e.artplayerPluginAds})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAds=n()}(this,function(){"use strict";function e(e){console.warn("Artplayer Ads:",e)}function n(n){const t=[];let i=!1;function l(e,n){if(!i){t.push(n);try{e()}finally{i&&n()}}}return{on(e,t){const a=()=>{i||t()};l(()=>{n.on(e,a)},()=>{n.off(e,a)})},dom(e,n,t){const a=()=>{i||t()};l(()=>e.addEventListener(n,a),()=>e.removeEventListener(n,a))},dispose(){if(!i){i=!0;for(const i of t.splice(0).reverse())try{i()}catch(n){e(n)}}}}}const t=(e,n)=>n.replace("%s",String(e));function i(i,l,a,o){const r=n(i),s=n(i),d=i.template;let u,p,c="waiting",y=!1,f=!1,g=!1;const v=function(e,n,t){let i,l=0,a=!1,o=!1,r=!1;function s(){a&&o&&!r&&void 0===i&&(i=setTimeout(()=>{i=void 0,!r&&o&&(l+=1,n(l),r||(l>=e()?t():s()))},1e3))}function d(){o=!1,void 0!==i&&clearTimeout(i),i=void 0}return{start(){a||r||(a=!0,o=!0,s())},play(){a&&!r&&(o=!0,s())},pause:d,stop(){r=!0,d()}}}(()=>l.totalDuration,e=>p?.render(e),w),m=()=>"active"===c&&!i.isDestroy,h=()=>"destroyed"===c||i.isDestroy;function x(n){try{n?.pause()}catch(t){e(t)}}function b(n,t,i){try{Promise.resolve(n()).then(()=>{m()||i?.()},t).catch(e)}catch(l){t(l)}}function w(){if("ended"!==c&&"destroyed"!==c&&!i.isDestroy){if(c="ended",v.stop(),r.dispose(),y){if(b(()=>i.play(),n=>{"destroyed"!==c&&e(n)}),h())return;if(x(p?.video),h())return;p?.hide()}h()||i.emit("artplayerPluginAds:skip",l)}}function D(){const n=p?.video;if(x(n),n)try{n.removeAttribute("src"),n.load()}catch(t){e(t)}try{u?.remove()}catch(t){e(t)}finally{u&&d.$ads===u&&delete d.$ads}}function k(){"destroyed"!==c&&(c="destroyed",v.stop(),r.dispose(),s.dispose(),D())}function O(){if("waiting"===c&&!i.isDestroy){c="active",y=!0;try{if(p=function(e,n,i,l,a){const{append:o,query:r,setStyle:s}=l,d=o(e,'<div class="artplayer-plugin-ads"></div>');a(d);const u=o(d,i.video?'<video class="artplayer-plugin-ads-video" loop playsInline></video>':`<div class="artplayer-plugin-ads-html">${i.html}</div>`),p=i.video?u:null,c=o(d,'<div class="artplayer-plugin-ads-loading"></div>');o(c,n.loading);const y=o(d,'<div class="artplayer-plugin-ads-timer">\n <div class="artplayer-plugin-ads-close"></div>\n <div class="artplayer-plugin-ads-countdown"></div>\n </div>'),f=r(".artplayer-plugin-ads-close",y),g=r(".artplayer-plugin-ads-countdown",y),v=o(d,`<div class="artplayer-plugin-ads-control">\n <div class="artplayer-plugin-ads-detail">${i.i18n.detail}</div>\n <div class="artplayer-plugin-ads-muted"></div>\n <div class="artplayer-plugin-ads-fullscreen"></div>\n </div>`),m=r(".artplayer-plugin-ads-detail",v),h=r(".artplayer-plugin-ads-muted",v),x=r(".artplayer-plugin-ads-fullscreen",v);let b=i.playDuration<=0;function w(){s(n.volume,"display",p?.muted?"none":"inline-flex"),s(n.volumeClose,"display",p?.muted?"inline-flex":"none")}function D(e){const n=i.playDuration-e;b=0===e?i.playDuration<=0:n<1||Number.isNaN(n),f.innerHTML=b?i.i18n.close:t(n,i.i18n.canBeClosed),g.innerHTML=t(i.totalDuration-e,i.i18n.countdown)}return i.playDuration>=i.totalDuration&&s(f,"display","none"),i.url||s(m,"display","none"),p?(o(h,n.volume),o(h,n.volumeClose),p.muted=Boolean(i.muted),w()):s(h,"display","none"),o(x,n.fullscreenOn),o(x,n.fullscreenOff),D(0),{root:d,video:p,render:D,ready(){s(y,"display","flex"),s(v,"display","flex"),s(c,"display","none")},hide(){s(d,"display","none")},fullscreen(e){s(n.fullscreenOn,"display",e?"none":"inline-flex"),s(n.fullscreenOff,"display",e?"inline-flex":"none")},bind(e,n){e.dom(f,"click",()=>{b&&n.skip()}),e.dom(u,"click",n.click),i.url&&e.dom(m,"click",n.click),p&&e.dom(h,"click",()=>{p.muted=!p.muted,w()}),e.dom(x,"click",n.fullscreen)}}}(d.$player,a,l,o,e=>{u=e,d.$ads=e}),!m())return void D();if(i.pause(),!m())return;const n=p,s=u.ownerDocument;n.fullscreen(i.fullscreen),n.bind(r,{skip:w,click(){l.url&&(s.defaultView||window).open(l.url),m()&&i.emit("artplayerPluginAds:click",l)},fullscreen(){i.fullscreen=!i.fullscreen,m()&&n.fullscreen(i.fullscreen)}}),r.on("fullscreen",()=>n.fullscreen(i.fullscreen));const c=()=>s.hidden?v.pause():v.play();r.dom(s,"visibilitychange",c),r.on("document:visibilitychange",c);const y=()=>{if(m()&&!g){if(g=!0,v.start(),s.hidden&&v.pause(),n.video){const t=n.video;b(()=>t.play(),n=>{m()&&(e(n),w())},()=>x(t))}m()&&n.ready()}};n.video?(r.dom(n.video,"error",w),r.dom(n.video,"loadedmetadata",y),n.video.src=l.video):y()}catch(n){throw k(),n}}}try{s.on("destroy",k),r.on("ready",()=>{f||"waiting"!==c||(f=!0,r.on("play",O),r.on("video:playing",O))}),i.isDestroy&&k()}catch(A){throw k(),A}return{name:"artplayerPluginAds",skip:w,pause:v.pause,play:v.play}}function l(e){return n=>{const t=n.constructor;if("function"!==typeof t.validator||!["append","query","setStyle"].every(e=>"function"===typeof Reflect.get(t.utils||{},e)))thLine truncated
+2 -2
View File
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-ads.js v2.1.0
* artplayer-plugin-ads.js v3.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,l){"object"===typeof exports&&"undefined"!==typeof module?module.exports=l():"function"==typeof define&&define.amd?(t.artplayerPluginAds=l(),define(function(){return t.artplayerPluginAds})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAds=l()}(this,function(){"use strict";var e=Object.defineProperty,l=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,a=Object.prototype.propertyIsEnumerable,i=(l,n,a)=>n in l?e(l,n,{enumerable:!0,configurable:!0,writable:!0,value:a}):l[n]=a;function t(e){return r=>{!function(e){const{version:l,utils:{errorHandle:n}}=e.constructor,a=l.split(".").map(Number);n(a[0]+a[1]/100>=5,`Artplayer.js@${l} is not compatible the artplayerPluginAds@${t.version}. Please update it to version Artplayer.js@5.x.x`)}(r);const{template:{$player:o},icons:{volume:d,volumeClose:p,fullscreenOn:s,fullscreenOff:u,loading:c},constructor:{validator:y,utils:{query:g,append:f,setStyle:m}}}=r;e=y(((e,t)=>{for(var r in t||(t={}))n.call(t,r)&&i(e,r,t[r]);if(l)for(var r of l(t))a.call(t,r)&&i(e,r,t[r]);return e})({html:"",video:"",url:"",playDuration:5,totalDuration:10,muted:!1,i18n:{close:"\u5173\u95ed\u5e7f\u544a",countdown:"%s\u79d2",detail:"\u67e5\u770b\u8be6\u60c5",canBeClosed:"%s\u79d2\u540e\u53ef\u5173\u95ed\u5e7f\u544a"}},e),{html:"?string",video:"?string",url:"?string",playDuration:"number",totalDuration:"number",muted:"?boolean",i18n:{close:"string",countdown:"string",detail:"string",canBeClosed:"string"}});let v=null,x=null,h=null,b=null,w=null,$=null,k=0,D=null,P=!1,j=!1,A=!1;function O(e,l){return l.replace("%s",e)}function C(){P=!0,r.play(),e.video&&v.pause(),m(r.template.$ads,"display","none"),r.emit("artplayerPluginAds:skip",e)}function T(){P||(D=setTimeout(()=>{k+=1;const l=e.playDuration-k;l>=1?h.innerHTML=O(l,e.i18n.canBeClosed):(h.innerHTML=e.i18n.close,A||(A=!0)),b.innerHTML=O(e.totalDuration-k,e.i18n.countdown),k>=e.totalDuration?C():T()},1e3))}function B(){P||clearTimeout(D)}function H(){j||(j=!0,function(){r.template.$ads=f(o,'<div class="artplayer-plugin-ads"></div>'),v=f(r.template.$ads,e.video?`<video class="artplayer-plugin-ads-video" src="${e.video}" loop playsInline></video>`:`<div class="artplayer-plugin-ads-html">${e.html}</div>`),$=f(r.template.$ads,'<div class="artplayer-plugin-ads-loading"></div>'),f($,c),x=f(r.template.$ads,`<div class="artplayer-plugin-ads-timer">\n <div class="artplayer-plugin-ads-close">${e.playDuration<=0?e.i18n.close:O(e.playDuration,e.i18n.canBeClosed)}</div>\n <div class="artplayer-plugin-ads-countdown">${O(e.totalDuration,e.i18n.countdown)}</div>\n </div>`),h=g(".artplayer-plugin-ads-close",x),b=g(".artplayer-plugin-ads-countdown",x),e.playDuration>=e.totalDuration&&m(h,"display","none"),r.proxy(h,"click",()=>{A&&C()}),w=f(r.template.$ads,`<div class="artplayer-plugin-ads-control">\n <div class="artplayer-plugin-ads-detail">${e.i18n.detail}</div>\n <div class="artplayer-plugin-ads-muted"></div>\n <div class="artplayer-plugin-ads-fullscreen"></div>\n </div>`);const l=g(".artplayer-plugin-ads-detail",w),n=g(".artplayer-plugin-ads-muted",w),a=g(".artplayer-plugin-ads-fullscreen",w);if(e.url?r.proxy(l,"click",()=>{window.open(e.url),r.emit("artplayerPluginAds:click",e)}):m(l,"display","none"),e.video){const l=f(n,d),a=f(n,p);m(a,"display","none"),e.muted&&(v.muted=!0,m(l,"display","none"),m(a,"display","inline-flex")),r.proxy(n,"click",()=>{v.muted=!v.muted,v.muted?(m(l,"display","none"),m(a,"display","inline-flex")):(m(l,"display","inline-flex"),m(a,"display","none"))})}else m(n,"display","none");const i=f(a,s),t=f(a,u);m(t,"display","none"),r.proxy(a,"click",()=>{r.fullscreen=!r.fullscreen,r.fullscreen?(m(i,"display","inline-flex"),m(t,"display","none")):(m(i,"display","none"),m(t,"display","inline-flex"))}),r.proxy(v,"click",()=>{e.url&&window.open(e.url),r.emit("artplayerPluginAds:click",e)})}(),r.pause(),e.video?(r.proxy(v,"error",C),r.proxy(v,"loadedmetadata",()=>{T(),v.play(),m(x,"display","flex"),m(w,"display","flex"),m($,"display","none")})):(T(),m(x,"display","flex"),m(w,"display","flex"),m($,"display","none")),r.on("document:visibilitychange",()=>{document.hidden?B():T()}))}return r.on("ready",()=>{r.once("play",H),r.once("video:playing",H)}),{name:"artplayerPluginAds",skip:C,pause:B,play:T}}}if("undefined"!==typeof document&&!document.getElementById("artplayer-plugin-ads")){const e=document.createElement("style");e.id="artplayer-plugin-ads",e.textContent=".artplayer-plugin-ads{position:absolute;z-index:150;inset:0;width:100%;height:100%;overflow:hidden;font-size:13px;line-height:1;color:#fff;background-color:#000}.artplayer-plugin-ads .artplayer-plugin-ads-html{display:flex;align-items:center;justify-content:center;width:100%;height:100%}.artplayer-plugin-ads .artplayer-plugin-ads-video{width:100%;height:100%}.artplayer-plugin-ads .artplayer-plugin-ads-timer{display:noneLine truncated
!function(e,n){"object"===typeof exports&&"undefined"!==typeof module?module.exports=n():"function"==typeof define&&define.amd?(e.artplayerPluginAds=n(),define(function(){return e.artplayerPluginAds})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAds=n()}(this,function(){"use strict";var e=Object.defineProperty,n=Object.getOwnPropertySymbols,t=Object.prototype.hasOwnProperty,l=Object.prototype.propertyIsEnumerable,i=(n,t,l)=>t in n?e(n,t,{enumerable:!0,configurable:!0,writable:!0,value:l}):n[t]=l;function r(e,r){return r(((e,r)=>{for(var o in r||(r={}))t.call(r,o)&&i(e,o,r[o]);if(n)for(var o of n(r))l.call(r,o)&&i(e,o,r[o]);return e})({html:"",video:"",url:"",playDuration:5,totalDuration:10,muted:!1,i18n:{close:"\u5173\u95ed\u5e7f\u544a",countdown:"%s\u79d2",detail:"\u67e5\u770b\u8be6\u60c5",canBeClosed:"%s\u79d2\u540e\u53ef\u5173\u95ed\u5e7f\u544a"}},e),{html:"?string",video:"?string",url:"?string",playDuration:"number",totalDuration:"number",muted:"?boolean",i18n:{close:"string",countdown:"string",detail:"string",canBeClosed:"string"}})}function o(e){console.warn("Artplayer Ads:",e)}function a(e){const n=[];let t=!1;function l(e,l){if(!t){n.push(l);try{e()}finally{t&&l()}}}return{on(n,i){const r=()=>{t||i()};l(()=>{e.on(n,r)},()=>{e.off(n,r)})},dom(e,n,i){const r=()=>{t||i()};l(()=>e.addEventListener(n,r),()=>e.removeEventListener(n,r))},dispose(){if(!t){t=!0;for(const t of n.splice(0).reverse())try{t()}catch(e){o(e)}}}}}const s=(e,n)=>n.replace("%s",String(e));function d(e,n,t,l){const i=a(e),r=a(e),d=e.template;let u,p,c="waiting",y=!1,f=!1,g=!1;const v=function(e,n,t){let l,i=0,r=!1,o=!1,a=!1;function s(){r&&o&&!a&&void 0===l&&(l=setTimeout(()=>{l=void 0,!a&&o&&(i+=1,n(i),a||(i>=e()?t():s()))},1e3))}function d(){o=!1,void 0!==l&&clearTimeout(l),l=void 0}return{start(){r||a||(r=!0,o=!0,s())},play(){r&&!a&&(o=!0,s())},pause:d,stop(){a=!0,d()}}}(()=>n.totalDuration,e=>null==p?void 0:p.render(e),w),m=()=>"active"===c&&!e.isDestroy,h=()=>"destroyed"===c||e.isDestroy;function b(e){try{null==e||e.pause()}catch(n){o(n)}}function x(e,n,t){try{Promise.resolve(e()).then(()=>{m()||null==t||t()},n).catch(o)}catch(l){n(l)}}function w(){if("ended"!==c&&"destroyed"!==c&&!e.isDestroy){if(c="ended",v.stop(),i.dispose(),y){if(x(()=>e.play(),e=>{"destroyed"!==c&&o(e)}),h())return;if(b(null==p?void 0:p.video),h())return;null==p||p.hide()}h()||e.emit("artplayerPluginAds:skip",n)}}function D(){const e=null==p?void 0:p.video;if(b(e),e)try{e.removeAttribute("src"),e.load()}catch(n){o(n)}try{null==u||u.remove()}catch(n){o(n)}finally{u&&d.$ads===u&&delete d.$ads}}function k(){"destroyed"!==c&&(c="destroyed",v.stop(),i.dispose(),r.dispose(),D())}function O(){if("waiting"===c&&!e.isDestroy){c="active",y=!0;try{if(p=function(e,n,t,l,i){const{append:r,query:o,setStyle:a}=l,d=r(e,'<div class="artplayer-plugin-ads"></div>');i(d);const u=r(d,t.video?'<video class="artplayer-plugin-ads-video" loop playsInline></video>':`<div class="artplayer-plugin-ads-html">${t.html}</div>`),p=t.video?u:null,c=r(d,'<div class="artplayer-plugin-ads-loading"></div>');r(c,n.loading);const y=r(d,'<div class="artplayer-plugin-ads-timer">\n <div class="artplayer-plugin-ads-close"></div>\n <div class="artplayer-plugin-ads-countdown"></div>\n </div>'),f=o(".artplayer-plugin-ads-close",y),g=o(".artplayer-plugin-ads-countdown",y),v=r(d,`<div class="artplayer-plugin-ads-control">\n <div class="artplayer-plugin-ads-detail">${t.i18n.detail}</div>\n <div class="artplayer-plugin-ads-muted"></div>\n <div class="artplayer-plugin-ads-fullscreen"></div>\n </div>`),m=o(".artplayer-plugin-ads-detail",v),h=o(".artplayer-plugin-ads-muted",v),b=o(".artplayer-plugin-ads-fullscreen",v);let x=t.playDuration<=0;function w(){a(n.volume,"display",(null==p?void 0:p.muted)?"none":"inline-flex"),a(n.volumeClose,"display",(null==p?void 0:p.muted)?"inline-flex":"none")}function D(e){const n=t.playDuration-e;x=0===e?t.playDuration<=0:n<1||Number.isNaN(n),f.innerHTML=x?t.i18n.close:s(n,t.i18n.canBeClosed),g.innerHTML=s(t.totalDuration-e,t.i18n.countdown)}return t.playDuration>=t.totalDuration&&a(f,"display","none"),t.url||a(m,"display","none"),p?(r(h,n.volume),r(h,n.volumeClose),p.muted=Boolean(t.muted),w()):a(h,"display","none"),r(b,n.fullscreenOn),r(b,n.fullscreenOff),D(0),{root:d,video:p,render:D,ready(){a(y,"display","flex"),a(v,"display","flex"),a(c,"display","none")},hide(){a(d,"display","none")},fullscreen(e){a(n.fullscreenOn,"display",e?"none":"inline-flex"),a(n.fullscreenOff,"display",e?"inline-flex":"none")},bind(e,n){e.dom(f,"click",()=>{x&&n.skip()}),e.dom(u,"click",n.click),t.url&&e.dom(m,"click",n.click),p&&e.dom(h,"click",()=>{p.muted=!p.muted,w()}),e.dom(b,"click",n.fullscreen)}}}(d.$player,t,n,l,e=>{u=e,d.$ads=e}),!m())return void D();if(e.pause(),!m())return;const r=p,a=u.ownerDocument;r.fullscreen(e.fullscreen),r.bind(i,{skip:w,click(){n.url&&(a.defaultView||window).open(n.url),m()&&e.emit("artplayerPluginAds:click",n)},fullscrLine truncated
+385 -234
View File
@@ -1,251 +1,402 @@
/*!
* artplayer-plugin-ads.js v2.1.0
* artplayer-plugin-ads.js v3.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
const style = ".artplayer-plugin-ads {\n position: absolute;\n z-index: 150;\n left: 0;\n top: 0;\n right: 0;\n bottom: 0;\n width: 100%;\n height: 100%;\n overflow: hidden;\n font-size: 13px;\n line-height: 1;\n color: #fff;\n background-color: #000;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-html {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-video {\n width: 100%;\n height: 100%;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-timer {\n display: none;\n position: absolute;\n top: 10px;\n right: 10px;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-timer > div {\n display: flex;\n align-items: center;\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: 15px;\n margin-left: 5px;\n padding: 5px 10px;\n cursor: pointer;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-control {\n display: none;\n position: absolute;\n bottom: 10px;\n right: 10px;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-control > div {\n display: flex;\n align-items: center;\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: 15px;\n margin-left: 5px;\n padding: 5px 10px;\n cursor: pointer;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-control .art-icon svg {\n width: 20px;\n height: 20px;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n left: 0;\n top: 0;\n right: 0;\n bottom: 0;\n width: 100%;\n height: 100%;\n}\n";
function checkVersion(art) {
const {
version,
utils: { errorHandle }
} = art.constructor;
const arr = version.split(".").map(Number);
const major = arr[0];
const minor = arr[1] / 100;
errorHandle(
major + minor >= 5,
`Artplayer.js@${version} is not compatible the artplayerPluginAds@${artplayerPluginAds.version}. Please update it to version Artplayer.js@5.x.x`
);
function normalizeOptions(input, validate) {
return validate({
html: "",
video: "",
url: "",
playDuration: 5,
totalDuration: 10,
muted: false,
i18n: {
close: "关闭广告",
countdown: "%s秒",
detail: "查看详情",
canBeClosed: "%s秒后可关闭广告"
},
...input
}, {
html: "?string",
video: "?string",
url: "?string",
playDuration: "number",
totalDuration: "number",
muted: "?boolean",
i18n: { close: "string", countdown: "string", detail: "string", canBeClosed: "string" }
});
}
function artplayerPluginAds(option) {
return (art) => {
checkVersion(art);
const {
template: { $player },
icons: { volume, volumeClose, fullscreenOn, fullscreenOff, loading },
constructor: {
validator,
utils: { query, append, setStyle }
}
} = art;
option = validator(
{
html: "",
video: "",
url: "",
playDuration: 5,
totalDuration: 10,
muted: false,
i18n: {
close: "关闭广告",
countdown: "%s秒",
detail: "查看详情",
canBeClosed: "%s秒后可关闭广告"
},
...option
},
{
html: "?string",
video: "?string",
url: "?string",
playDuration: "number",
totalDuration: "number",
muted: "?boolean",
i18n: {
close: "string",
countdown: "string",
detail: "string",
canBeClosed: "string"
}
}
);
let $ads = null;
let $timer = null;
let $close = null;
let $countdown = null;
let $control = null;
let $loading = null;
let time = 0;
let timer = null;
let isEnd = false;
let isInit = false;
let isCanClose = false;
function getI18n(val, str) {
return str.replace("%s", val);
}
function skip() {
isEnd = true;
art.play();
if (option.video)
$ads.pause();
setStyle(art.template.$ads, "display", "none");
art.emit("artplayerPluginAds:skip", option);
}
function play() {
if (isEnd)
function createCountdown(total, render, complete) {
let elapsed = 0;
let ready = false;
let running = false;
let closed = false;
let timer;
function schedule() {
if (!ready || !running || closed || timer !== void 0)
return;
timer = setTimeout(() => {
timer = void 0;
if (closed || !running)
return;
timer = setTimeout(() => {
time += 1;
const playDuration = option.playDuration - time;
if (playDuration >= 1) {
$close.innerHTML = getI18n(playDuration, option.i18n.canBeClosed);
} else {
$close.innerHTML = option.i18n.close;
if (!isCanClose) {
isCanClose = true;
}
}
$countdown.innerHTML = getI18n(option.totalDuration - time, option.i18n.countdown);
if (time >= option.totalDuration) {
skip();
} else {
play();
}
}, 1e3);
}
function pause() {
if (isEnd)
elapsed += 1;
render(elapsed);
if (closed)
return;
if (elapsed >= total())
complete();
else
schedule();
}, 1e3);
}
function pause() {
running = false;
if (timer !== void 0)
clearTimeout(timer);
}
function show() {
art.template.$ads = append($player, '<div class="artplayer-plugin-ads"></div>');
$ads = append(
art.template.$ads,
option.video ? `<video class="artplayer-plugin-ads-video" src="${option.video}" loop playsInline></video>` : `<div class="artplayer-plugin-ads-html">${option.html}</div>`
);
$loading = append(art.template.$ads, '<div class="artplayer-plugin-ads-loading"></div>');
append($loading, loading);
$timer = append(
art.template.$ads,
`<div class="artplayer-plugin-ads-timer">
<div class="artplayer-plugin-ads-close">${option.playDuration <= 0 ? option.i18n.close : getI18n(option.playDuration, option.i18n.canBeClosed)}</div>
<div class="artplayer-plugin-ads-countdown">${getI18n(
option.totalDuration,
option.i18n.countdown
)}</div>
</div>`
);
$close = query(".artplayer-plugin-ads-close", $timer);
$countdown = query(".artplayer-plugin-ads-countdown", $timer);
if (option.playDuration >= option.totalDuration) {
setStyle($close, "display", "none");
}
art.proxy($close, "click", () => {
if (isCanClose) {
skip();
}
});
$control = append(
art.template.$ads,
`<div class="artplayer-plugin-ads-control">
<div class="artplayer-plugin-ads-detail">${option.i18n.detail}</div>
<div class="artplayer-plugin-ads-muted"></div>
<div class="artplayer-plugin-ads-fullscreen"></div>
</div>`
);
const $detail = query(".artplayer-plugin-ads-detail", $control);
const $muted = query(".artplayer-plugin-ads-muted", $control);
const $fullscreen = query(".artplayer-plugin-ads-fullscreen", $control);
if (option.url) {
art.proxy($detail, "click", () => {
window.open(option.url);
art.emit("artplayerPluginAds:click", option);
});
} else {
setStyle($detail, "display", "none");
}
if (option.video) {
const $volume = append($muted, volume);
const $volumeClose = append($muted, volumeClose);
setStyle($volumeClose, "display", "none");
if (option.muted) {
$ads.muted = true;
setStyle($volume, "display", "none");
setStyle($volumeClose, "display", "inline-flex");
}
art.proxy($muted, "click", () => {
$ads.muted = !$ads.muted;
if ($ads.muted) {
setStyle($volume, "display", "none");
setStyle($volumeClose, "display", "inline-flex");
} else {
setStyle($volume, "display", "inline-flex");
setStyle($volumeClose, "display", "none");
}
});
} else {
setStyle($muted, "display", "none");
}
const $fullscreenOn = append($fullscreen, fullscreenOn);
const $fullscreenOff = append($fullscreen, fullscreenOff);
setStyle($fullscreenOff, "display", "none");
art.proxy($fullscreen, "click", () => {
art.fullscreen = !art.fullscreen;
if (art.fullscreen) {
setStyle($fullscreenOn, "display", "inline-flex");
setStyle($fullscreenOff, "display", "none");
} else {
setStyle($fullscreenOn, "display", "none");
setStyle($fullscreenOff, "display", "inline-flex");
}
});
art.proxy($ads, "click", () => {
if (option.url)
window.open(option.url);
art.emit("artplayerPluginAds:click", option);
});
}
function init() {
if (isInit)
timer = void 0;
}
return {
start() {
if (ready || closed)
return;
isInit = true;
show();
art.pause();
if (option.video) {
art.proxy($ads, "error", skip);
art.proxy($ads, "loadedmetadata", () => {
play();
$ads.play();
setStyle($timer, "display", "flex");
setStyle($control, "display", "flex");
setStyle($loading, "display", "none");
});
} else {
play();
setStyle($timer, "display", "flex");
setStyle($control, "display", "flex");
setStyle($loading, "display", "none");
}
art.on("document:visibilitychange", () => {
if (document.hidden) {
pause();
} else {
play();
}
});
ready = true;
running = true;
schedule();
},
play() {
if (!ready || closed)
return;
running = true;
schedule();
},
pause,
stop() {
closed = true;
pause();
}
art.on("ready", () => {
art.once("play", init);
art.once("video:playing", init);
});
return {
name: "artplayerPluginAds",
skip,
pause,
play
};
};
}
if (typeof document !== "undefined") {
if (!document.getElementById("artplayer-plugin-ads")) {
const $style = document.createElement("style");
$style.id = "artplayer-plugin-ads";
$style.textContent = style;
document.head.appendChild($style);
function report(error) {
console.warn("Artplayer Ads:", error);
}
function createResources(host) {
const cleaners = [];
let closed = false;
function install(add, remove) {
if (closed)
return;
cleaners.push(remove);
try {
add();
} finally {
if (closed)
remove();
}
}
return {
on(name, callback) {
const listener = () => {
if (!closed)
callback();
};
install(() => {
host.on(name, listener);
}, () => {
host.off(name, listener);
});
},
dom(target, name, callback) {
const listener = () => {
if (!closed)
callback();
};
install(() => target.addEventListener(name, listener), () => target.removeEventListener(name, listener));
},
dispose() {
if (closed)
return;
closed = true;
for (const clean of cleaners.splice(0).reverse()) {
try {
clean();
} catch (error) {
report(error);
}
}
}
};
}
const translate = (value, text) => text.replace("%s", String(value));
function createView(parent, icons, option, utils, own) {
const { append, query, setStyle } = utils;
const root = append(parent, '<div class="artplayer-plugin-ads"></div>');
own(root);
const content = append(root, option.video ? '<video class="artplayer-plugin-ads-video" loop playsInline></video>' : `<div class="artplayer-plugin-ads-html">${option.html}</div>`);
const video = option.video ? content : null;
const loading = append(root, '<div class="artplayer-plugin-ads-loading"></div>');
append(loading, icons.loading);
const timer = append(root, `<div class="artplayer-plugin-ads-timer">
<div class="artplayer-plugin-ads-close"></div>
<div class="artplayer-plugin-ads-countdown"></div>
</div>`);
const close = query(".artplayer-plugin-ads-close", timer);
const countdown = query(".artplayer-plugin-ads-countdown", timer);
const control = append(root, `<div class="artplayer-plugin-ads-control">
<div class="artplayer-plugin-ads-detail">${option.i18n.detail}</div>
<div class="artplayer-plugin-ads-muted"></div>
<div class="artplayer-plugin-ads-fullscreen"></div>
</div>`);
const detail = query(".artplayer-plugin-ads-detail", control);
const muted = query(".artplayer-plugin-ads-muted", control);
const fullscreen = query(".artplayer-plugin-ads-fullscreen", control);
let canClose = option.playDuration <= 0;
if (option.playDuration >= option.totalDuration)
setStyle(close, "display", "none");
if (!option.url)
setStyle(detail, "display", "none");
if (video) {
append(muted, icons.volume);
append(muted, icons.volumeClose);
video.muted = Boolean(option.muted);
syncMuted();
} else {
setStyle(muted, "display", "none");
}
append(fullscreen, icons.fullscreenOn);
append(fullscreen, icons.fullscreenOff);
function syncMuted() {
setStyle(icons.volume, "display", video?.muted ? "none" : "inline-flex");
setStyle(icons.volumeClose, "display", video?.muted ? "inline-flex" : "none");
}
function render(elapsed) {
const remaining = option.playDuration - elapsed;
canClose = elapsed === 0 ? option.playDuration <= 0 : remaining < 1 || Number.isNaN(remaining);
close.innerHTML = canClose ? option.i18n.close : translate(remaining, option.i18n.canBeClosed);
countdown.innerHTML = translate(option.totalDuration - elapsed, option.i18n.countdown);
}
render(0);
return {
root,
video,
render,
ready() {
setStyle(timer, "display", "flex");
setStyle(control, "display", "flex");
setStyle(loading, "display", "none");
},
hide() {
setStyle(root, "display", "none");
},
fullscreen(active) {
setStyle(icons.fullscreenOn, "display", active ? "none" : "inline-flex");
setStyle(icons.fullscreenOff, "display", active ? "inline-flex" : "none");
},
bind(events, callbacks) {
events.dom(close, "click", () => {
if (canClose)
callbacks.skip();
});
events.dom(content, "click", callbacks.click);
if (option.url)
events.dom(detail, "click", callbacks.click);
if (video) {
events.dom(muted, "click", () => {
video.muted = !video.muted;
syncMuted();
});
}
events.dom(fullscreen, "click", callbacks.fullscreen);
}
};
}
function createSession(art, option, icons, utils) {
const events = createResources(art);
const lifetime = createResources(art);
const template = art.template;
let state = "waiting";
let initialized = false;
let armed = false;
let mediaReady = false;
let root;
let view;
const clock = createCountdown(() => option.totalDuration, (time) => view?.render(time), skip);
const active = () => state === "active" && !art.isDestroy;
const destroyed = () => state === "destroyed" || art.isDestroy;
function pauseVideo(video) {
try {
video?.pause();
} catch (error) {
report(error);
}
}
function requestPlay(start, rejected, late) {
try {
Promise.resolve(start()).then(() => {
if (!active())
late?.();
}, rejected).catch(report);
} catch (error) {
rejected(error);
}
}
function skip() {
if (state === "ended" || state === "destroyed" || art.isDestroy)
return;
state = "ended";
clock.stop();
events.dispose();
if (initialized) {
requestPlay(() => art.play(), (error) => {
if (state !== "destroyed")
report(error);
});
if (destroyed())
return;
pauseVideo(view?.video);
if (destroyed())
return;
view?.hide();
}
if (!destroyed())
art.emit("artplayerPluginAds:skip", option);
}
function disposeView() {
const video = view?.video;
pauseVideo(video);
if (video) {
try {
video.removeAttribute("src");
video.load();
} catch (error) {
report(error);
}
}
try {
root?.remove();
} catch (error) {
report(error);
} finally {
if (root && template.$ads === root)
delete template.$ads;
}
}
function destroy() {
if (state === "destroyed")
return;
state = "destroyed";
clock.stop();
events.dispose();
lifetime.dispose();
disposeView();
}
function init() {
if (state !== "waiting" || art.isDestroy)
return;
state = "active";
initialized = true;
try {
view = createView(template.$player, icons, option, utils, (node) => {
root = node;
template.$ads = node;
});
if (!active()) {
disposeView();
return;
}
art.pause();
if (!active())
return;
const current = view;
const document2 = root.ownerDocument;
current.fullscreen(art.fullscreen);
current.bind(events, {
skip,
click() {
if (option.url)
(document2.defaultView || window).open(option.url);
if (active())
art.emit("artplayerPluginAds:click", option);
},
fullscreen() {
art.fullscreen = !art.fullscreen;
if (active())
current.fullscreen(art.fullscreen);
}
});
events.on("fullscreen", () => current.fullscreen(art.fullscreen));
const visibility = () => document2.hidden ? clock.pause() : clock.play();
events.dom(document2, "visibilitychange", visibility);
events.on("document:visibilitychange", visibility);
const ready = () => {
if (!active() || mediaReady)
return;
mediaReady = true;
clock.start();
if (document2.hidden)
clock.pause();
if (current.video) {
const video = current.video;
requestPlay(() => video.play(), (error) => {
if (active()) {
report(error);
skip();
}
}, () => pauseVideo(video));
}
if (active())
current.ready();
};
if (current.video) {
events.dom(current.video, "error", skip);
events.dom(current.video, "loadedmetadata", ready);
current.video.src = option.video;
} else {
ready();
}
} catch (error) {
destroy();
throw error;
}
}
try {
lifetime.on("destroy", destroy);
events.on("ready", () => {
if (armed || state !== "waiting")
return;
armed = true;
events.on("play", init);
events.on("video:playing", init);
});
if (art.isDestroy)
destroy();
} catch (error) {
destroy();
throw error;
}
return { name: "artplayerPluginAds", skip, pause: clock.pause, play: clock.play };
}
const style = ".artplayer-plugin-ads {\n position: absolute;\n z-index: 150;\n left: 0;\n top: 0;\n right: 0;\n bottom: 0;\n width: 100%;\n height: 100%;\n overflow: hidden;\n font-size: 13px;\n line-height: 1;\n color: #fff;\n background-color: #000;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-html {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-video {\n width: 100%;\n height: 100%;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-timer {\n display: none;\n position: absolute;\n top: 10px;\n right: 10px;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-timer > div {\n display: flex;\n align-items: center;\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: 15px;\n margin-left: 5px;\n padding: 5px 10px;\n cursor: pointer;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-control {\n display: none;\n position: absolute;\n bottom: 10px;\n right: 10px;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-control > div {\n display: flex;\n align-items: center;\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: 15px;\n margin-left: 5px;\n padding: 5px 10px;\n cursor: pointer;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-control .art-icon svg {\n width: 20px;\n height: 20px;\n}\n.artplayer-plugin-ads .artplayer-plugin-ads-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n left: 0;\n top: 0;\n right: 0;\n bottom: 0;\n width: 100%;\n height: 100%;\n}\n";
function artplayerPluginAds(input) {
return (art) => {
const constructor = art.constructor;
if (typeof constructor.validator !== "function" || !["append", "query", "setStyle"].every((name) => typeof Reflect.get(constructor.utils || {}, name) === "function")) {
throw new Error("Artplayer Ads requires the core validator and DOM utilities");
}
const option = normalizeOptions(input, constructor.validator);
const { volume, volumeClose, fullscreenOn, fullscreenOff, loading } = art.icons;
return createSession(art, option, { volume, volumeClose, fullscreenOn, fullscreenOff, loading }, constructor.utils);
};
}
const index = Object.assign(artplayerPluginAds, { default: artplayerPluginAds });
if (typeof document !== "undefined" && !document.getElementById("artplayer-plugin-ads")) {
const element = document.createElement("style");
element.id = "artplayer-plugin-ads";
element.textContent = style;
document.head.appendChild(element);
}
export {
artplayerPluginAds as default
index as default
};
+2 -2
View File
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-ambilight.js v1.1.0
* artplayer-plugin-ambilight.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerPluginAmbilight=t(),define(function(){return t.artplayerPluginAmbilight})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAmbilight=t()}(this,function(){"use strict";return function(e={}){return t=>{const{$video:n}=t.template,{createElement:r,addClass:i,setStyles:o}=t.constructor.utils,{blur:a="50px",opacity:l=.5,frequency:u=10,duration:f=.3}=e,s=r("div"),d=((c=s).innerHTML=Array.from({length:9}).fill("<div></div>").join(""),Array.from(c.children));var c,m,p,g;!function(e,t){i(e,"artplayer-plugin-ambilight"),t.parentNode.insertBefore(e,t),o(e,{position:"absolute",top:0,left:0,zIndex:9,inset:0,display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gridTemplateRows:"1fr 1fr 1fr"})}(s,n),m=a,p=l,g=f,d.forEach(e=>{o(e,{opacity:p,filter:`blur(${m})`,transition:`background-color ${g}s ease`})});const y=function(e,n,i){const o=r("canvas"),a=o.getContext("2d");o.width=3,o.height=3;let l=0;return function r(){const o=performance.now();if(o-l<1e3/i||!t.playing)return void(h=requestAnimationFrame(r));l=o;const u=e.videoWidth/3,f=e.videoHeight/3,s=[[0,0],[u,0],[2*u,0],[0,f],[u,f],[2*u,f],[0,2*f],[u,2*f],[2*u,2*f]].map(([t,n])=>function(t,n,r,i){a.drawImage(e,t,n,r,i,0,0,1,1);const[o,l,u]=a.getImageData(0,0,1,1).data;return`rgb(${o}, ${l}, ${u})`}(t,n,u,f));n.forEach((e,t)=>{e.style.backgroundColor=s[t]}),h=requestAnimationFrame(r)}}(n,d,u);let h=null;function b(){h||y()}function v(){h&&(cancelAnimationFrame(h),h=null)}return t.on("ready",b),t.on("destroy",v),{name:"artplayerPluginAmbilight",start:b,stop:v}}}});
!function(t,n){"object"===typeof exports&&"undefined"!==typeof module?module.exports=n():"function"==typeof define&&define.amd?(t.artplayerPluginAmbilight=n(),define(function(){return t.artplayerPluginAmbilight})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginAmbilight=n()}(this,function(){"use strict";function t(t,n,e){let r="stopped",i=null,o=0,l=!1,u=0;function c(){const s=o,f=()=>"running"===r&&s===o;l=!0;try{const r=performance.now();if(r-u<1e3/t||!n()||!f())return;u=r,e(f)}finally{l=!1,"running"===r&&null===i&&function(){const t=o;try{i=requestAnimationFrame(()=>{"running"===r&&t===o&&(i=null,c())})}catch(n){throw r="stopped",o++,n}}()}}return{start:function(){"stopped"===r&&(r="running",o++,l||c())},stop:function(){if("destroyed"===r)return;r="stopped",o++;const t=i;i=null,null!==t&&cancelAnimationFrame(t)},destroy:function(){if("destroyed"===r)return;r="destroyed",o++;const t=i;i=null,null!==t&&cancelAnimationFrame(t)}}}function n(n={}){return e=>{let r=e,i=e.isDestroy,o=null,l=null,u=null;const c=[],s={name:"artplayerPluginAmbilight",start(){i||u?.start()},stop(){i||u?.stop()}};if(i)return r=null,s;function f(){const t=[u?.destroy,l?.destroy,o?.destroy];u=null,l=null,o=null;const n=[];for(const r of t)try{r?.()}catch(e){n.push(e)}if(n.length)throw n[0]}function a(){if(i)return;i=!0;const t=r;r=null;const n=[];for(const[r,i]of c.splice(0))try{t?.off(r,i)}catch(e){n.push(e)}try{f()}catch(e){n.push(e)}if(n.length)throw n[0]}function d(t,n){c.push([t,n]),r?.on(t,n)}try{if(d("destroy",a),i)return s;const{$video:c}=e.template,h=e.constructor.utils,{blur:y="50px",opacity:p=.5,frequency:g=10,duration:m=.3}=n;if(i)return s;if(o=function(t){const n=t.createElement("div");n.innerHTML=Array.from({length:9}).fill("<div></div>").join("");const e=Array.from(n.children);return{mount:function(r,i,o){if(o()&&(t.addClass(n,"artplayer-plugin-ambilight"),o()&&(r.parentNode.insertBefore(n,r),o()))){t.setStyles(n,{position:"absolute",top:0,left:0,zIndex:9,inset:0,display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gridTemplateRows:"1fr 1fr 1fr"});for(const n of e){if(!o())return;t.setStyles(n,{opacity:i.opacity,filter:`blur(${i.blur})`,transition:`background-color ${i.duration}s ease`})}}},render:function(t,n){for(let r=0;r<t.length;r++){if(!n())return;const i=e[r],o=t[r];i&&void 0!==o&&(i.style.backgroundColor=o)}},destroy:function(){try{n.parentNode?.removeChild(n)}finally{e.length=0}}}}(h),i||o.mount(c,{blur:y,opacity:p,duration:m},()=>!i),i)return f(),s;const b=h.createElement("canvas");if(i)return b.width=0,b.height=0,s;if(l=function(t,n,e){let r;try{r=t.getContext("2d"),t.width=3,t.height=3}catch(l){throw t.width=0,t.height=0,l}let i=!1,o=!1;return{read:function(l){if(i||!l())return null;const u="CANVAS"===n.nodeName,c=u?n.width:n.videoWidth,s=u?n.height:n.videoHeight;if(!Number.isFinite(c)||!Number.isFinite(s)||c<=0||s<=0)return null;const f=c/3,a=s/3,d=[];try{if(o){const n=e();if(i||!l())return n.width=0,n.height=0,null;if(r=null,r=(t=n).getContext("2d"),i||!l())return t.width=0,t.height=0,null;t.width=3,t.height=3,o=!1}if(!r)return null;for(let t=0;t<3;t++)for(let e=0;e<3;e++){if(i||!l())return null;if(r.drawImage(n,e*f,t*a,f,a,0,0,1,1),i||!l())return null;const[o,u,c]=r.getImageData(0,0,1,1).data;d.push(`rgb(${o}, ${u}, ${c})`)}return d}catch{return i||(o=!0,t.width=0,t.height=0),null}},destroy:function(){i||(i=!0,t.width=0,t.height=0)}}}(b,c,()=>h.createElement("canvas")),i)return f(),s;u=t(g,()=>Boolean(r?.playing),t=>{const n=l?.read(t);n&&t()&&o?.render(n,t)}),d("ready",s.start),i&&f()}catch(h){try{a()}catch{}try{f()}catch{}throw h}return s}}return Object.assign(n,{default:n})});
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-ambilight.js v1.1.0
* artplayer-plugin-ambilight.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerPluginAmbilight=t(),define(function(){return t.artplayerPluginAmbilight})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAmbilight=t()}(this,function(){"use strict";return function(e={}){return t=>{const{$video:n}=t.template,{createElement:r,addClass:i,setStyles:o}=t.constructor.utils,{blur:a="50px",opacity:l=.5,frequency:u=10,duration:f=.3}=e,s=r("div"),d=((c=s).innerHTML=Array.from({length:9}).fill("<div></div>").join(""),Array.from(c.children));var c,m,p,g;!function(e,t){i(e,"artplayer-plugin-ambilight"),t.parentNode.insertBefore(e,t),o(e,{position:"absolute",top:0,left:0,zIndex:9,inset:0,display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gridTemplateRows:"1fr 1fr 1fr"})}(s,n),m=a,p=l,g=f,d.forEach(e=>{o(e,{opacity:p,filter:`blur(${m})`,transition:`background-color ${g}s ease`})});const y=function(e,n,i){const o=r("canvas"),a=o.getContext("2d");o.width=3,o.height=3;let l=0;return function r(){const o=performance.now();if(o-l<1e3/i||!t.playing)return void(h=requestAnimationFrame(r));l=o;const u=e.videoWidth/3,f=e.videoHeight/3,s=[[0,0],[u,0],[2*u,0],[0,f],[u,f],[2*u,f],[0,2*f],[u,2*f],[2*u,2*f]].map(([t,n])=>function(t,n,r,i){a.drawImage(e,t,n,r,i,0,0,1,1);const[o,l,u]=a.getImageData(0,0,1,1).data;return`rgb(${o}, ${l}, ${u})`}(t,n,u,f));n.forEach((e,t)=>{e.style.backgroundColor=s[t]}),h=requestAnimationFrame(r)}}(n,d,u);let h=null;function b(){h||y()}function v(){h&&(cancelAnimationFrame(h),h=null)}return t.on("ready",b),t.on("destroy",v),{name:"artplayerPluginAmbilight",start:b,stop:v}}}});
!function(t,n){"object"===typeof exports&&"undefined"!==typeof module?module.exports=n():"function"==typeof define&&define.amd?(t.artplayerPluginAmbilight=n(),define(function(){return t.artplayerPluginAmbilight})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginAmbilight=n()}(this,function(){"use strict";function t(t,n,e){let r="stopped",i=null,o=0,l=!1,u=0;function c(){const s=o,f=()=>"running"===r&&s===o;l=!0;try{const r=performance.now();if(r-u<1e3/t||!n()||!f())return;u=r,e(f)}finally{l=!1,"running"===r&&null===i&&function(){const t=o;try{i=requestAnimationFrame(()=>{"running"===r&&t===o&&(i=null,c())})}catch(n){throw r="stopped",o++,n}}()}}return{start:function(){"stopped"===r&&(r="running",o++,l||c())},stop:function(){if("destroyed"===r)return;r="stopped",o++;const t=i;i=null,null!==t&&cancelAnimationFrame(t)},destroy:function(){if("destroyed"===r)return;r="destroyed",o++;const t=i;i=null,null!==t&&cancelAnimationFrame(t)}}}function n(n={}){return e=>{let r=e,i=e.isDestroy,o=null,l=null,u=null;const c=[],s={name:"artplayerPluginAmbilight",start(){i||null==u||u.start()},stop(){i||null==u||u.stop()}};if(i)return r=null,s;function f(){const t=[null==u?void 0:u.destroy,null==l?void 0:l.destroy,null==o?void 0:o.destroy];u=null,l=null,o=null;const n=[];for(const r of t)try{null==r||r()}catch(e){n.push(e)}if(n.length)throw n[0]}function a(){if(i)return;i=!0;const t=r;r=null;const n=[];for(const[r,i]of c.splice(0))try{null==t||t.off(r,i)}catch(e){n.push(e)}try{f()}catch(e){n.push(e)}if(n.length)throw n[0]}function d(t,n){c.push([t,n]),null==r||r.on(t,n)}try{if(d("destroy",a),i)return s;const{$video:c}=e.template,h=e.constructor.utils,{blur:y="50px",opacity:p=.5,frequency:g=10,duration:m=.3}=n;if(i)return s;if(o=function(t){const n=t.createElement("div");n.innerHTML=Array.from({length:9}).fill("<div></div>").join("");const e=Array.from(n.children);return{mount:function(r,i,o){if(o()&&(t.addClass(n,"artplayer-plugin-ambilight"),o()&&(r.parentNode.insertBefore(n,r),o()))){t.setStyles(n,{position:"absolute",top:0,left:0,zIndex:9,inset:0,display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gridTemplateRows:"1fr 1fr 1fr"});for(const n of e){if(!o())return;t.setStyles(n,{opacity:i.opacity,filter:`blur(${i.blur})`,transition:`background-color ${i.duration}s ease`})}}},render:function(t,n){for(let r=0;r<t.length;r++){if(!n())return;const i=e[r],o=t[r];i&&void 0!==o&&(i.style.backgroundColor=o)}},destroy:function(){var t;try{null==(t=n.parentNode)||t.removeChild(n)}finally{e.length=0}}}}(h),i||o.mount(c,{blur:y,opacity:p,duration:m},()=>!i),i)return f(),s;const b=h.createElement("canvas");if(i)return b.width=0,b.height=0,s;if(l=function(t,n,e){let r;try{r=t.getContext("2d"),t.width=3,t.height=3}catch(l){throw t.width=0,t.height=0,l}let i=!1,o=!1;return{read:function(l){if(i||!l())return null;const u="CANVAS"===n.nodeName,c=u?n.width:n.videoWidth,s=u?n.height:n.videoHeight;if(!Number.isFinite(c)||!Number.isFinite(s)||c<=0||s<=0)return null;const f=c/3,a=s/3,d=[];try{if(o){const n=e();if(i||!l())return n.width=0,n.height=0,null;if(r=null,r=(t=n).getContext("2d"),i||!l())return t.width=0,t.height=0,null;t.width=3,t.height=3,o=!1}if(!r)return null;for(let t=0;t<3;t++)for(let e=0;e<3;e++){if(i||!l())return null;if(r.drawImage(n,e*f,t*a,f,a,0,0,1,1),i||!l())return null;const[o,u,c]=r.getImageData(0,0,1,1).data;d.push(`rgb(${o}, ${u}, ${c})`)}return d}catch(h){return i||(o=!0,t.width=0,t.height=0),null}},destroy:function(){i||(i=!0,t.width=0,t.height=0)}}}(b,c,()=>h.createElement("canvas")),i)return f(),s;u=t(g,()=>Boolean(null==r?void 0:r.playing),t=>{const n=null==l?void 0:l.read(t);n&&t()&&(null==o||o.render(n,t))}),d("ready",s.start),i&&f()}catch(h){try{a()}catch(y){}try{f()}catch(y){}throw h}return s}}return Object.assign(n,{default:n})});
+295 -90
View File
@@ -1,104 +1,309 @@
/*!
* artplayer-plugin-ambilight.js v1.1.0
* artplayer-plugin-ambilight.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
function isCanvas(source) {
return source.nodeName === "CANVAS";
}
function createColorSampler(canvas, video, createCanvas) {
let context;
try {
context = canvas.getContext("2d");
canvas.width = 3;
canvas.height = 3;
} catch (error) {
canvas.width = 0;
canvas.height = 0;
throw error;
}
let destroyed = false;
let replaceCanvas = false;
function read(active) {
if (destroyed || !active())
return null;
const canvasOutput = isCanvas(video);
const width = canvasOutput ? video.width : video.videoWidth;
const height = canvasOutput ? video.height : video.videoHeight;
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0)
return null;
const w = width / 3;
const h = height / 3;
const colors = [];
try {
if (replaceCanvas) {
const replacement = createCanvas();
if (destroyed || !active()) {
replacement.width = 0;
replacement.height = 0;
return null;
}
canvas = replacement;
context = null;
context = canvas.getContext("2d");
if (destroyed || !active()) {
canvas.width = 0;
canvas.height = 0;
return null;
}
canvas.width = 3;
canvas.height = 3;
replaceCanvas = false;
}
if (!context)
return null;
for (let row = 0; row < 3; row++) {
for (let column = 0; column < 3; column++) {
if (destroyed || !active())
return null;
context.drawImage(video, column * w, row * h, w, h, 0, 0, 1, 1);
if (destroyed || !active())
return null;
const [r, g, b] = context.getImageData(0, 0, 1, 1).data;
colors.push(`rgb(${r}, ${g}, ${b})`);
}
}
return colors;
} catch {
if (!destroyed) {
replaceCanvas = true;
canvas.width = 0;
canvas.height = 0;
}
return null;
}
}
function destroy() {
if (destroyed)
return;
destroyed = true;
canvas.width = 0;
canvas.height = 0;
}
return { read, destroy };
}
function createFrameLoop(frequency, playing, update) {
let state = "stopped";
let pending = null;
let generation = 0;
let inFrame = false;
let lastUpdateTime = 0;
function schedule() {
const current = generation;
try {
pending = requestAnimationFrame(() => {
if (state !== "running" || current !== generation)
return;
pending = null;
tick();
});
} catch (error) {
state = "stopped";
generation++;
throw error;
}
}
function tick() {
const current = generation;
const active = () => state === "running" && current === generation;
inFrame = true;
try {
const now = performance.now();
if (now - lastUpdateTime < 1e3 / frequency || !playing() || !active())
return;
lastUpdateTime = now;
update(active);
} finally {
inFrame = false;
if (state === "running" && pending === null)
schedule();
}
}
function start() {
if (state !== "stopped")
return;
state = "running";
generation++;
if (!inFrame)
tick();
}
function stop() {
if (state === "destroyed")
return;
state = "stopped";
generation++;
const frame = pending;
pending = null;
if (frame !== null)
cancelAnimationFrame(frame);
}
function destroy() {
if (state === "destroyed")
return;
state = "destroyed";
generation++;
const frame = pending;
pending = null;
if (frame !== null)
cancelAnimationFrame(frame);
}
return { start, stop, destroy };
}
function createAmbilightView(utils) {
const element = utils.createElement("div");
element.innerHTML = Array.from({ length: 9 }).fill("<div></div>").join("");
const items = Array.from(element.children);
function mount(video, option, active) {
if (!active())
return;
utils.addClass(element, "artplayer-plugin-ambilight");
if (!active())
return;
video.parentNode.insertBefore(element, video);
if (!active())
return;
utils.setStyles(element, { position: "absolute", top: 0, left: 0, zIndex: 9, inset: 0, display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gridTemplateRows: "1fr 1fr 1fr" });
for (const item of items) {
if (!active())
return;
utils.setStyles(item, { opacity: option.opacity, filter: `blur(${option.blur})`, transition: `background-color ${option.duration}s ease` });
}
}
function render(colors, active) {
for (let index2 = 0; index2 < colors.length; index2++) {
if (!active())
return;
const item = items[index2];
const color = colors[index2];
if (item && color !== void 0)
item.style.backgroundColor = color;
}
}
function destroy() {
try {
element.parentNode?.removeChild(element);
} finally {
items.length = 0;
}
}
return { mount, render, destroy };
}
function artplayerPluginAmbilight(option = {}) {
return (art) => {
const { $video } = art.template;
const { createElement, addClass, setStyles } = art.constructor.utils;
const { blur = "50px", opacity = 0.5, frequency = 10, duration = 0.3 } = option;
const $ambilight = createElement("div");
const gridItems = createGridItems($ambilight);
setupAmbilight($ambilight, $video);
setupGridItems(gridItems, blur, opacity, duration);
const updateColors = createColorUpdater($video, gridItems, frequency);
let animationFrameId = null;
function start() {
if (!animationFrameId) {
updateColors();
}
}
function stop() {
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
animationFrameId = null;
}
}
art.on("ready", start);
art.on("destroy", stop);
return {
let host = art;
let closed = art.isDestroy;
let view = null;
let sampler = null;
let loop = null;
const subscriptions = [];
const result = {
name: "artplayerPluginAmbilight",
start,
stop
};
function createGridItems($ambilight2) {
$ambilight2.innerHTML = Array.from({ length: 9 }).fill("<div></div>").join("");
return Array.from($ambilight2.children);
}
function setupAmbilight($ambilight2, $video2) {
addClass($ambilight2, "artplayer-plugin-ambilight");
$video2.parentNode.insertBefore($ambilight2, $video2);
setStyles($ambilight2, {
position: "absolute",
top: 0,
left: 0,
zIndex: 9,
inset: 0,
display: "grid",
gridTemplateColumns: "1fr 1fr 1fr",
gridTemplateRows: "1fr 1fr 1fr"
});
}
function setupGridItems(gridItems2, blur2, opacity2, duration2) {
gridItems2.forEach(($item) => {
setStyles($item, {
opacity: opacity2,
filter: `blur(${blur2})`,
transition: `background-color ${duration2}s ease`
});
});
}
function createColorUpdater($video2, gridItems2, frequency2) {
const canvas = createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = 3;
canvas.height = 3;
function getAverageColor(x, y, w, h) {
ctx.drawImage($video2, x, y, w, h, 0, 0, 1, 1);
const [r, g, b] = ctx.getImageData(0, 0, 1, 1).data;
return `rgb(${r}, ${g}, ${b})`;
start() {
if (!closed)
loop?.start();
},
stop() {
if (!closed)
loop?.stop();
}
let lastUpdateTime = 0;
return function updateColors2() {
const now = performance.now();
if (now - lastUpdateTime < 1e3 / frequency2 || !art.playing) {
animationFrameId = requestAnimationFrame(updateColors2);
return;
}
lastUpdateTime = now;
const w = $video2.videoWidth / 3;
const h = $video2.videoHeight / 3;
const colors = [
[0, 0],
[w, 0],
[2 * w, 0],
[0, h],
[w, h],
[2 * w, h],
[0, 2 * h],
[w, 2 * h],
[2 * w, 2 * h]
].map(([x, y]) => getAverageColor(x, y, w, h));
gridItems2.forEach(($item, index) => {
$item.style.backgroundColor = colors[index];
});
animationFrameId = requestAnimationFrame(updateColors2);
};
};
if (closed) {
host = null;
return result;
}
function releaseResources() {
const releases = [loop?.destroy, sampler?.destroy, view?.destroy];
loop = null;
sampler = null;
view = null;
const failures = [];
for (const release of releases) {
try {
release?.();
} catch (error) {
failures.push(error);
}
}
if (failures.length)
throw failures[0];
}
function destroy() {
if (closed)
return;
closed = true;
const current = host;
host = null;
const failures = [];
for (const [event, callback] of subscriptions.splice(0)) {
try {
current?.off(event, callback);
} catch (error) {
failures.push(error);
}
}
try {
releaseResources();
} catch (error) {
failures.push(error);
}
if (failures.length)
throw failures[0];
}
function listen(event, callback) {
subscriptions.push([event, callback]);
host?.on(event, callback);
}
try {
listen("destroy", destroy);
if (closed)
return result;
const { $video } = art.template;
const utils = art.constructor.utils;
const { blur = "50px", opacity = 0.5, frequency = 10, duration = 0.3 } = option;
if (closed)
return result;
view = createAmbilightView(utils);
if (!closed)
view.mount($video, { blur, opacity, duration }, () => !closed);
if (closed) {
releaseResources();
return result;
}
const canvas = utils.createElement("canvas");
if (closed) {
canvas.width = 0;
canvas.height = 0;
return result;
}
sampler = createColorSampler(canvas, $video, () => utils.createElement("canvas"));
if (closed) {
releaseResources();
return result;
}
loop = createFrameLoop(frequency, () => Boolean(host?.playing), (valid) => {
const colors = sampler?.read(valid);
if (colors && valid())
view?.render(colors, valid);
});
listen("ready", result.start);
if (closed)
releaseResources();
} catch (error) {
try {
destroy();
} catch {
}
try {
releaseResources();
} catch {
}
throw error;
}
return result;
};
}
const index = Object.assign(artplayerPluginAmbilight, { default: artplayerPluginAmbilight });
export {
artplayerPluginAmbilight as default
index as default
};
+2 -2
View File
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-asr.js v2.1.0
* artplayer-plugin-asr.js v3.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginAsr=e(),define(function(){return t.artplayerPluginAsr})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginAsr=e()}(this,function(){"use strict";if("undefined"!==typeof document&&!document.getElementById("artplayer-plugin-asr")){const t=document.createElement("style");t.id="artplayer-plugin-asr",t.textContent=".art-video-player .art-layer-asr{pointer-events:none!important;position:absolute;z-index:150;inset:0;display:flex;flex-direction:column;justify-content:end;padding:0 2%;font-size:1rem;gap:var(--art-subtitle-gap);padding-bottom:var(--art-subtitle-bottom);transition:padding-bottom var(--art-transition-duration) ease;text-shadow:var(--art-subtitle-border) 1px 0 1px,var(--art-subtitle-border) 0 1px 1px,var(--art-subtitle-border) -1px 0 1px,var(--art-subtitle-border) 0 -1px 1px,var(--art-subtitle-border) 1px 1px 1px,var(--art-subtitle-border) -1px -1px 1px,var(--art-subtitle-border) 1px -1px 1px,var(--art-subtitle-border) -1px 1px 1px}.art-video-player.art-control-show .art-layer-asr{padding-bottom:calc(var(--art-control-height) + var(--art-subtitle-bottom))}",document.head.appendChild(t)}return function(t={}){const{length:e=3,interval:n=100,sampleRate:r=16e3,autoHideTimeout:a=1e4,onAudioChunk:o=()=>null}=t;return t=>{let i=!1,l=null,s=null,u=null,c=null,d=[],p=null,f=!1,y=null,m=null,g=null;const h=t.layers.add({name:"asr",html:""});function w(){h.style.display="none"}function b(t){var n;"string"===typeof t&&(clearTimeout(y),y=setTimeout(w,a),h.style.display="",h.innerHTML=(n=t,n.split(/(?<=[\u3001\u3002\uff01\uff1f!?.])\s*/u).map(t=>t.trim()).filter(Boolean).slice(-e)).map(t=>`<div class="art-asr-line">${t}</div>`).join(""))}async function v(){if(!s&&t.video)try{return s=l.createMediaElementSource(t.video),s}catch(e){console.warn("[artplayerPluginAsr] Direct connection failed:",e)}try{if(m||(m=await async function(t){try{return t.captureStream?t.captureStream():t.mozCaptureStream?t.mozCaptureStream():(console.warn("[artplayerPluginAsr] captureStream not supported"),null)}catch(e){return console.warn("[artplayerPluginAsr] Error capturing stream:",e),null}}(t.video)),m)return g=l.createMediaStreamSource(m),g}catch(e){console.warn("[artplayerPluginAsr] MediaStream fallback failed:",e)}return null}async function x(){i&&(i=!1,clearInterval(p),p=null,u&&(u.disconnect(),u.port.onmessage=null,u=null),c&&(c.disconnect(),c=null),d=[])}async function A(){await x(),g&&(g.disconnect(),g=null),s&&(s.disconnect(),s=null),m&&(m.getTracks().forEach(t=>t.stop()),m=null),l&&(await l.close(),l=null),f=!1}return t.on("video:volumechange",()=>{c&&(c.gain.value=t.volume)}),t.on("play",async function(){if(!i)try{await async function(){return l||(l=new(window.AudioContext||window.webkitAudioContext)({sampleRate:r}),"suspended"===l.state&&await l.resume(),l)}();const t=await v();if(!t)throw new Error("Could not establish audio source");if(!f){const t=(()=>{const t=new Blob(["\n class RecorderProcessor extends AudioWorkletProcessor {\n process(inputs) {\n const input = inputs[0];\n if (input && input[0]) {\n this.port.postMessage(input[0]);\n }\n return true;\n }\n }\n registerProcessor('recorder-processor', RecorderProcessor);\n "],{type:"application/javascript"});return URL.createObjectURL(t)})();await l.audioWorklet.addModule(t),URL.revokeObjectURL(t),f=!0}c=l.createGain(),c.gain.value=1,u=new AudioWorkletNode(l,"recorder-processor"),u.port.onmessage=t=>{d.push(new Float32Array(t.data))},t.connect(u),t.connect(c),c.connect(l.destination);const e=r*(n/1e3);p=setInterval(async()=>{if(0===d.length)return;let t=new Float32Array(0);for(;t.length<e&&d.length;){const e=d.shift(),n=new Float32Array(t.length+e.length);n.set(t,0),n.set(e,t.length),t=n}if(t.length<e)return;const n=function(t){const e=t.length,n=new ArrayBuffer(2*e),r=new DataView(n);for(let a=0;a<e;a++){const e=Math.max(-1,Math.min(1,t[a]));r.setInt16(2*a,e<0?32768*e:32767*e,!0)}return n}(t.slice(0,e)),a=function(t,e){const n=t.byteLength,r=new ArrayBuffer(44+n),a=new DataView(r),o=(t,e)=>{for(let n=0;n<e.length;n++)a.setUint8(t+n,e.charCodeAt(n))};return o(0,"RIFF"),a.setUint32(4,36+n,!0),o(8,"WAVE"),o(12,"fmt "),a.setUint32(16,16,!0),a.setUint16(20,1,!0),a.setUint16(22,1,!0),a.setUint32(24,e,!0),a.setUint32(28,2*e,!0),a.setUint16(32,2,!0),a.setUint16(34,16,!0),o(36,"data"),a.setUint32(40,n,!0),new Uint8Array(r).set(new Uint8Array(t),44),r}(n,r);b(await o({pcm:n,wav:a}))},n),i=!0}catch(t){console.error("[artplayerPluginAsr] Initialization failed:",t),await x()}}),t.on("pause",x),t.on("destroy",A),{name:"artplayerPluginAsr",stop:A,hide:w,append:b}}}});
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginAsr=e(),define(function(){return t.artplayerPluginAsr})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginAsr=e()}(this,function(){"use strict";class t{constructor(t,e,i=!1){this.video=t,this.sampleRate=e,this.captureOnly=i,this.closed=!1,this.direct=!1,this.workletLoaded=!1}assertOpen(){if(this.closed)throw new Error("Audio capture was closed")}revokeWorklet(){void 0!==this.blobUrl&&(URL.revokeObjectURL(this.blobUrl),this.blobUrl=void 0)}async initialize(){this.assertOpen();const t=window,e=window.AudioContext||t.webkitAudioContext;if(!e)throw new Error("AudioContext is not supported");const i=this.context??(this.context=new e({sampleRate:this.sampleRate}));if("suspended"===i.state&&await i.resume(),this.assertOpen(),!this.workletLoaded){this.blobUrl=URL.createObjectURL(new Blob(["\nclass RecorderProcessor extends AudioWorkletProcessor {\n process(inputs) {\n const input = inputs[0];\n if (input && input[0]) {\n this.port.postMessage(input[0]);\n }\n return true;\n }\n}\nregisterProcessor('recorder-processor', RecorderProcessor);\n"],{type:"application/javascript"}));try{await i.audioWorklet.addModule(this.blobUrl),this.workletLoaded=!0}finally{this.revokeWorklet()}}if(this.assertOpen(),!this.source){if(!this.captureOnly)try{this.source=i.createMediaElementSource(this.video),this.direct=!0}catch(s){console.warn("[artplayerPluginAsr] Direct connection failed:",s)}if(!this.source){const t=this.video.captureStream||this.video.mozCaptureStream;if(!t)throw new Error("Could not establish audio source");this.stream=t.call(this.video),this.source=i.createMediaStreamSource(this.stream)}}}prepare(){return this.preparation??(this.preparation=this.initialize().catch(t=>{throw this.preparation=void 0,t})),this.preparation}get ownsMediaConnection(){return this.direct}idle(){const t=this.gain;this.disconnect(),this.direct&&this.context&&this.source&&(this.gain=t||this.context.createGain(),t||(this.gain.gain.value=1),this.source.connect(this.gain),this.gain.connect(this.context.destination))}connect(t){this.assertOpen();const e=this.context,i=this.source;if(!e||!i)throw new Error("Audio capture is not prepared");const s=this.gain;this.disconnect();const r=this.gain=s||e.createGain();s||(r.gain.value=this.direct?1:0);const n=this.recorder=new AudioWorkletNode(e,"recorder-processor");n.port.onmessage=e=>{this.closed||this.recorder!==n||t(e.data)},i.connect(n),this.direct?i.connect(r):n.connect(r),r.connect(e.destination)}disconnect(){this.recorder&&(this.recorder.port.onmessage=null,this.recorder.disconnect(),this.recorder=void 0),this.gain?.disconnect(),this.gain=void 0,this.source?.disconnect()}async close(){if(this.closed)return;this.closed=!0,this.disconnect(),this.revokeWorklet(),this.stream?.getTracks().forEach(t=>t.stop()),this.stream=void 0;const t=this.context;this.context=void 0,this.source=void 0,t&&"closed"!==t.state&&await t.close()}}class e{constructor(){this.offset=0,this.size=0}get length(){return this.size}push(t){if(0===t.length)return;const e={samples:new Float32Array(t)};this.tail?this.tail.next=e:this.head=e,this.tail=e,this.size+=t.length}take(t){if(!Number.isSafeInteger(t)||t<=0)throw new RangeError("Sample count must be a positive safe integer");if(t>this.size)return null;const e=new Float32Array(t);let i=0;for(;this.head&&i<t;){const s=this.head.samples,r=Math.min(s.length-this.offset,t-i);e.set(s.subarray(this.offset,this.offset+r),i),i+=r,this.offset+=r,this.offset===s.length&&(this.head=this.head.next,this.offset=0)}return this.head||(this.tail=void 0),this.size-=t,e}clear(){this.head=void 0,this.tail=void 0,this.offset=0,this.size=0}}class i{constructor(t,i,s){this.video=t,this.options=i,this.append=s,this.queue=new e,this.closing=Promise.resolve(),this.running=!1,this.terminal=!1,this.epoch=0}reset(){this.epoch++,this.pending=void 0,this.queue.clear()}pause(){this.reset(),this.running=!1,clearInterval(this.timer),this.timer=void 0,this.starting=void 0,this.graph?.idle()}restart(){const t=this.running||Boolean(this.starting);if(this.pause(),this.graph&&!this.graph.ownsMediaConnection){const e=this.stop(),i=this.epoch;return e.then(()=>t&&!this.terminal&&this.epoch===i?this.start():void 0)}return t?this.start():Promise.resolve()}start(){if(this.terminal||this.running)return Promise.resolve();if(this.starting)return this.starting;const e=this.epoch,i=()=>!this.terminal&&this.epoch===e,s=(async()=>{if(await this.closing,!i())return;const{sampleRate:e,interval:s}=this.options,r=Math.floor(e*s/1e3);if(!Number.isSafeInteger(r)||r<1||!Number.isFinite(s)||s<=0)throw new Error("Audio chunk length must be positive and finite");const n=this.graph??(this.graph=new t(this.video,e,this.options.captureOnly));await n.prepare(),i()?(n.connect(t=>{if(this.running&&this.graph===n)return this.queue.length+tLine truncated
+2 -2
View File
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-asr.js v2.1.0
* artplayer-plugin-asr.js v3.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginAsr=e(),define(function(){return t.artplayerPluginAsr})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginAsr=e()}(this,function(){"use strict";var t=(t,e,n)=>new Promise((r,o)=>{var a=t=>{try{l(n.next(t))}catch(e){o(e)}},i=t=>{try{l(n.throw(t))}catch(e){o(e)}},l=t=>t.done?r(t.value):Promise.resolve(t.value).then(a,i);l((n=n.apply(t,e)).next())});if("undefined"!==typeof document&&!document.getElementById("artplayer-plugin-asr")){const t=document.createElement("style");t.id="artplayer-plugin-asr",t.textContent=".art-video-player .art-layer-asr{pointer-events:none!important;position:absolute;z-index:150;inset:0;display:flex;flex-direction:column;justify-content:end;padding:0 2%;font-size:1rem;gap:var(--art-subtitle-gap);padding-bottom:var(--art-subtitle-bottom);transition:padding-bottom var(--art-transition-duration) ease;text-shadow:var(--art-subtitle-border) 1px 0 1px,var(--art-subtitle-border) 0 1px 1px,var(--art-subtitle-border) -1px 0 1px,var(--art-subtitle-border) 0 -1px 1px,var(--art-subtitle-border) 1px 1px 1px,var(--art-subtitle-border) -1px -1px 1px,var(--art-subtitle-border) 1px -1px 1px,var(--art-subtitle-border) -1px 1px 1px}.art-video-player.art-control-show .art-layer-asr{padding-bottom:calc(var(--art-control-height) + var(--art-subtitle-bottom))}",document.head.appendChild(t)}return function(e={}){const{length:n=3,interval:r=100,sampleRate:o=16e3,autoHideTimeout:a=1e4,onAudioChunk:i=()=>null}=e;return e=>{let l=!1,s=null,u=null,c=null,d=null,p=[],f=null,y=!1,m=null,h=null,g=null;const v=e.layers.add({name:"asr",html:""});function b(){v.style.display="none"}function x(t){var e;"string"===typeof t&&(clearTimeout(m),m=setTimeout(b,a),v.style.display="",v.innerHTML=(e=t,e.split(new RegExp("(?<=[\u3001\u3002\uff01\uff1f!?.])\\s*","u")).map(t=>t.trim()).filter(Boolean).slice(-n)).map(t=>`<div class="art-asr-line">${t}</div>`).join(""))}function w(){return t(this,null,function*(){if(!u&&e.video)try{return u=s.createMediaElementSource(e.video),u}catch(n){console.warn("[artplayerPluginAsr] Direct connection failed:",n)}try{if(h||(h=yield function(e){return t(this,null,function*(){try{return e.captureStream?e.captureStream():e.mozCaptureStream?e.mozCaptureStream():(console.warn("[artplayerPluginAsr] captureStream not supported"),null)}catch(n){return console.warn("[artplayerPluginAsr] Error capturing stream:",n),null}})}(e.video)),h)return g=s.createMediaStreamSource(h),g}catch(n){console.warn("[artplayerPluginAsr] MediaStream fallback failed:",n)}return null})}function A(){return t(this,null,function*(){l&&(l=!1,clearInterval(f),f=null,c&&(c.disconnect(),c.port.onmessage=null,c=null),d&&(d.disconnect(),d=null),p=[])})}function U(){return t(this,null,function*(){yield A(),g&&(g.disconnect(),g=null),u&&(u.disconnect(),u=null),h&&(h.getTracks().forEach(t=>t.stop()),h=null),s&&(yield s.close(),s=null),y=!1})}return e.on("video:volumechange",()=>{d&&(d.gain.value=e.volume)}),e.on("play",function(){return t(this,null,function*(){if(!l)try{yield function(){return t(this,null,function*(){return s||(s=new(window.AudioContext||window.webkitAudioContext)({sampleRate:o}),"suspended"===s.state&&(yield s.resume()),s)})}();const e=yield w();if(!e)throw new Error("Could not establish audio source");if(!y){const t=(()=>{const t=new Blob(["\n class RecorderProcessor extends AudioWorkletProcessor {\n process(inputs) {\n const input = inputs[0];\n if (input && input[0]) {\n this.port.postMessage(input[0]);\n }\n return true;\n }\n }\n registerProcessor('recorder-processor', RecorderProcessor);\n "],{type:"application/javascript"});return URL.createObjectURL(t)})();yield s.audioWorklet.addModule(t),URL.revokeObjectURL(t),y=!0}d=s.createGain(),d.gain.value=1,c=new AudioWorkletNode(s,"recorder-processor"),c.port.onmessage=t=>{p.push(new Float32Array(t.data))},e.connect(c),e.connect(d),d.connect(s.destination);const n=o*(r/1e3);f=setInterval(()=>t(null,null,function*(){if(0===p.length)return;let t=new Float32Array(0);for(;t.length<n&&p.length;){const e=p.shift(),n=new Float32Array(t.length+e.length);n.set(t,0),n.set(e,t.length),t=n}if(t.length<n)return;const e=function(t){const e=t.length,n=new ArrayBuffer(2*e),r=new DataView(n);for(let o=0;o<e;o++){const e=Math.max(-1,Math.min(1,t[o]));r.setInt16(2*o,e<0?32768*e:32767*e,!0)}return n}(t.slice(0,n)),r=function(t,e){const n=t.byteLength,r=new ArrayBuffer(44+n),o=new DataView(r),a=(t,e)=>{for(let n=0;n<e.length;n++)o.setUint8(t+n,e.charCodeAt(n))};return a(0,"RIFF"),o.setUint32(4,36+n,!0),a(8,"WAVE"),a(12,"fmt "),o.setUint32(16,16,!0),o.setUint16(20,1,!0),o.setUint16(22,1,!0),o.setUint32(24,e,!0),o.setUint32(28,2*e,!0),o.setUint16(32,2,!0),o.setUintLine truncated
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginAsr=e(),define(function(){return t.artplayerPluginAsr})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginAsr=e()}(this,function(){"use strict";var t=(t,e,i)=>new Promise((s,n)=>{var r=t=>{try{a(i.next(t))}catch(e){n(e)}},o=t=>{try{a(i.throw(t))}catch(e){n(e)}},a=t=>t.done?s(t.value):Promise.resolve(t.value).then(r,o);a((i=i.apply(t,e)).next())});class e{constructor(t,e,i=!1){this.video=t,this.sampleRate=e,this.captureOnly=i,this.closed=!1,this.direct=!1,this.workletLoaded=!1}assertOpen(){if(this.closed)throw new Error("Audio capture was closed")}revokeWorklet(){void 0!==this.blobUrl&&(URL.revokeObjectURL(this.blobUrl),this.blobUrl=void 0)}initialize(){return t(this,null,function*(){var t;this.assertOpen();const e=window,i=window.AudioContext||e.webkitAudioContext;if(!i)throw new Error("AudioContext is not supported");const s=null!=(t=this.context)?t:this.context=new i({sampleRate:this.sampleRate});if("suspended"===s.state&&(yield s.resume()),this.assertOpen(),!this.workletLoaded){this.blobUrl=URL.createObjectURL(new Blob(["\nclass RecorderProcessor extends AudioWorkletProcessor {\n process(inputs) {\n const input = inputs[0];\n if (input && input[0]) {\n this.port.postMessage(input[0]);\n }\n return true;\n }\n}\nregisterProcessor('recorder-processor', RecorderProcessor);\n"],{type:"application/javascript"}));try{yield s.audioWorklet.addModule(this.blobUrl),this.workletLoaded=!0}finally{this.revokeWorklet()}}if(this.assertOpen(),!this.source){if(!this.captureOnly)try{this.source=s.createMediaElementSource(this.video),this.direct=!0}catch(n){console.warn("[artplayerPluginAsr] Direct connection failed:",n)}if(!this.source){const t=this.video.captureStream||this.video.mozCaptureStream;if(!t)throw new Error("Could not establish audio source");this.stream=t.call(this.video),this.source=s.createMediaStreamSource(this.stream)}}})}prepare(){return null!=this.preparation||(this.preparation=this.initialize().catch(t=>{throw this.preparation=void 0,t})),this.preparation}get ownsMediaConnection(){return this.direct}idle(){const t=this.gain;this.disconnect(),this.direct&&this.context&&this.source&&(this.gain=t||this.context.createGain(),t||(this.gain.gain.value=1),this.source.connect(this.gain),this.gain.connect(this.context.destination))}connect(t){this.assertOpen();const e=this.context,i=this.source;if(!e||!i)throw new Error("Audio capture is not prepared");const s=this.gain;this.disconnect();const n=this.gain=s||e.createGain();s||(n.gain.value=this.direct?1:0);const r=this.recorder=new AudioWorkletNode(e,"recorder-processor");r.port.onmessage=e=>{this.closed||this.recorder!==r||t(e.data)},i.connect(r),this.direct?i.connect(n):r.connect(n),n.connect(e.destination)}disconnect(){var t,e;this.recorder&&(this.recorder.port.onmessage=null,this.recorder.disconnect(),this.recorder=void 0),null==(t=this.gain)||t.disconnect(),this.gain=void 0,null==(e=this.source)||e.disconnect()}close(){return t(this,null,function*(){var t;if(this.closed)return;this.closed=!0,this.disconnect(),this.revokeWorklet(),null==(t=this.stream)||t.getTracks().forEach(t=>t.stop()),this.stream=void 0;const e=this.context;this.context=void 0,this.source=void 0,e&&"closed"!==e.state&&(yield e.close())})}}class i{constructor(){this.offset=0,this.size=0}get length(){return this.size}push(t){if(0===t.length)return;const e={samples:new Float32Array(t)};this.tail?this.tail.next=e:this.head=e,this.tail=e,this.size+=t.length}take(t){if(!Number.isSafeInteger(t)||t<=0)throw new RangeError("Sample count must be a positive safe integer");if(t>this.size)return null;const e=new Float32Array(t);let i=0;for(;this.head&&i<t;){const s=this.head.samples,n=Math.min(s.length-this.offset,t-i);e.set(s.subarray(this.offset,this.offset+n),i),i+=n,this.offset+=n,this.offset===s.length&&(this.head=this.head.next,this.offset=0)}return this.head||(this.tail=void 0),this.size-=t,e}clear(){this.head=void 0,this.tail=void 0,this.offset=0,this.size=0}}class s{constructor(t,e,s){this.video=t,this.options=e,this.append=s,this.queue=new i,this.closing=Promise.resolve(),this.running=!1,this.terminal=!1,this.epoch=0}reset(){this.epoch++,this.pending=void 0,this.queue.clear()}pause(){var t;this.reset(),this.running=!1,clearInterval(this.timer),this.timer=void 0,this.starting=void 0,null==(t=this.graph)||t.idle()}restart(){const t=this.running||Boolean(this.starting);if(this.pause(),this.graph&&!this.graph.ownsMediaConnection){const e=this.stop(),i=this.epoch;return e.then(()=>t&&!this.terminal&&this.epoch===i?this.start():void 0)}return t?this.start():Promise.resolve()}start(){if(this.terminal||this.running)return Promise.resolve();if(this.starting)return this.starting;const i=this.epoch,s=()=>!this.terminal&&this.epoch===i,n=(()=>t(this,null,function*(){var t;if(yield this.closing,!Line truncated
+381 -230
View File
@@ -1,251 +1,402 @@
/*!
* artplayer-plugin-asr.js v2.1.0
* artplayer-plugin-asr.js v3.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
const style = ".art-video-player .art-layer-asr {\n pointer-events: none !important;\n position: absolute;\n z-index: 150;\n inset: 0px;\n display: flex;\n flex-direction: column;\n justify-content: end;\n padding: 0 2%;\n font-size: 1rem;\n gap: var(--art-subtitle-gap);\n padding-bottom: var(--art-subtitle-bottom);\n transition: padding-bottom var(--art-transition-duration) ease;\n text-shadow: var(--art-subtitle-border) 1px 0 1px, var(--art-subtitle-border) 0 1px 1px, var(--art-subtitle-border) -1px 0 1px, var(--art-subtitle-border) 0 -1px 1px, var(--art-subtitle-border) 1px 1px 1px, var(--art-subtitle-border) -1px -1px 1px, var(--art-subtitle-border) 1px -1px 1px, var(--art-subtitle-border) -1px 1px 1px;\n}\n.art-video-player.art-control-show .art-layer-asr {\n padding-bottom: calc(var(--art-control-height) + var(--art-subtitle-bottom));\n}\n";
function artplayerPluginAsr(option = {}) {
const {
length = 3,
interval = 100,
sampleRate = 16e3,
autoHideTimeout = 1e4,
onAudioChunk = () => null
} = option;
return (art) => {
let started = false;
let audioCtx = null;
let sourceNode = null;
let recorderNode = null;
let gainNode = null;
let bufferChunks = [];
let timer = null;
let workletLoaded = false;
let hideTimer = null;
let mediaStream = null;
let mediaStreamSource = null;
const $asr = art.layers.add({
name: "asr",
html: ""
});
function splitByPunctuation(text) {
return text.split(/(?<=[、。!?!?.])\s*/u).map((s) => s.trim()).filter(Boolean).slice(-length);
}
function hide() {
$asr.style.display = "none";
}
function append(subtitle) {
if (typeof subtitle !== "string")
return;
clearTimeout(hideTimer);
hideTimer = setTimeout(hide, autoHideTimeout);
$asr.style.display = "";
$asr.innerHTML = splitByPunctuation(subtitle).map((line) => `<div class="art-asr-line">${line}</div>`).join("");
}
const recorderProcessorCode = `
class RecorderProcessor extends AudioWorkletProcessor {
process(inputs) {
const input = inputs[0];
if (input && input[0]) {
this.port.postMessage(input[0]);
}
return true;
}
}
registerProcessor('recorder-processor', RecorderProcessor);
`;
const createWorkletBlobUrl = () => {
const blob = new Blob([recorderProcessorCode], { type: "application/javascript" });
return URL.createObjectURL(blob);
};
function floatTo16BitPCM(float32Array) {
const len = float32Array.length;
const buffer = new ArrayBuffer(len * 2);
const view = new DataView(buffer);
for (let i = 0; i < len; i++) {
const s = Math.max(-1, Math.min(1, float32Array[i]));
view.setInt16(i * 2, s < 0 ? s * 32768 : s * 32767, true);
}
return buffer;
}
function pcmToWav(pcmBuffer, sampleRate2) {
const pcmLength = pcmBuffer.byteLength;
const wavBuffer = new ArrayBuffer(44 + pcmLength);
const view = new DataView(wavBuffer);
const writeString = (offset, str) => {
for (let i = 0; i < str.length; i++) {
view.setUint8(offset + i, str.charCodeAt(i));
const recorderProcessorCode = `
class RecorderProcessor extends AudioWorkletProcessor {
process(inputs) {
const input = inputs[0];
if (input && input[0]) {
this.port.postMessage(input[0]);
}
};
writeString(0, "RIFF");
view.setUint32(4, 36 + pcmLength, true);
writeString(8, "WAVE");
writeString(12, "fmt ");
view.setUint32(16, 16, true);
view.setUint16(20, 1, true);
view.setUint16(22, 1, true);
view.setUint32(24, sampleRate2, true);
view.setUint32(28, sampleRate2 * 2, true);
view.setUint16(32, 2, true);
view.setUint16(34, 16, true);
writeString(36, "data");
view.setUint32(40, pcmLength, true);
new Uint8Array(wavBuffer).set(new Uint8Array(pcmBuffer), 44);
return wavBuffer;
return true;
}
async function setupAudioContext() {
if (audioCtx)
return audioCtx;
audioCtx = new (window.AudioContext || window.webkitAudioContext)({ sampleRate });
if (audioCtx.state === "suspended")
await audioCtx.resume();
return audioCtx;
}
registerProcessor('recorder-processor', RecorderProcessor);
`;
class AudioGraph {
constructor(video, sampleRate, captureOnly = false) {
this.video = video;
this.sampleRate = sampleRate;
this.captureOnly = captureOnly;
this.closed = false;
this.direct = false;
this.workletLoaded = false;
}
assertOpen() {
if (this.closed)
throw new Error("Audio capture was closed");
}
revokeWorklet() {
if (this.blobUrl !== void 0) {
URL.revokeObjectURL(this.blobUrl);
this.blobUrl = void 0;
}
async function setupAudioSource() {
if (!sourceNode && art.video) {
}
async initialize() {
this.assertOpen();
const platform = window;
const Context = window.AudioContext || platform.webkitAudioContext;
if (!Context)
throw new Error("AudioContext is not supported");
const context = this.context ?? (this.context = new Context({ sampleRate: this.sampleRate }));
if (context.state === "suspended")
await context.resume();
this.assertOpen();
if (!this.workletLoaded) {
this.blobUrl = URL.createObjectURL(new Blob([recorderProcessorCode], { type: "application/javascript" }));
try {
await context.audioWorklet.addModule(this.blobUrl);
this.workletLoaded = true;
} finally {
this.revokeWorklet();
}
}
this.assertOpen();
if (!this.source) {
if (!this.captureOnly) {
try {
sourceNode = audioCtx.createMediaElementSource(art.video);
return sourceNode;
} catch (err) {
console.warn("[artplayerPluginAsr] Direct connection failed:", err);
this.source = context.createMediaElementSource(this.video);
this.direct = true;
} catch (error) {
console.warn("[artplayerPluginAsr] Direct connection failed:", error);
}
}
try {
if (!mediaStream) {
mediaStream = await captureAudioFromVideo(art.video);
}
if (mediaStream) {
mediaStreamSource = audioCtx.createMediaStreamSource(mediaStream);
return mediaStreamSource;
}
} catch (err) {
console.warn("[artplayerPluginAsr] MediaStream fallback failed:", err);
}
return null;
}
async function captureAudioFromVideo(videoElement) {
try {
if (videoElement.captureStream)
return videoElement.captureStream();
if (videoElement.mozCaptureStream)
return videoElement.mozCaptureStream();
console.warn("[artplayerPluginAsr] captureStream not supported");
return null;
} catch (err) {
console.warn("[artplayerPluginAsr] Error capturing stream:", err);
return null;
}
}
async function startCapture() {
if (started)
return;
try {
await setupAudioContext();
const audioSource = await setupAudioSource();
if (!audioSource)
if (!this.source) {
const capture = this.video.captureStream || this.video.mozCaptureStream;
if (!capture)
throw new Error("Could not establish audio source");
if (!workletLoaded) {
const blobUrl = createWorkletBlobUrl();
await audioCtx.audioWorklet.addModule(blobUrl);
URL.revokeObjectURL(blobUrl);
workletLoaded = true;
}
gainNode = audioCtx.createGain();
gainNode.gain.value = 1;
recorderNode = new AudioWorkletNode(audioCtx, "recorder-processor");
recorderNode.port.onmessage = (event) => {
bufferChunks.push(new Float32Array(event.data));
};
audioSource.connect(recorderNode);
audioSource.connect(gainNode);
gainNode.connect(audioCtx.destination);
const CHUNK_SAMPLES = sampleRate * (interval / 1e3);
timer = setInterval(async () => {
if (bufferChunks.length === 0)
return;
let accumulated = new Float32Array(0);
while (accumulated.length < CHUNK_SAMPLES && bufferChunks.length) {
const next = bufferChunks.shift();
const tmp = new Float32Array(accumulated.length + next.length);
tmp.set(accumulated, 0);
tmp.set(next, accumulated.length);
accumulated = tmp;
}
if (accumulated.length < CHUNK_SAMPLES)
return;
const chunkToSend = accumulated.slice(0, CHUNK_SAMPLES);
const pcm = floatTo16BitPCM(chunkToSend);
const wav = pcmToWav(pcm, sampleRate);
const subtitle = await onAudioChunk({ pcm, wav });
append(subtitle);
}, interval);
started = true;
} catch (err) {
console.error("[artplayerPluginAsr] Initialization failed:", err);
await stopCapture();
this.stream = capture.call(this.video);
this.source = context.createMediaStreamSource(this.stream);
}
}
async function stopCapture() {
if (!started)
return;
started = false;
clearInterval(timer);
timer = null;
if (recorderNode) {
recorderNode.disconnect();
recorderNode.port.onmessage = null;
recorderNode = null;
}
if (gainNode) {
gainNode.disconnect();
gainNode = null;
}
bufferChunks = [];
}
prepare() {
this.preparation ?? (this.preparation = this.initialize().catch((error) => {
this.preparation = void 0;
throw error;
}));
return this.preparation;
}
get ownsMediaConnection() {
return this.direct;
}
idle() {
const gain = this.gain;
this.disconnect();
if (this.direct && this.context && this.source) {
this.gain = gain || this.context.createGain();
if (!gain)
this.gain.gain.value = 1;
this.source.connect(this.gain);
this.gain.connect(this.context.destination);
}
async function destroy() {
await stopCapture();
if (mediaStreamSource) {
mediaStreamSource.disconnect();
mediaStreamSource = null;
}
if (sourceNode) {
sourceNode.disconnect();
sourceNode = null;
}
if (mediaStream) {
mediaStream.getTracks().forEach((track) => track.stop());
mediaStream = null;
}
if (audioCtx) {
await audioCtx.close();
audioCtx = null;
}
workletLoaded = false;
}
art.on("video:volumechange", () => {
if (gainNode) {
gainNode.gain.value = art.volume;
}
});
art.on("play", startCapture);
art.on("pause", stopCapture);
art.on("destroy", destroy);
return {
name: "artplayerPluginAsr",
stop: destroy,
hide,
append
}
connect(receive) {
this.assertOpen();
const context = this.context;
const source = this.source;
if (!context || !source)
throw new Error("Audio capture is not prepared");
const previousGain = this.gain;
this.disconnect();
const gain = this.gain = previousGain || context.createGain();
if (!previousGain)
gain.gain.value = this.direct ? 1 : 0;
const recorder = this.recorder = new AudioWorkletNode(context, "recorder-processor");
recorder.port.onmessage = (event) => {
if (!this.closed && this.recorder === recorder)
receive(event.data);
};
source.connect(recorder);
if (this.direct)
source.connect(gain);
else recorder.connect(gain);
gain.connect(context.destination);
}
disconnect() {
if (this.recorder) {
this.recorder.port.onmessage = null;
this.recorder.disconnect();
this.recorder = void 0;
}
this.gain?.disconnect();
this.gain = void 0;
this.source?.disconnect();
}
async close() {
if (this.closed)
return;
this.closed = true;
this.disconnect();
this.revokeWorklet();
this.stream?.getTracks().forEach((track) => track.stop());
this.stream = void 0;
const context = this.context;
this.context = void 0;
this.source = void 0;
if (context && context.state !== "closed")
await context.close();
}
}
function encodeAudio(samples, sampleRate) {
const pcm = new ArrayBuffer(samples.length * 2);
const pcmView = new DataView(pcm);
for (let index = 0; index < samples.length; index++) {
const value = Math.max(-1, Math.min(1, samples[index]));
pcmView.setInt16(index * 2, value < 0 ? value * 32768 : value * 32767, true);
}
const wav = new ArrayBuffer(44 + pcm.byteLength);
const header = new DataView(wav);
function writeString(offset, value) {
for (let index = 0; index < value.length; index++)
header.setUint8(offset + index, value.charCodeAt(index));
}
writeString(0, "RIFF");
header.setUint32(4, 36 + pcm.byteLength, true);
writeString(8, "WAVE");
writeString(12, "fmt ");
header.setUint32(16, 16, true);
header.setUint16(20, 1, true);
header.setUint16(22, 1, true);
header.setUint32(24, sampleRate, true);
header.setUint32(28, sampleRate * 2, true);
header.setUint16(32, 2, true);
header.setUint16(34, 16, true);
writeString(36, "data");
header.setUint32(40, pcm.byteLength, true);
new Uint8Array(wav).set(new Uint8Array(pcm), 44);
return { pcm, wav };
}
class SampleQueue {
constructor() {
this.offset = 0;
this.size = 0;
}
get length() {
return this.size;
}
push(input) {
if (input.length === 0)
return;
const block = { samples: new Float32Array(input) };
if (this.tail)
this.tail.next = block;
else
this.head = block;
this.tail = block;
this.size += input.length;
}
take(count) {
if (!Number.isSafeInteger(count) || count <= 0)
throw new RangeError("Sample count must be a positive safe integer");
if (count > this.size)
return null;
const output = new Float32Array(count);
let written = 0;
while (this.head && written < count) {
const samples = this.head.samples;
const amount = Math.min(samples.length - this.offset, count - written);
output.set(samples.subarray(this.offset, this.offset + amount), written);
written += amount;
this.offset += amount;
if (this.offset === samples.length) {
this.head = this.head.next;
this.offset = 0;
}
}
if (!this.head)
this.tail = void 0;
this.size -= count;
return output;
}
clear() {
this.head = void 0;
this.tail = void 0;
this.offset = 0;
this.size = 0;
}
}
class Capture {
constructor(video, options, append) {
this.video = video;
this.options = options;
this.append = append;
this.queue = new SampleQueue();
this.closing = Promise.resolve();
this.running = false;
this.terminal = false;
this.epoch = 0;
}
reset() {
this.epoch++;
this.pending = void 0;
this.queue.clear();
}
pause() {
this.reset();
this.running = false;
clearInterval(this.timer);
this.timer = void 0;
this.starting = void 0;
this.graph?.idle();
}
restart() {
const active = this.running || Boolean(this.starting);
this.pause();
if (this.graph && !this.graph.ownsMediaConnection) {
const stopping = this.stop();
const epoch = this.epoch;
return stopping.then(() => active && !this.terminal && this.epoch === epoch ? this.start() : void 0);
}
return active ? this.start() : Promise.resolve();
}
start() {
if (this.terminal || this.running)
return Promise.resolve();
if (this.starting)
return this.starting;
const epoch = this.epoch;
const current = () => !this.terminal && this.epoch === epoch;
const operation = (async () => {
await this.closing;
if (!current())
return;
const { sampleRate, interval } = this.options;
const count = Math.floor(sampleRate * interval / 1e3);
if (!Number.isSafeInteger(count) || count < 1 || !Number.isFinite(interval) || interval <= 0)
throw new Error("Audio chunk length must be positive and finite");
const graph = this.graph ?? (this.graph = new AudioGraph(this.video, sampleRate, this.options.captureOnly));
await graph.prepare();
if (!current()) {
if (!this.running && this.graph === graph)
graph.idle();
return;
}
graph.connect((samples) => {
if (!this.running || this.graph !== graph)
return;
if (this.queue.length + samples.length > Math.max(sampleRate * 60, count * 2)) {
console.error("[artplayerPluginAsr] Audio callback backlog exceeded its capture limit");
this.pause();
return;
}
this.queue.push(samples);
});
this.running = true;
this.timer = setInterval(() => this.tick(count), interval);
})().catch(async (error) => {
if (current()) {
console.error("[artplayerPluginAsr] Initialization failed:", error);
await this.stop();
}
}).finally(() => {
if (this.starting === operation)
this.starting = void 0;
});
this.starting = operation;
return operation;
}
async tick(count) {
if (!this.running || this.pending)
return;
const samples = this.queue.take(count);
if (!samples)
return;
const epoch = this.epoch;
const pending = this.pending = {};
try {
const text = await this.options.onAudioChunk(encodeAudio(samples, this.options.sampleRate));
if (this.running && !this.terminal && this.epoch === epoch)
this.append(text);
} catch (error) {
if (this.epoch === epoch && !this.terminal)
console.error("[artplayerPluginAsr] Audio callback failed:", error);
} finally {
if (this.pending === pending)
this.pending = void 0;
}
}
stop(terminal = false) {
this.terminal || (this.terminal = terminal);
this.pause();
const graph = this.graph;
if (terminal || !graph?.ownsMediaConnection) {
this.graph = void 0;
this.closing = Promise.all([this.closing, graph?.close()]).then(() => void 0);
}
return this.closing;
}
}
const style = ".art-video-player .art-layer-asr {\n pointer-events: none !important;\n position: absolute;\n z-index: 150;\n inset: 0px;\n display: flex;\n flex-direction: column;\n justify-content: end;\n padding: 0 2%;\n font-size: 1rem;\n gap: var(--art-subtitle-gap);\n padding-bottom: var(--art-subtitle-bottom);\n transition: padding-bottom var(--art-transition-duration) ease;\n text-shadow: var(--art-subtitle-border) 1px 0 1px, var(--art-subtitle-border) 0 1px 1px, var(--art-subtitle-border) -1px 0 1px, var(--art-subtitle-border) 0 -1px 1px, var(--art-subtitle-border) 1px 1px 1px, var(--art-subtitle-border) -1px -1px 1px, var(--art-subtitle-border) 1px -1px 1px, var(--art-subtitle-border) -1px 1px 1px;\n}\n.art-video-player.art-control-show .art-layer-asr {\n padding-bottom: calc(var(--art-control-height) + var(--art-subtitle-bottom));\n}\n";
function createSubtitles(layer, length, autoHideTimeout) {
let timer;
let destroyed = false;
function cancelTimer() {
clearTimeout(timer);
timer = void 0;
}
function hide() {
if (!destroyed)
layer.style.display = "none";
}
function append(subtitle) {
if (destroyed || typeof subtitle !== "string")
return;
cancelTimer();
timer = setTimeout(hide, autoHideTimeout);
layer.style.display = "";
layer.innerHTML = subtitle.split(/(?<=[、。!?!?.])\s*/u).map((line) => line.trim()).filter(Boolean).slice(-length).map((line) => `<div class="art-asr-line">${line}</div>`).join("");
}
return {
append,
hide,
destroy() {
destroyed = true;
cancelTimer();
}
};
}
if (typeof document !== "undefined") {
if (!document.getElementById("artplayer-plugin-asr")) {
const $style = document.createElement("style");
$style.id = "artplayer-plugin-asr";
$style.textContent = style;
document.head.appendChild($style);
}
function artplayerPluginAsr(option = {}) {
const { length = 3, interval = 100, sampleRate = 16e3, autoHideTimeout = 1e4, onAudioChunk = () => null, audioInput } = option;
if (audioInput !== void 0 && audioInput.type !== "capture")
throw new TypeError("Unsupported ASR audio input");
const captureOnly = audioInput?.type === "capture";
return (art) => {
const layer = art.layers.add({ name: "asr", html: "" });
if (!layer)
throw new Error("Could not create ASR subtitle layer");
const subtitles = createSubtitles(layer, length, autoHideTimeout);
const capture = new Capture(art.video, { interval, sampleRate, onAudioChunk, captureOnly }, subtitles.append);
const play = () => capture.start();
const pause = () => capture.pause();
const restart = () => capture.restart();
const stop = () => capture.stop();
const destroy = () => {
subtitles.destroy();
art.off("play", play);
art.off("pause", pause);
art.off("restart", restart);
art.off("video:error", stop);
art.off("destroy", destroy);
return capture.stop(true);
};
art.on("play", play);
art.on("pause", pause);
art.on("restart", restart);
art.on("video:error", stop);
art.on("destroy", destroy);
return { name: "artplayerPluginAsr", stop, hide: subtitles.hide, append: subtitles.append };
};
}
Object.defineProperty(artplayerPluginAsr, "default", { value: artplayerPluginAsr });
if (typeof document !== "undefined" && !document.getElementById("artplayer-plugin-asr")) {
const styleElement = document.createElement("style");
styleElement.id = "artplayer-plugin-asr";
styleElement.textContent = style;
document.head.appendChild(styleElement);
}
export {
artplayerPluginAsr as default
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-audio-track.js v1.1.0
* artplayer-plugin-audio-track.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,o){"object"===typeof exports&&"undefined"!==typeof module?module.exports=o():"function"==typeof define&&define.amd?(t.artplayerPluginAudioTrack=o(),define(function(){return t.artplayerPluginAudioTrack})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAudioTrack=o()}(this,function(){"use strict";return function(e){return o=>{let{url:n,offset:a=0,sync:t=.3}=e;const u=new Audio;function i(){if(!o.video||!n)return;const e=o.currentTime+a;Math.abs(u.currentTime-e)>t&&(u.currentTime=e)}return u.preload="auto",n&&(u.src=n),o.on("play",()=>{n&&(i(),u.play().catch(e=>{console.warn(e)}))}),o.on("pause",()=>{u.pause()}),o.on("seek",()=>{i()}),o.on("video:timeupdate",()=>{o.playing&&i()}),o.on("video:ratechange",()=>{u.playbackRate=o.video.playbackRate}),o.on("video:volumechange",()=>{u.volume=o.volume,u.muted=o.muted}),o.on("video:waiting",()=>{u.pause()}),o.on("video:playing",()=>{n&&o.playing&&u.play().catch(e=>{console.warn(e)})}),o.on("destroy",()=>{u.pause(),u.src="",u.load()}),u.volume=o.volume,u.muted=o.muted,u.playbackRate=o.video?.playbackRate||1,{name:"artplayerPluginAudioTrack",audio:u,update:function(e){e.url&&e.url!==n&&(n=e.url,u.src=n,o.playing&&u.play().catch(e=>console.warn(e))),void 0!==e.offset&&(a=e.offset),void 0!==e.sync&&(t=e.sync)}}}}});
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAudioTrack=t(),define(function(){return e.artplayerPluginAudioTrack})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAudioTrack=t()}(this,function(){"use strict";return function(e){return t=>{const o=function(e){let{url:t,offset:o=0,sync:n=.3}=e;const a=new Audio;let i=!1;function u(){!i&&t&&a.play().catch(e=>{i||console.warn(e)})}function c(){if(i)return;i=!0;const e=[];for(const o of[()=>a.pause(),()=>a.removeAttribute("src"),()=>a.load()])try{o()}catch(t){e.push(t)}if(e.length)throw e[0]}try{a.preload="auto",t&&(a.src=t)}catch(r){try{c()}catch{}throw r}return{audio:a,play:u,pause:function(){i||a.pause()},destroy:c,sync(e){if(i||!t)return;const u=e+o;Math.abs(a.currentTime-u)>n&&(a.currentTime=u)},update(e,c){i||(e.url&&e.url!==t&&(t=e.url,a.src=t,c&&u()),void 0!==e.offset&&(o=e.offset),void 0!==e.sync&&(n=e.sync))}}}(e),{audio:n}=o,a=[];let i=!0;function u(){t.video&&o.sync(t.currentTime)}function c(){const e=t.video;return!!e&&("playing"in e&&"boolean"===typeof e.playing?e.playing:t.playing||!1===e.paused&&!e.ended&&e.readyState>2)}function r(e,o){const n=()=>{i&&o()};a.push([e,n]),t.on(e,n)}function d(){if(!i)return;i=!1;const e=[];for(const[o,i]of a.splice(0))try{t.off(o,i)}catch(n){e.push(n)}try{o.destroy()}catch(n){e.push(n)}if(e.length)throw e[0]}try{r("play",()=>{u(),o.play()});for(const e of["pause","video:pause","video:ended","video:waiting","video:emptied","video:seeking"])r(e,o.pause);r("seek",u),r("video:seeked",()=>{u(),c()&&o.play()}),r("video:timeupdate",()=>{t.playing&&u()}),r("video:ratechange",()=>{n.playbackRate=t.video.playbackRate}),r("video:volumechange",()=>{n.volume=t.volume,n.muted=t.muted}),r("video:playing",()=>{c()&&(u(),o.play())}),r("video:canplay",()=>{n.paused&&c()&&(u(),o.play())}),r("destroy",d),n.volume=t.volume,n.muted=t.muted,n.playbackRate=t.video?.playbackRate||1}catch(s){try{d()}catch{}throw s}return{name:"artplayerPluginAudioTrack",audio:n,update(e){i&&o.update(e,t.playing)}}}}});
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-audio-track.js v1.1.0
* artplayer-plugin-audio-track.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,o){"object"===typeof exports&&"undefined"!==typeof module?module.exports=o():"function"==typeof define&&define.amd?(t.artplayerPluginAudioTrack=o(),define(function(){return t.artplayerPluginAudioTrack})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAudioTrack=o()}(this,function(){"use strict";return function(e){return o=>{var n;let{url:a,offset:t=0,sync:u=.3}=e;const i=new Audio;function l(){if(!o.video||!a)return;const e=o.currentTime+t;Math.abs(i.currentTime-e)>u&&(i.currentTime=e)}return i.preload="auto",a&&(i.src=a),o.on("play",()=>{a&&(l(),i.play().catch(e=>{console.warn(e)}))}),o.on("pause",()=>{i.pause()}),o.on("seek",()=>{l()}),o.on("video:timeupdate",()=>{o.playing&&l()}),o.on("video:ratechange",()=>{i.playbackRate=o.video.playbackRate}),o.on("video:volumechange",()=>{i.volume=o.volume,i.muted=o.muted}),o.on("video:waiting",()=>{i.pause()}),o.on("video:playing",()=>{a&&o.playing&&i.play().catch(e=>{console.warn(e)})}),o.on("destroy",()=>{i.pause(),i.src="",i.load()}),i.volume=o.volume,i.muted=o.muted,i.playbackRate=(null==(n=o.video)?void 0:n.playbackRate)||1,{name:"artplayerPluginAudioTrack",audio:i,update:function(e){e.url&&e.url!==a&&(a=e.url,i.src=a,o.playing&&i.play().catch(e=>console.warn(e))),void 0!==e.offset&&(t=e.offset),void 0!==e.sync&&(u=e.sync)}}}}});
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAudioTrack=t(),define(function(){return e.artplayerPluginAudioTrack})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAudioTrack=t()}(this,function(){"use strict";return function(e){return t=>{var o;const n=function(e){let{url:t,offset:o=0,sync:n=.3}=e;const a=new Audio;let i=!1;function u(){!i&&t&&a.play().catch(e=>{i||console.warn(e)})}function c(){if(i)return;i=!0;const e=[];for(const o of[()=>a.pause(),()=>a.removeAttribute("src"),()=>a.load()])try{o()}catch(t){e.push(t)}if(e.length)throw e[0]}try{a.preload="auto",t&&(a.src=t)}catch(r){try{c()}catch(d){}throw r}return{audio:a,play:u,pause:function(){i||a.pause()},destroy:c,sync(e){if(i||!t)return;const u=e+o;Math.abs(a.currentTime-u)>n&&(a.currentTime=u)},update(e,c){i||(e.url&&e.url!==t&&(t=e.url,a.src=t,c&&u()),void 0!==e.offset&&(o=e.offset),void 0!==e.sync&&(n=e.sync))}}}(e),{audio:a}=n,i=[];let u=!0;function c(){t.video&&n.sync(t.currentTime)}function r(){const e=t.video;return!!e&&("playing"in e&&"boolean"===typeof e.playing?e.playing:t.playing||!1===e.paused&&!e.ended&&e.readyState>2)}function d(e,o){const n=()=>{u&&o()};i.push([e,n]),t.on(e,n)}function l(){if(!u)return;u=!1;const e=[];for(const[n,a]of i.splice(0))try{t.off(n,a)}catch(o){e.push(o)}try{n.destroy()}catch(o){e.push(o)}if(e.length)throw e[0]}try{d("play",()=>{c(),n.play()});for(const e of["pause","video:pause","video:ended","video:waiting","video:emptied","video:seeking"])d(e,n.pause);d("seek",c),d("video:seeked",()=>{c(),r()&&n.play()}),d("video:timeupdate",()=>{t.playing&&c()}),d("video:ratechange",()=>{a.playbackRate=t.video.playbackRate}),d("video:volumechange",()=>{a.volume=t.volume,a.muted=t.muted}),d("video:playing",()=>{r()&&(c(),n.play())}),d("video:canplay",()=>{a.paused&&r()&&(c(),n.play())}),d("destroy",l),a.volume=t.volume,a.muted=t.muted,a.playbackRate=(null==(o=t.video)?void 0:o.playbackRate)||1}catch(s){try{l()}catch(p){}throw s}return{name:"artplayerPluginAudioTrack",audio:a,update(e){u&&n.update(e,t.playing)}}}}});
+156 -66
View File
@@ -1,89 +1,179 @@
/*!
* artplayer-plugin-audio-track.js v1.1.0
* artplayer-plugin-audio-track.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
function artplayerPluginAudioTrack(option) {
return (art) => {
let { url, offset = 0, sync = 0.3 } = option;
const audio = new Audio();
function createAudioTrack(option) {
let { url, offset = 0, sync = 0.3 } = option;
const audio = new Audio();
let closed = false;
function play() {
if (closed || !url)
return;
audio.play().catch((error) => {
if (!closed)
console.warn(error);
});
}
function pause() {
if (!closed)
audio.pause();
}
function destroy() {
if (closed)
return;
closed = true;
const failures = [];
for (const release of [() => audio.pause(), () => audio.removeAttribute("src"), () => audio.load()]) {
try {
release();
} catch (error) {
failures.push(error);
}
}
if (failures.length)
throw failures[0];
}
try {
audio.preload = "auto";
if (url) {
if (url)
audio.src = url;
} catch (error) {
try {
destroy();
} catch {
}
function syncAudio() {
if (!art.video || !url)
throw error;
}
return {
audio,
play,
pause,
destroy,
sync(time) {
if (closed || !url)
return;
const videoTime = art.currentTime;
const targetTime = videoTime + offset;
if (Math.abs(audio.currentTime - targetTime) > sync) {
audio.currentTime = targetTime;
}
}
art.on("play", () => {
if (!url)
const target = time + offset;
if (Math.abs(audio.currentTime - target) > sync)
audio.currentTime = target;
},
update(newOption, playing) {
if (closed)
return;
syncAudio();
audio.play().catch((err) => {
console.warn(err);
});
});
art.on("pause", () => {
audio.pause();
});
art.on("seek", () => {
syncAudio();
});
art.on("video:timeupdate", () => {
if (art.playing) {
syncAudio();
}
});
art.on("video:ratechange", () => {
audio.playbackRate = art.video.playbackRate;
});
art.on("video:volumechange", () => {
audio.volume = art.volume;
audio.muted = art.muted;
});
art.on("video:waiting", () => {
audio.pause();
});
art.on("video:playing", () => {
if (url && art.playing) {
audio.play().catch((err) => {
console.warn(err);
});
}
});
art.on("destroy", () => {
audio.pause();
audio.src = "";
audio.load();
});
function update(newOption) {
if (newOption.url && newOption.url !== url) {
url = newOption.url;
audio.src = url;
if (art.playing) {
audio.play().catch((err) => console.warn(err));
if (playing)
play();
}
if (newOption.offset !== void 0)
offset = newOption.offset;
if (newOption.sync !== void 0)
sync = newOption.sync;
}
};
}
function artplayerPluginAudioTrack(option) {
return (art) => {
const track = createAudioTrack(option);
const { audio } = track;
const subscriptions = [];
let active = true;
function syncAudio() {
if (art.video)
track.sync(art.currentTime);
}
function canResumeAudio() {
const video = art.video;
if (!video)
return false;
if ("playing" in video && typeof video.playing === "boolean")
return video.playing;
return art.playing || video.paused === false && !video.ended && video.readyState > 2;
}
function listen(event, callback) {
const listener = () => {
if (active)
callback();
};
subscriptions.push([event, listener]);
art.on(event, listener);
}
function destroy() {
if (!active)
return;
active = false;
const failures = [];
for (const [event, listener] of subscriptions.splice(0)) {
try {
art.off(event, listener);
} catch (error) {
failures.push(error);
}
}
if (newOption.offset !== void 0) {
offset = newOption.offset;
}
if (newOption.sync !== void 0) {
sync = newOption.sync;
try {
track.destroy();
} catch (error) {
failures.push(error);
}
if (failures.length)
throw failures[0];
}
try {
listen("play", () => {
syncAudio();
track.play();
});
for (const event of ["pause", "video:pause", "video:ended", "video:waiting", "video:emptied", "video:seeking"])
listen(event, track.pause);
listen("seek", syncAudio);
listen("video:seeked", () => {
syncAudio();
if (canResumeAudio())
track.play();
});
listen("video:timeupdate", () => {
if (art.playing)
syncAudio();
});
listen("video:ratechange", () => {
audio.playbackRate = art.video.playbackRate;
});
listen("video:volumechange", () => {
audio.volume = art.volume;
audio.muted = art.muted;
});
listen("video:playing", () => {
if (canResumeAudio()) {
syncAudio();
track.play();
}
});
listen("video:canplay", () => {
if (audio.paused && canResumeAudio()) {
syncAudio();
track.play();
}
});
listen("destroy", destroy);
audio.volume = art.volume;
audio.muted = art.muted;
audio.playbackRate = art.video?.playbackRate || 1;
} catch (error) {
try {
destroy();
} catch {
}
throw error;
}
audio.volume = art.volume;
audio.muted = art.muted;
audio.playbackRate = art.video?.playbackRate || 1;
return {
name: "artplayerPluginAudioTrack",
audio,
update
update(newOption) {
if (active)
track.update(newOption, art.playing);
}
};
};
}
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-auto-thumbnail.js v1.1.0
* artplayer-plugin-auto-thumbnail.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerPluginAutoThumbnail=t(),define(function(){return t.artplayerPluginAutoThumbnail})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAutoThumbnail=t()}(this,function(){"use strict";return function(e){return async t=>(t.on("video:loadedmetadata",()=>{const n=e.url||t.option.url,o=e.width||160,i=e.number||100,u=e.scale||1;!function({url:e,width:t,number:n},o){const i=document.createElement("video");i.crossOrigin="anonymous",i.src=e,i.onloadedmetadata=()=>{const e=i.duration,u=document.createElement("canvas"),a=u.getContext("2d"),l=Math.floor(t*i.videoHeight/i.videoWidth);u.width=10*t,u.height=l*Math.ceil(n/10);let r=null;!function d(c){u.toBlob(e=>{URL.revokeObjectURL(r),r=URL.createObjectURL(e),o({url:r,height:l})},"image/jpeg"),c>=n||(i.currentTime=e*c/n,i.onseeked=()=>{a.drawImage(i,c%10*t,Math.floor(c/10)*l,t,l),d(c+1)})}(0)}}({url:n,width:o,number:i},e=>{t.thumbnails={...e,column:10,number:i,width:o,scale:u}})}),{name:"artplayerPluginAutoThumbnail"})}});
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAutoThumbnail=t(),define(function(){return e.artplayerPluginAutoThumbnail})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAutoThumbnail=t()}(this,function(){"use strict";function e(e){let t,n=!1;for(const r of e)try{r()}catch(i){n||(n=!0,t=i)}return{failed:n,failure:t}}function t(t,n){const i="function"===typeof n.requestVideoFrameCallback&&"function"===typeof n.cancelVideoFrameCallback;let r;function o(){const t=r;r=void 0;const i=e([()=>{n.onloadeddata=null},()=>{n.onseeked=null},()=>{t&&null!==t.timer&&clearTimeout(t.timer)},()=>{t&&null!==t.frame&&n.cancelVideoFrameCallback(t.frame)}]);if(i.failed)throw i.failure}return t.own(o),(e,a)=>{if(o(),!t.active())return;const u={frame:null,timer:null,sought:!1,presented:!i,retries:0,sequence:0,started:!1};r=u;const d=()=>t.active()&&r===u,l=t.guard(()=>{d()&&u.sought&&u.presented&&(o(),t.active()&&a())}),c=()=>{u.sought=!1,(()=>{if(!i)return;const e=++u.sequence;u.presented=!1;const r=u.frame;if(u.frame=null,null!==r&&n.cancelVideoFrameCallback(r),!d())return;let o=!1;const a=n.requestVideoFrameCallback(t.guard(()=>{d()&&e===u.sequence&&!o&&(o=!0,u.frame=null,u.presented=!0,l())}));d()&&e===u.sequence&&!o?u.frame=a:n.cancelVideoFrameCallback(a)})(),d()&&(n.currentTime=e)},s=t.guard(()=>{d()&&!u.started&&(u.started=!0,n.onloadeddata=null,n.onseeked=t.guard(()=>{if(!d()||n.seeking)return;const t=n.currentTime;if(d())if(!Number.isFinite(t)||Math.abs(t-e)>.05){if(++u.retries>3)throw new Error("Auto-thumbnail seek did not reach the requested time");c()}else u.sought=!0,l()}),c())});if(u.timer=setTimeout(t.guard(()=>{if(d())throw new Error("Auto-thumbnail frame readiness timed out")}),3e4),!d())return void clearTimeout(u.timer);const f=!i||n.readyState>=2;d()&&(f?s():n.onloadeddata=s)}}function n(e,n){const i=function(e){const t=document.createElement("video");e.own(()=>t.remove()),e.own(()=>t.load()),e.own(()=>t.removeAttribute("src")),e.own(()=>t.pause());for(const n of["onloadedmetadata","onloadeddata","onseeked","onerror"])e.own(()=>{t[n]=null});return e.active()?(t.crossOrigin="anonymous",t.muted=!0,t.playsInline=!0,t.tabIndex=-1,t.setAttribute("aria-hidden","true"),t.style.cssText="position:fixed;left:0;top:0;visibility:hidden;pointer-events:none;display:block;width:auto;height:auto;max-width:none;max-height:none",document.documentElement.appendChild(t),e.active()||t.remove(),t):t}(e);if(!e.active())return;let r=null;const o=()=>{const e=r;r=null,null!==e&&clearTimeout(e)};e.own(o),i.onerror=e.guard(()=>{throw i.error||new Error("Auto-thumbnail media failed to load")}),i.onloadedmetadata=e.guard(()=>{o(),i.onloadedmetadata=null;const r=i.duration,a=i.videoHeight,u=i.videoWidth,{height:d,canvasWidth:l,canvasHeight:c}=function(e,t){if(!Number.isFinite(t.duration)||t.duration<=0||!Number.isFinite(t.videoWidth)||t.videoWidth<=0||!Number.isFinite(t.videoHeight)||t.videoHeight<=0)throw new TypeError("Auto-thumbnail requires finite media duration and dimensions");const n=Math.floor(e.width*t.videoHeight/t.videoWidth),i=Math.trunc(10*e.width),r=Math.trunc(n*Math.ceil(e.number/10));if(![n,i,r].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:n,canvasWidth:i,canvasHeight:r}}(n,{duration:r,videoHeight:a,videoWidth:u});if(!e.active())return;i.width=u,i.height=a,i.style.width=`${u}px`,i.style.height=`${a}px`;const s=document.createElement("canvas");if(e.own(()=>{s.height=0}),e.own(()=>{s.width=0}),!e.active())return;if(s.width=l,!e.active())return;if(s.height=c,!e.active())return;const f=s.getContext("2d");if(!f)throw new Error("Auto-thumbnail canvas context is unavailable");if(!e.active())return;const m=t(e,i),h=function(e,t){let n;function i(){const e=n;n=void 0,e&&null!==e.timer&&clearTimeout(e.timer)}return e.own(i),r=>{if(!e.active())return;if(n)throw new Error("Auto-thumbnail encoding is already pending");const o={timer:null};n=o;const a=()=>e.active()&&n===o;o.timer=setTimeout(e.guard(()=>{if(a())throw new Error("Auto-thumbnail encoding timed out")}),3e4),a()?t.toBlob(e.guard(t=>{a()&&(i(),e.active()&&r(t))}),"image/jpeg"):clearTimeout(o.timer)}}(e,s);let v=0;const b=e.guard(()=>{v>=n.number?e.dispose():m(r*v/n.number,e.guard(()=>{f.drawImage(i,v%10*n.width,Math.floor(v/10)*d,n.width,d),e.active()&&h(t=>{e.publish(t,{height:d,column:10,number:n.number,width:n.width,scale:n.scale}),e.active()&&(v+=1,b())})}))});b()}),e.active()&&(r=setTimeout(e.guard(()=>{if(null!==r)throw new Error("Auto-thumbnail metadata timed out")}),3e4),e.active()?i.src=n.url:o())}function i(t){return async i=>{if(i.isDestroy)return{name:"artplayerPluginAutoThumbnail"};const r=e=>console.warn("ArtPlayer auto-thumbnail failed:",e),o=function(t,n){let i,r,o=!1;const a=new Set;function u(e){void 0!==e&&a.delete(e)&&URL.revokeObjectURL(e)}functiLine truncated
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-auto-thumbnail.js v1.1.0
* artplayer-plugin-auto-thumbnail.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerPluginAutoThumbnail=t(),define(function(){return t.artplayerPluginAutoThumbnail})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAutoThumbnail=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.defineProperties,n=Object.getOwnPropertyDescriptors,r=Object.getOwnPropertySymbols,o=Object.prototype.hasOwnProperty,a=Object.prototype.propertyIsEnumerable,i=(t,n,r)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[n]=r;return function(e){return l=>{return u=null,c=null,d=function*(){return l.on("video:loadedmetadata",()=>{const u=e.url||l.option.url,c=e.width||160,d=e.number||100,s=e.scale||1;!function({url:e,width:t,number:n},r){const o=document.createElement("video");o.crossOrigin="anonymous",o.src=e,o.onloadedmetadata=()=>{const e=o.duration,a=document.createElement("canvas"),i=a.getContext("2d"),l=Math.floor(t*o.videoHeight/o.videoWidth);a.width=10*t,a.height=l*Math.ceil(n/10);let u=null;!function c(d){a.toBlob(e=>{URL.revokeObjectURL(u),u=URL.createObjectURL(e),r({url:u,height:l})},"image/jpeg"),d>=n||(o.currentTime=e*d/n,o.onseeked=()=>{i.drawImage(o,d%10*t,Math.floor(d/10)*l,t,l),c(d+1)})}(0)}}({url:u,width:c,number:d},e=>{var u;l.thumbnails=(u=((e,t)=>{for(var n in t||(t={}))o.call(t,n)&&i(e,n,t[n]);if(r)for(var n of r(t))a.call(t,n)&&i(e,n,t[n]);return e})({},e),t(u,n({column:10,number:d,width:c,scale:s})))})}),{name:"artplayerPluginAutoThumbnail"}},new Promise((e,t)=>{var n=e=>{try{o(d.next(e))}catch(n){t(n)}},r=e=>{try{o(d.throw(e))}catch(n){t(n)}},o=t=>t.done?e(t.value):Promise.resolve(t.value).then(n,r);o((d=d.apply(u,c)).next())});var u,c,d}}});
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAutoThumbnail=t(),define(function(){return e.artplayerPluginAutoThumbnail})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAutoThumbnail=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable,i=(t,n,r)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[n]=r;function o(e){let t,n=!1;for(const i of e)try{i()}catch(r){n||(n=!0,t=r)}return{failed:n,failure:t}}function a(e,a){let u,l,d=!1;const c=new Set;function s(e){void 0!==e&&c.delete(e)&&URL.revokeObjectURL(e)}function f(){const e=u;u=void 0,null==e||e.dispose()}return{start:function(){if(d)return;const f=u,m=[];let h=!1;const v={active:()=>!d&&!h&&u===v,own(e){if(h){const t=o([e]);t.failed&&a(t.failure)}else m.push(e)},dispose(){if(h)return;h=!0,u===v&&(u=void 0);const e=o(m.splice(0).reverse());e.failed&&a(e.failure)},fail(e){v.active()&&(v.dispose(),a(e))},guard:e=>(...t)=>{if(v.active())try{return e(...t)}catch(n){v.fail(n)}},publish(u,d){if(!v.active())return;if(!u)throw new Error("Auto-thumbnail encoding returned no Blob");const f=URL.createObjectURL(u);if(c.add(f),!v.active())return void s(f);const m=l;l=f;try{e(((e,o)=>{for(var a in o||(o={}))n.call(o,a)&&i(e,a,o[a]);if(t)for(var a of t(o))r.call(o,a)&&i(e,a,o[a]);return e})({url:f},d))}catch(h){l===f&&(l=void 0!==m&&c.has(m)?m:void 0);const e=o([()=>s(f)]);throw e.failed&&a(e.failure),h}s(m)}};return u=v,null==f||f.dispose(),v},cancel:f,destroy:function(){if(d)return;d=!0;const e=o([f,...[...c].map(e=>()=>s(e))]);l=void 0,e.failed&&a(e.failure)},get closed(){return d}}}function u(e,t){const n="function"===typeof t.requestVideoFrameCallback&&"function"===typeof t.cancelVideoFrameCallback;let r;function i(){const e=r;r=void 0;const n=o([()=>{t.onloadeddata=null},()=>{t.onseeked=null},()=>{e&&null!==e.timer&&clearTimeout(e.timer)},()=>{e&&null!==e.frame&&t.cancelVideoFrameCallback(e.frame)}]);if(n.failed)throw n.failure}return e.own(i),(o,a)=>{if(i(),!e.active())return;const u={frame:null,timer:null,sought:!1,presented:!n,retries:0,sequence:0,started:!1};r=u;const l=()=>e.active()&&r===u,d=e.guard(()=>{l()&&u.sought&&u.presented&&(i(),e.active()&&a())}),c=()=>{u.sought=!1,(()=>{if(!n)return;const r=++u.sequence;u.presented=!1;const i=u.frame;if(u.frame=null,null!==i&&t.cancelVideoFrameCallback(i),!l())return;let o=!1;const a=t.requestVideoFrameCallback(e.guard(()=>{l()&&r===u.sequence&&!o&&(o=!0,u.frame=null,u.presented=!0,d())}));l()&&r===u.sequence&&!o?u.frame=a:t.cancelVideoFrameCallback(a)})(),l()&&(t.currentTime=o)},s=e.guard(()=>{l()&&!u.started&&(u.started=!0,t.onloadeddata=null,t.onseeked=e.guard(()=>{if(!l()||t.seeking)return;const e=t.currentTime;if(l())if(!Number.isFinite(e)||Math.abs(e-o)>.05){if(++u.retries>3)throw new Error("Auto-thumbnail seek did not reach the requested time");c()}else u.sought=!0,d()}),c())});if(u.timer=setTimeout(e.guard(()=>{if(l())throw new Error("Auto-thumbnail frame readiness timed out")}),3e4),!l())return void clearTimeout(u.timer);const f=!n||t.readyState>=2;l()&&(f?s():t.onloadeddata=s)}}function l(e,t){const n=function(e){const t=document.createElement("video");e.own(()=>t.remove()),e.own(()=>t.load()),e.own(()=>t.removeAttribute("src")),e.own(()=>t.pause());for(const n of["onloadedmetadata","onloadeddata","onseeked","onerror"])e.own(()=>{t[n]=null});return e.active()?(t.crossOrigin="anonymous",t.muted=!0,t.playsInline=!0,t.tabIndex=-1,t.setAttribute("aria-hidden","true"),t.style.cssText="position:fixed;left:0;top:0;visibility:hidden;pointer-events:none;display:block;width:auto;height:auto;max-width:none;max-height:none",document.documentElement.appendChild(t),e.active()||t.remove(),t):t}(e);if(!e.active())return;let r=null;const i=()=>{const e=r;r=null,null!==e&&clearTimeout(e)};e.own(i),n.onerror=e.guard(()=>{throw n.error||new Error("Auto-thumbnail media failed to load")}),n.onloadedmetadata=e.guard(()=>{i(),n.onloadedmetadata=null;const r=n.duration,o=n.videoHeight,a=n.videoWidth,{height:l,canvasWidth:d,canvasHeight:c}=function(e,t){if(!Number.isFinite(t.duration)||t.duration<=0||!Number.isFinite(t.videoWidth)||t.videoWidth<=0||!Number.isFinite(t.videoHeight)||t.videoHeight<=0)throw new TypeError("Auto-thumbnail requires finite media duration and dimensions");const n=Math.floor(e.width*t.videoHeight/t.videoWidth),r=Math.trunc(10*e.width),i=Math.trunc(n*Math.ceil(e.number/10));if(![n,r,i].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:n,canvasWidth:r,canvasHeight:i}}(t,{duration:r,videoHeight:o,videoWidth:a});if(!e.active())return;n.width=a,n.height=o,n.style.width=`${a}px`,n.style.height=`${o}px`;const s=document.createElement("canvas");if(e.own(()=>{s.height=0}),e.own(()=Line truncated
+432 -47
View File
@@ -1,63 +1,448 @@
/*!
* artplayer-plugin-auto-thumbnail.js v1.1.0
* artplayer-plugin-auto-thumbnail.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
function create({ url, width, number }, callback) {
const video = document.createElement("video");
video.crossOrigin = "anonymous";
video.src = url;
video.onloadedmetadata = () => {
const duration = video.duration;
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
const height = Math.floor(width * video.videoHeight / video.videoWidth);
canvas.width = width * 10;
canvas.height = height * Math.ceil(number / 10);
let blobUrl = null;
function seekAndDraw(index) {
canvas.toBlob((blob) => {
URL.revokeObjectURL(blobUrl);
blobUrl = URL.createObjectURL(blob);
callback({
url: blobUrl,
height
});
}, "image/jpeg");
if (index >= number)
return;
video.currentTime = duration * index / number;
video.onseeked = () => {
ctx.drawImage(video, index % 10 * width, Math.floor(index / 10) * height, width, height);
seekAndDraw(index + 1);
};
function createEncoder(job, canvas) {
let pending;
function clear() {
const previous = pending;
pending = void 0;
if (previous && previous.timer !== null)
clearTimeout(previous.timer);
}
job.own(clear);
return (publish) => {
if (!job.active())
return;
if (pending)
throw new Error("Auto-thumbnail encoding is already pending");
const current = { timer: null };
pending = current;
const active = () => job.active() && pending === current;
current.timer = setTimeout(job.guard(() => {
if (active())
throw new Error("Auto-thumbnail encoding timed out");
}), 3e4);
if (!active()) {
clearTimeout(current.timer);
return;
}
seekAndDraw(0);
canvas.toBlob(job.guard((blob) => {
if (!active())
return;
clear();
if (job.active())
publish(blob);
}), "image/jpeg");
};
}
function cleanupAll(actions) {
let failure;
let failed = false;
for (const action of actions) {
try {
action();
} catch (error) {
if (!failed) {
failed = true;
failure = error;
}
}
}
return { failed, failure };
}
function createSession(publish, report) {
let closed = false;
let current;
let lastUrl;
const urls = /* @__PURE__ */ new Set();
function release(url) {
if (url !== void 0 && urls.delete(url))
URL.revokeObjectURL(url);
}
function cancel() {
const previous = current;
current = void 0;
previous?.dispose();
}
function destroy() {
if (closed)
return;
closed = true;
const result = cleanupAll([cancel, ...[...urls].map((url) => () => release(url))]);
lastUrl = void 0;
if (result.failed)
report(result.failure);
}
function start() {
if (closed)
return;
const previous = current;
const actions = [];
let disposed = false;
const job = {
active: () => !closed && !disposed && current === job,
own(action) {
if (disposed) {
const result = cleanupAll([action]);
if (result.failed)
report(result.failure);
} else {
actions.push(action);
}
},
dispose() {
if (disposed)
return;
disposed = true;
if (current === job)
current = void 0;
const result = cleanupAll(actions.splice(0).reverse());
if (result.failed)
report(result.failure);
},
fail(error) {
if (!job.active())
return;
job.dispose();
report(error);
},
guard(callback) {
return (...args) => {
if (!job.active())
return;
try {
return callback(...args);
} catch (error) {
job.fail(error);
}
};
},
publish(blob, config) {
if (!job.active())
return;
if (!blob)
throw new Error("Auto-thumbnail encoding returned no Blob");
const url = URL.createObjectURL(blob);
urls.add(url);
if (!job.active()) {
release(url);
return;
}
const previousUrl = lastUrl;
lastUrl = url;
try {
publish({ url, ...config });
} catch (error) {
if (lastUrl === url)
lastUrl = previousUrl !== void 0 && urls.has(previousUrl) ? previousUrl : void 0;
const result = cleanupAll([() => release(url)]);
if (result.failed)
report(result.failure);
throw error;
}
release(previousUrl);
}
};
current = job;
previous?.dispose();
return job;
}
return {
start,
cancel,
destroy,
get closed() {
return closed;
}
};
}
function createFrameReader(job, video) {
const presentedFrames = typeof video.requestVideoFrameCallback === "function" && typeof video.cancelVideoFrameCallback === "function";
let pending;
function clear() {
const previous = pending;
pending = void 0;
const result = cleanupAll([
() => {
video.onloadeddata = null;
},
() => {
video.onseeked = null;
},
() => {
if (previous && previous.timer !== null)
clearTimeout(previous.timer);
},
() => {
if (previous && previous.frame !== null)
video.cancelVideoFrameCallback(previous.frame);
}
]);
if (result.failed)
throw result.failure;
}
job.own(clear);
return (target, draw) => {
clear();
if (!job.active())
return;
const current = { frame: null, timer: null, sought: false, presented: !presentedFrames, retries: 0, sequence: 0, started: false };
pending = current;
const active = () => job.active() && pending === current;
const finish = job.guard(() => {
if (!active() || !current.sought || !current.presented)
return;
clear();
if (job.active())
draw();
});
const requestFrame = () => {
if (!presentedFrames)
return;
const sequence = ++current.sequence;
current.presented = false;
const previous = current.frame;
current.frame = null;
if (previous !== null)
video.cancelVideoFrameCallback(previous);
if (!active())
return;
let delivered = false;
const id = video.requestVideoFrameCallback(job.guard(() => {
if (!active() || sequence !== current.sequence || delivered)
return;
delivered = true;
current.frame = null;
current.presented = true;
finish();
}));
if (active() && sequence === current.sequence && !delivered)
current.frame = id;
else
video.cancelVideoFrameCallback(id);
};
const seek = () => {
current.sought = false;
requestFrame();
if (active())
video.currentTime = target;
};
const begin = job.guard(() => {
if (!active() || current.started)
return;
current.started = true;
video.onloadeddata = null;
video.onseeked = job.guard(() => {
if (!active() || video.seeking)
return;
const time = video.currentTime;
if (!active())
return;
if (!Number.isFinite(time) || Math.abs(time - target) > 0.05) {
if (++current.retries > 3)
throw new Error("Auto-thumbnail seek did not reach the requested time");
seek();
return;
}
current.sought = true;
finish();
});
seek();
});
current.timer = setTimeout(job.guard(() => {
if (active())
throw new Error("Auto-thumbnail frame readiness timed out");
}), 3e4);
if (!active()) {
clearTimeout(current.timer);
return;
}
const ready = !presentedFrames || video.readyState >= 2;
if (!active())
return;
if (!ready)
video.onloadeddata = begin;
else
begin();
};
}
function readOptions(option, getFallbackUrl) {
const config = {
url: option.url || getFallbackUrl(),
width: option.width || 160,
number: option.number || 100,
scale: option.scale || 1
};
if (!Number.isFinite(Number(config.width)) || config.width <= 0 || !Number.isFinite(Number(config.number)) || config.number <= 0)
throw new TypeError("Auto-thumbnail width and number must be finite positive numbers");
return config;
}
function sheetSize(config, video) {
if (!Number.isFinite(video.duration) || video.duration <= 0 || !Number.isFinite(video.videoWidth) || video.videoWidth <= 0 || !Number.isFinite(video.videoHeight) || video.videoHeight <= 0)
throw new TypeError("Auto-thumbnail requires finite media duration and dimensions");
const height = Math.floor(config.width * video.videoHeight / video.videoWidth);
const canvasWidth = Math.trunc(config.width * 10);
const canvasHeight = Math.trunc(height * Math.ceil(config.number / 10));
if (![height, canvasWidth, canvasHeight].every((value) => Number.isSafeInteger(value) && value > 0 && value <= 4294967295))
throw new RangeError("Auto-thumbnail canvas dimensions are invalid");
return { height, canvasWidth, canvasHeight };
}
function createVideo(job) {
const video = document.createElement("video");
job.own(() => video.remove());
job.own(() => video.load());
job.own(() => video.removeAttribute("src"));
job.own(() => video.pause());
for (const property of ["onloadedmetadata", "onloadeddata", "onseeked", "onerror"])
job.own(() => {
video[property] = null;
});
if (!job.active())
return video;
video.crossOrigin = "anonymous";
video.muted = true;
video.playsInline = true;
video.tabIndex = -1;
video.setAttribute("aria-hidden", "true");
video.style.cssText = "position:fixed;left:0;top:0;visibility:hidden;pointer-events:none;display:block;width:auto;height:auto;max-width:none;max-height:none";
document.documentElement.appendChild(video);
if (!job.active())
video.remove();
return video;
}
function extract(job, config) {
const video = createVideo(job);
if (!job.active())
return;
let metadataTimer = null;
const clearMetadataTimer = () => {
const previous = metadataTimer;
metadataTimer = null;
if (previous !== null)
clearTimeout(previous);
};
job.own(clearMetadataTimer);
video.onerror = job.guard(() => {
throw video.error || new Error("Auto-thumbnail media failed to load");
});
video.onloadedmetadata = job.guard(() => {
clearMetadataTimer();
video.onloadedmetadata = null;
const duration = video.duration;
const videoHeight = video.videoHeight;
const videoWidth = video.videoWidth;
const { height, canvasWidth, canvasHeight } = sheetSize(config, {
duration,
videoHeight,
videoWidth
});
if (!job.active())
return;
video.width = videoWidth;
video.height = videoHeight;
video.style.width = `${videoWidth}px`;
video.style.height = `${videoHeight}px`;
const canvas = document.createElement("canvas");
job.own(() => {
canvas.height = 0;
});
job.own(() => {
canvas.width = 0;
});
if (!job.active())
return;
canvas.width = canvasWidth;
if (!job.active())
return;
canvas.height = canvasHeight;
if (!job.active())
return;
const ctx = canvas.getContext("2d");
if (!ctx)
throw new Error("Auto-thumbnail canvas context is unavailable");
if (!job.active())
return;
const readFrame = createFrameReader(job, video);
const encode = createEncoder(job, canvas);
let index = 0;
const seek = job.guard(() => {
if (index >= config.number) {
job.dispose();
return;
}
readFrame(duration * index / config.number, job.guard(() => {
ctx.drawImage(video, index % 10 * config.width, Math.floor(index / 10) * height, config.width, height);
if (!job.active())
return;
encode((blob) => {
job.publish(blob, { height, column: 10, number: config.number, width: config.width, scale: config.scale });
if (job.active()) {
index += 1;
seek();
}
});
}));
});
seek();
});
if (!job.active())
return;
metadataTimer = setTimeout(job.guard(() => {
if (metadataTimer !== null)
throw new Error("Auto-thumbnail metadata timed out");
}), 3e4);
if (!job.active()) {
clearMetadataTimer();
return;
}
video.src = config.url;
}
function artplayerPluginAutoThumbnail(option) {
return async (art) => {
art.on("video:loadedmetadata", () => {
const url = option.url || art.option.url;
const width = option.width || 160;
const number = option.number || 100;
const scale = option.scale || 1;
create({ url, width, number }, (config) => {
art.thumbnails = {
...config,
column: 10,
number,
width,
scale
};
});
});
return {
name: "artplayerPluginAutoThumbnail"
if (art.isDestroy)
return { name: "artplayerPluginAutoThumbnail" };
const report = (error) => console.warn("ArtPlayer auto-thumbnail failed:", error);
const session = createSession((config) => {
art.thumbnails = config;
}, report);
const subscriptions = [];
const onMetadata = () => {
const job = session.start();
if (job) {
job.guard(() => {
const config = readOptions(option, () => art.option.url);
if (job.active())
extract(job, config);
})();
}
};
const onDestroy = () => {
const actions = subscriptions.splice(0);
const result = cleanupAll([session.destroy, ...actions]);
if (result.failed)
report(result.failure);
};
try {
const events = [["destroy", onDestroy], ["restart", session.cancel], ["video:loadedmetadata", onMetadata]];
for (const [name, callback] of events) {
if (session.closed)
break;
subscriptions.push(() => art.off(name, callback));
art.on(name, callback);
if (session.closed)
art.off(name, callback);
}
} catch (error) {
onDestroy();
throw error;
}
return { name: "artplayerPluginAutoThumbnail" };
};
}
artplayerPluginAutoThumbnail.default = artplayerPluginAutoThumbnail;
export {
artplayerPluginAutoThumbnail as default
};
+2 -2
View File
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-chapter.js v1.1.0
* artplayer-plugin-chapter.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginChapter=e(),define(function(){return t.artplayerPluginChapter})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginChapter=e()}(this,function(){"use strict";if("undefined"!==typeof document){const t="artplayer-plugin-chapter";let e=document.getElementById(t);e||(e=document.createElement("style"),e.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(e)}):(document.head||document.documentElement).appendChild(e)),e.textContent=".artplayer-plugin-chapter .art-control-progress-inner{height:100%!important;background-color:transparent!important}.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-hover,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-loaded,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-played{display:none!important}.artplayer-plugin-chapter .art-control-thumbnails{bottom:calc(var(--art-bottom-gap) + 64px)!important}.artplayer-plugin-chapter .art-chapters{position:absolute;z-index:0;inset:0;display:flex;align-items:center;gap:4px;height:100%;transform:scaleY(1.25)}.artplayer-plugin-chapter .art-chapters .art-chapter{display:flex;align-items:center;height:100%}.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner{position:relative;cursor:pointer;width:100%;height:50%;border-radius:10px;overflow:hidden;transition:height var(--art-transition-duration) ease;background-color:var(--art-progress-color)}.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner{height:100%}.artplayer-plugin-chapter .art-chapter-title{transform-origin:bottom center;transform:scale(.5);opacity:0;position:absolute;z-index:70;top:-50px;left:0;padding:3px 5px;line-height:1;font-size:14px;border-radius:var(--art-border-radius);white-space:nowrap;background-color:var(--art-tip-background);transition:transform var(--art-transition-duration) ease,opacity var(--art-transition-duration) ease}.artplayer-plugin-chapter.art-progress-hover .art-chapter-title{transform:scale(1);opacity:1}"}return function(t={}){return e=>{const{$player:r}=e.template,{setStyle:a,append:n,clamp:o,query:i,addClass:p,removeClass:s}=e.constructor.utils;let d=[];const l=e.query(".art-control-progress-inner"),c=n(l,'<div class="art-chapters"></div>'),h=n(l,'<div class="art-chapter-title"></div>');function u({$chapter:t,width:e}){const r=t.dataset.title.trim();if(r){h.textContent=r;const t=h.clientWidth;e<=t/2?a(h,"left",0):e>l.clientWidth-t/2?a(h,"left",l.clientWidth-t+"px"):a(h,"left",e-t/2+"px")}}function g(t=[]){if(d=[],c.textContent="",s(r,"artplayer-plugin-chapter"),Array.isArray(t)&&t.length&&e.duration){t=t.sort((t,e)=>t.start-e.start);for(let r=0;r<t.length;r++){const a=t[r],n=t[r+1];if(a.end===1/0&&(a.end=e.duration),"number"!==typeof a.start||"number"!==typeof a.end||"string"!==typeof a.title)throw new TypeError("Illegal chapter data type");if(a.start<0||a.end>e.duration||a.start>=a.end)throw new Error("Illegal chapter time point");if(n&&a.end>n.start)throw new Error("Illegal chapter time point")}t[0].start>0&&t.unshift({start:0,end:t[0].start,title:""}),t[t.length-1].end<e.duration&&t.push({start:t[t.length-1].end,end:e.duration,title:""});for(let e=0;e<t.length-1;e++)t[e].end!==t[e+1].start&&t.splice(e+1,0,{start:t[e].end,end:t[e+1].start,title:""});d=t.map(t=>{const r=n(c,'\n <div class="art-chapter">\n <div class="art-chapter-inner">\n <div class="art-progress-hover"></div>\n <div class="art-progress-loaded"></div>\n <div class="art-progress-played"></div>\n </div>\n </div>\n '),a=o(t.start,0,e.duration),p=o(t.end,0,e.duration),s=p-a,d=s/e.duration;return r.dataset.start=a,r.dataset.end=p,r.dataset.duration=s,r.dataset.title=t.title.trim(),r.style.width=100*d+"%",{$chapter:r,$hover:i(".art-progress-hover",r),$loaded:i(".art-progress-loaded",r),$played:i(".art-progress-played",r)}}),p(r,"artplayer-plugin-chapter"),e.emit("setBar","loaded",e.loaded||0)}}return e.on("setBar",(t,r)=>{if(d.length)for(let n=0;n<d.length;n++){const{$chapter:o,$loaded:i,$played:p,$hover:s}=d[n],l={hover:s,loaded:i,played:p}[t];if(!l)return;const h=c.clientWidth*r,g=e.duration*r,y=Number.parseFloat(o.dataset.duration),f=Number.parseFloat(o.dataset.start),m=Number.parseFloat(o.dataset.end);if(g<f&&a(l,"width",0),g>m&&a(l,"width","100%"),g>=f&&g<=m){a(l,"width",100*((g-f)/y)+"%"),"hover"===t&&h>0&&u({$chapter:o,width:h})}}}),e.once("video:loadedmetadata",()=>g(t.chapters)),{name:"artplayerPluginChapter",update:({chapters:t})=>g(t)}}}});
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginChapter=e(),define(function(){return t.artplayerPluginChapter})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginChapter=e()}(this,function(){"use strict";return function(){if("undefined"===typeof document)return;const t="artplayer-plugin-chapter",e=()=>{let e=document.getElementById(t);e||(e=document.createElement("style"),e.id=t,(document.head||document.documentElement).appendChild(e)),e.textContent=".artplayer-plugin-chapter .art-control-progress-inner{height:100%!important;background-color:transparent!important}.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-hover,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-loaded,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-played{display:none!important}.artplayer-plugin-chapter .art-control-thumbnails{bottom:calc(var(--art-bottom-gap) + 64px)!important}.artplayer-plugin-chapter .art-chapters{position:absolute;z-index:0;inset:0;display:flex;align-items:center;gap:4px;height:100%;transform:scaleY(1.25)}.artplayer-plugin-chapter .art-chapters .art-chapter{display:flex;align-items:center;height:100%}.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner{position:relative;cursor:pointer;width:100%;height:50%;border-radius:10px;overflow:hidden;transition:height var(--art-transition-duration) ease;background-color:var(--art-progress-color)}.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner{height:100%}.artplayer-plugin-chapter .art-chapter-title{transform-origin:bottom center;transform:scale(.5);opacity:0;position:absolute;z-index:70;top:-50px;left:0;padding:3px 5px;line-height:1;font-size:14px;border-radius:var(--art-border-radius);white-space:nowrap;box-sizing:border-box;max-width:100%;overflow:hidden;text-overflow:ellipsis;background-color:var(--art-tip-background);transition:transform var(--art-transition-duration) ease,opacity var(--art-transition-duration) ease}.artplayer-plugin-chapter.art-progress-hover .art-chapter-title{transform:scale(1);opacity:1}"};document.getElementById(t)||"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e,{once:!0})}(),function(t={}){return e=>{const r=e.template.$player,a=e.query(".art-control-progress-inner");if(!a)throw new Error("Missing ArtPlayer progress container");const n="artplayer-plugin-chapter";let o=function(t){const e=(e,r)=>{const a=t.ownerDocument.createElement("div");return a.className=r,e.appendChild(a),a},r=e(t,"art-chapters"),a=e(t,"art-chapter-title");let n=[];function o(){a.textContent="",a.style.left="0px",a.style.visibility="hidden"}function i(){n=[],r.textContent="",o()}return o(),{clear:i,render:function(t,a){n=t.map(t=>{const n=e(r,"art-chapter"),o=e(n,"art-chapter-inner"),i=t.end-t.start;return n.dataset.start=String(t.start),n.dataset.end=String(t.end),n.dataset.duration=String(i),n.dataset.title=t.title.trim(),n.style.width=i/a*100+"%",{start:t.start,end:t.end,title:t.title.trim(),bars:{hover:e(o,"art-progress-hover"),loaded:e(o,"art-progress-loaded"),played:e(o,"art-progress-played")}}})},setBar:function(e,i,s){if("hover"!==e&&"loaded"!==e&&"played"!==e)return;if(!Number.isFinite(i))return;const l=s*i;let d;for(const t of n)t.bars[e].style.width=l<t.start?"0px":l>t.end?"100%":(l-t.start)/(t.end-t.start)*100+"%",l>=t.start&&l<=t.end&&(d=t);if("hover"!==e)return;o();const p=r.clientWidth*i;d?.title&&p>0&&(a.textContent=d.title,a.style.visibility="visible",a.style.left=`${Math.max(0,Math.min(p-a.clientWidth/2,t.clientWidth-a.clientWidth))}px`)},destroy:function(){i(),r.remove(),a.remove()}}}(a);function i(t){if(!o||e.isDestroy)return;o.clear(),r.classList.remove(n);const a=function(t=[],e){if(!Array.isArray(t)||!t.length||!Number.isFinite(e)||e<=0)return[];t.sort((t,e)=>t.start-e.start);for(const[n,o]of t.entries()){if(!o||"number"!==typeof o.start||"number"!==typeof o.end||"string"!==typeof o.title)throw new TypeError("Illegal chapter data type");o.end===1/0&&(o.end=e);const r=t[n+1];if(!Number.isFinite(o.start)||!Number.isFinite(o.end)||o.start<0||o.end>e||o.start>=o.end||r&&o.end>r.start)throw new Error("Illegal chapter time point")}const r=t[0],a=t[t.length-1];r&&r.start>0&&t.unshift({start:0,end:r.start,title:""}),a&&a.end<e&&t.push({start:a.end,end:e,title:""});for(let n=0;n<t.length-1;n++){const e=t[n],r=t[n+1];e&&r&&e.end!==r.start&&t.splice(n+1,0,{start:e.end,end:r.start,title:""})}return t}(t,e.duration);a.length&&(o.render(a,e.duration),r.classList.add(n),e.emit("setBar","loaded",e.loaded||0))}function s(t,r){e.isDestroy||o?.setBar(t,r,e.duration)}function l(){i(t.chapters)}return e.on("setBar",s),e.once("video:loadedmetadata",l),e.on("destroy",function t(){e.off("setBar",s),e.off("video:loadedmetadata",l),e.off("destroy",t),o?.destroy(),o=void 0,r.classList.remove(n)}),{name:"artplayerPluginChapteLine truncated
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-chapter.js v1.1.0
* artplayer-plugin-chapter.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginChapter=e(),define(function(){return t.artplayerPluginChapter})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginChapter=e()}(this,function(){"use strict";if("undefined"!==typeof document){const t="artplayer-plugin-chapter";let e=document.getElementById(t);e||(e=document.createElement("style"),e.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(e)}):(document.head||document.documentElement).appendChild(e)),e.textContent=".artplayer-plugin-chapter .art-control-progress-inner{height:100%!important;background-color:transparent!important}.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-hover,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-loaded,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-played{display:none!important}.artplayer-plugin-chapter .art-control-thumbnails{bottom:calc(var(--art-bottom-gap) + 64px)!important}.artplayer-plugin-chapter .art-chapters{position:absolute;z-index:0;inset:0;display:flex;align-items:center;gap:4px;height:100%;transform:scaleY(1.25)}.artplayer-plugin-chapter .art-chapters .art-chapter{display:flex;align-items:center;height:100%}.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner{position:relative;cursor:pointer;width:100%;height:50%;border-radius:10px;overflow:hidden;transition:height var(--art-transition-duration) ease;background-color:var(--art-progress-color)}.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner{height:100%}.artplayer-plugin-chapter .art-chapter-title{transform-origin:bottom center;transform:scale(.5);opacity:0;position:absolute;z-index:70;top:-50px;left:0;padding:3px 5px;line-height:1;font-size:14px;border-radius:var(--art-border-radius);white-space:nowrap;background-color:var(--art-tip-background);transition:transform var(--art-transition-duration) ease,opacity var(--art-transition-duration) ease}.artplayer-plugin-chapter.art-progress-hover .art-chapter-title{transform:scale(1);opacity:1}"}return function(t={}){return e=>{const{$player:r}=e.template,{setStyle:a,append:n,clamp:o,query:i,addClass:p,removeClass:s}=e.constructor.utils;let d=[];const l=e.query(".art-control-progress-inner"),c=n(l,'<div class="art-chapters"></div>'),h=n(l,'<div class="art-chapter-title"></div>');function u({$chapter:t,width:e}){const r=t.dataset.title.trim();if(r){h.textContent=r;const t=h.clientWidth;e<=t/2?a(h,"left",0):e>l.clientWidth-t/2?a(h,"left",l.clientWidth-t+"px"):a(h,"left",e-t/2+"px")}}function g(t=[]){if(d=[],c.textContent="",s(r,"artplayer-plugin-chapter"),Array.isArray(t)&&t.length&&e.duration){t=t.sort((t,e)=>t.start-e.start);for(let r=0;r<t.length;r++){const a=t[r],n=t[r+1];if(a.end===1/0&&(a.end=e.duration),"number"!==typeof a.start||"number"!==typeof a.end||"string"!==typeof a.title)throw new TypeError("Illegal chapter data type");if(a.start<0||a.end>e.duration||a.start>=a.end)throw new Error("Illegal chapter time point");if(n&&a.end>n.start)throw new Error("Illegal chapter time point")}t[0].start>0&&t.unshift({start:0,end:t[0].start,title:""}),t[t.length-1].end<e.duration&&t.push({start:t[t.length-1].end,end:e.duration,title:""});for(let e=0;e<t.length-1;e++)t[e].end!==t[e+1].start&&t.splice(e+1,0,{start:t[e].end,end:t[e+1].start,title:""});d=t.map(t=>{const r=n(c,'\n <div class="art-chapter">\n <div class="art-chapter-inner">\n <div class="art-progress-hover"></div>\n <div class="art-progress-loaded"></div>\n <div class="art-progress-played"></div>\n </div>\n </div>\n '),a=o(t.start,0,e.duration),p=o(t.end,0,e.duration),s=p-a,d=s/e.duration;return r.dataset.start=a,r.dataset.end=p,r.dataset.duration=s,r.dataset.title=t.title.trim(),r.style.width=100*d+"%",{$chapter:r,$hover:i(".art-progress-hover",r),$loaded:i(".art-progress-loaded",r),$played:i(".art-progress-played",r)}}),p(r,"artplayer-plugin-chapter"),e.emit("setBar","loaded",e.loaded||0)}}return e.on("setBar",(t,r)=>{if(d.length)for(let n=0;n<d.length;n++){const{$chapter:o,$loaded:i,$played:p,$hover:s}=d[n],l={hover:s,loaded:i,played:p}[t];if(!l)return;const h=c.clientWidth*r,g=e.duration*r,y=Number.parseFloat(o.dataset.duration),f=Number.parseFloat(o.dataset.start),m=Number.parseFloat(o.dataset.end);if(g<f&&a(l,"width",0),g>m&&a(l,"width","100%"),g>=f&&g<=m){a(l,"width",100*((g-f)/y)+"%"),"hover"===t&&h>0&&u({$chapter:o,width:h})}}}),e.once("video:loadedmetadata",()=>g(t.chapters)),{name:"artplayerPluginChapter",update:({chapters:t})=>g(t)}}}});
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginChapter=e(),define(function(){return t.artplayerPluginChapter})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginChapter=e()}(this,function(){"use strict";return function(){if("undefined"===typeof document)return;const t="artplayer-plugin-chapter",e=()=>{let e=document.getElementById(t);e||(e=document.createElement("style"),e.id=t,(document.head||document.documentElement).appendChild(e)),e.textContent=".artplayer-plugin-chapter .art-control-progress-inner{height:100%!important;background-color:transparent!important}.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-hover,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-loaded,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-played{display:none!important}.artplayer-plugin-chapter .art-control-thumbnails{bottom:calc(var(--art-bottom-gap) + 64px)!important}.artplayer-plugin-chapter .art-chapters{position:absolute;z-index:0;inset:0;display:flex;align-items:center;gap:4px;height:100%;transform:scaleY(1.25)}.artplayer-plugin-chapter .art-chapters .art-chapter{display:flex;align-items:center;height:100%}.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner{position:relative;cursor:pointer;width:100%;height:50%;border-radius:10px;overflow:hidden;transition:height var(--art-transition-duration) ease;background-color:var(--art-progress-color)}.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner{height:100%}.artplayer-plugin-chapter .art-chapter-title{transform-origin:bottom center;transform:scale(.5);opacity:0;position:absolute;z-index:70;top:-50px;left:0;padding:3px 5px;line-height:1;font-size:14px;border-radius:var(--art-border-radius);white-space:nowrap;box-sizing:border-box;max-width:100%;overflow:hidden;text-overflow:ellipsis;background-color:var(--art-tip-background);transition:transform var(--art-transition-duration) ease,opacity var(--art-transition-duration) ease}.artplayer-plugin-chapter.art-progress-hover .art-chapter-title{transform:scale(1);opacity:1}"};document.getElementById(t)||"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e,{once:!0})}(),function(t={}){return e=>{const r=e.template.$player,a=e.query(".art-control-progress-inner");if(!a)throw new Error("Missing ArtPlayer progress container");const n="artplayer-plugin-chapter";let o=function(t){const e=(e,r)=>{const a=t.ownerDocument.createElement("div");return a.className=r,e.appendChild(a),a},r=e(t,"art-chapters"),a=e(t,"art-chapter-title");let n=[];function o(){a.textContent="",a.style.left="0px",a.style.visibility="hidden"}function i(){n=[],r.textContent="",o()}return o(),{clear:i,render:function(t,a){n=t.map(t=>{const n=e(r,"art-chapter"),o=e(n,"art-chapter-inner"),i=t.end-t.start;return n.dataset.start=String(t.start),n.dataset.end=String(t.end),n.dataset.duration=String(i),n.dataset.title=t.title.trim(),n.style.width=i/a*100+"%",{start:t.start,end:t.end,title:t.title.trim(),bars:{hover:e(o,"art-progress-hover"),loaded:e(o,"art-progress-loaded"),played:e(o,"art-progress-played")}}})},setBar:function(e,i,s){if("hover"!==e&&"loaded"!==e&&"played"!==e)return;if(!Number.isFinite(i))return;const l=s*i;let d;for(const t of n)t.bars[e].style.width=l<t.start?"0px":l>t.end?"100%":(l-t.start)/(t.end-t.start)*100+"%",l>=t.start&&l<=t.end&&(d=t);if("hover"!==e)return;o();const p=r.clientWidth*i;(null==d?void 0:d.title)&&p>0&&(a.textContent=d.title,a.style.visibility="visible",a.style.left=`${Math.max(0,Math.min(p-a.clientWidth/2,t.clientWidth-a.clientWidth))}px`)},destroy:function(){i(),r.remove(),a.remove()}}}(a);function i(t){if(!o||e.isDestroy)return;o.clear(),r.classList.remove(n);const a=function(t=[],e){if(!Array.isArray(t)||!t.length||!Number.isFinite(e)||e<=0)return[];t.sort((t,e)=>t.start-e.start);for(const[n,o]of t.entries()){if(!o||"number"!==typeof o.start||"number"!==typeof o.end||"string"!==typeof o.title)throw new TypeError("Illegal chapter data type");o.end===1/0&&(o.end=e);const r=t[n+1];if(!Number.isFinite(o.start)||!Number.isFinite(o.end)||o.start<0||o.end>e||o.start>=o.end||r&&o.end>r.start)throw new Error("Illegal chapter time point")}const r=t[0],a=t[t.length-1];r&&r.start>0&&t.unshift({start:0,end:r.start,title:""}),a&&a.end<e&&t.push({start:a.end,end:e,title:""});for(let n=0;n<t.length-1;n++){const e=t[n],r=t[n+1];e&&r&&e.end!==r.start&&t.splice(n+1,0,{start:e.end,end:r.start,title:""})}return t}(t,e.duration);a.length&&(o.render(a,e.duration),r.classList.add(n),e.emit("setBar","loaded",e.loaded||0))}function s(t,r){e.isDestroy||null==o||o.setBar(t,r,e.duration)}function l(){i(t.chapters)}return e.on("setBar",s),e.once("video:loadedmetadata",l),e.on("destroy",function t(){e.off("setBar",s),e.off("video:loadedmetadata",l),e.off("destroy",t),null==o||o.destroy(),o=void 0,r.classList.remove(nLine truncated
+160 -148
View File
@@ -1,159 +1,171 @@
/*!
* artplayer-plugin-chapter.js v1.1.0
* artplayer-plugin-chapter.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
const style = ".artplayer-plugin-chapter .art-control-progress-inner {\n height: 100% !important;\n background-color: transparent !important;\n}\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-hover,\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-loaded,\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-played {\n display: none !important;\n}\n.artplayer-plugin-chapter .art-control-thumbnails {\n bottom: calc(var(--art-bottom-gap) + 64px) !important;\n}\n.artplayer-plugin-chapter .art-chapters {\n position: absolute;\n z-index: 0;\n inset: 0;\n display: flex;\n align-items: center;\n gap: 4px;\n height: 100%;\n transform: scaleY(1.25);\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter {\n display: flex;\n align-items: center;\n height: 100%;\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner {\n position: relative;\n cursor: pointer;\n width: 100%;\n height: 50%;\n border-radius: 10px;\n overflow: hidden;\n transition: height var(--art-transition-duration) ease;\n background-color: var(--art-progress-color);\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner {\n height: 100%;\n}\n.artplayer-plugin-chapter .art-chapter-title {\n transform-origin: bottom center;\n transform: scale(0.5);\n opacity: 0;\n position: absolute;\n z-index: 70;\n top: -50px;\n left: 0;\n padding: 3px 5px;\n line-height: 1;\n font-size: 14px;\n border-radius: var(--art-border-radius);\n white-space: nowrap;\n background-color: var(--art-tip-background);\n transition: transform var(--art-transition-duration) ease, opacity var(--art-transition-duration) ease;\n}\n.artplayer-plugin-chapter.art-progress-hover .art-chapter-title {\n transform: scale(1);\n opacity: 1;\n}\n";
function artplayerPluginChapter(option = {}) {
return (art) => {
const { $player } = art.template;
const { setStyle, append, clamp, query, addClass, removeClass } = art.constructor.utils;
const html = `
<div class="art-chapter">
<div class="art-chapter-inner">
<div class="art-progress-hover"></div>
<div class="art-progress-loaded"></div>
<div class="art-progress-played"></div>
</div>
</div>
`;
let $chapters = [];
const $inner = art.query(".art-control-progress-inner");
const $control = append($inner, '<div class="art-chapters"></div>');
const $title = append($inner, '<div class="art-chapter-title"></div>');
function showTitle({ $chapter, width }) {
const title = $chapter.dataset.title.trim();
if (title) {
$title.textContent = title;
const titleWidth = $title.clientWidth;
if (width <= titleWidth / 2) {
setStyle($title, "left", 0);
} else if (width > $inner.clientWidth - titleWidth / 2) {
setStyle($title, "left", `${$inner.clientWidth - titleWidth}px`);
} else {
setStyle($title, "left", `${width - titleWidth / 2}px`);
}
}
}
function update(chapters = []) {
$chapters = [];
$control.textContent = "";
removeClass($player, "artplayer-plugin-chapter");
if (!Array.isArray(chapters))
return;
if (!chapters.length)
return;
if (!art.duration)
return;
chapters = chapters.sort((a, b) => a.start - b.start);
for (let i = 0; i < chapters.length; i++) {
const chapter = chapters[i];
const nextChapter = chapters[i + 1];
if (chapter.end === Infinity) {
chapter.end = art.duration;
}
if (typeof chapter.start !== "number" || typeof chapter.end !== "number" || typeof chapter.title !== "string") {
throw new TypeError("Illegal chapter data type");
}
if (chapter.start < 0 || chapter.end > art.duration || chapter.start >= chapter.end) {
throw new Error("Illegal chapter time point");
}
if (nextChapter && chapter.end > nextChapter.start) {
throw new Error("Illegal chapter time point");
}
}
if (chapters[0].start > 0) {
chapters.unshift({ start: 0, end: chapters[0].start, title: "" });
}
if (chapters[chapters.length - 1].end < art.duration) {
chapters.push({ start: chapters[chapters.length - 1].end, end: art.duration, title: "" });
}
for (let i = 0; i < chapters.length - 1; i++) {
if (chapters[i].end !== chapters[i + 1].start) {
chapters.splice(i + 1, 0, {
start: chapters[i].end,
end: chapters[i + 1].start,
title: ""
});
}
}
$chapters = chapters.map((chapter) => {
const $chapter = append($control, html);
const start = clamp(chapter.start, 0, art.duration);
const end = clamp(chapter.end, 0, art.duration);
const duration = end - start;
const percentage = duration / art.duration;
$chapter.dataset.start = start;
$chapter.dataset.end = end;
$chapter.dataset.duration = duration;
$chapter.dataset.title = chapter.title.trim();
$chapter.style.width = `${percentage * 100}%`;
return {
$chapter,
$hover: query(".art-progress-hover", $chapter),
$loaded: query(".art-progress-loaded", $chapter),
$played: query(".art-progress-played", $chapter)
};
});
addClass($player, "artplayer-plugin-chapter");
art.emit("setBar", "loaded", art.loaded || 0);
}
art.on("setBar", (type, percentage) => {
if (!$chapters.length)
return;
for (let i = 0; i < $chapters.length; i++) {
const { $chapter, $loaded, $played, $hover } = $chapters[i];
const $target = {
hover: $hover,
loaded: $loaded,
played: $played
}[type];
if (!$target)
return;
const width = $control.clientWidth * percentage;
const currentTime = art.duration * percentage;
const duration = Number.parseFloat($chapter.dataset.duration);
const start = Number.parseFloat($chapter.dataset.start);
const end = Number.parseFloat($chapter.dataset.end);
if (currentTime < start) {
setStyle($target, "width", 0);
}
if (currentTime > end) {
setStyle($target, "width", "100%");
}
if (currentTime >= start && currentTime <= end) {
const percentage2 = (currentTime - start) / duration;
setStyle($target, "width", `${percentage2 * 100}%`);
if (type === "hover" && width > 0) {
showTitle({ $chapter, width });
}
}
}
});
art.once("video:loadedmetadata", () => update(option.chapters));
return {
name: "artplayerPluginChapter",
update: ({ chapters }) => update(chapters)
};
};
}
if (typeof document !== "undefined") {
const id = "artplayer-plugin-chapter";
let $style = document.getElementById(id);
if (!$style) {
$style = document.createElement("style");
$style.id = id;
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", () => {
document.head.appendChild($style);
});
} else {
(document.head || document.documentElement).appendChild($style);
function normalizeChapters(chapters = [], duration) {
if (!Array.isArray(chapters) || !chapters.length || !Number.isFinite(duration) || duration <= 0)
return [];
chapters.sort((a, b) => a.start - b.start);
for (const [index, chapter] of chapters.entries()) {
if (!chapter || typeof chapter.start !== "number" || typeof chapter.end !== "number" || typeof chapter.title !== "string")
throw new TypeError("Illegal chapter data type");
if (chapter.end === Infinity)
chapter.end = duration;
const next = chapters[index + 1];
if (!Number.isFinite(chapter.start) || !Number.isFinite(chapter.end) || chapter.start < 0 || chapter.end > duration || chapter.start >= chapter.end || next && chapter.end > next.start) {
throw new Error("Illegal chapter time point");
}
}
$style.textContent = style;
const first = chapters[0];
const last = chapters[chapters.length - 1];
if (first && first.start > 0)
chapters.unshift({ start: 0, end: first.start, title: "" });
if (last && last.end < duration)
chapters.push({ start: last.end, end: duration, title: "" });
for (let index = 0; index < chapters.length - 1; index++) {
const current = chapters[index];
const next = chapters[index + 1];
if (current && next && current.end !== next.start)
chapters.splice(index + 1, 0, { start: current.end, end: next.start, title: "" });
}
return chapters;
}
function createProgress(inner) {
const create = (parent, className) => {
const element = inner.ownerDocument.createElement("div");
element.className = className;
parent.appendChild(element);
return element;
};
const control = create(inner, "art-chapters");
const title = create(inner, "art-chapter-title");
let segments = [];
function clearTitle() {
title.textContent = "";
title.style.left = "0px";
title.style.visibility = "hidden";
}
function clear() {
segments = [];
control.textContent = "";
clearTitle();
}
function render(chapters, duration) {
segments = chapters.map((chapter) => {
const element = create(control, "art-chapter");
const body = create(element, "art-chapter-inner");
const length = chapter.end - chapter.start;
element.dataset.start = String(chapter.start);
element.dataset.end = String(chapter.end);
element.dataset.duration = String(length);
element.dataset.title = chapter.title.trim();
element.style.width = `${length / duration * 100}%`;
return {
start: chapter.start,
end: chapter.end,
title: chapter.title.trim(),
bars: {
hover: create(body, "art-progress-hover"),
loaded: create(body, "art-progress-loaded"),
played: create(body, "art-progress-played")
}
};
});
}
function setBar(type, percentage, duration) {
if (type !== "hover" && type !== "loaded" && type !== "played")
return;
if (!Number.isFinite(percentage))
return;
const currentTime = duration * percentage;
let hovered;
for (const segment of segments) {
const target = segment.bars[type];
target.style.width = currentTime < segment.start ? "0px" : currentTime > segment.end ? "100%" : `${(currentTime - segment.start) / (segment.end - segment.start) * 100}%`;
if (currentTime >= segment.start && currentTime <= segment.end)
hovered = segment;
}
if (type !== "hover")
return;
clearTitle();
const width = control.clientWidth * percentage;
if (hovered?.title && width > 0) {
title.textContent = hovered.title;
title.style.visibility = "visible";
title.style.left = `${Math.max(0, Math.min(width - title.clientWidth / 2, inner.clientWidth - title.clientWidth))}px`;
}
}
function destroy() {
clear();
control.remove();
title.remove();
}
clearTitle();
return { clear, render, setBar, destroy };
}
const style = ".artplayer-plugin-chapter .art-control-progress-inner {\n height: 100% !important;\n background-color: transparent !important;\n}\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-hover,\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-loaded,\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-played {\n display: none !important;\n}\n.artplayer-plugin-chapter .art-control-thumbnails {\n bottom: calc(var(--art-bottom-gap) + 64px) !important;\n}\n.artplayer-plugin-chapter .art-chapters {\n position: absolute;\n z-index: 0;\n inset: 0;\n display: flex;\n align-items: center;\n gap: 4px;\n height: 100%;\n transform: scaleY(1.25);\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter {\n display: flex;\n align-items: center;\n height: 100%;\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner {\n position: relative;\n cursor: pointer;\n width: 100%;\n height: 50%;\n border-radius: 10px;\n overflow: hidden;\n transition: height var(--art-transition-duration) ease;\n background-color: var(--art-progress-color);\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner {\n height: 100%;\n}\n.artplayer-plugin-chapter .art-chapter-title {\n transform-origin: bottom center;\n transform: scale(0.5);\n opacity: 0;\n position: absolute;\n z-index: 70;\n top: -50px;\n left: 0;\n padding: 3px 5px;\n line-height: 1;\n font-size: 14px;\n border-radius: var(--art-border-radius);\n white-space: nowrap;\n box-sizing: border-box;\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n background-color: var(--art-tip-background);\n transition: transform var(--art-transition-duration) ease, opacity var(--art-transition-duration) ease;\n}\n.artplayer-plugin-chapter.art-progress-hover .art-chapter-title {\n transform: scale(1);\n opacity: 1;\n}\n";
function installStyle() {
if (typeof document === "undefined")
return;
const id = "artplayer-plugin-chapter";
const install = () => {
let element = document.getElementById(id);
if (!element) {
element = document.createElement("style");
element.id = id;
(document.head || document.documentElement).appendChild(element);
}
element.textContent = style;
};
if (document.getElementById(id) || document.readyState !== "loading")
install();
else
document.addEventListener("DOMContentLoaded", install, { once: true });
}
function artplayerPluginChapter(option = {}) {
return (art) => {
const player = art.template.$player;
const inner = art.query(".art-control-progress-inner");
if (!inner)
throw new Error("Missing ArtPlayer progress container");
const className = "artplayer-plugin-chapter";
let progress = createProgress(inner);
function update(chapters) {
if (!progress || art.isDestroy)
return;
progress.clear();
player.classList.remove(className);
const normalized = normalizeChapters(chapters, art.duration);
if (!normalized.length)
return;
progress.render(normalized, art.duration);
player.classList.add(className);
art.emit("setBar", "loaded", art.loaded || 0);
}
function setBar(type, percentage) {
if (!art.isDestroy)
progress?.setBar(type, percentage, art.duration);
}
function initialize() {
update(option.chapters);
}
function destroy() {
art.off("setBar", setBar);
art.off("video:loadedmetadata", initialize);
art.off("destroy", destroy);
progress?.destroy();
progress = void 0;
player.classList.remove(className);
}
art.on("setBar", setBar);
art.once("video:loadedmetadata", initialize);
art.on("destroy", destroy);
return { name: "artplayerPluginChapter", update: ({ chapters }) => update(chapters) };
};
}
installStyle();
export {
artplayerPluginChapter as default
};
+2 -2
View File
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-chromecast.js v1.1.0
* artplayer-plugin-chromecast.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerPluginChromecast=t(),define(function(){return t.artplayerPluginChromecast})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginChromecast=t()}(this,function(){"use strict";return function(e){let t=!1,o=null,n=null;const a=e=>{const t=document.querySelector(".art-icon-cast");if(t)switch(e){case"connected":t.style.color="red";break;case"connecting":case"disconnecting":t.style.color="orange";break;default:t.style.color="white"}},c=()=>new Promise((c,s)=>{var i;window.__onGCastApiAvailable=i=>{if(i){const s=window.cast.framework.CastContext.getInstance();s.setOptions({receiverApplicationId:window.chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID,autoJoinPolicy:window.chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED}),s.addEventListener(window.cast.framework.CastContextEventType.SESSION_STATE_CHANGED,t=>{const c=window.cast.framework.SessionState;switch(n=t.sessionState,o=t.session,t.sessionState){case c.NO_SESSION:e.onStateChange?.("disconnected"),a("disconnected");break;case c.SESSION_STARTING:e.onStateChange?.("connecting"),a("connecting");break;case c.SESSION_STARTED:e.onStateChange?.("connected"),a("connected");break;case c.SESSION_ENDING:e.onStateChange?.("disconnecting"),a("disconnecting");break;case c.SESSION_RESUMED:e.onStateChange?.("connected"),a("connected")}}),s.addEventListener(window.cast.framework.CastContextEventType.CAST_STATE_CHANGED,t=>{const o=window.cast.framework.CastState;switch(t.castState){case o.NO_DEVICES_AVAILABLE:e.onCastAvailable?.(!1);break;case o.NOT_CONNECTED:case o.CONNECTING:case o.CONNECTED:e.onCastAvailable?.(!0)}}),t=!0,c()}else s(new Error("Cast API is not available"))},window.chrome&&window.chrome.cast||(i=e.sdk||"https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1",new Promise((e,t)=>{const o=document.createElement("script");o.src=i,o.onload=e,o.onerror=t,document.body.appendChild(o)})).catch(s)}),s=(t,o)=>{const n=e.url||t.option.url,a=new window.chrome.cast.media.MediaInfo(n,e.mimeType||function(e){return{mp4:"video/mp4",webm:"video/webm",ogg:"video/ogg",ogv:"video/ogg",mp3:"audio/mp3",wav:"audio/wav",flv:"video/x-flv",mov:"video/quicktime",avi:"video/x-msvideo",wmv:"video/x-ms-wmv",mpd:"application/dash+xml",m3u8:"application/x-mpegURL"}[e.split("?")[0].split("#")[0].split(".").pop().toLowerCase()]||"application/octet-stream"}(n)),c=new window.chrome.cast.media.LoadRequest(a);o.loadMedia(c).then(()=>{t.notice.show="Casting started",e.onCastStart?.()}).catch(o=>{throw t.notice.show="Error casting media",e.onError?.(o),o})};return async a=>(a.controls.add({name:"chromecast",position:"right",tooltip:"Chromecast",html:`<i class="art-icon art-icon-cast">${e.icon||'<svg height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M512 96H64v99c-13-2-26.4-3-40-3H0V96C0 60.7 28.7 32 64 32H512c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H288V456c0-13.6-1-27-3-40H512V96zM24 224c128.1 0 232 103.9 232 232c0 13.3-10.7 24-24 24s-24-10.7-24-24c0-101.6-82.4-184-184-184c-13.3 0-24-10.7-24-24s10.7-24 24-24zm8 192a32 32 0 1 1 0 64 32 32 0 1 1 0-64zM0 344c0-13.3 10.7-24 24-24c75.1 0 136 60.9 136 136c0 13.3-10.7 24-24 24s-24-10.7-24-24c0-48.6-39.4-88-88-88c-13.3 0-24-10.7-24-24z"/></svg>'}</i>`,click:async()=>{if(!t)try{await c()}catch(i){throw a.notice.show="Failed to initialize Cast API",e.onError?.(i),i}const n=window.cast.framework.CastContext.getInstance();if(o)s(a,o);else try{const e=await n.requestSession();s(a,e)}catch(i){throw a.notice.show="Error connecting to cast session",e.onError?.(i),i}}}),{name:"artplayerPluginChromecast",getCastState:()=>n,isCasting:()=>null!==o})}});
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginChromecast=t(),define(function(){return e.artplayerPluginChromecast})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginChromecast=t()}(this,function(){"use strict";const e={mp4:"video/mp4",webm:"video/webm",ogg:"video/ogg",ogv:"video/ogg",mp3:"audio/mp3",wav:"audio/wav",flv:"video/x-flv",mov:"video/quicktime",avi:"video/x-msvideo",wmv:"video/x-ms-wmv",mpd:"application/dash+xml",m3u8:"application/x-mpegURL"};function t(t,o,n,i){const r=n.url||i,s=r.split("?")[0].split("#")[0].split(".").pop().toLowerCase(),a=new t.media.MediaInfo(r,n.mimeType||e[s]||"application/octet-stream");return o.loadMedia(new t.media.LoadRequest(a))}const o=new WeakMap,n=new WeakSet;function i(e){const t=e.cast?.framework,o=e.chrome?.cast;if("function"===typeof t?.CastContext?.getInstance&&t.CastContextEventType&&t.SessionState&&t.CastState&&"function"===typeof o?.media?.MediaInfo&&"function"===typeof o.media.LoadRequest&&o.AutoJoinPolicy)return{framework:t,media:o.media,autoJoinPolicy:o.AutoJoinPolicy.ORIGIN_SCOPED}}function r(e,t){let o;const n=new Promise((n,i)=>{o={ready:t,resolve:n,reject:i},e.subscribers.add(o)});let i=!1;return{promise:n,release:()=>{i||(i=!0,e.subscribers.delete(o),o.reject(new Error("Cast initialization cancelled")),e.subscribers.size||e.cancel())}}}function s(e,s){let a,c,l,d,u,f,m=!1,v=null,S=null,p=0,E=!1;const w=new Promise(e=>{f=()=>e(void 0)});let C;const h=()=>!m&&!e.isDestroy,y=e=>{if(s.onStateChange?.(e),!h())return;const t=C?.querySelector(".art-icon-cast");t&&(t.style.color="connected"===e?"red":"connecting"===e||"disconnecting"===e?"orange":"white")},g=e=>{if(!h()||!a)return;S=e.sessionState;const t=a.framework.SessionState;S===t.NO_SESSION||S===t.SESSION_ENDED||S===t.SESSION_START_FAILED?((S!==t.NO_SESSION||E)&&(p++,u?.()),v=null,y("disconnected")):((S===t.SESSION_ENDING||v&&e.session&&e.session!==v)&&(p++,u?.()),v=e.session||null,S===t.SESSION_STARTING?y("connecting"):S===t.SESSION_ENDING?y("disconnecting"):S!==t.SESSION_STARTED&&S!==t.SESSION_RESUMED||y("connected"))},A=e=>{if(!h()||!a)return;const t=a.framework.CastState;e.castState===t.NO_DEVICES_AVAILABLE?s.onCastAvailable?.(!1):e.castState!==t.NOT_CONNECTED&&e.castState!==t.CONNECTING&&e.castState!==t.CONNECTED||s.onCastAvailable?.(!0)},_=()=>{const e=c,t=a;if(c=void 0,a=void 0,e&&t){const n=t.framework.CastContextEventType,i=[];try{e.removeEventListener(n.SESSION_STATE_CHANGED,g)}catch(o){i.push(o)}try{e.removeEventListener(n.CAST_STATE_CHANGED,A)}catch(o){i.push(o)}if(i.length)throw i[0]}},N=()=>{if(m)return;m=!0,f();const t=d;d=void 0;const o=[];for(const i of[t,_,()=>e.off("destroy",N)])try{i?.()}catch(n){o.push(n)}if(v=null,C=void 0,o.length)throw o[0]};async function I(){const l=p,f=()=>h()&&p===l;let m;const S=new Promise(e=>{m=()=>e(void 0)});u=m;let C="Failed to initialize Cast API";try{if(!a||!c){const e=function(e,t){const n=window,s=i(n);if(s)return{promise:new Promise((e,o)=>{try{t(s),e(s)}catch(n){o(n)}}),release:()=>{}};const a=o.get(n);if(a)return r(a,t);const c={subscribers:new Set,cancel:()=>v(void 0,new Error("Cast initialization cancelled"))};o.set(n,c);const l=r(c,t),d=n.__onGCastApiAvailable;let u,f,m=!1;function v(e,t){if(!m){m=!0,void 0!==f&&n.clearTimeout(f),o.delete(n),n.__onGCastApiAvailable===S&&(n.__onGCastApiAvailable=d),u&&(u.onload=null,u.onerror=null,e||u.remove());for(const o of c.subscribers)try{e?(o.ready(e),o.resolve(e)):o.reject(t)}catch(i){o.reject(i)}c.subscribers.clear()}}function S(e,t){try{d?.call(n,e,t)}finally{v(e?i(n):void 0,new Error("Cast API is not available"))}}n.__onGCastApiAvailable=S;try{f=n.setTimeout(()=>v(void 0,new Error("Timed out initializing Cast API")),3e4),u=document.createElement("script"),u.src=e||"https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1",u.onerror=e=>v(void 0,e),u.onload=()=>{const e=i(n);e&&v(e)},document.body.appendChild(u)}catch(p){v(void 0,p)}return l}(s.sdk,e=>{if(!f())return;if(a=e,c=function(e){const t=e.framework.CastContext.getInstance();return n.has(t)||(t.setOptions({receiverApplicationId:e.media.DEFAULT_MEDIA_RECEIVER_APP_ID,autoJoinPolicy:e.autoJoinPolicy}),n.add(t)),t}(a),!f())return;const t=a.framework.CastContextEventType;try{c.addEventListener(t.SESSION_STATE_CHANGED,g),h()&&c.addEventListener(t.CAST_STATE_CHANGED,A)}catch(o){try{_()}catch{}throw o}});d=e.release,await Promise.race([e.promise,w,S]),e.release(),d=void 0}if(!f()||!c||!a)return;C="Error connecting to cast session",E=!0;let l=c.getCurrentSession();if(!f())return;if(!l){if(await Promise.race([c.requestSession(),w,S]),!f())return;l=c.getCurrentSession()}if(!f())return;if(!l)throw new Error("No active Cast session");v=l,C="Error casting media",await Promise.race([t(a,l,s,e.option.url),w,S]),f()&&(e.notice.show="Casting started",s.onCastStart?.())}catch(y){if(f())throw e.notice.show=C,s.onError?.(y),y}Line truncated
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-chromecast.js v1.1.0
* artplayer-plugin-chromecast.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerPluginChromecast=t(),define(function(){return t.artplayerPluginChromecast})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginChromecast=t()}(this,function(){"use strict";var e=(e,t,n)=>new Promise((o,a)=>{var c=e=>{try{i(n.next(e))}catch(t){a(t)}},s=e=>{try{i(n.throw(e))}catch(t){a(t)}},i=e=>e.done?o(e.value):Promise.resolve(e.value).then(c,s);i((n=n.apply(e,t)).next())});return function(t){let n=!1,o=null,a=null;const c=e=>{const t=document.querySelector(".art-icon-cast");if(t)switch(e){case"connected":t.style.color="red";break;case"connecting":case"disconnecting":t.style.color="orange";break;default:t.style.color="white"}},s=()=>new Promise((e,s)=>{var i;window.__onGCastApiAvailable=i=>{if(i){const s=window.cast.framework.CastContext.getInstance();s.setOptions({receiverApplicationId:window.chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID,autoJoinPolicy:window.chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED}),s.addEventListener(window.cast.framework.CastContextEventType.SESSION_STATE_CHANGED,e=>{var n,s,i,l,r;const d=window.cast.framework.SessionState;switch(a=e.sessionState,o=e.session,e.sessionState){case d.NO_SESSION:null==(n=t.onStateChange)||n.call(t,"disconnected"),c("disconnected");break;case d.SESSION_STARTING:null==(s=t.onStateChange)||s.call(t,"connecting"),c("connecting");break;case d.SESSION_STARTED:null==(i=t.onStateChange)||i.call(t,"connected"),c("connected");break;case d.SESSION_ENDING:null==(l=t.onStateChange)||l.call(t,"disconnecting"),c("disconnecting");break;case d.SESSION_RESUMED:null==(r=t.onStateChange)||r.call(t,"connected"),c("connected")}}),s.addEventListener(window.cast.framework.CastContextEventType.CAST_STATE_CHANGED,e=>{var n,o,a;const c=window.cast.framework.CastState;switch(e.castState){case c.NO_DEVICES_AVAILABLE:null==(n=t.onCastAvailable)||n.call(t,!1);break;case c.NOT_CONNECTED:null==(o=t.onCastAvailable)||o.call(t,!0);break;case c.CONNECTING:case c.CONNECTED:null==(a=t.onCastAvailable)||a.call(t,!0)}}),n=!0,e()}else s(new Error("Cast API is not available"))},window.chrome&&window.chrome.cast||(i=t.sdk||"https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1",new Promise((e,t)=>{const n=document.createElement("script");n.src=i,n.onload=e,n.onerror=t,document.body.appendChild(n)})).catch(s)}),i=(e,n)=>{const o=t.url||e.option.url,a=new window.chrome.cast.media.MediaInfo(o,t.mimeType||function(e){return{mp4:"video/mp4",webm:"video/webm",ogg:"video/ogg",ogv:"video/ogg",mp3:"audio/mp3",wav:"audio/wav",flv:"video/x-flv",mov:"video/quicktime",avi:"video/x-msvideo",wmv:"video/x-ms-wmv",mpd:"application/dash+xml",m3u8:"application/x-mpegURL"}[e.split("?")[0].split("#")[0].split(".").pop().toLowerCase()]||"application/octet-stream"}(o)),c=new window.chrome.cast.media.LoadRequest(a);n.loadMedia(c).then(()=>{var n;e.notice.show="Casting started",null==(n=t.onCastStart)||n.call(t)}).catch(n=>{var o;throw e.notice.show="Error casting media",null==(o=t.onError)||o.call(t,n),n})};return c=>e(null,null,function*(){return c.controls.add({name:"chromecast",position:"right",tooltip:"Chromecast",html:`<i class="art-icon art-icon-cast">${t.icon||'<svg height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M512 96H64v99c-13-2-26.4-3-40-3H0V96C0 60.7 28.7 32 64 32H512c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H288V456c0-13.6-1-27-3-40H512V96zM24 224c128.1 0 232 103.9 232 232c0 13.3-10.7 24-24 24s-24-10.7-24-24c0-101.6-82.4-184-184-184c-13.3 0-24-10.7-24-24s10.7-24 24-24zm8 192a32 32 0 1 1 0 64 32 32 0 1 1 0-64zM0 344c0-13.3 10.7-24 24-24c75.1 0 136 60.9 136 136c0 13.3-10.7 24-24 24s-24-10.7-24-24c0-48.6-39.4-88-88-88c-13.3 0-24-10.7-24-24z"/></svg>'}</i>`,click:()=>e(null,null,function*(){var e,a;if(!n)try{yield s()}catch(r){throw c.notice.show="Failed to initialize Cast API",null==(e=t.onError)||e.call(t,r),r}const l=window.cast.framework.CastContext.getInstance();if(o)i(c,o);else try{const e=yield l.requestSession();i(c,e)}catch(r){throw c.notice.show="Error connecting to cast session",null==(a=t.onError)||a.call(t,r),r}})}),{name:"artplayerPluginChromecast",getCastState:()=>a,isCasting:()=>null!==o}})}});
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginChromecast=t(),define(function(){return e.artplayerPluginChromecast})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginChromecast=t()}(this,function(){"use strict";var e=(e,t,o)=>new Promise((n,i)=>{var r=e=>{try{a(o.next(e))}catch(t){i(t)}},s=e=>{try{a(o.throw(e))}catch(t){i(t)}},a=e=>e.done?n(e.value):Promise.resolve(e.value).then(r,s);a((o=o.apply(e,t)).next())});const t={mp4:"video/mp4",webm:"video/webm",ogg:"video/ogg",ogv:"video/ogg",mp3:"audio/mp3",wav:"audio/wav",flv:"video/x-flv",mov:"video/quicktime",avi:"video/x-msvideo",wmv:"video/x-ms-wmv",mpd:"application/dash+xml",m3u8:"application/x-mpegURL"};function o(e,o,n,i){const r=n.url||i,s=r.split("?")[0].split("#")[0].split(".").pop().toLowerCase(),a=new e.media.MediaInfo(r,n.mimeType||t[s]||"application/octet-stream");return o.loadMedia(new e.media.LoadRequest(a))}const n=new WeakMap,i=new WeakSet;function r(e){var t,o,n,i;const r=null==(t=e.cast)?void 0:t.framework,s=null==(o=e.chrome)?void 0:o.cast;if("function"===typeof(null==(n=null==r?void 0:r.CastContext)?void 0:n.getInstance)&&r.CastContextEventType&&r.SessionState&&r.CastState&&"function"===typeof(null==(i=null==s?void 0:s.media)?void 0:i.MediaInfo)&&"function"===typeof s.media.LoadRequest&&s.AutoJoinPolicy)return{framework:r,media:s.media,autoJoinPolicy:s.AutoJoinPolicy.ORIGIN_SCOPED}}function s(e,t){let o;const n=new Promise((n,i)=>{o={ready:t,resolve:n,reject:i},e.subscribers.add(o)});let i=!1;return{promise:n,release:()=>{i||(i=!0,e.subscribers.delete(o),o.reject(new Error("Cast initialization cancelled")),e.subscribers.size||e.cancel())}}}function a(t,a){let l,c,u,d,v,f,m=!1,S=null,p=null,E=0,C=!1;const w=new Promise(e=>{f=()=>e(void 0)});let h;const y=()=>!m&&!t.isDestroy,g=e=>{var t;if(null==(t=a.onStateChange)||t.call(a,e),!y())return;const o=null==h?void 0:h.querySelector(".art-icon-cast");o&&(o.style.color="connected"===e?"red":"connecting"===e||"disconnecting"===e?"orange":"white")},A=e=>{if(!y()||!l)return;p=e.sessionState;const t=l.framework.SessionState;p===t.NO_SESSION||p===t.SESSION_ENDED||p===t.SESSION_START_FAILED?((p!==t.NO_SESSION||C)&&(E++,null==v||v()),S=null,g("disconnected")):((p===t.SESSION_ENDING||S&&e.session&&e.session!==S)&&(E++,null==v||v()),S=e.session||null,p===t.SESSION_STARTING?g("connecting"):p===t.SESSION_ENDING?g("disconnecting"):p!==t.SESSION_STARTED&&p!==t.SESSION_RESUMED||g("connected"))},_=e=>{var t,o;if(!y()||!l)return;const n=l.framework.CastState;e.castState===n.NO_DEVICES_AVAILABLE?null==(t=a.onCastAvailable)||t.call(a,!1):e.castState!==n.NOT_CONNECTED&&e.castState!==n.CONNECTING&&e.castState!==n.CONNECTED||null==(o=a.onCastAvailable)||o.call(a,!0)},N=()=>{const e=c,t=l;if(c=void 0,l=void 0,e&&t){const n=t.framework.CastContextEventType,i=[];try{e.removeEventListener(n.SESSION_STATE_CHANGED,A)}catch(o){i.push(o)}try{e.removeEventListener(n.CAST_STATE_CHANGED,_)}catch(o){i.push(o)}if(i.length)throw i[0]}},I=()=>{if(m)return;m=!0,f();const e=d;d=void 0;const o=[];for(const i of[e,N,()=>t.off("destroy",I)])try{null==i||i()}catch(n){o.push(n)}if(S=null,h=void 0,o.length)throw o[0]};function T(){return e(this,null,function*(){var e,u;const f=E,m=()=>y()&&E===f;let p;const h=new Promise(e=>{p=()=>e(void 0)});v=p;let g="Failed to initialize Cast API";try{if(!l||!c){const e=function(e,t){const o=window,i=r(o);if(i)return{promise:new Promise((e,o)=>{try{t(i),e(i)}catch(n){o(n)}}),release:()=>{}};const a=n.get(o);if(a)return s(a,t);const l={subscribers:new Set,cancel:()=>m(void 0,new Error("Cast initialization cancelled"))};n.set(o,l);const c=s(l,t),u=o.__onGCastApiAvailable;let d,v,f=!1;function m(e,t){if(!f){f=!0,void 0!==v&&o.clearTimeout(v),n.delete(o),o.__onGCastApiAvailable===S&&(o.__onGCastApiAvailable=u),d&&(d.onload=null,d.onerror=null,e||d.remove());for(const o of l.subscribers)try{e?(o.ready(e),o.resolve(e)):o.reject(t)}catch(i){o.reject(i)}l.subscribers.clear()}}function S(e,t){try{null==u||u.call(o,e,t)}finally{m(e?r(o):void 0,new Error("Cast API is not available"))}}o.__onGCastApiAvailable=S;try{v=o.setTimeout(()=>m(void 0,new Error("Timed out initializing Cast API")),3e4),d=document.createElement("script"),d.src=e||"https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1",d.onerror=e=>m(void 0,e),d.onload=()=>{const e=r(o);e&&m(e)},document.body.appendChild(d)}catch(p){m(void 0,p)}return c}(a.sdk,e=>{if(!m())return;if(l=e,c=function(e){const t=e.framework.CastContext.getInstance();return i.has(t)||(t.setOptions({receiverApplicationId:e.media.DEFAULT_MEDIA_RECEIVER_APP_ID,autoJoinPolicy:e.autoJoinPolicy}),i.add(t)),t}(l),!m())return;const t=l.framework.CastContextEventType;try{c.addEventListener(t.SESSION_STATE_CHANGED,A),y()&&c.addEventListener(t.CAST_STATE_CHANGED,_)}catch(o){try{N()}catch(n){}throw o}});d=e.release,yield Promise.race([e.promise,w,h]),e.relLine truncated
+348 -162
View File
@@ -1,176 +1,362 @@
/*!
* artplayer-plugin-chromecast.js v1.1.0
* artplayer-plugin-chromecast.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
function loadScript(src) {
return new Promise((resolve, reject) => {
const script = document.createElement("script");
script.src = src;
script.onload = resolve;
script.onerror = reject;
document.body.appendChild(script);
});
}
function getMimeType(url) {
const icon = '<svg height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7V4h17v14h-8M3 11a10 10 0 0 1 10 10M3 16a5 5 0 0 1 5 5"/><circle cx="3" cy="21" r="1" fill="currentColor" stroke="none"/></svg>\r\n';
const mimeTypes = {
mp4: "video/mp4",
webm: "video/webm",
ogg: "video/ogg",
ogv: "video/ogg",
mp3: "audio/mp3",
wav: "audio/wav",
flv: "video/x-flv",
mov: "video/quicktime",
avi: "video/x-msvideo",
wmv: "video/x-ms-wmv",
mpd: "application/dash+xml",
m3u8: "application/x-mpegURL"
};
function loadMedia(sdk, session, option, currentUrl) {
const url = option.url || currentUrl;
const extension = url.split("?")[0].split("#")[0].split(".").pop().toLowerCase();
const mimeTypes = {
mp4: "video/mp4",
webm: "video/webm",
ogg: "video/ogg",
ogv: "video/ogg",
mp3: "audio/mp3",
wav: "audio/wav",
flv: "video/x-flv",
mov: "video/quicktime",
avi: "video/x-msvideo",
wmv: "video/x-ms-wmv",
mpd: "application/dash+xml",
m3u8: "application/x-mpegURL"
};
return mimeTypes[extension] || "application/octet-stream";
const info = new sdk.media.MediaInfo(url, option.mimeType || mimeTypes[extension] || "application/octet-stream");
return session.loadMedia(new sdk.media.LoadRequest(info));
}
function artplayerPluginChromecast(option) {
const DEFAULT_ICON = `<svg height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M512 96H64v99c-13-2-26.4-3-40-3H0V96C0 60.7 28.7 32 64 32H512c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H288V456c0-13.6-1-27-3-40H512V96zM24 224c128.1 0 232 103.9 232 232c0 13.3-10.7 24-24 24s-24-10.7-24-24c0-101.6-82.4-184-184-184c-13.3 0-24-10.7-24-24s10.7-24 24-24zm8 192a32 32 0 1 1 0 64 32 32 0 1 1 0-64zM0 344c0-13.3 10.7-24 24-24c75.1 0 136 60.9 136 136c0 13.3-10.7 24-24 24s-24-10.7-24-24c0-48.6-39.4-88-88-88c-13.3 0-24-10.7-24-24z"/></svg>`;
const DEFAULT_SDK = "https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1";
let isCastInitialized = false;
let castSession = null;
let castState = null;
const updateCastButton = (state) => {
const button = document.querySelector(".art-icon-cast");
if (button) {
switch (state) {
case "connected":
button.style.color = "red";
break;
case "connecting":
case "disconnecting":
button.style.color = "orange";
break;
case "disconnected":
default:
button.style.color = "white";
break;
const DEFAULT_SDK = "https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1";
const pending = /* @__PURE__ */ new WeakMap();
const configured = /* @__PURE__ */ new WeakSet();
function ready(host) {
const framework = host.cast?.framework;
const api = host.chrome?.cast;
if (typeof framework?.CastContext?.getInstance === "function" && framework.CastContextEventType && framework.SessionState && framework.CastState && typeof api?.media?.MediaInfo === "function" && typeof api.media.LoadRequest === "function" && api.AutoJoinPolicy) {
return { framework, media: api.media, autoJoinPolicy: api.AutoJoinPolicy.ORIGIN_SCOPED };
}
}
function configure(sdk) {
const context = sdk.framework.CastContext.getInstance();
if (!configured.has(context)) {
context.setOptions({ receiverApplicationId: sdk.media.DEFAULT_MEDIA_RECEIVER_APP_ID, autoJoinPolicy: sdk.autoJoinPolicy });
configured.add(context);
}
return context;
}
function lease(loading, onReady) {
let subscriber;
const promise = new Promise((resolve, reject) => {
subscriber = { ready: onReady, resolve, reject };
loading.subscribers.add(subscriber);
});
let released = false;
return { promise, release: () => {
if (released)
return;
released = true;
loading.subscribers.delete(subscriber);
subscriber.reject(new Error("Cast initialization cancelled"));
if (!loading.subscribers.size)
loading.cancel();
} };
}
function loadSdk(src, onReady) {
const host = window;
const loaded = ready(host);
if (loaded) {
const promise = new Promise((resolve, reject) => {
try {
onReady(loaded);
resolve(loaded);
} catch (error) {
reject(error);
}
});
return { promise, release: () => {
} };
}
const existing = pending.get(host);
if (existing)
return lease(existing, onReady);
const loading = { subscribers: /* @__PURE__ */ new Set(), cancel: () => finish(void 0, new Error("Cast initialization cancelled")) };
pending.set(host, loading);
const subscription = lease(loading, onReady);
const previous = host.__onGCastApiAvailable;
let script;
let timer;
let settled = false;
function finish(sdk, error) {
if (settled)
return;
settled = true;
if (timer !== void 0)
host.clearTimeout(timer);
pending.delete(host);
if (host.__onGCastApiAvailable === available)
host.__onGCastApiAvailable = previous;
if (script) {
script.onload = null;
script.onerror = null;
if (!sdk)
script.remove();
}
for (const subscriber of loading.subscribers) {
try {
if (sdk) {
subscriber.ready(sdk);
subscriber.resolve(sdk);
} else {
subscriber.reject(error);
}
} catch (error2) {
subscriber.reject(error2);
}
}
};
const initializeCastApi = () => {
return new Promise((resolve, reject) => {
window.__onGCastApiAvailable = (isAvailable) => {
if (isAvailable) {
const context = window.cast.framework.CastContext.getInstance();
context.setOptions({
receiverApplicationId: window.chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID,
autoJoinPolicy: window.chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED
});
context.addEventListener(
window.cast.framework.CastContextEventType.SESSION_STATE_CHANGED,
(event) => {
const SessionState = window.cast.framework.SessionState;
castState = event.sessionState;
castSession = event.session;
switch (event.sessionState) {
case SessionState.NO_SESSION:
option.onStateChange?.("disconnected");
updateCastButton("disconnected");
break;
case SessionState.SESSION_STARTING:
option.onStateChange?.("connecting");
updateCastButton("connecting");
break;
case SessionState.SESSION_STARTED:
option.onStateChange?.("connected");
updateCastButton("connected");
break;
case SessionState.SESSION_ENDING:
option.onStateChange?.("disconnecting");
updateCastButton("disconnecting");
break;
case SessionState.SESSION_RESUMED:
option.onStateChange?.("connected");
updateCastButton("connected");
break;
}
}
);
context.addEventListener(window.cast.framework.CastContextEventType.CAST_STATE_CHANGED, (event) => {
const CastState = window.cast.framework.CastState;
switch (event.castState) {
case CastState.NO_DEVICES_AVAILABLE:
option.onCastAvailable?.(false);
break;
case CastState.NOT_CONNECTED:
option.onCastAvailable?.(true);
break;
case CastState.CONNECTING:
case CastState.CONNECTED:
option.onCastAvailable?.(true);
break;
}
});
isCastInitialized = true;
resolve();
} else {
reject(new Error("Cast API is not available"));
}
};
if (!window.chrome || !window.chrome.cast) {
loadScript(option.sdk || DEFAULT_SDK).catch(reject);
}
});
};
const castVideo = (art, session) => {
const url = option.url || art.option.url;
const mediaInfo = new window.chrome.cast.media.MediaInfo(url, option.mimeType || getMimeType(url));
const request = new window.chrome.cast.media.LoadRequest(mediaInfo);
session.loadMedia(request).then(() => {
art.notice.show = "Casting started";
option.onCastStart?.();
}).catch((error) => {
art.notice.show = "Error casting media";
option.onError?.(error);
throw error;
});
};
return async (art) => {
art.controls.add({
name: "chromecast",
position: "right",
tooltip: "Chromecast",
html: `<i class="art-icon art-icon-cast">${option.icon || DEFAULT_ICON}</i>`,
click: async () => {
if (!isCastInitialized) {
try {
await initializeCastApi();
} catch (error) {
art.notice.show = "Failed to initialize Cast API";
option.onError?.(error);
throw error;
}
}
const context = window.cast.framework.CastContext.getInstance();
if (castSession) {
castVideo(art, castSession);
} else {
try {
const session = await context.requestSession();
castVideo(art, session);
} catch (error) {
art.notice.show = "Error connecting to cast session";
option.onError?.(error);
throw error;
}
}
}
});
return {
name: "artplayerPluginChromecast",
getCastState: () => castState,
isCasting: () => castSession !== null
loading.subscribers.clear();
}
function available(value, errorInfo) {
try {
previous?.call(host, value, errorInfo);
} finally {
const sdk = value ? ready(host) : void 0;
finish(sdk, new Error("Cast API is not available"));
}
}
host.__onGCastApiAvailable = available;
try {
timer = host.setTimeout(() => finish(void 0, new Error("Timed out initializing Cast API")), 3e4);
script = document.createElement("script");
script.src = src || DEFAULT_SDK;
script.onerror = (error) => finish(void 0, error);
script.onload = () => {
const sdk = ready(host);
if (sdk)
finish(sdk);
};
};
document.body.appendChild(script);
} catch (error) {
finish(void 0, error);
}
return subscription;
}
function createController(art, option) {
let disposed = false;
let sdk;
let context;
let session = null;
let state = null;
let activeClick;
let releaseLoader;
let generation = 0;
let operationStarted = false;
let cancelOperation;
let cancel;
const cancelled = new Promise((resolve) => {
cancel = () => resolve(void 0);
});
let element;
const active = () => !disposed && !art.isDestroy;
const update = (value) => {
option.onStateChange?.(value);
if (!active())
return;
const button = element?.querySelector(".art-icon-cast");
if (button)
button.style.color = value === "connected" ? "red" : value === "connecting" || value === "disconnecting" ? "orange" : "white";
};
const onSession = (event) => {
if (!active() || !sdk)
return;
state = event.sessionState;
const states = sdk.framework.SessionState;
if (state === states.NO_SESSION || state === states.SESSION_ENDED || state === states.SESSION_START_FAILED) {
if (state !== states.NO_SESSION || operationStarted) {
generation++;
cancelOperation?.();
}
session = null;
update("disconnected");
} else {
if (state === states.SESSION_ENDING || session && event.session && event.session !== session) {
generation++;
cancelOperation?.();
}
session = event.session || null;
if (state === states.SESSION_STARTING)
update("connecting");
else if (state === states.SESSION_ENDING)
update("disconnecting");
else if (state === states.SESSION_STARTED || state === states.SESSION_RESUMED)
update("connected");
}
};
const onAvailability = (event) => {
if (!active() || !sdk)
return;
const states = sdk.framework.CastState;
if (event.castState === states.NO_DEVICES_AVAILABLE)
option.onCastAvailable?.(false);
else if (event.castState === states.NOT_CONNECTED || event.castState === states.CONNECTING || event.castState === states.CONNECTED)
option.onCastAvailable?.(true);
};
const detach = () => {
const ownedContext = context;
const ownedSdk = sdk;
context = void 0;
sdk = void 0;
if (ownedContext && ownedSdk) {
const events = ownedSdk.framework.CastContextEventType;
const errors = [];
try {
ownedContext.removeEventListener(events.SESSION_STATE_CHANGED, onSession);
} catch (error) {
errors.push(error);
}
try {
ownedContext.removeEventListener(events.CAST_STATE_CHANGED, onAvailability);
} catch (error) {
errors.push(error);
}
if (errors.length)
throw errors[0];
}
};
const destroy = () => {
if (disposed)
return;
disposed = true;
cancel();
const release = releaseLoader;
releaseLoader = void 0;
const errors = [];
for (const cleanup of [release, detach, () => art.off("destroy", destroy)]) {
try {
cleanup?.();
} catch (error) {
errors.push(error);
}
}
session = null;
element = void 0;
if (errors.length)
throw errors[0];
};
async function cast() {
const epoch = generation;
const currentOperation = () => active() && generation === epoch;
let stop;
const superseded = new Promise((resolve) => {
stop = () => resolve(void 0);
});
cancelOperation = stop;
let failureNotice = "Failed to initialize Cast API";
try {
if (!sdk || !context) {
const loading = loadSdk(option.sdk, (available) => {
if (!currentOperation())
return;
sdk = available;
context = configure(sdk);
if (!currentOperation())
return;
const events = sdk.framework.CastContextEventType;
try {
context.addEventListener(events.SESSION_STATE_CHANGED, onSession);
if (active())
context.addEventListener(events.CAST_STATE_CHANGED, onAvailability);
} catch (error) {
try {
detach();
} catch {
}
throw error;
}
});
releaseLoader = loading.release;
await Promise.race([loading.promise, cancelled, superseded]);
loading.release();
releaseLoader = void 0;
}
if (!currentOperation() || !context || !sdk)
return;
failureNotice = "Error connecting to cast session";
operationStarted = true;
let current = context.getCurrentSession();
if (!currentOperation())
return;
if (!current) {
await Promise.race([context.requestSession(), cancelled, superseded]);
if (!currentOperation())
return;
current = context.getCurrentSession();
}
if (!currentOperation())
return;
if (!current)
throw new Error("No active Cast session");
session = current;
failureNotice = "Error casting media";
await Promise.race([loadMedia(sdk, current, option, art.option.url), cancelled, superseded]);
if (currentOperation()) {
art.notice.show = "Casting started";
option.onCastStart?.();
}
} catch (error) {
if (currentOperation()) {
art.notice.show = failureNotice;
option.onError?.(error);
throw error;
}
} finally {
releaseLoader?.();
releaseLoader = void 0;
if (cancelOperation === stop)
cancelOperation = void 0;
operationStarted = false;
}
}
const click = () => {
if (!active())
return Promise.resolve();
if (!activeClick) {
let resolve;
let reject;
activeClick = new Promise((yes, no) => {
resolve = yes;
reject = no;
});
activeClick.catch(() => {
});
cast().then(() => {
activeClick = void 0;
resolve();
}, (error) => {
activeClick = void 0;
reject(error);
});
}
return activeClick;
};
art.controls.add({
name: "chromecast",
position: "right",
tooltip: "Chromecast",
html: `<i class="art-icon art-icon-cast">${option.icon || icon}</i>`,
mounted(control) {
if (active())
element = control;
},
click
});
art.on("destroy", destroy);
if (art.isDestroy)
destroy();
return { name: "artplayerPluginChromecast", getCastState: () => state, isCasting: () => session !== null };
}
function artplayerPluginChromecast(option) {
return async (art) => createController(art, option);
}
Object.defineProperty(artplayerPluginChromecast, "default", { value: artplayerPluginChromecast, writable: true, configurable: true });
export {
artplayerPluginChromecast as default
};
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-danmuku-mask.js v1.1.0
* artplayer-plugin-danmuku-mask.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerPluginDanmukuMask=t(),define(function(){return t.artplayerPluginDanmukuMask})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDanmukuMask=t()}(this,function(){"use strict";function e(e,t){for(var n=0;n<t.length;n++){const r=t[n];if("string"!==typeof r&&!Array.isArray(r))for(const t in r)if("default"!==t&&!(t in e)){const n=Object.getOwnPropertyDescriptor(r,t);n&&Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>r[t]})}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}class t{constructor(e,t){this.backend=e,this.dataMover=t,this.data=new WeakMap,this.dataIdsCount=0}get(e){return this.data.has(e)||this.dataMover.moveData(this.backend,e),this.data.get(e)}set(e,t){this.dataIdsCount++,this.data.set(e,t)}has(e){return this.data.has(e)}delete(e){return this.dataIdsCount--,this.data.delete(e)}numDataIds(){return this.dataIdsCount}}class n{refCount(e){return r("refCount")}incRef(e){return r("incRef")}timerAvailable(){return!0}time(e){return r("time")}read(e){return r("read")}readSync(e){return r("readSync")}readToGPU(e,t){return r("readToGPU")}numDataIds(){return r("numDataIds")}disposeData(e,t){return r("disposeData")}write(e,t,n){return r("write")}move(e,t,n,a,s){return r("move")}createTensorFromGPUData(e,t,n){return r("createTensorFromGPUData")}memory(){return r("memory")}floatPrecision(){return r("floatPrecision")}epsilon(){return 32===this.floatPrecision()?1e-7:1e-4}dispose(){return r("dispose")}}function r(e){throw new Error(`'${e}' not yet implemented or not found in the registry. This kernel may not be supported by the tfjs backend you have chosen`)}function a(e,t,n){return Math.max(e,Math.min(t,n))}function s(e){return e%2===0?e:e+1}function o(e,t,n){const r=e[t];e[t]=e[n],e[n]=r}function i(e,t){if(!e)throw new Error("string"===typeof t?t:t())}function u(e,t,n=""){i(d(e,t),()=>n+` Shapes ${e} and ${t} must match`)}function l(e){i(null!=e,()=>"The input to the tensor constructor must be a non-null value.")}function c(e){if(0===e.length)return 1;let t=e[0];for(let n=1;n<e.length;n++)t*=e[n];return t}function d(e,t){if(e===t)return!0;if(null==e||null==t)return!1;if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(e[n]!==t[n])return!1;return!0}function p(e){return e%1===0}function h(e){const t=Math.ceil(Math.sqrt(e));return[t,Math.ceil(e/t)]}function f(e,t){return t<=e.length?e:e+" ".repeat(t-e.length)}function m(e,t=e=>0,n,r){return new Promise((a,s)=>{let o=0;const i=()=>{if(e())return void a();o++;const u=t(o);null!=n&&o>=n?s():null!=r?r(i,u):setTimeout(i,u)};i()})}function g(e,t){let n=1,r=-1;for(let s=0;s<e.length;++s)if(e[s]>=0)n*=e[s];else if(-1===e[s]){if(-1!==r)throw Error(`Shapes can only have 1 implicit size. Found -1 at dim ${r} and dim ${s}`);r=s}else if(e[s]<0)throw Error(`Shapes can not be < 0. Found ${e[s]} at dim ${s}`);if(-1===r){if(t>0&&t!==n)throw Error(`Size(${t}) must match the product of shape ${e}`);return e}if(0===n)throw Error(`Cannot infer the missing size in [${e}] when there are 0 elements`);if(t%n!==0)throw Error(`The implicit shape can't be a fractional number. Got ${t} / ${n}`);const a=e.slice();return a[r]=t/n,a}function y(e,t){const n=t.length;return i((e=null==e?t.map((e,t)=>t):[].concat(e)).every(e=>e>=-n&&e<n),()=>`All values in axis param must be in range [-${n}, ${n}) but got axis ${e}`),i(e.every(e=>p(e)),()=>`All values in axis param must be integers but got axis ${e}`),e.map(e=>e<0?n+e:e)}function b(e,t){const n=[],r=[],a=null!=t&&Array.isArray(t)&&0===t.length,s=null==t||a?null:y(t,e).sort();let o=0;for(let i=0;i<e.length;++i){if(null!=s){if(s[o]===i&&1!==e[i])throw new Error(`Can't squeeze axis ${i} since its dim '${e[i]}' is not 1`);(null==s[o]||s[o]>i)&&1===e[i]&&(n.push(e[i]),r.push(i)),s[o]<=i&&o++}1!==e[i]&&(n.push(e[i]),r.push(i))}return{newShape:n,keptDims:r}}function x(e,t){return v(e,t)}function v(e,t){let n=null;if(null==e||"float32"===e)n=new Float32Array(t);else if("int32"===e)n=new Int32Array(t);else if("bool"===e)n=new Uint8Array(t);else{if("string"!==e)throw new Error(`Unknown data type ${e}`);n=new Array(t)}return n}function w(e,t){return"complex64"!==t&&(("float32"!==t||"complex64"===e)&&(("int32"!==t||"float32"===e||"complex64"===e)&&("bool"!==t||"bool"!==e)))}function k(e){if("float32"===e||"int32"===e)return 4;if("complex64"===e)return 8;if("bool"===e)return 1;throw new Error(`Unknown dtype ${e}`)}function I(e){return"string"===typeof e||e instanceof String}function N(e){return Array.isArray(e)?N(e[0]):e instanceof Float32Array?"float32":e instanceof Int32Array||e instanceof Uint8Array||e instanceof Uint8ClampedArray?"int32":"number"===typeof e?"float32":I(e)?"string":function(e){return"boolean"===typeof e}(e)?"bool":"float32"}function S(e){return!!(e&&e.constructor&&e.call&&e.apply)}function T(e,t){for(let n=t;n<e;++n)if(e%n===0)return nLine truncated
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginDanmukuMask=t(),define(function(){return e.artplayerPluginDanmukuMask})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDanmukuMask=t()}(this,function(){"use strict";function e(e,t){for(var n=0;n<t.length;n++){const r=t[n];if("string"!==typeof r&&!Array.isArray(r))for(const t in r)if("default"!==t&&!(t in e)){const n=Object.getOwnPropertyDescriptor(r,t);n&&Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>r[t]})}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}class t{constructor(e,t){this.backend=e,this.dataMover=t,this.data=new WeakMap,this.dataIdsCount=0}get(e){return this.data.has(e)||this.dataMover.moveData(this.backend,e),this.data.get(e)}set(e,t){this.dataIdsCount++,this.data.set(e,t)}has(e){return this.data.has(e)}delete(e){return this.dataIdsCount--,this.data.delete(e)}numDataIds(){return this.dataIdsCount}}class n{refCount(e){return r("refCount")}incRef(e){return r("incRef")}timerAvailable(){return!0}time(e){return r("time")}read(e){return r("read")}readSync(e){return r("readSync")}readToGPU(e,t){return r("readToGPU")}numDataIds(){return r("numDataIds")}disposeData(e,t){return r("disposeData")}write(e,t,n){return r("write")}move(e,t,n,a,s){return r("move")}createTensorFromGPUData(e,t,n){return r("createTensorFromGPUData")}memory(){return r("memory")}floatPrecision(){return r("floatPrecision")}epsilon(){return 32===this.floatPrecision()?1e-7:1e-4}dispose(){return r("dispose")}}function r(e){throw new Error(`'${e}' not yet implemented or not found in the registry. This kernel may not be supported by the tfjs backend you have chosen`)}function a(e,t,n){return Math.max(e,Math.min(t,n))}function s(e){return e%2===0?e:e+1}function o(e,t,n){const r=e[t];e[t]=e[n],e[n]=r}function i(e,t){if(!e)throw new Error("string"===typeof t?t:t())}function u(e,t,n=""){i(d(e,t),()=>n+` Shapes ${e} and ${t} must match`)}function l(e){i(null!=e,()=>"The input to the tensor constructor must be a non-null value.")}function c(e){if(0===e.length)return 1;let t=e[0];for(let n=1;n<e.length;n++)t*=e[n];return t}function d(e,t){if(e===t)return!0;if(null==e||null==t)return!1;if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(e[n]!==t[n])return!1;return!0}function p(e){return e%1===0}function h(e){const t=Math.ceil(Math.sqrt(e));return[t,Math.ceil(e/t)]}function f(e,t){return t<=e.length?e:e+" ".repeat(t-e.length)}function m(e,t=e=>0,n,r){return new Promise((a,s)=>{let o=0;const i=()=>{if(e())return void a();o++;const u=t(o);null!=n&&o>=n?s():null!=r?r(i,u):setTimeout(i,u)};i()})}function g(e,t){let n=1,r=-1;for(let s=0;s<e.length;++s)if(e[s]>=0)n*=e[s];else if(-1===e[s]){if(-1!==r)throw Error(`Shapes can only have 1 implicit size. Found -1 at dim ${r} and dim ${s}`);r=s}else if(e[s]<0)throw Error(`Shapes can not be < 0. Found ${e[s]} at dim ${s}`);if(-1===r){if(t>0&&t!==n)throw Error(`Size(${t}) must match the product of shape ${e}`);return e}if(0===n)throw Error(`Cannot infer the missing size in [${e}] when there are 0 elements`);if(t%n!==0)throw Error(`The implicit shape can't be a fractional number. Got ${t} / ${n}`);const a=e.slice();return a[r]=t/n,a}function y(e,t){const n=t.length;return i((e=null==e?t.map((e,t)=>t):[].concat(e)).every(e=>e>=-n&&e<n),()=>`All values in axis param must be in range [-${n}, ${n}) but got axis ${e}`),i(e.every(e=>p(e)),()=>`All values in axis param must be integers but got axis ${e}`),e.map(e=>e<0?n+e:e)}function b(e,t){const n=[],r=[],a=null!=t&&Array.isArray(t)&&0===t.length,s=null==t||a?null:y(t,e).sort();let o=0;for(let i=0;i<e.length;++i){if(null!=s){if(s[o]===i&&1!==e[i])throw new Error(`Can't squeeze axis ${i} since its dim '${e[i]}' is not 1`);(null==s[o]||s[o]>i)&&1===e[i]&&(n.push(e[i]),r.push(i)),s[o]<=i&&o++}1!==e[i]&&(n.push(e[i]),r.push(i))}return{newShape:n,keptDims:r}}function x(e,t){return v(e,t)}function v(e,t){let n=null;if(null==e||"float32"===e)n=new Float32Array(t);else if("int32"===e)n=new Int32Array(t);else if("bool"===e)n=new Uint8Array(t);else{if("string"!==e)throw new Error(`Unknown data type ${e}`);n=new Array(t)}return n}function w(e,t){return"complex64"!==t&&(("float32"!==t||"complex64"===e)&&(("int32"!==t||"float32"===e||"complex64"===e)&&("bool"!==t||"bool"!==e)))}function k(e){if("float32"===e||"int32"===e)return 4;if("complex64"===e)return 8;if("bool"===e)return 1;throw new Error(`Unknown dtype ${e}`)}function I(e){return"string"===typeof e||e instanceof String}function N(e){return Array.isArray(e)?N(e[0]):e instanceof Float32Array?"float32":e instanceof Int32Array||e instanceof Uint8Array||e instanceof Uint8ClampedArray?"int32":"number"===typeof e?"float32":I(e)?"string":function(e){return"boolean"===typeof e}(e)?"bool":"float32"}function S(e){return!!(e&&e.constructor&&e.call&&e.apply)}function T(e,t){for(let n=t;n<e;++n)if(e%n===0)return nLine truncated
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-danmuku-mask.js v1.1.0
* artplayer-plugin-danmuku-mask.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerPluginDanmukuMask=t(),define(function(){return t.artplayerPluginDanmukuMask})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDanmukuMask=t()}(this,function(){"use strict";var e=(e,t,n)=>new Promise((r,a)=>{var s=e=>{try{i(n.next(e))}catch(t){a(t)}},o=e=>{try{i(n.throw(e))}catch(t){a(t)}},i=e=>e.done?r(e.value):Promise.resolve(e.value).then(s,o);i((n=n.apply(e,t)).next())});function t(e,t){for(var n=0;n<t.length;n++){const r=t[n];if("string"!==typeof r&&!Array.isArray(r))for(const t in r)if("default"!==t&&!(t in e)){const n=Object.getOwnPropertyDescriptor(r,t);n&&Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>r[t]})}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}class n{constructor(e,t){this.backend=e,this.dataMover=t,this.data=new WeakMap,this.dataIdsCount=0}get(e){return this.data.has(e)||this.dataMover.moveData(this.backend,e),this.data.get(e)}set(e,t){this.dataIdsCount++,this.data.set(e,t)}has(e){return this.data.has(e)}delete(e){return this.dataIdsCount--,this.data.delete(e)}numDataIds(){return this.dataIdsCount}}class r{refCount(e){return a("refCount")}incRef(e){return a("incRef")}timerAvailable(){return!0}time(e){return a("time")}read(e){return a("read")}readSync(e){return a("readSync")}readToGPU(e,t){return a("readToGPU")}numDataIds(){return a("numDataIds")}disposeData(e,t){return a("disposeData")}write(e,t,n){return a("write")}move(e,t,n,r,s){return a("move")}createTensorFromGPUData(e,t,n){return a("createTensorFromGPUData")}memory(){return a("memory")}floatPrecision(){return a("floatPrecision")}epsilon(){return 32===this.floatPrecision()?1e-7:1e-4}dispose(){return a("dispose")}}function a(e){throw new Error(`'${e}' not yet implemented or not found in the registry. This kernel may not be supported by the tfjs backend you have chosen`)}function s(e,t,n){return Math.max(e,Math.min(t,n))}function o(e){return e%2===0?e:e+1}function i(e,t,n){const r=e[t];e[t]=e[n],e[n]=r}function u(e,t){if(!e)throw new Error("string"===typeof t?t:t())}function l(e,t,n=""){u(p(e,t),()=>n+` Shapes ${e} and ${t} must match`)}function c(e){u(null!=e,()=>"The input to the tensor constructor must be a non-null value.")}function d(e){if(0===e.length)return 1;let t=e[0];for(let n=1;n<e.length;n++)t*=e[n];return t}function p(e,t){if(e===t)return!0;if(null==e||null==t)return!1;if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(e[n]!==t[n])return!1;return!0}function h(e){return e%1===0}function f(e){const t=Math.ceil(Math.sqrt(e));return[t,Math.ceil(e/t)]}function m(e,t){return t<=e.length?e:e+" ".repeat(t-e.length)}function g(e,t=e=>0,n,r){return new Promise((a,s)=>{let o=0;const i=()=>{if(e())return void a();o++;const u=t(o);null!=n&&o>=n?s():null!=r?r(i,u):setTimeout(i,u)};i()})}function y(e,t){let n=1,r=-1;for(let s=0;s<e.length;++s)if(e[s]>=0)n*=e[s];else if(-1===e[s]){if(-1!==r)throw Error(`Shapes can only have 1 implicit size. Found -1 at dim ${r} and dim ${s}`);r=s}else if(e[s]<0)throw Error(`Shapes can not be < 0. Found ${e[s]} at dim ${s}`);if(-1===r){if(t>0&&t!==n)throw Error(`Size(${t}) must match the product of shape ${e}`);return e}if(0===n)throw Error(`Cannot infer the missing size in [${e}] when there are 0 elements`);if(t%n!==0)throw Error(`The implicit shape can't be a fractional number. Got ${t} / ${n}`);const a=e.slice();return a[r]=t/n,a}function b(e,t){const n=t.length;return u((e=null==e?t.map((e,t)=>t):[].concat(e)).every(e=>e>=-n&&e<n),()=>`All values in axis param must be in range [-${n}, ${n}) but got axis ${e}`),u(e.every(e=>h(e)),()=>`All values in axis param must be integers but got axis ${e}`),e.map(e=>e<0?n+e:e)}function x(e,t){const n=[],r=[],a=null!=t&&Array.isArray(t)&&0===t.length,s=null==t||a?null:b(t,e).sort();let o=0;for(let i=0;i<e.length;++i){if(null!=s){if(s[o]===i&&1!==e[i])throw new Error(`Can't squeeze axis ${i} since its dim '${e[i]}' is not 1`);(null==s[o]||s[o]>i)&&1===e[i]&&(n.push(e[i]),r.push(i)),s[o]<=i&&o++}1!==e[i]&&(n.push(e[i]),r.push(i))}return{newShape:n,keptDims:r}}function v(e,t){return w(e,t)}function w(e,t){let n=null;if(null==e||"float32"===e)n=new Float32Array(t);else if("int32"===e)n=new Int32Array(t);else if("bool"===e)n=new Uint8Array(t);else{if("string"!==e)throw new Error(`Unknown data type ${e}`);n=new Array(t)}return n}function k(e,t){return"complex64"!==t&&(("float32"!==t||"complex64"===e)&&(("int32"!==t||"float32"===e||"complex64"===e)&&("bool"!==t||"bool"!==e)))}function I(e){if("float32"===e||"int32"===e)return 4;if("complex64"===e)return 8;if("bool"===e)return 1;throw new Error(`Unknown dtype ${e}`)}function N(e){return"string"===typeof e||e instanceof String}function S(e){return Array.isArray(e)?S(e[0]):e instanceof Float32Array?"float32":e instanceof Int32Array||e instanceof Uint8Array||e instanceof Uint8ClampedArray?"int32":"number"===tLine truncated
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginDanmukuMask=t(),define(function(){return e.artplayerPluginDanmukuMask})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDanmukuMask=t()}(this,function(){"use strict";var e=(e,t,n)=>new Promise((r,a)=>{var s=e=>{try{i(n.next(e))}catch(t){a(t)}},o=e=>{try{i(n.throw(e))}catch(t){a(t)}},i=e=>e.done?r(e.value):Promise.resolve(e.value).then(s,o);i((n=n.apply(e,t)).next())});function t(e,t){for(var n=0;n<t.length;n++){const r=t[n];if("string"!==typeof r&&!Array.isArray(r))for(const t in r)if("default"!==t&&!(t in e)){const n=Object.getOwnPropertyDescriptor(r,t);n&&Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>r[t]})}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}class n{constructor(e,t){this.backend=e,this.dataMover=t,this.data=new WeakMap,this.dataIdsCount=0}get(e){return this.data.has(e)||this.dataMover.moveData(this.backend,e),this.data.get(e)}set(e,t){this.dataIdsCount++,this.data.set(e,t)}has(e){return this.data.has(e)}delete(e){return this.dataIdsCount--,this.data.delete(e)}numDataIds(){return this.dataIdsCount}}class r{refCount(e){return a("refCount")}incRef(e){return a("incRef")}timerAvailable(){return!0}time(e){return a("time")}read(e){return a("read")}readSync(e){return a("readSync")}readToGPU(e,t){return a("readToGPU")}numDataIds(){return a("numDataIds")}disposeData(e,t){return a("disposeData")}write(e,t,n){return a("write")}move(e,t,n,r,s){return a("move")}createTensorFromGPUData(e,t,n){return a("createTensorFromGPUData")}memory(){return a("memory")}floatPrecision(){return a("floatPrecision")}epsilon(){return 32===this.floatPrecision()?1e-7:1e-4}dispose(){return a("dispose")}}function a(e){throw new Error(`'${e}' not yet implemented or not found in the registry. This kernel may not be supported by the tfjs backend you have chosen`)}function s(e,t,n){return Math.max(e,Math.min(t,n))}function o(e){return e%2===0?e:e+1}function i(e,t,n){const r=e[t];e[t]=e[n],e[n]=r}function u(e,t){if(!e)throw new Error("string"===typeof t?t:t())}function l(e,t,n=""){u(p(e,t),()=>n+` Shapes ${e} and ${t} must match`)}function c(e){u(null!=e,()=>"The input to the tensor constructor must be a non-null value.")}function d(e){if(0===e.length)return 1;let t=e[0];for(let n=1;n<e.length;n++)t*=e[n];return t}function p(e,t){if(e===t)return!0;if(null==e||null==t)return!1;if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(e[n]!==t[n])return!1;return!0}function h(e){return e%1===0}function f(e){const t=Math.ceil(Math.sqrt(e));return[t,Math.ceil(e/t)]}function m(e,t){return t<=e.length?e:e+" ".repeat(t-e.length)}function g(e,t=e=>0,n,r){return new Promise((a,s)=>{let o=0;const i=()=>{if(e())return void a();o++;const u=t(o);null!=n&&o>=n?s():null!=r?r(i,u):setTimeout(i,u)};i()})}function y(e,t){let n=1,r=-1;for(let s=0;s<e.length;++s)if(e[s]>=0)n*=e[s];else if(-1===e[s]){if(-1!==r)throw Error(`Shapes can only have 1 implicit size. Found -1 at dim ${r} and dim ${s}`);r=s}else if(e[s]<0)throw Error(`Shapes can not be < 0. Found ${e[s]} at dim ${s}`);if(-1===r){if(t>0&&t!==n)throw Error(`Size(${t}) must match the product of shape ${e}`);return e}if(0===n)throw Error(`Cannot infer the missing size in [${e}] when there are 0 elements`);if(t%n!==0)throw Error(`The implicit shape can't be a fractional number. Got ${t} / ${n}`);const a=e.slice();return a[r]=t/n,a}function b(e,t){const n=t.length;return u((e=null==e?t.map((e,t)=>t):[].concat(e)).every(e=>e>=-n&&e<n),()=>`All values in axis param must be in range [-${n}, ${n}) but got axis ${e}`),u(e.every(e=>h(e)),()=>`All values in axis param must be integers but got axis ${e}`),e.map(e=>e<0?n+e:e)}function x(e,t){const n=[],r=[],a=null!=t&&Array.isArray(t)&&0===t.length,s=null==t||a?null:b(t,e).sort();let o=0;for(let i=0;i<e.length;++i){if(null!=s){if(s[o]===i&&1!==e[i])throw new Error(`Can't squeeze axis ${i} since its dim '${e[i]}' is not 1`);(null==s[o]||s[o]>i)&&1===e[i]&&(n.push(e[i]),r.push(i)),s[o]<=i&&o++}1!==e[i]&&(n.push(e[i]),r.push(i))}return{newShape:n,keptDims:r}}function v(e,t){return w(e,t)}function w(e,t){let n=null;if(null==e||"float32"===e)n=new Float32Array(t);else if("int32"===e)n=new Int32Array(t);else if("bool"===e)n=new Uint8Array(t);else{if("string"!==e)throw new Error(`Unknown data type ${e}`);n=new Array(t)}return n}function k(e,t){return"complex64"!==t&&(("float32"!==t||"complex64"===e)&&(("int32"!==t||"float32"===e||"complex64"===e)&&("bool"!==t||"bool"!==e)))}function I(e){if("float32"===e||"int32"===e)return 4;if("complex64"===e)return 8;if("bool"===e)return 1;throw new Error(`Unknown dtype ${e}`)}function N(e){return"string"===typeof e||e instanceof String}function S(e){return Array.isArray(e)?S(e[0]):e instanceof Float32Array?"float32":e instanceof Int32Array||e instanceof Uint8Array||e instanceof Uint8ClampedArray?"int32":"number"===tLine truncated
+271 -108
View File
@@ -1,5 +1,5 @@
/*!
* artplayer-plugin-danmuku-mask.js v1.1.0
* artplayer-plugin-danmuku-mask.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
@@ -23,6 +23,20 @@ function _mergeNamespaces(n, m) {
}
return Object.freeze(Object.defineProperty(n, Symbol.toStringTag, { value: "Module" }));
}
function maskConfig(option) {
return {
solutionPath: option.solutionPath || "https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation",
modelSelection: option.modelSelection || 1,
smoothSegmentation: option.smoothSegmentation !== void 0 ? option.smoothSegmentation : true,
minDetectionConfidence: option.minDetectionConfidence || 0.5,
minTrackingConfidence: option.minTrackingConfidence || 0.5,
selfieMode: option.selfieMode || false,
drawContour: option.drawContour || false,
foregroundThreshold: option.foregroundThreshold || 0.5,
opacity: option.opacity || 1,
maskBlurAmount: option.maskBlurAmount || 3
};
}
const EPSILON_FLOAT32$1 = 1e-7;
const EPSILON_FLOAT16$1 = 1e-4;
class DataStorage {
@@ -49040,129 +49054,278 @@ const kernelConfigs = [
for (const kernelConfig of kernelConfigs) {
registerKernel(kernelConfig);
}
function artplayerPluginDanmukuMask(option = {}) {
return (art) => {
const {
template: { $video, $danmuku }
} = art;
let segmenter = null;
let canvas = null;
let ctx = null;
let animationFrameId = null;
let isInitialized = false;
const config = {
solutionPath: option.solutionPath || "https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation",
modelSelection: option.modelSelection || 1,
smoothSegmentation: option.smoothSegmentation !== void 0 ? option.smoothSegmentation : true,
minDetectionConfidence: option.minDetectionConfidence || 0.5,
minTrackingConfidence: option.minTrackingConfidence || 0.5,
selfieMode: option.selfieMode || false,
drawContour: option.drawContour || false,
foregroundThreshold: option.foregroundThreshold || 0.5,
opacity: option.opacity || 1,
maskBlurAmount: option.maskBlurAmount || 3
async function loadSegmenter(config, active) {
try {
await setBackend("webgl");
} catch (error) {
if (!active())
return null;
console.warn("WebGL backend not available, falling back to CPU", error.message);
await setBackend("cpu");
}
if (!active())
return null;
try {
return await ke(Se.MediaPipeSelfieSegmentation, {
runtime: "mediapipe",
modelType: "general",
solutionPath: config.solutionPath,
modelSelection: config.modelSelection,
smoothSegmentation: config.smoothSegmentation,
minDetectionConfidence: config.minDetectionConfidence,
minTrackingConfidence: config.minTrackingConfidence,
selfieMode: config.selfieMode
});
} catch (error) {
if (active())
console.error("Error initializing segmenter:", error);
return null;
}
}
async function releaseSegmenter(segmenter) {
try {
await segmenter.dispose();
} catch (error) {
console.warn("Failed to dispose danmuku mask segmenter:", error);
}
}
const toBinaryMask = (...args) => Ue(...args);
const drawMask = (...args) => Ne(...args);
function makeWhiteTransparent(imageData) {
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
if (data[i] > 250 && data[i + 1] > 250 && data[i + 2] > 250)
data[i + 3] = 0;
}
return imageData;
}
function createOutput(layer) {
const canvas = document.createElement("canvas");
try {
const ctx = canvas.getContext("2d");
if (!ctx)
throw new Error("Danmuku mask requires a 2D canvas context");
Object.assign(layer.style, {
maskMode: "alpha",
maskSize: "contain",
maskRepeat: "no-repeat",
backgroundSize: "contain",
backgroundRepeat: "no-repeat"
});
return { canvas, ctx };
} catch (error) {
canvas.width = 0;
canvas.height = 0;
throw error;
}
}
async function renderMask(output, video, layer, segmenter, config, active) {
const { canvas, ctx } = output;
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
const segmentation = await segmenter.segmentPeople(video);
if (!active() || !segmentation || !segmentation.length)
return;
const mask = await toBinaryMask(
segmentation,
{ r: 255, g: 255, b: 255, a: 255 },
{ r: 0, g: 0, b: 0, a: 255 },
config.drawContour,
config.foregroundThreshold
);
if (!active())
return;
await drawMask(canvas, video, mask, config.opacity, config.maskBlurAmount);
if (!active())
return;
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
ctx.putImageData(makeWhiteTransparent(imageData), 0, 0);
const url = canvas.toDataURL();
if (active())
layer.style.maskImage = `url(${url})`;
}
function releaseOutput(output) {
if (output) {
output.canvas.width = 0;
output.canvas.height = 0;
}
}
class MaskController {
constructor(art, config, { $video, $danmuku }) {
this.art = art;
this.config = config;
this.video = $video;
this.layer = $danmuku;
this.closed = art.isDestroy;
this.run = null;
this.tail = Promise.resolve();
this.start = this.start.bind(this);
this.stop = this.stop.bind(this);
this.destroy = this.destroy.bind(this);
this.ready = () => {
this.start().catch((error) => console.error("Failed to start danmuku mask:", error));
};
async function initTensorFlow() {
if (!this.closed) {
try {
await setBackend("webgl");
art.on("destroy", this.destroy);
if (!this.closed)
art.on("ready", this.ready);
} catch (error) {
console.warn("WebGL backend not available, falling back to CPU", error.message);
await setBackend("cpu");
}
}
async function initSegmenter() {
await initTensorFlow();
const model = Se.MediaPipeSelfieSegmentation;
const segmenterConfig = {
runtime: "mediapipe",
modelType: "general",
solutionPath: config.solutionPath,
modelSelection: config.modelSelection,
smoothSegmentation: config.smoothSegmentation,
minDetectionConfidence: config.minDetectionConfidence,
minTrackingConfidence: config.minTrackingConfidence,
selfieMode: config.selfieMode
};
try {
segmenter = await ke(model, segmenterConfig);
isInitialized = true;
} catch (error) {
console.error("Error initializing segmenter:", error);
isInitialized = false;
}
}
function setupDanmukuStyle() {
Object.assign($danmuku.style, {
maskMode: "alpha",
maskSize: "contain",
maskRepeat: "no-repeat",
backgroundSize: "contain",
backgroundRepeat: "no-repeat"
});
}
function createCanvas2() {
canvas = document.createElement("canvas");
ctx = canvas.getContext("2d");
}
function makeWhiteTransparent(imageData) {
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
if (data[i] > 250 && data[i + 1] > 250 && data[i + 2] > 250) {
data[i + 3] = 0;
this.closed = true;
this.halt();
try {
art.off("ready", this.ready);
} catch {
}
try {
art.off("destroy", this.destroy);
} catch {
}
throw error;
}
return imageData;
}
async function segmentBody() {
if (!isInitialized || $video.paused || $video.ended) {
animationFrameId = requestAnimationFrame(segmentBody);
return;
}
}
active(run) {
return run === this.run && run.running && !this.closed && !this.art.isDestroy;
}
release(run) {
if (run.releasing)
return run.releasing;
const segmenter = run.segmenter;
run.segmenter = null;
const output = run.output;
run.output = null;
run.releasing = (async () => {
await Promise.resolve();
try {
canvas.width = $video.videoWidth;
canvas.height = $video.videoHeight;
const segmentation = await segmenter.segmentPeople($video);
if (!segmentation || segmentation.length === 0) {
animationFrameId = requestAnimationFrame(segmentBody);
releaseOutput(output);
} finally {
if (segmenter)
await releaseSegmenter(segmenter);
}
})();
return run.releasing;
}
schedule(run) {
if (!this.active(run) || run.frame !== null || run.busy)
return;
run.frame = requestAnimationFrame(() => {
run.frame = null;
this.tick(run);
});
}
tick(run) {
if (!this.active(run) || run.busy)
return;
const video = this.video;
if (video.paused || video.ended || !(video.videoWidth > 0 && video.videoHeight > 0)) {
this.schedule(run);
return;
}
run.busy = true;
const work = (async () => {
try {
await Promise.resolve();
if (this.active(run))
await renderMask(run.output, video, this.layer, run.segmenter, this.config, () => this.active(run));
} catch (error) {
if (this.active(run))
console.error("Error in segmentBody:", error);
} finally {
run.busy = false;
if (!this.active(run))
await this.release(run);
else this.schedule(run);
}
})();
this.tail = work.catch((error) => console.warn("Failed to release danmuku mask resources:", error));
}
async start() {
if (this.closed || this.art.isDestroy)
return;
if (this.run?.running)
return this.run.started;
let cancel;
const cancelled = new Promise((resolve) => cancel = resolve);
const run = { running: true, initializing: true, busy: false, frame: null, segmenter: null, output: null, cancel, started: null };
const previous = this.tail;
this.run = run;
const initialize = (async () => {
try {
await previous;
if (!this.active(run))
return;
if (!this.video || !this.layer?.style)
throw new Error("Danmuku mask requires core video and danmuku template nodes");
run.segmenter = await loadSegmenter(this.config, () => this.active(run));
if (!this.active(run))
return;
if (!run.segmenter) {
run.running = false;
return;
}
const foregroundColor = { r: 255, g: 255, b: 255, a: 255 };
const backgroundColor = { r: 0, g: 0, b: 0, a: 255 };
const mask = await Ue(
segmentation,
foregroundColor,
backgroundColor,
config.drawContour,
config.foregroundThreshold
);
await Ne(canvas, $video, mask, config.opacity, config.maskBlurAmount);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
ctx.putImageData(makeWhiteTransparent(imageData), 0, 0);
$danmuku.style.maskImage = `url(${canvas.toDataURL()})`;
run.output = createOutput(this.layer);
} catch (error) {
console.error("Error in segmentBody:", error);
if (this.active(run)) {
run.running = false;
throw error;
}
} finally {
run.initializing = false;
if (!this.active(run))
await this.release(run);
}
animationFrameId = requestAnimationFrame(segmentBody);
if (this.active(run))
this.tick(run);
})();
this.tail = initialize.catch(() => {
});
run.started = Promise.race([initialize, cancelled]);
return run.started;
}
halt() {
const run = this.run;
if (run) {
run.running = false;
run.cancel();
if (run.frame !== null) {
cancelAnimationFrame(run.frame);
run.frame = null;
}
if (!run.initializing && !run.busy)
this.tail = this.release(run).catch((error) => console.warn("Failed to release danmuku mask resources:", error));
}
}
stop() {
this.halt();
if (this.layer?.style)
this.layer.style.maskImage = "none";
}
destroy() {
if (this.closed)
return;
this.closed = true;
try {
this.stop();
} finally {
try {
this.art.off("ready", this.ready);
} finally {
this.art.off("destroy", this.destroy);
}
}
}
}
function artplayerPluginDanmukuMask(option = {}) {
return (art) => {
const { template: { $video, $danmuku } } = art;
const controller = new MaskController(art, maskConfig(option), { $video, $danmuku });
async function startSegmentation() {
if (!isInitialized) {
await initSegmenter();
}
if (!canvas) {
createCanvas2();
}
setupDanmukuStyle();
segmentBody();
await controller.start();
}
function stopSegmentation() {
$danmuku.style.maskImage = "none";
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
animationFrameId = null;
}
controller.stop();
}
art.on("ready", startSegmentation);
art.on("destroy", stopSegmentation);
return {
name: "artplayerPluginDanmukuMask",
start: startSegmentation,
+2 -2
View File
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-danmuku.js v5.3.0
* artplayer-plugin-danmuku.js v6.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDanmuku=e(),define(function(){return t.artplayerPluginDanmuku})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDanmuku=e()}(this,function(){"use strict";function t(t){switch(t){case 1:case 2:case 3:default:return 0;case 4:return 2;case 5:return 1}}function e(e){if("string"!==typeof e)return[];const i=e.matchAll(/<d[^>]*?p="(?<p>[^"]+)"[^>]*>(?<text>.*?)<\/d>/gs);return Array.from(i).map(e=>{const i=e.groups.p.split(",");if(i.length>=8){return{text:e.groups.text.trim().replaceAll("&quot;",'"').replaceAll("&apos;","'").replaceAll("&lt;","<").replaceAll("&gt;",">").replaceAll("&amp;","&"),time:Number(i[0]),mode:t(Number(i[1])),fontSize:Number(i[2]),color:`#${Number(i[3]).toString(16)}`,timestamp:Number(i[4]),pool:Number(i[5]),userID:i[6],rowID:Number(i[7])}}return null}).filter(Boolean)}function i({data:t}){const{xml:i,id:a}=t;if(!a||!i)return;const n=e(i);globalThis.postMessage({danmus:n,id:a})}function a(){const a=`\n ${t.toString()}\n ${e.toString()}\n onmessage = ${i.toString()}\n `,n=new Blob([a],{type:"application/javascript"});return new Worker(URL.createObjectURL(n))}const n='/*!\n * artplayer-plugin-danmuku.js v5.3.0\n * Github: https://github.com/zhw2590582/ArtPlayer\n * (c) 2017-2026 Harvey Zhao\n * Released under the MIT License.\n */\nfunction t({target:t,visibles:e,clientWidth:i,clientHeight:h,marginBottom:n,marginTop:o,antiOverlap:s}){const r=h-n,p=e.filter(e=>e.mode===t.mode&&e.top<=r).sort((t,e)=>t.top-e.top);if(0===p.length)return 2===t.mode?r-t.height:o;if(p.unshift({type:"top",top:0,left:0,right:0,height:o,width:i,speed:0,distance:i}),p.push({type:"bottom",top:r,left:0,right:0,height:n,width:i,speed:0,distance:i}),2===t.mode)for(let g=p.length-2;g>=0;g-=1){const e=p[g],i=p[g+1],h=e.top+e.height;if(i.top-h>=t.height)return i.top-t.height}else for(let g=1;g<p.length;g+=1){const e=p[g],i=p[g-1],h=i.top+i.height;if(e.top-h>=t.height)return h}const a=[];for(let g=1;g<p.length-1;g+=1){const t=p[g];if(a.length){const e=a[a.length-1];e[0].top===t.top?e.push(t):a.push([t])}else a.push([t])}if(!s){switch(t.mode){case 0:a.sort((t,e)=>{const i=Math.min(...e.map(t=>t.right)),h=Math.min(...t.map(t=>t.right));return i*e.length-h*t.length});break;case 1:case 2:a.sort((t,e)=>{const i=Math.max(...e.map(t=>t.width));return Math.max(...t.map(t=>t.width))*t.length-i*e.length})}return a[0][0].top}switch(t.mode){case 0:{const e=a.find(e=>e.every(e=>{if(i<e.distance)return!1;if(t.speed<e.speed)return!0;return e.right/(t.speed-e.speed)>e.time}));return e&&e[0]?e[0].top:void 0}case 1:case 2:return}}onmessage=e=>{const{data:i}=e;if(!i.id||!i.type)return;const h=(0,{getDanmuTop:t}[i.type])(i);globalThis.postMessage({result:h,id:i.id})};\n',s="undefined"!==typeof self&&self.Blob&&new Blob(["URL.revokeObjectURL(import.meta.url);",n],{type:"text/javascript;charset=utf-8"});function o(t){let e;try{if(e=s&&(self.URL||self.webkitURL).createObjectURL(s),!e)throw"";const i=new Worker(e,{type:"module",name:t?.name});return i.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(e)}),i}catch(i){return new Worker("data:text/javascript;charset=utf-8,"+encodeURIComponent(n),{type:"module",name:t?.name})}}class r{constructor(t,e){const{constructor:i,template:a}=t;this.utils=i.utils,this.validator=i.validator,this.$danmuku=a.$danmuku,this.$player=a.$player,this.art=t,this.queue=[],this.$refs=[],this.isStop=!1,this.isHide=!1,this.timer=null,this.index=0,this.option=r.option,this.states={wait:[],ready:[],emit:[],stop:[]},this.config(e,!0),this.worker=new o,this.start=this.start.bind(this),this.stop=this.stop.bind(this),this.reset=this.reset.bind(this),this.resize=this.resize.bind(this),this.destroy=this.destroy.bind(this),t.on("video:play",this.start),t.on("video:playing",this.start),t.on("video:pause",this.stop),t.on("video:waiting",this.stop),t.on("destroy",this.destroy),t.on("resize",this.resize),this.load()}static get option(){return{danmuku:[],speed:5,margin:[10,"25%"],opacity:1,color:"#FFFFFF",mode:0,modes:[0,1,2],fontSize:25,antiOverlap:!0,synchronousPlayback:!1,mount:void 0,heatmap:!1,width:512,points:[],filter:()=>!0,beforeEmit:()=>!0,beforeVisible:()=>!0,visible:!0,emitter:!0,maxLength:200,lockTime:5,theme:"dark",OPACITY:{},FONT_SIZE:{},MARGIN:{},SPEED:{},COLOR:[]}}static get scheme(){return{danmuku:"array|function|string",speed:"number",margin:"array",opacity:"number",color:"string",mode:"number",modes:"array",fontSize:"number|string",antiOverlap:"boolean",synchronousPlayback:"boolean",mount:"?htmldivelement|string",heatmap:"object|boolean",width:"number",points:"array",filter:"function",beforeEmit:"function",beforeVisible:"function",visible:"boolean",emitter:"boolean",maxLength:"number",lockTime:"number",theme:"string",OPACITY:"object",FONT_SIZE:"object",MARGIN:"object",SPEED:"object",COLOR:"array"}}static get cssLine truncated
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDanmuku=e(),define(function(){return t.artplayerPluginDanmuku})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDanmuku=e()}(this,function(){"use strict";function t(t){return t instanceof Promise||"[object Promise]"===Object.prototype.toString.call(t)}function e(t){switch(t){case 1:case 2:case 3:default:return 0;case 4:return 2;case 5:return 1}}function i(t){if("string"!==typeof t)return[];const i=t.matchAll(/<d[^>]*?p="(?<p>[^"]+)"[^>]*>(?<text>.*?)<\/d>/gs);return Array.from(i).map(t=>{const i=t.groups.p.split(",");if(i.length>=8){return{text:t.groups.text.trim().replaceAll("&quot;",'"').replaceAll("&apos;","'").replaceAll("&lt;","<").replaceAll("&gt;",">").replaceAll("&amp;","&"),time:Number(i[0]),mode:e(Number(i[1])),fontSize:Number(i[2]),color:`#${Number(i[3]).toString(16)}`,timestamp:Number(i[4]),pool:Number(i[5]),userID:i[6],rowID:Number(i[7])}}return null}).filter(Boolean)}function n({data:t}){const{xml:e,id:n}=t,s=i(e);globalThis.postMessage({danmus:s,id:n})}let s=0;function a(t,{signal:a,onCancel:r}={}){return new Promise((o,l)=>{let d,h,c,p=!1;const u=++s,m=()=>g(void 0,function(t){if(void 0!==t?.reason)return t.reason;const e=new Error("Bilibili Danmu loading cancelled");return e.name="AbortError",e}(a));function f(){let t,e=!1;try{if(d){const t=d;d=void 0,t.onmessage=null,t.onerror=null,t.onmessageerror=null,t.terminate()}}catch(i){t=i,e=!0}if(void 0!==h){const n=h;h=void 0;try{URL.revokeObjectURL(n)}catch(i){e||(t=i),e=!0}}if(e)throw t}function g(t,e){if(p)return;p=!0;let i=arguments.length>1;a?.removeEventListener("abort",m),c?.();try{f()}catch(n){i||(e=n),i=!0}i?l(e):o(t)}function y(t,e){if(!p){console.error("Error parsing Bilibili Danmu:",e);try{g(i(t))}catch(n){g(void 0,n)}}}a?.aborted?m():(a?.addEventListener("abort",m),c=r?.(m),p?c?.():async function(){const s=a?await fetch(t,{signal:a}):await fetch(t);if(p)return;const r=await s.text();if(!p)try{const t=`\n ${e.toString()}\n ${i.toString()}\n onmessage = ${n.toString()}\n `;if(h=URL.createObjectURL(new Blob([t],{type:"application/javascript"})),p)return void f();if(d=new Worker(h),p)return void f();d.onmessage=t=>{if(p||t.data?.id!==u)return;const{danmus:e}=t.data;Array.isArray(e)?g(e):g(void 0,new Error("Invalid Bilibili Danmu worker response"))},d.onerror=t=>{t.preventDefault?.(),y(r,t.error||t)},d.onmessageerror=t=>y(r,t.error||t),d.postMessage({xml:r,id:u})}catch(o){y(r,o)}}().catch(t=>g(void 0,t)))})}const r=new WeakMap,o=Symbol("cancelled danmuku input");function l(t){return r.has(t)||r.set(t,{closed:!1,tasks:new Set,emitting:[]}),r.get(t)}function d(t){const e=l(t),i=e.emitting[e.emitting.length-1];return!e.closed&&!t.art.isDestroy&&(!i||i.active())}function h(t){const e=l(t);e.closed=!0;for(const i of[...e.tasks])i.cancel()}function c(t,e,i){const n=t.states[e]||[];for(let s=0;s<n.length;s++)i(n[s]);return n}class p{constructor(t){this.owner=t,this.nodes=new Set}acquire(){const t=this.owner.$refs.pop()||document.createElement("div");return t.style.cssText=this.owner.constructor.cssText,t.dataset.mode="",t.dataset.id="",t.className="",this.nodes.add(t),t}get visibles(){const t=[],{clientWidth:e}=this.owner.$player,i=this.owner.getLeft(this.owner.$player);return this.owner.filter("emit",n=>{const s=n.$ref.offsetTop,a=this.owner.getLeft(n.$ref)-i,r=n.$ref.clientHeight,o=n.$ref.clientWidth,l=a+o,d=e-l,h=l/n.$restTime,c={};c.top=s,c.left=a,c.height=r,c.width=o,c.right=d,c.speed=h,c.distance=l,c.time=n.$restTime,c.mode=n.mode,t.push(c)}),t}left(t){const e=t.getBoundingClientRect();return this.owner.isRotate?e.top:e.left}makeWait(t){this.owner.setState(t,"wait"),t.$ref&&(t.$ref.style.cssText=this.owner.constructor.cssText,t.$ref.style.visibility="hidden",t.$ref.style.marginLeft="0px",t.$ref.style.transform="translateX(0px)",t.$ref.style.transition="transform 0s linear 0s",this.owner.$refs.push(t.$ref),t.$ref=null)}resize(){const{clientWidth:t}=this.owner.$player;this.owner.filter("stop",e=>{if(0===e.mode)e.$ref.style.left=`${t}px`}),this.owner.filter("emit",e=>{switch(e.$lastStartTime=Date.now(),e.mode){case 0:{const i=t+e.$ref.clientWidth;e.$ref.style.left=`${t}px`,e.$ref.style.transform=`translateX(${-i}px)`,e.$ref.style.transition=`transform ${e.$restTime}s linear 0s`;break}}})}continue(){const{clientWidth:t}=this.owner.$player;return this.owner.filter("stop",e=>{switch(this.owner.setState(e,"emit"),e.$lastStartTime=Date.now(),e.mode){case 0:{const i=t+e.$ref.clientWidth;e.$ref.style.transform=`translateX(${-i}px)`,e.$ref.style.transition=`transform ${e.$restTime}s linear 0s`;break}}}),this}suspend(){const{clientWidth:t}=this.owner.$player;return this.owner.filter("emit",e=>{switch(this.owner.setState(e,"stop"),e.mode){case 0:{const i=t-(this.owner.getLeft(e.$ref)-this.owner.getLeft(this.owner.$player));e.$ref.style.transform=`translLine truncated
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-danmuku.js v5.3.0
* artplayer-plugin-danmuku.js v6.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDanmuku=e(),define(function(){return t.artplayerPluginDanmuku})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDanmuku=e()}(this,function(){"use strict";var t=Object.defineProperty,e=Object.defineProperties,i=Object.getOwnPropertyDescriptors,a=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,o=Math.pow,r=(e,i,a)=>i in e?t(e,i,{enumerable:!0,configurable:!0,writable:!0,value:a}):e[i]=a,l=(t,e)=>{for(var i in e||(e={}))n.call(e,i)&&r(t,i,e[i]);if(a)for(var i of a(e))s.call(e,i)&&r(t,i,e[i]);return t},d=(t,a)=>e(t,i(a)),p=(t,e,i)=>new Promise((a,n)=>{var s=t=>{try{r(i.next(t))}catch(e){n(e)}},o=t=>{try{r(i.throw(t))}catch(e){n(e)}},r=t=>t.done?a(t.value):Promise.resolve(t.value).then(s,o);r((i=i.apply(t,e)).next())});function h(t){switch(t){case 1:case 2:case 3:default:return 0;case 4:return 2;case 5:return 1}}function u(t){if("string"!==typeof t)return[];const e=new RegExp('<d[^>]*?p="(?<p>[^"]+)"[^>]*>(?<text>.*?)<\\/d>',"gs"),i=t.matchAll(e);return Array.from(i).map(t=>{const e=t.groups.p.split(",");if(e.length>=8){return{text:t.groups.text.trim().replaceAll("&quot;",'"').replaceAll("&apos;","'").replaceAll("&lt;","<").replaceAll("&gt;",">").replaceAll("&amp;","&"),time:Number(e[0]),mode:h(Number(e[1])),fontSize:Number(e[2]),color:`#${Number(e[3]).toString(16)}`,timestamp:Number(e[4]),pool:Number(e[5]),userID:e[6],rowID:Number(e[7])}}return null}).filter(Boolean)}function c({data:t}){const{xml:e,id:i}=t;if(!i||!e)return;const a=u(e);globalThis.postMessage({danmus:a,id:i})}function m(){const t=`\n ${h.toString()}\n ${u.toString()}\n onmessage = ${c.toString()}\n `,e=new Blob([t],{type:"application/javascript"});return new Worker(URL.createObjectURL(e))}const f='/*!\n * artplayer-plugin-danmuku.js v5.3.0\n * Github: https://github.com/zhw2590582/ArtPlayer\n * (c) 2017-2026 Harvey Zhao\n * Released under the MIT License.\n */\nfunction t({target:t,visibles:e,clientWidth:i,clientHeight:h,marginBottom:n,marginTop:o,antiOverlap:s}){const r=h-n,p=e.filter(e=>e.mode===t.mode&&e.top<=r).sort((t,e)=>t.top-e.top);if(0===p.length)return 2===t.mode?r-t.height:o;if(p.unshift({type:"top",top:0,left:0,right:0,height:o,width:i,speed:0,distance:i}),p.push({type:"bottom",top:r,left:0,right:0,height:n,width:i,speed:0,distance:i}),2===t.mode)for(let g=p.length-2;g>=0;g-=1){const e=p[g],i=p[g+1],h=e.top+e.height;if(i.top-h>=t.height)return i.top-t.height}else for(let g=1;g<p.length;g+=1){const e=p[g],i=p[g-1],h=i.top+i.height;if(e.top-h>=t.height)return h}const a=[];for(let g=1;g<p.length-1;g+=1){const t=p[g];if(a.length){const e=a[a.length-1];e[0].top===t.top?e.push(t):a.push([t])}else a.push([t])}if(!s){switch(t.mode){case 0:a.sort((t,e)=>{const i=Math.min(...e.map(t=>t.right)),h=Math.min(...t.map(t=>t.right));return i*e.length-h*t.length});break;case 1:case 2:a.sort((t,e)=>{const i=Math.max(...e.map(t=>t.width));return Math.max(...t.map(t=>t.width))*t.length-i*e.length})}return a[0][0].top}switch(t.mode){case 0:{const e=a.find(e=>e.every(e=>{if(i<e.distance)return!1;if(t.speed<e.speed)return!0;return e.right/(t.speed-e.speed)>e.time}));return e&&e[0]?e[0].top:void 0}case 1:case 2:return}}onmessage=e=>{const{data:i}=e;if(!i.id||!i.type)return;const h=(0,{getDanmuTop:t}[i.type])(i);globalThis.postMessage({result:h,id:i.id})};\n',g="undefined"!==typeof self&&self.Blob&&new Blob(["URL.revokeObjectURL(import.meta.url);",f],{type:"text/javascript;charset=utf-8"});function y(t){let e;try{if(e=g&&(self.URL||self.webkitURL).createObjectURL(g),!e)throw"";const i=new Worker(e,{type:"module",name:null==t?void 0:t.name});return i.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(e)}),i}catch(i){return new Worker("data:text/javascript;charset=utf-8,"+encodeURIComponent(f),{type:"module",name:null==t?void 0:t.name})}}class v{constructor(t,e){const{constructor:i,template:a}=t;this.utils=i.utils,this.validator=i.validator,this.$danmuku=a.$danmuku,this.$player=a.$player,this.art=t,this.queue=[],this.$refs=[],this.isStop=!1,this.isHide=!1,this.timer=null,this.index=0,this.option=v.option,this.states={wait:[],ready:[],emit:[],stop:[]},this.config(e,!0),this.worker=new y,this.start=this.start.bind(this),this.stop=this.stop.bind(this),this.reset=this.reset.bind(this),this.resize=this.resize.bind(this),this.destroy=this.destroy.bind(this),t.on("video:play",this.start),t.on("video:playing",this.start),t.on("video:pause",this.stop),t.on("video:waiting",this.stop),t.on("destroy",this.destroy),t.on("resize",this.resize),this.load()}static get option(){return{danmuku:[],speed:5,margin:[10,"25%"],opacity:1,color:"#FFFFFF",mode:0,modes:[0,1,2],fontSize:25,antiOverlap:!0,synchronousPlayback:!1,mount:void 0,heatmap:!1,width:512,points:[],filter:()=>!0,beforeEmit:()=>!0,beforeVisible:()=>!0,vLine truncated
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDanmuku=e(),define(function(){return t.artplayerPluginDanmuku})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDanmuku=e()}(this,function(){"use strict";var t=Object.defineProperty,e=Object.defineProperties,i=Object.getOwnPropertyDescriptors,n=Object.getOwnPropertySymbols,s=Object.prototype.hasOwnProperty,a=Object.prototype.propertyIsEnumerable,r=Math.pow,o=(e,i,n)=>i in e?t(e,i,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[i]=n,l=(t,e)=>{for(var i in e||(e={}))s.call(e,i)&&o(t,i,e[i]);if(n)for(var i of n(e))a.call(e,i)&&o(t,i,e[i]);return t},d=(t,n)=>e(t,i(n)),h=(t,e,i)=>new Promise((n,s)=>{var a=t=>{try{o(i.next(t))}catch(e){s(e)}},r=t=>{try{o(i.throw(t))}catch(e){s(e)}},o=t=>t.done?n(t.value):Promise.resolve(t.value).then(a,r);o((i=i.apply(t,e)).next())});function c(t){return t instanceof Promise||"[object Promise]"===Object.prototype.toString.call(t)}function p(t){switch(t){case 1:case 2:case 3:default:return 0;case 4:return 2;case 5:return 1}}function u(t){if("string"!==typeof t)return[];const e=new RegExp('<d[^>]*?p="(?<p>[^"]+)"[^>]*>(?<text>.*?)<\\/d>',"gs"),i=t.matchAll(e);return Array.from(i).map(t=>{const e=t.groups.p.split(",");if(e.length>=8){return{text:t.groups.text.trim().replaceAll("&quot;",'"').replaceAll("&apos;","'").replaceAll("&lt;","<").replaceAll("&gt;",">").replaceAll("&amp;","&"),time:Number(e[0]),mode:p(Number(e[1])),fontSize:Number(e[2]),color:`#${Number(e[3]).toString(16)}`,timestamp:Number(e[4]),pool:Number(e[5]),userID:e[6],rowID:Number(e[7])}}return null}).filter(Boolean)}function m({data:t}){const{xml:e,id:i}=t,n=u(e);globalThis.postMessage({danmus:n,id:i})}let f=0;function g(t,{signal:e,onCancel:i}={}){return new Promise((n,s)=>{let a,r,o,l=!1;const d=++f,c=()=>y(void 0,function(t){if(void 0!==(null==t?void 0:t.reason))return t.reason;const e=new Error("Bilibili Danmu loading cancelled");return e.name="AbortError",e}(e));function g(){let t,e=!1;try{if(a){const t=a;a=void 0,t.onmessage=null,t.onerror=null,t.onmessageerror=null,t.terminate()}}catch(i){t=i,e=!0}if(void 0!==r){const n=r;r=void 0;try{URL.revokeObjectURL(n)}catch(i){e||(t=i),e=!0}}if(e)throw t}function y(t,i){if(l)return;l=!0;let a=arguments.length>1;null==e||e.removeEventListener("abort",c),null==o||o();try{g()}catch(r){a||(i=r),a=!0}a?s(i):n(t)}function v(t,e){if(!l){console.error("Error parsing Bilibili Danmu:",e);try{y(u(t))}catch(i){y(void 0,i)}}}(null==e?void 0:e.aborted)?c():(null==e||e.addEventListener("abort",c),o=null==i?void 0:i(c),l?null==o||o():function(){return h(this,null,function*(){const i=e?yield fetch(t,{signal:e}):yield fetch(t);if(l)return;const n=yield i.text();if(!l)try{const t=`\n ${p.toString()}\n ${u.toString()}\n onmessage = ${m.toString()}\n `;if(r=URL.createObjectURL(new Blob([t],{type:"application/javascript"})),l)return void g();if(a=new Worker(r),l)return void g();a.onmessage=t=>{var e;if(l||(null==(e=t.data)?void 0:e.id)!==d)return;const{danmus:i}=t.data;Array.isArray(i)?y(i):y(void 0,new Error("Invalid Bilibili Danmu worker response"))},a.onerror=t=>{var e;null==(e=t.preventDefault)||e.call(t),v(n,t.error||t)},a.onmessageerror=t=>v(n,t.error||t),a.postMessage({xml:n,id:d})}catch(s){v(n,s)}})}().catch(t=>y(void 0,t)))})}const y=new WeakMap,v=Symbol("cancelled danmuku input");function w(t){return y.has(t)||y.set(t,{closed:!1,tasks:new Set,emitting:[]}),y.get(t)}function k(t){const e=w(t),i=e.emitting[e.emitting.length-1];return!e.closed&&!t.art.isDestroy&&(!i||i.active())}function x(t){const e=w(t);e.closed=!0;for(const i of[...e.tasks])i.cancel()}function b(t,e,i){const n=t.states[e]||[];for(let s=0;s<n.length;s++)i(n[s]);return n}class ${constructor(t){this.owner=t,this.nodes=new Set}acquire(){const t=this.owner.$refs.pop()||document.createElement("div");return t.style.cssText=this.owner.constructor.cssText,t.dataset.mode="",t.dataset.id="",t.className="",this.nodes.add(t),t}get visibles(){const t=[],{clientWidth:e}=this.owner.$player,i=this.owner.getLeft(this.owner.$player);return this.owner.filter("emit",n=>{const s=n.$ref.offsetTop,a=this.owner.getLeft(n.$ref)-i,r=n.$ref.clientHeight,o=n.$ref.clientWidth,l=a+o,d=e-l,h=l/n.$restTime,c={};c.top=s,c.left=a,c.height=r,c.width=o,c.right=d,c.speed=h,c.distance=l,c.time=n.$restTime,c.mode=n.mode,t.push(c)}),t}left(t){const e=t.getBoundingClientRect();return this.owner.isRotate?e.top:e.left}makeWait(t){this.owner.setState(t,"wait"),t.$ref&&(t.$ref.style.cssText=this.owner.constructor.cssText,t.$ref.style.visibility="hidden",t.$ref.style.marginLeft="0px",t.$ref.style.transform="translateX(0px)",t.$ref.style.transition="transform 0s linear 0s",this.owner.$refs.push(t.$ref),t.$ref=null)}resize(){const{clientWidth:t}=this.owner.$player;this.owner.filter("stop",e=>{if(0===e.mode)e.$ref.style.left=`${t}px`}),this.owner.filter("emitLine truncated
File diff suppressed because it is too large. Load diff
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-dash-control.js v1.1.0
* artplayer-plugin-dash-control.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDashControl=e(),define(function(){return t.artplayerPluginDashControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDashControl=e()}(this,function(){"use strict";function t(t,e){const o=new Map;return t.filter(t=>{const n=t[e];return void 0===n||!o.has(n)&&o.set(n,1)})}return function(e={}){return o=>{const{$video:n}=o.template,{errorHandle:i}=o.constructor.utils;function a(){i(o.dash.getVideoElement()===n,'Cannot find instance of DASH from "art.dash"'),function(n){const i=n.getBitrateInfoListFor("video");if(!i||!i.length)return;const a=e.quality||{},l=a.auto||"Auto",s=a.title||"Quality",r=a.getName||(t=>`${t.height}p`),c=n.getQualityFor("video"),u=n.getSettings().streaming.abr.autoSwitchBitrate.video,d=u?l:r(i[c]),h=t(i.map(t=>({html:r(t),value:t.qualityIndex,default:c===t.qualityIndex&&!u})),"html").sort((t,e)=>e.value-t.value);h.push({html:l,value:"auto",default:u});const g=t=>("auto"===t.value?n.updateSettings({streaming:{abr:{autoSwitchBitrate:{video:!0}}}}):(n.updateSettings({streaming:{abr:{autoSwitchBitrate:{video:!1}}}}),n.setQualityFor("video",t.value)),o.notice.show=`${s}: ${t.html}`,a.control&&o.controls.check(t),a.setting&&o.setting.check(t),t.html);a.control&&o.controls.update({name:"dash-quality",position:"right",html:d,style:{padding:"0 10px"},selector:h,onSelect:g}),a.setting&&o.setting.update({name:"dash-quality",tooltip:d,html:s,icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>',width:200,selector:h,onSelect:g})}(o.dash),function(n){const i=n.getTracksFor("audio");if(!i||!i.length)return;const a=e.audio||{},l=a.auto||"Auto",s=a.title||"Audio",r=a.getName||(t=>t.lang||t.id),c=n.getCurrentTrackFor("audio")||i[0],u=c?r(c):l,d=t(i.map(t=>({html:r(t),value:t,default:c===t})),"html"),h=t=>(n.setCurrentTrack(t.value),o.notice.show=`${s}: ${t.html}`,a.control&&o.controls.check(t),a.setting&&o.setting.check(t),t.html);a.control&&o.controls.update({name:"dash-audio",position:"right",html:u,style:{padding:"0 10px"},selector:d,onSelect:h}),a.setting&&o.setting.update({name:"dash-audio",tooltip:u,html:s,icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>',width:200,selector:d,onSelect:h})}(o.dash)}return o.on("ready",a),o.on("restart",a),{name:"artplayerPluginDashControl",update:a}}}});
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDashControl=e(),define(function(){return t.artplayerPluginDashControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDashControl=e()}(this,function(){"use strict";function t(t,e=()=>!0){let n,r=!1;for(const i of t){if(!e())break;try{i()}catch(o){r||(r=!0,n=o)}}if(r)throw n}function e(t){const e=new Map;return t.filter(t=>{if(void 0===t.html)return!0;const n=e.get(t.html);return n?(t.default&&Object.assign(n,t),!1):(e.set(t.html,t),!0)})}function n(e,n,r){let o;const i=new Map;function s(t,r=i.get(t)){if(!r||i.get(t)!==r)return;i.delete(t);const o=e[t];"controls"===t&&o.cache?.get&&o.cache.get(n)?.option?.onSelect!==r||"setting"===t&&o.find&&o.find(n)?.onSelect!==r||o.remove(n)}function c(){o=void 0,t([...i].map(([t,e])=>()=>s(t,e)))}return{update:function(t,a,l){if(!a)return void c();const u={};o=u;const f=()=>u===o&&l(),d=n=>f()?(a.select(n,f),f()?(e.notice.show=`${a.title}: ${n.html}`,f()&&t.control&&e.controls.check(n),f()&&t.setting&&e.setting.check(n),n.html):n.html):n.html;t.control?(i.set("controls",d),e.controls.update({name:n,position:"right",html:a.html,style:{padding:"0 10px"},selector:a.selector,onSelect:d})):s("controls"),f()&&(t.setting?(i.set("setting",d),e.setting.update({name:n,tooltip:a.html,html:a.title,icon:r,width:200,selector:a.selector,onSelect:d})):s("setting"))},clear:c,captureNavigation:function(t){const r=e.setting,o=r.find?.(n),s=i.get("setting");if(t()&&s&&!0===r.show&&o?.onSelect===s&&o.selector&&r.active===o.selector&&"function"===typeof r.render)return()=>{if(!t()||e.setting!==r||!0!==r.show||!r.option||r.active!==r.option)return;const o=r.find?.(n),s=i.get("setting");t()&&s&&o?.onSelect===s&&o.selector&&r.render?.(o.selector)}}}}function r(e){let n;const r=t=>n===t&&e.active(t.dash),o=t=>t.dash.getSettings().streaming.abr.autoSwitchBitrate.video;function i(){const e=n;e&&(n=void 0,e.epoch++,t(e.callbacks.splice(0).map(([t,n])=>()=>e.off.call(e.dash,t,n))))}function s(t,r){if(n===t){try{i()}catch(o){console.warn("ArtPlayer DASH subscription cleanup failed:",o)}if(!n&&e.active(t.dash))try{e.reset()}catch(o){console.warn("ArtPlayer DASH cleanup failed:",o)}}console.warn("ArtPlayer DASH refresh failed:",r)}function c(t){if(!r(t)||t.suspended||t.queued||t.running)return;t.queued=!0;const n=t.epoch;Promise.resolve().then(()=>{if(r(t)&&t.epoch===n&&!t.suspended){t.queued=!1,t.running=!0;try{t.automatic=o(t),r(t)&&e.refresh()}catch(i){s(t,i)}finally{t.running=!1}}})}return{bind:function(t){const a=n;if(a?.dash===t){const t=o(a);return void(r(a)&&(a.automatic=t,a.suspended=!1))}if(i(),n||!e.active(t)||"function"!==typeof t.on||"function"!==typeof t.off)return;const l={dash:t,off:t.off,callbacks:[],epoch:0,queued:!1,running:!1,suspended:!1,automatic:!1};n=l;const u=t.on;try{l.automatic=o(l);const n=["qualityChangeRequested","qualityChangeRendered","trackChangeRendered","streamUpdated","streamInitialized"].map(t=>[t,()=>{"streamUpdated"!==t&&"streamInitialized"!==t||(l.suspended=!1),c(l)}]),i=function(t,e){const n=t;try{if("function"!==typeof n.getVersion||"4.5.2"!==n.getVersion())return;if("function"!==typeof n.getVideoElement||"function"!==typeof n.getActiveStream||"function"!==typeof n.getDashMetrics)return}catch{return}let r=!1;return()=>{if(!r&&e()){r=!0;try{const t=n.getVideoElement?.();if(!t?.seeking||!Number.isFinite(t.currentTime))return;const r=t.currentTime,o=n.getActiveStream?.(),i=n.getDashMetrics?.(),s=o?.getProcessors?.();if(!Array.isArray(s)||"function"!==typeof i?.getCurrentBufferLevel||"function"!==typeof i.addBufferLevel)return;for(const c of s){if(!e())return;const s=c.getType?.();if("audio"!==s&&"video"!==s)continue;const a=c.getBufferController?.();if("function"!==typeof a?.getRangeAt||"function"!==typeof a.getIsPruningInProgress||"function"!==typeof a.getAllRangesWithSafetyFactor)continue;const l=i.getCurrentBufferLevel(s),u=a.getRangeAt(r),f=null===u||u&&Number.isFinite(u.end)&&u.end<=r;if(!Number.isFinite(l)||l<=0||!f||!1!==a.getIsPruningInProgress())continue;const d=a.getAllRangesWithSafetyFactor(r);if(Array.isArray(d)&&0===d.length){if(!e()||n.getActiveStream?.()!==o||n.getDashMetrics?.()!==i||n.getVideoElement?.()!==t||t.currentTime!==r||!t.seeking||!e())return;i.addBufferLevel(s,new Date,0)}}}catch(t){console.warn("ArtPlayer DASH seek buffer refresh failed:",t)}finally{r=!1}}}}(t,()=>r(l)&&!l.suspended);i&&n.push(["playbackSeeking",i]),n.push(["playbackTimeUpdated",()=>{if(r(l)&&!l.suspended)try{const t=o(l);r(l)&&t!==l.automatic&&(l.automatic=t,c(l))}catch(t){s(l,t)}}]),n.push(["streamTeardownComplete",()=>{if(r(l)){l.epoch++,l.queued=!1,l.suspended=!0;try{e.reset()}catch(t){s(l,t)}}}]);for(const e of n){if(!r(l))break;l.callbacks.push(e),u.call(t,...e)}}catch(f){if(n===l)try{i()}catch(d){console.warn("ArtPlayer DASH subscription cleanup failed:",d)}throw f}},release:i}}return function(oLine truncated
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-dash-control.js v1.1.0
* artplayer-plugin-dash-control.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDashControl=e(),define(function(){return t.artplayerPluginDashControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDashControl=e()}(this,function(){"use strict";function t(t,e){const o=new Map;return t.filter(t=>{const n=t[e];return void 0===n||!o.has(n)&&o.set(n,1)})}return function(e={}){return o=>{const{$video:n}=o.template,{errorHandle:i}=o.constructor.utils;function a(){i(o.dash.getVideoElement()===n,'Cannot find instance of DASH from "art.dash"'),function(n){const i=n.getBitrateInfoListFor("video");if(!i||!i.length)return;const a=e.quality||{},l=a.auto||"Auto",s=a.title||"Quality",r=a.getName||(t=>`${t.height}p`),c=n.getQualityFor("video"),u=n.getSettings().streaming.abr.autoSwitchBitrate.video,d=u?l:r(i[c]),h=t(i.map(t=>({html:r(t),value:t.qualityIndex,default:c===t.qualityIndex&&!u})),"html").sort((t,e)=>e.value-t.value);h.push({html:l,value:"auto",default:u});const g=t=>("auto"===t.value?n.updateSettings({streaming:{abr:{autoSwitchBitrate:{video:!0}}}}):(n.updateSettings({streaming:{abr:{autoSwitchBitrate:{video:!1}}}}),n.setQualityFor("video",t.value)),o.notice.show=`${s}: ${t.html}`,a.control&&o.controls.check(t),a.setting&&o.setting.check(t),t.html);a.control&&o.controls.update({name:"dash-quality",position:"right",html:d,style:{padding:"0 10px"},selector:h,onSelect:g}),a.setting&&o.setting.update({name:"dash-quality",tooltip:d,html:s,icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>',width:200,selector:h,onSelect:g})}(o.dash),function(n){const i=n.getTracksFor("audio");if(!i||!i.length)return;const a=e.audio||{},l=a.auto||"Auto",s=a.title||"Audio",r=a.getName||(t=>t.lang||t.id),c=n.getCurrentTrackFor("audio")||i[0],u=c?r(c):l,d=t(i.map(t=>({html:r(t),value:t,default:c===t})),"html"),h=t=>(n.setCurrentTrack(t.value),o.notice.show=`${s}: ${t.html}`,a.control&&o.controls.check(t),a.setting&&o.setting.check(t),t.html);a.control&&o.controls.update({name:"dash-audio",position:"right",html:u,style:{padding:"0 10px"},selector:d,onSelect:h}),a.setting&&o.setting.update({name:"dash-audio",tooltip:u,html:s,icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>',width:200,selector:d,onSelect:h})}(o.dash)}return o.on("ready",a),o.on("restart",a),{name:"artplayerPluginDashControl",update:a}}}});
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginDashControl=t(),define(function(){return e.artplayerPluginDashControl})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDashControl=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,r=(t,n,o)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[n]=o,i=(e,i)=>{for(var l in i||(i={}))n.call(i,l)&&r(e,l,i[l]);if(t)for(var l of t(i))o.call(i,l)&&r(e,l,i[l]);return e};function l(e,t=()=>!0){let n,o=!1;for(const i of e){if(!t())break;try{i()}catch(r){o||(o=!0,n=r)}}if(o)throw n}function c(e){const t=new Map;return e.filter(e=>{if(void 0===e.html)return!0;const n=t.get(e.html);return n?(e.default&&Object.assign(n,e),!1):(t.set(e.html,e),!0)})}function a(e,t,n){let o;const r=new Map;function i(n,o=r.get(n)){var i,l,c,a;if(!o||r.get(n)!==o)return;r.delete(n);const s=e[n];"controls"===n&&(null==(i=s.cache)?void 0:i.get)&&(null==(c=null==(l=s.cache.get(t))?void 0:l.option)?void 0:c.onSelect)!==o||"setting"===n&&s.find&&(null==(a=s.find(t))?void 0:a.onSelect)!==o||s.remove(t)}function c(){o=void 0,l([...r].map(([e,t])=>()=>i(e,t)))}return{update:function(l,a,s){if(!a)return void c();const u={};o=u;const f=()=>u===o&&s(),d=t=>f()?(a.select(t,f),f()?(e.notice.show=`${a.title}: ${t.html}`,f()&&l.control&&e.controls.check(t),f()&&l.setting&&e.setting.check(t),t.html):t.html):t.html;l.control?(r.set("controls",d),e.controls.update({name:t,position:"right",html:a.html,style:{padding:"0 10px"},selector:a.selector,onSelect:d})):i("controls"),f()&&(l.setting?(r.set("setting",d),e.setting.update({name:t,tooltip:a.html,html:a.title,icon:n,width:200,selector:a.selector,onSelect:d})):i("setting"))},clear:c,captureNavigation:function(n){var o;const i=e.setting,l=null==(o=i.find)?void 0:o.call(i,t),c=r.get("setting");if(n()&&c&&!0===i.show&&(null==l?void 0:l.onSelect)===c&&l.selector&&i.active===l.selector&&"function"===typeof i.render)return()=>{var o,l;if(!n()||e.setting!==i||!0!==i.show||!i.option||i.active!==i.option)return;const c=null==(o=i.find)?void 0:o.call(i,t),a=r.get("setting");n()&&a&&(null==c?void 0:c.onSelect)===a&&c.selector&&(null==(l=i.render)||l.call(i,c.selector))}}}}function s(e){let t;const n=n=>t===n&&e.active(n.dash),o=e=>e.dash.getSettings().streaming.abr.autoSwitchBitrate.video;function r(){const e=t;e&&(t=void 0,e.epoch++,l(e.callbacks.splice(0).map(([t,n])=>()=>e.off.call(e.dash,t,n))))}function i(n,o){if(t===n){try{r()}catch(i){console.warn("ArtPlayer DASH subscription cleanup failed:",i)}if(!t&&e.active(n.dash))try{e.reset()}catch(i){console.warn("ArtPlayer DASH cleanup failed:",i)}}console.warn("ArtPlayer DASH refresh failed:",o)}function c(t){if(!n(t)||t.suspended||t.queued||t.running)return;t.queued=!0;const r=t.epoch;Promise.resolve().then(()=>{if(n(t)&&t.epoch===r&&!t.suspended){t.queued=!1,t.running=!0;try{t.automatic=o(t),n(t)&&e.refresh()}catch(l){i(t,l)}finally{t.running=!1}}})}return{bind:function(l){const a=t;if((null==a?void 0:a.dash)===l){const e=o(a);return void(n(a)&&(a.automatic=e,a.suspended=!1))}if(r(),t||!e.active(l)||"function"!==typeof l.on||"function"!==typeof l.off)return;const s={dash:l,off:l.off,callbacks:[],epoch:0,queued:!1,running:!1,suspended:!1,automatic:!1};t=s;const u=l.on;try{s.automatic=o(s);const t=["qualityChangeRequested","qualityChangeRendered","trackChangeRendered","streamUpdated","streamInitialized"].map(e=>[e,()=>{"streamUpdated"!==e&&"streamInitialized"!==e||(s.suspended=!1),c(s)}]),r=function(e,t){const n=e;try{if("function"!==typeof n.getVersion||"4.5.2"!==n.getVersion())return;if("function"!==typeof n.getVideoElement||"function"!==typeof n.getActiveStream||"function"!==typeof n.getDashMetrics)return}catch(r){return}let o=!1;return()=>{var e,r,i,l,c,a,s,u,f;if(!o&&t()){o=!0;try{const o=null==(e=n.getVideoElement)?void 0:e.call(n);if(!(null==o?void 0:o.seeking)||!Number.isFinite(o.currentTime))return;const d=o.currentTime,g=null==(r=n.getActiveStream)?void 0:r.call(n),h=null==(i=n.getDashMetrics)?void 0:i.call(n),p=null==(l=null==g?void 0:g.getProcessors)?void 0:l.call(g);if(!Array.isArray(p)||"function"!==typeof(null==h?void 0:h.getCurrentBufferLevel)||"function"!==typeof h.addBufferLevel)return;for(const e of p){if(!t())return;const r=null==(c=e.getType)?void 0:c.call(e);if("audio"!==r&&"video"!==r)continue;const i=null==(a=e.getBufferController)?void 0:a.call(e);if("function"!==typeof(null==i?void 0:i.getRangeAt)||"function"!==typeof i.getIsPruningInProgress||"function"!==typeof i.getAllRangesWithSafetyFactor)continue;const l=h.getCurrentBufferLevel(r),p=i.getRangeAt(d),v=null===p||p&&Number.isFinite(p.end)&&p.end<=d;if(!Number.isFinite(l)||l<=0||!v||!1!==i.getIsPruningInProgress())continue;const y=i.getAllRangesWithSafetyFactor(d);if(Array.isArray(y)&&0===y.lengLine truncated
+450 -146
View File
@@ -1,165 +1,469 @@
/*!
* artplayer-plugin-dash-control.js v1.1.0
* artplayer-plugin-dash-control.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
const $audio = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>';
const $quality = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>';
function uniqBy(array, property) {
const seen = /* @__PURE__ */ new Map();
return array.filter((item) => {
const key = item[property];
if (key === void 0) {
return true;
function runCleanups(actions, current = () => true) {
let failed = false;
let failure;
for (const action of actions) {
if (!current())
break;
try {
action();
} catch (error) {
if (!failed) {
failed = true;
failure = error;
}
}
return !seen.has(key) && seen.set(key, 1);
}
if (failed)
throw failure;
}
function qualityAdapter(dash) {
const modern = typeof dash.getRepresentationsByType === "function";
return {
levels: () => modern ? dash.getRepresentationsByType("video") : dash.getBitrateInfoListFor("video"),
current(levels) {
if (modern)
return dash.getCurrentRepresentationForType("video");
const quality = dash.getQualityFor("video");
return levels.find((level) => level.qualityIndex === quality);
},
item(level, index, selected, automatic) {
return modern ? { value: index, id: level.id, default: !automatic && selected != null && level.id === selected.id } : { value: level.qualityIndex, default: !automatic && selected != null && level.qualityIndex === selected.qualityIndex };
},
select(item, valid) {
const automatic = item.value === "auto";
dash.updateSettings({ streaming: { abr: { autoSwitchBitrate: { video: automatic } } } });
if (!automatic && valid()) {
if (modern)
dash.setRepresentationForTypeById("video", item.id);
else
dash.setQualityFor("video", item.value);
}
}
};
}
function uniqueLabels(items) {
const seen = /* @__PURE__ */ new Map();
return items.filter((item) => {
if (item.html === void 0)
return true;
const first = seen.get(item.html);
if (first) {
if (item.default)
Object.assign(first, item);
return false;
}
seen.set(item.html, item);
return true;
});
}
function qualityModel(dash, config, active) {
const adapter = qualityAdapter(dash);
const levels = adapter.levels();
if (!active() || !levels?.length)
return null;
const auto = config.auto || "Auto";
const getName = config.getName || ((level) => `${level.height}p`);
const selected = adapter.current(levels);
if (!active())
return null;
const automatic = dash.getSettings().streaming.abr.autoSwitchBitrate.video;
if (!active())
return null;
const html = !automatic && selected ? getName(selected) : auto;
if (!active())
return null;
const items = [];
for (const [index, level] of levels.entries()) {
const label = getName(level);
if (!active())
return null;
items.push({ html: label, ...adapter.item(level, index, selected, automatic) });
}
const selector = uniqueLabels(items).sort((left, right) => right.value - left.value);
selector.push({ html: auto, value: "auto", default: automatic });
return { html, title: config.title || "Quality", selector, select: adapter.select };
}
function selectedTrack(tracks, current) {
if (tracks.includes(current))
return current;
if (current.id == null && current.index == null)
return void 0;
const fields = ["id", "index", "lang"];
const matching = tracks.filter((track) => fields.every((key) => current[key] == null || track[key] === current[key]));
return matching.length === 1 ? matching[0] : void 0;
}
function audioModel(dash, config, active) {
const tracks = dash.getTracksFor("audio");
if (!active() || !tracks?.length)
return null;
const auto = config.auto || "Auto";
const getName = config.getName || ((track) => track.lang || track.id);
const current = dash.getCurrentTrackFor("audio") || tracks[0];
if (!active())
return null;
const html = current ? getName(current) : auto;
if (!active())
return null;
const selected = selectedTrack(tracks, current);
const items = [];
for (const track of tracks) {
const label = getName(track);
if (!active())
return null;
items.push({ html: label, value: track, default: track === selected });
}
const selector = uniqueLabels(items);
return { html, title: config.title || "Audio", selector, select: (item) => dash.setCurrentTrack(item.value) };
}
function createMenu(art, name, icon) {
let current;
const owned = /* @__PURE__ */ new Map();
function remove(surface, callback = owned.get(surface)) {
if (!callback || owned.get(surface) !== callback)
return;
owned.delete(surface);
const registry = art[surface];
if (surface === "controls" && registry.cache?.get && registry.cache.get(name)?.option?.onSelect !== callback)
return;
if (surface === "setting" && registry.find && registry.find(name)?.onSelect !== callback)
return;
registry.remove(name);
}
function clear() {
current = void 0;
runCleanups([...owned].map(([surface, callback]) => () => remove(surface, callback)));
}
function update(config, model, active) {
if (!model) {
clear();
return;
}
const state = {};
current = state;
const valid = () => state === current && active();
const onSelect = (item) => {
if (!valid())
return item.html;
model.select(item, valid);
if (!valid())
return item.html;
art.notice.show = `${model.title}: ${item.html}`;
if (valid() && config.control)
art.controls.check(item);
if (valid() && config.setting)
art.setting.check(item);
return item.html;
};
if (config.control) {
owned.set("controls", onSelect);
art.controls.update({ name, position: "right", html: model.html, style: { padding: "0 10px" }, selector: model.selector, onSelect });
} else {
remove("controls");
}
if (!valid())
return;
if (config.setting) {
owned.set("setting", onSelect);
art.setting.update({ name, tooltip: model.html, html: model.title, icon, width: 200, selector: model.selector, onSelect });
} else {
remove("setting");
}
}
function captureNavigation(active) {
const setting = art.setting;
const item = setting.find?.(name);
const callback = owned.get("setting");
if (!active() || !callback || setting.show !== true || item?.onSelect !== callback || !item.selector || setting.active !== item.selector || typeof setting.render !== "function")
return;
return () => {
if (!active() || art.setting !== setting || setting.show !== true || !setting.option || setting.active !== setting.option)
return;
const replacement = setting.find?.(name);
const callback2 = owned.get("setting");
if (active() && callback2 && replacement?.onSelect === callback2 && replacement.selector)
setting.render?.(replacement.selector);
};
}
return { update, clear, captureNavigation };
}
const $quality = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>';
function createSeekRecovery(value, active) {
const sdk = value;
try {
if (typeof sdk.getVersion !== "function" || sdk.getVersion() !== "4.5.2")
return;
if (typeof sdk.getVideoElement !== "function" || typeof sdk.getActiveStream !== "function" || typeof sdk.getDashMetrics !== "function")
return;
} catch {
return;
}
let running = false;
return () => {
if (running || !active())
return;
running = true;
try {
const video = sdk.getVideoElement?.();
if (!video?.seeking || !Number.isFinite(video.currentTime))
return;
const time = video.currentTime;
const stream = sdk.getActiveStream?.();
const metrics = sdk.getDashMetrics?.();
const processors = stream?.getProcessors?.();
if (!Array.isArray(processors) || typeof metrics?.getCurrentBufferLevel !== "function" || typeof metrics.addBufferLevel !== "function")
return;
for (const processor of processors) {
if (!active())
return;
const type = processor.getType?.();
if (type !== "audio" && type !== "video")
continue;
const buffer = processor.getBufferController?.();
if (typeof buffer?.getRangeAt !== "function" || typeof buffer.getIsPruningInProgress !== "function" || typeof buffer.getAllRangesWithSafetyFactor !== "function")
continue;
const cached = metrics.getCurrentBufferLevel(type);
const range = buffer.getRangeAt(time);
const empty = range === null || range && Number.isFinite(range.end) && range.end <= time;
if (!Number.isFinite(cached) || cached <= 0 || !empty || buffer.getIsPruningInProgress() !== false)
continue;
const removals = buffer.getAllRangesWithSafetyFactor(time);
if (!Array.isArray(removals) || removals.length !== 0)
continue;
if (!active() || sdk.getActiveStream?.() !== stream || sdk.getDashMetrics?.() !== metrics || sdk.getVideoElement?.() !== video || video.currentTime !== time || !video.seeking || !active())
return;
metrics.addBufferLevel(type, /* @__PURE__ */ new Date(), 0);
}
} catch (error) {
console.warn("ArtPlayer DASH seek buffer refresh failed:", error);
} finally {
running = false;
}
};
}
function observeSDK(options) {
let binding;
const active = (record) => binding === record && options.active(record.dash);
const automatic = (record) => record.dash.getSettings().streaming.abr.autoSwitchBitrate.video;
function release() {
const record = binding;
if (!record)
return;
binding = void 0;
record.epoch++;
runCleanups(record.callbacks.splice(0).map(([name, callback]) => () => record.off.call(record.dash, name, callback)));
}
function fail(record, error) {
if (binding === record) {
try {
release();
} catch (cleanupError) {
console.warn("ArtPlayer DASH subscription cleanup failed:", cleanupError);
}
if (!binding && options.active(record.dash)) {
try {
options.reset();
} catch (cleanupError) {
console.warn("ArtPlayer DASH cleanup failed:", cleanupError);
}
}
}
console.warn("ArtPlayer DASH refresh failed:", error);
}
function schedule(record) {
if (!active(record) || record.suspended || record.queued || record.running)
return;
record.queued = true;
const epoch = record.epoch;
void Promise.resolve().then(() => {
if (!active(record) || record.epoch !== epoch || record.suspended)
return;
record.queued = false;
record.running = true;
try {
record.automatic = automatic(record);
if (active(record))
options.refresh();
} catch (error) {
fail(record, error);
} finally {
record.running = false;
}
});
}
function bind(dash) {
const previous = binding;
if (previous?.dash === dash) {
const value = automatic(previous);
if (active(previous)) {
previous.automatic = value;
previous.suspended = false;
}
return;
}
release();
if (binding || !options.active(dash) || typeof dash.on !== "function" || typeof dash.off !== "function")
return;
const record = { dash, off: dash.off, callbacks: [], epoch: 0, queued: false, running: false, suspended: false, automatic: false };
binding = record;
const on = dash.on;
try {
record.automatic = automatic(record);
const changed = ["qualityChangeRequested", "qualityChangeRendered", "trackChangeRendered", "streamUpdated", "streamInitialized"];
const entries = changed.map((name) => [name, () => {
if (name === "streamUpdated" || name === "streamInitialized")
record.suspended = false;
schedule(record);
}]);
const recoverSeek = createSeekRecovery(dash, () => active(record) && !record.suspended);
if (recoverSeek)
entries.push(["playbackSeeking", recoverSeek]);
entries.push(["playbackTimeUpdated", () => {
if (!active(record) || record.suspended)
return;
try {
const value = automatic(record);
if (active(record) && value !== record.automatic) {
record.automatic = value;
schedule(record);
}
} catch (error) {
fail(record, error);
}
}]);
entries.push(["streamTeardownComplete", () => {
if (!active(record))
return;
record.epoch++;
record.queued = false;
record.suspended = true;
try {
options.reset();
} catch (error) {
fail(record, error);
}
}]);
for (const entry of entries) {
if (!active(record))
break;
record.callbacks.push(entry);
on.call(dash, ...entry);
}
} catch (error) {
if (binding === record) {
try {
release();
} catch (cleanupError) {
console.warn("ArtPlayer DASH subscription cleanup failed:", cleanupError);
}
}
throw error;
}
}
return { bind, release };
}
function artplayerPluginDashControl(option = {}) {
return (art) => {
return (player) => {
const art = player;
const { $video } = art.template;
const { errorHandle } = art.constructor.utils;
function updateQuality(dash) {
const qualities = dash.getBitrateInfoListFor("video");
if (!qualities || !qualities.length)
return;
const config = option.quality || {};
const auto = config.auto || "Auto";
const title = config.title || "Quality";
const getName = config.getName || ((level) => `${level.height}p`);
const currentQuality = dash.getQualityFor("video");
const currentAuto = dash.getSettings().streaming.abr.autoSwitchBitrate.video;
const defaultHtml = currentAuto ? auto : getName(qualities[currentQuality]);
const selector = uniqBy(
qualities.map((item) => {
return {
html: getName(item),
value: item.qualityIndex,
default: currentQuality === item.qualityIndex && !currentAuto
};
}),
"html"
).sort((a, b) => b.value - a.value);
selector.push({
html: auto,
value: "auto",
default: currentAuto
});
const onSelect = (item) => {
if (item.value === "auto") {
dash.updateSettings({
streaming: {
abr: {
autoSwitchBitrate: {
video: true
}
}
}
});
} else {
dash.updateSettings({
streaming: {
abr: {
autoSwitchBitrate: {
video: false
}
}
}
});
dash.setQualityFor("video", item.value);
}
art.notice.show = `${title}: ${item.html}`;
if (config.control)
art.controls.check(item);
if (config.setting)
art.setting.check(item);
return item.html;
};
if (config.control) {
art.controls.update({
name: "dash-quality",
position: "right",
html: defaultHtml,
style: { padding: "0 10px" },
selector,
onSelect
});
}
if (config.setting) {
art.setting.update({
name: "dash-quality",
tooltip: defaultHtml,
html: title,
icon: $quality,
width: 200,
selector,
onSelect
});
}
}
function updateAudio(dash) {
const audioTracks = dash.getTracksFor("audio");
if (!audioTracks || !audioTracks.length)
return;
const config = option.audio || {};
const auto = config.auto || "Auto";
const title = config.title || "Audio";
const getName = config.getName || ((track) => track.lang || track.id);
const currentTrack = dash.getCurrentTrackFor("audio") || audioTracks[0];
const defaultHtml = currentTrack ? getName(currentTrack) : auto;
const selector = uniqBy(
audioTracks.map((item) => {
return {
html: getName(item),
value: item,
default: currentTrack === item
};
}),
"html"
);
const onSelect = (item) => {
dash.setCurrentTrack(item.value);
art.notice.show = `${title}: ${item.html}`;
if (config.control)
art.controls.check(item);
if (config.setting)
art.setting.check(item);
return item.html;
};
if (config.control) {
art.controls.update({
name: "dash-audio",
position: "right",
html: defaultHtml,
style: { padding: "0 10px" },
selector,
onSelect
});
}
if (config.setting) {
art.setting.update({
name: "dash-audio",
tooltip: defaultHtml,
html: title,
icon: $audio,
width: 200,
selector,
onSelect
});
let closed = false;
let revision = 0;
const quality = createMenu(art, "dash-quality", $quality);
const audio = createMenu(art, "dash-audio", $audio);
const subscriptions = [];
const observer = observeSDK({
active: (dash) => !closed && !art.isDestroy && art.dash === dash,
refresh() {
const dash = art.dash;
let version = revision;
const current = () => !closed && !art.isDestroy && art.dash === dash && revision === version;
const restore = quality.captureNavigation(current) || audio.captureNavigation(current);
if (!current())
return;
version++;
update();
if (current())
restore?.();
},
reset() {
const version = ++revision;
clear(() => version === revision);
}
});
function clear(current = () => true) {
runCleanups([quality.clear, audio.clear], current);
}
function update() {
errorHandle(art.dash.getVideoElement() === $video, 'Cannot find instance of DASH from "art.dash"');
updateQuality(art.dash);
updateAudio(art.dash);
if (closed || art.isDestroy)
return;
const version = ++revision;
const dash = art.dash;
const current = () => !closed && !art.isDestroy && version === revision && art.dash === dash;
const valid = () => current() && dash.getVideoElement() === $video && current();
try {
errorHandle(dash.getVideoElement() === $video, 'Cannot find instance of DASH from "art.dash"');
if (!current())
return;
observer.bind(dash);
if (!valid())
return;
const qualityConfig = option.quality || {};
const qualities = qualityModel(dash, qualityConfig, valid);
if (!valid())
return;
quality.update(qualityConfig, qualities, valid);
if (!valid())
return;
const audioConfig = option.audio || {};
const tracks = audioModel(dash, audioConfig, valid);
if (valid())
audio.update(audioConfig, tracks, valid);
} catch (error) {
if (current()) {
const cleanupVersion = ++revision;
for (const cleanup of [observer.release, () => clear(() => revision === cleanupVersion)]) {
try {
cleanup();
} catch (cleanupError) {
console.warn("ArtPlayer DASH cleanup failed:", cleanupError);
}
}
}
throw error;
}
}
art.on("ready", update);
art.on("restart", update);
return {
name: "artplayerPluginDashControl",
update
};
function destroy() {
if (closed)
return;
closed = true;
revision++;
const actions = [observer.release, clear, ...subscriptions.splice(0).map(([name, callback]) => () => art.off(name, callback))];
runCleanups(actions);
}
try {
const entries = [["ready", update], ["restart", update], ["destroy", destroy]];
for (const entry of entries) {
if (closed)
break;
subscriptions.push(entry);
art.on(...entry);
}
} catch (error) {
try {
destroy();
} catch (cleanupError) {
console.warn("ArtPlayer DASH subscription cleanup failed:", cleanupError);
}
throw error;
}
return { name: "artplayerPluginDashControl", update };
};
}
export {
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-document-pip.js v1.1.0
* artplayer-plugin-document-pip.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerPluginDocumentPip=t(),define(function(){return t.artplayerPluginDocumentPip})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDocumentPip=t()}(this,function(){"use strict";if("undefined"!==typeof document){const e="artplayer-plugin-document-pip";let t=document.getElementById(e);t||(t=document.createElement("style"),t.id=e,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(t)}):(document.head||document.documentElement).appendChild(t)),t.textContent=".artplayer-document-pip.art-video-player{width:100%!important;height:100%!important}"}return function(e={}){const t={width:480,height:270,fallbackToVideoPiP:!0,placeholder:"Playing in Document Picture-in-Picture",...e};return e=>{const n="documentPictureInPicture"in window&&"function"===typeof window.documentPictureInPicture?.requestWindow,{proxy:i,icons:o,i18n:r,template:{$player:d},constructor:{utils:{append:l,tooltip:c,addClass:a,removeClass:p,sleep:u}}}=e,s={win:null,originalParent:null,originalNext:null,currentDoc:null,placeholder:null};async function m(){if(!n&&t.fallbackToVideoPiP)return e.pip=!0,void console.warn("[artplayer-plugin-document-pip] Document Picture-in-Picture is not supported, falling back to Video Picture-in-Picture");if(!s.win)try{const n=await window.documentPictureInPicture.requestWindow({width:t.width,height:t.height});s.win=n,s.currentDoc=n.document,s.placeholder=document.createElement("div"),s.placeholder.className="artplayer-document-pip-placeholder",s.placeholder.style.cssText="display:flex;justify-content:center;align-items:center;width:100%;height:100%;",s.placeholder.textContent=t.placeholder,s.originalParent=d.parentNode,s.originalNext=d.nextSibling,s.originalParent.insertBefore(s.placeholder,s.originalNext);const i=n.document.createElement("div");i.id="__art_dpip_root",n.document.body.appendChild(i),function(e){const t=e.createElement("style");if(t.textContent="\n html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }\n #__art_dpip_root { position:absolute; inset:0; display:flex; }\n #__art_dpip_root > * { width:100% !important; height:100% !important; }\n ",e.head.appendChild(t),!e.querySelector('meta[name="viewport"]')){const t=e.createElement("meta");t.name="viewport",t.content="width=device-width,initial-scale=1",e.head.appendChild(t)}try{document.querySelectorAll('link[rel="stylesheet"]').forEach(t=>{const n=e.createElement("link");n.rel="stylesheet",n.href=t.href,t.media&&(n.media=t.media),t.crossOrigin&&(n.crossOrigin=t.crossOrigin),t.referrerPolicy&&(n.referrerPolicy=t.referrerPolicy),e.head.appendChild(n)})}catch{}try{document.querySelectorAll("style").forEach(t=>{const n=e.createElement("style");n.textContent=t.textContent,e.head.appendChild(n)})}catch{}}(n.document);const o=n.document.adoptNode(d);i.appendChild(o),s.currentDoc=n.document;const r=()=>e.resize?.(),l=()=>h();n.addEventListener("resize",r),n.addEventListener("pagehide",l),n.addEventListener("unload",l),s.cleanup=()=>{n.removeEventListener("resize",r),n.removeEventListener("pagehide",l),n.removeEventListener("unload",l)},a(d,"artplayer-document-pip"),e.events.bindGlobalEvents?.(),e.emit("document-pip",!0),await u(100),e.emit("resize")}catch(i){e.notice.show="Document Picture-in-Picture open failed",console.warn("[artplayer-plugin-document-pip] open failed:",i)}}async function h(){if(s.win)try{s.cleanup?.(),function(){if(!s.placeholder)return;const e=s.placeholder.ownerDocument||document,t=e.adoptNode(d);s.originalParent.insertBefore(t,s.placeholder),s.placeholder.remove(),s.placeholder=null,s.currentDoc=e}(),s.win.close(),s.win=null,p(d,"artplayer-document-pip"),e.events.bindGlobalEvents?.(),e.emit("document-pip",!1),await u(100),e.emit("resize")}catch(t){e.notice.show="Document Picture-in-Picture close failed",console.warn("[artplayer-plugin-document-pip] close failed:",t)}}function f(){s.win?h():m()}return e.controls.add({name:"document-pip",position:"right",index:40,tooltip:e.i18n.get("PIP Mode"),mounted:t=>{l(t,o.pip),i(t,"click",f),e.on("document-pip",e=>{c(t,r.get(e?"Exit PIP Mode":"PIP Mode"))})}}),e.on("destroy",h),{name:"artplayerPluginDocumentPip",get isSupported(){return n},get isActive(){return!!s.win},open:m,close:h,toggle:f}}}});
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginDocumentPip=t(),define(function(){return e.artplayerPluginDocumentPip})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDocumentPip=t()}(this,function(){"use strict";function e(e){const t=[];for(const o of e)try{o()}catch(n){t.push(n)}return t}const t=".artplayer-document-pip.art-video-player{width:100%!important;height:100%!important}";function n(t){let n=!1,o=0,i=null,r=null,c=null;const l=()=>!n&&t.alive(),s=e=>e===o&&l();function u(){o++,r?.finish(),r=null,c?.cancel(),c=null}function a(t){const n=e(t.releases.splice(0));return n.push(...e([()=>t.window.close()])),n}async function d(e){if(!s(e))return;const n=function(){let e;const t=new Promise(t=>{e=t});let n=setTimeout(()=>{n=null,e()},100);return{promise:t,cancel(){null!==n&&clearTimeout(n),n=null,e()}}}();c=n,await n.promise,c===n&&(c=null),s(e)&&t.resize()}async function p(){u();const e=o,n=i;if(i=null,!n)return;const r=a(n);if(n.announced)try{t.activate(!1)}catch(c){r.push(c)}r.length&&l()&&t.report("close",r[0]),s(e)&&await d(e)}return{get active(){return null!==i},get opening(){return null!==r},open:async function(){if(!l()||i)return;if(r)return r.promise;u();const n=o;let c,f;const m=new Promise((e,t)=>{c=e,f=t}),h={promise:m,finish:c};r=h;const y=()=>{r===h&&(r=null),c()},g=o=>{if(s(n)){const n=i;i=null,n&&(a(n),n.announced&&e([()=>t.activate(!1)]));try{t.report("open",o)}catch(r){f(r)}}},v=async o=>{if(!s(n))return void(i?.window!==o&&e([()=>o.close()]));const r={window:o,releases:[],announced:!1};i=r;try{const e=t.project(o.document);if(r.releases.push(e.destroy),e.mount(),!s(n))return void a(r);for(const[i,c]of[["resize",()=>{s(n)&&t.nativeResize()}],["pagehide",()=>{p()}],["unload",()=>{p()}]])if(r.releases.unshift(()=>o.removeEventListener(i,c)),o.addEventListener(i,c),!s(n))return void a(r);r.announced=!0,t.activate(!0),await d(n)}catch(c){g(c)}};try{const e=t.request();Promise.resolve(e).then(v,g).then(y,e=>{s(n)&&f(e),y()})}catch(w){try{g(w)}finally{y()}}return m},close:p,destroy(){n||(n=!0,p().catch(()=>{}))}}}function o(t={}){const o={width:480,height:270,fallbackToVideoPiP:!0,placeholder:"Playing in Document Picture-in-Picture",...t};return t=>{const i=window,r="documentPictureInPicture"in i&&"function"===typeof i.documentPictureInPicture?.requestWindow;let c=t,l=t.template.$player,s=t.isDestroy;const u=t.constructor.utils,a=()=>!s&&!!c&&!c.isDestroy,d=n({alive:a,request:()=>i.documentPictureInPicture.requestWindow({width:o.width,height:o.height}),project:t=>function(t,n,o){const i=t.ownerDocument,r=t.parentNode,c=t.nextSibling;if(!r)throw new Error("Document Picture-in-Picture requires a mounted player");const l=i.createElement("div");l.className="artplayer-document-pip-placeholder",l.style.cssText="display:flex;justify-content:center;align-items:center;width:100%;height:100%;",l.textContent=o??"";const s=n.createElement("div");s.id="__art_dpip_root";const u=[];let a=!1;const d=()=>{const e=l.parentNode===r?l:c?.parentNode===r?c:null;if(t.parentNode!==r||t.nextSibling!==e)try{r.insertBefore(t,e)}catch(n){throw i.body.appendChild(t),n}},p=()=>{const t=e([d,()=>l.remove(),...u.splice(0).map(e=>()=>e.remove()),()=>s.remove()]);if(t.length)throw t[0]};return{mount(){if(!a){if(r.insertBefore(l,c?.parentNode===r?c:null),a||n.body.appendChild(s),a||function(e,t,n,o){const i=e=>{o()&&(n(e),t.head.appendChild(e),o()||e.remove())},r=t.createElement("style");if(r.textContent="\n html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }\n #__art_dpip_root { position:absolute; inset:0; display:flex; }\n #__art_dpip_root > * { width:100% !important; height:100% !important; }\n ",i(r),!t.querySelector('meta[name="viewport"]')){const e=t.createElement("meta");e.name="viewport",e.content="width=device-width,initial-scale=1",i(e)}try{e.querySelectorAll('link[rel="stylesheet"]').forEach(e=>{const n=t.createElement("link");n.rel="stylesheet",n.href=e.href,e.media&&(n.media=e.media),e.crossOrigin&&(n.crossOrigin=e.crossOrigin),e.referrerPolicy&&(n.referrerPolicy=e.referrerPolicy),i(n)})}catch{}try{e.querySelectorAll("style").forEach(e=>{const n=t.createElement("style");n.textContent=e.textContent,i(n)})}catch{}}(i,n,e=>u.push(e),()=>!a),!a){const e=n.adoptNode(t);a||s.appendChild(e)}a&&p()}},destroy(){a||(a=!0,p())}}}(l,t,o.placeholder),activate(e){c&&l&&(e?u.addClass(l,"artplayer-document-pip"):u.removeClass(l,"artplayer-document-pip"),a()&&(c.events.bindGlobalEvents?.(),a()&&c.emit("document-pip",e)))},resize:()=>{a()&&c.emit("resize")},nativeResize:()=>{a()&&c.resize?.()},report(e,t){a()&&(c.notice.show=`Document Picture-in-Picture ${e} failed`,console.warn(`[artplayer-plugin-document-pip] ${e} failed:`,t))}});async function p(){if(a())return!r&&o.fallbackToVideoPiP?(c.pip=!0,void console.warn("[artplayer-plugin-document-pip] Document PiLine truncated
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-document-pip.js v1.1.0
* artplayer-plugin-document-pip.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerPluginDocumentPip=t(),define(function(){return t.artplayerPluginDocumentPip})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDocumentPip=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable,o=(t,n,i)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[n]=i,r=(e,t,n)=>new Promise((i,o)=>{var r=e=>{try{c(n.next(e))}catch(t){o(t)}},l=e=>{try{c(n.throw(e))}catch(t){o(t)}},c=e=>e.done?i(e.value):Promise.resolve(e.value).then(r,l);c((n=n.apply(e,t)).next())});if("undefined"!==typeof document){const e="artplayer-plugin-document-pip";let t=document.getElementById(e);t||(t=document.createElement("style"),t.id=e,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(t)}):(document.head||document.documentElement).appendChild(t)),t.textContent=".artplayer-document-pip.art-video-player{width:100%!important;height:100%!important}"}return function(e={}){const l=((e,r)=>{for(var l in r||(r={}))n.call(r,l)&&o(e,l,r[l]);if(t)for(var l of t(r))i.call(r,l)&&o(e,l,r[l]);return e})({width:480,height:270,fallbackToVideoPiP:!0,placeholder:"Playing in Document Picture-in-Picture"},e);return e=>{var t;const n="documentPictureInPicture"in window&&"function"===typeof(null==(t=window.documentPictureInPicture)?void 0:t.requestWindow),{proxy:i,icons:o,i18n:c,template:{$player:a},constructor:{utils:{append:d,tooltip:p,addClass:u,removeClass:s,sleep:m}}}=e,h={win:null,originalParent:null,originalNext:null,currentDoc:null,placeholder:null};function y(){return r(this,null,function*(){var t,i;if(!n&&l.fallbackToVideoPiP)return e.pip=!0,void console.warn("[artplayer-plugin-document-pip] Document Picture-in-Picture is not supported, falling back to Video Picture-in-Picture");if(!h.win)try{const n=yield window.documentPictureInPicture.requestWindow({width:l.width,height:l.height});h.win=n,h.currentDoc=n.document,h.placeholder=document.createElement("div"),h.placeholder.className="artplayer-document-pip-placeholder",h.placeholder.style.cssText="display:flex;justify-content:center;align-items:center;width:100%;height:100%;",h.placeholder.textContent=l.placeholder,h.originalParent=a.parentNode,h.originalNext=a.nextSibling,h.originalParent.insertBefore(h.placeholder,h.originalNext);const o=n.document.createElement("div");o.id="__art_dpip_root",n.document.body.appendChild(o),function(e){const t=e.createElement("style");if(t.textContent="\n html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }\n #__art_dpip_root { position:absolute; inset:0; display:flex; }\n #__art_dpip_root > * { width:100% !important; height:100% !important; }\n ",e.head.appendChild(t),!e.querySelector('meta[name="viewport"]')){const t=e.createElement("meta");t.name="viewport",t.content="width=device-width,initial-scale=1",e.head.appendChild(t)}try{document.querySelectorAll('link[rel="stylesheet"]').forEach(t=>{const n=e.createElement("link");n.rel="stylesheet",n.href=t.href,t.media&&(n.media=t.media),t.crossOrigin&&(n.crossOrigin=t.crossOrigin),t.referrerPolicy&&(n.referrerPolicy=t.referrerPolicy),e.head.appendChild(n)})}catch(n){}try{document.querySelectorAll("style").forEach(t=>{const n=e.createElement("style");n.textContent=t.textContent,e.head.appendChild(n)})}catch(n){}}(n.document);const r=n.document.adoptNode(a);o.appendChild(r),h.currentDoc=n.document;const c=()=>{var t;return null==(t=e.resize)?void 0:t.call(e)},d=()=>f();n.addEventListener("resize",c),n.addEventListener("pagehide",d),n.addEventListener("unload",d),h.cleanup=()=>{n.removeEventListener("resize",c),n.removeEventListener("pagehide",d),n.removeEventListener("unload",d)},u(a,"artplayer-document-pip"),null==(i=(t=e.events).bindGlobalEvents)||i.call(t),e.emit("document-pip",!0),yield m(100),e.emit("resize")}catch(o){e.notice.show="Document Picture-in-Picture open failed",console.warn("[artplayer-plugin-document-pip] open failed:",o)}})}function f(){return r(this,null,function*(){var t,n,i;if(h.win)try{null==(t=h.cleanup)||t.call(h),function(){if(!h.placeholder)return;const e=h.placeholder.ownerDocument||document,t=e.adoptNode(a);h.originalParent.insertBefore(t,h.placeholder),h.placeholder.remove(),h.placeholder=null,h.currentDoc=e}(),h.win.close(),h.win=null,s(a,"artplayer-document-pip"),null==(i=(n=e.events).bindGlobalEvents)||i.call(n),e.emit("document-pip",!1),yield m(100),e.emit("resize")}catch(o){e.notice.show="Document Picture-in-Picture close failed",console.warn("[artplayer-plugin-document-pip] close failed:",o)}})}function g(){h.win?f():y()}return e.controls.add({name:"document-pip",position:"right",index:40,tooltip:e.i18n.get("PIP Mode"),mounted:t=>{d(t,o.pip),i(t,"click",g),e.on("document-pip",Line truncated
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginDocumentPip=t(),define(function(){return e.artplayerPluginDocumentPip})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDocumentPip=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,r=(t,n,o)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[n]=o,i=(e,t,n)=>new Promise((o,r)=>{var i=e=>{try{c(n.next(e))}catch(t){r(t)}},l=e=>{try{c(n.throw(e))}catch(t){r(t)}},c=e=>e.done?o(e.value):Promise.resolve(e.value).then(i,l);c((n=n.apply(e,t)).next())});function l(e){const t=[];for(const o of e)try{o()}catch(n){t.push(n)}return t}const c=".artplayer-document-pip.art-video-player{width:100%!important;height:100%!important}";function u(e){let t=!1,n=0,o=null,r=null,c=null;const u=()=>!t&&e.alive(),s=e=>e===n&&u();function a(){n++,null==r||r.finish(),r=null,null==c||c.cancel(),c=null}function d(e){const t=l(e.releases.splice(0));return t.push(...l([()=>e.window.close()])),t}function p(t){return i(this,null,function*(){if(!s(t))return;const n=function(){let e;const t=new Promise(t=>{e=t});let n=setTimeout(()=>{n=null,e()},100);return{promise:t,cancel(){null!==n&&clearTimeout(n),n=null,e()}}}();c=n,yield n.promise,c===n&&(c=null),s(t)&&e.resize()})}function f(){return i(this,null,function*(){a();const t=n,r=o;if(o=null,!r)return;const i=d(r);if(r.announced)try{e.activate(!1)}catch(l){i.push(l)}i.length&&u()&&e.report("close",i[0]),s(t)&&(yield p(t))})}return{get active(){return null!==o},get opening(){return null!==r},open:function(){return i(this,null,function*(){if(!u()||o)return;if(r)return r.promise;a();const t=n;let c,m;const h=new Promise((e,t)=>{c=e,m=t}),y={promise:h,finish:c};r=y;const v=()=>{r===y&&(r=null),c()},g=n=>{if(s(t)){const t=o;o=null,t&&(d(t),t.announced&&l([()=>e.activate(!1)]));try{e.report("open",n)}catch(r){m(r)}}},P=n=>i(null,null,function*(){if(!s(t))return void((null==o?void 0:o.window)!==n&&l([()=>n.close()]));const r={window:n,releases:[],announced:!1};o=r;try{const o=e.project(n.document);if(r.releases.push(o.destroy),o.mount(),!s(t))return void d(r);for(const[i,l]of[["resize",()=>{s(t)&&e.nativeResize()}],["pagehide",()=>{f()}],["unload",()=>{f()}]])if(r.releases.unshift(()=>n.removeEventListener(i,l)),n.addEventListener(i,l),!s(t))return void d(r);r.announced=!0,e.activate(!0),yield p(t)}catch(i){g(i)}});try{const n=e.request();Promise.resolve(n).then(P,g).then(v,e=>{s(t)&&m(e),v()})}catch(w){try{g(w)}finally{v()}}return h})},close:f,destroy(){t||(t=!0,f().catch(()=>{}))}}}function s(e={}){const c=((e,i)=>{for(var l in i||(i={}))n.call(i,l)&&r(e,l,i[l]);if(t)for(var l of t(i))o.call(i,l)&&r(e,l,i[l]);return e})({width:480,height:270,fallbackToVideoPiP:!0,placeholder:"Playing in Document Picture-in-Picture"},e);return e=>{var t;const n=window,o="documentPictureInPicture"in n&&"function"===typeof(null==(t=n.documentPictureInPicture)?void 0:t.requestWindow);let r=e,s=e.template.$player,a=e.isDestroy;const d=e.constructor.utils,p=()=>!a&&!!r&&!r.isDestroy,f=u({alive:p,request:()=>n.documentPictureInPicture.requestWindow({width:c.width,height:c.height}),project:e=>function(e,t,n){const o=e.ownerDocument,r=e.parentNode,i=e.nextSibling;if(!r)throw new Error("Document Picture-in-Picture requires a mounted player");const c=o.createElement("div");c.className="artplayer-document-pip-placeholder",c.style.cssText="display:flex;justify-content:center;align-items:center;width:100%;height:100%;",c.textContent=null!=n?n:"";const u=t.createElement("div");u.id="__art_dpip_root";const s=[];let a=!1;const d=()=>{const t=c.parentNode===r?c:(null==i?void 0:i.parentNode)===r?i:null;if(e.parentNode!==r||e.nextSibling!==t)try{r.insertBefore(e,t)}catch(n){throw o.body.appendChild(e),n}},p=()=>{const e=l([d,()=>c.remove(),...s.splice(0).map(e=>()=>e.remove()),()=>u.remove()]);if(e.length)throw e[0]};return{mount(){if(!a){if(r.insertBefore(c,(null==i?void 0:i.parentNode)===r?i:null),a||t.body.appendChild(u),a||function(e,t,n,o){const r=e=>{o()&&(n(e),t.head.appendChild(e),o()||e.remove())},i=t.createElement("style");if(i.textContent="\n html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }\n #__art_dpip_root { position:absolute; inset:0; display:flex; }\n #__art_dpip_root > * { width:100% !important; height:100% !important; }\n ",r(i),!t.querySelector('meta[name="viewport"]')){const e=t.createElement("meta");e.name="viewport",e.content="width=device-width,initial-scale=1",r(e)}try{e.querySelectorAll('link[rel="stylesheet"]').forEach(e=>{const n=t.createElement("link");n.rel="stylesheet",n.href=e.href,e.media&&(n.media=e.media),e.crossOrigin&&(n.crossOrigin=e.crossOrigin),e.referrerPolicy&&(n.referrerPolicy=e.referrerPolicy),r(n)})}catch(l){}try{e.querySelectorAll("styleLine truncated
+451 -164
View File
@@ -1,194 +1,481 @@
/*!
* artplayer-plugin-document-pip.js v1.1.0
* artplayer-plugin-document-pip.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
const style = ".artplayer-document-pip.art-video-player {\n width: 100% !important;\n height: 100% !important;\n}\n";
function artplayerPluginDocumentPip(userOptions = {}) {
const options = {
width: 480,
height: 270,
fallbackToVideoPiP: true,
placeholder: `Playing in Document Picture-in-Picture`,
...userOptions
function releaseAll(releases) {
const errors = [];
for (const release of releases) {
try {
release();
} catch (error) {
errors.push(error);
}
}
return errors;
}
function createDelay() {
let finish;
const promise = new Promise((resolve) => {
finish = resolve;
});
let timer = setTimeout(() => {
timer = null;
finish();
}, 100);
return {
promise,
cancel() {
if (timer !== null)
clearTimeout(timer);
timer = null;
finish();
}
};
return (art) => {
const isSupported = "documentPictureInPicture" in window && typeof window.documentPictureInPicture?.requestWindow === "function";
const { proxy, icons, i18n, template: { $player }, constructor: { utils: { append, tooltip, addClass, removeClass, sleep } } } = art;
const state = {
win: null,
originalParent: null,
originalNext: null,
currentDoc: null,
placeholder: null
};
function copyStylesTo(targetDoc) {
const base = targetDoc.createElement("style");
base.textContent = `
html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }
#__art_dpip_root { position:absolute; inset:0; display:flex; }
#__art_dpip_root > * { width:100% !important; height:100% !important; }
`;
targetDoc.head.appendChild(base);
if (!targetDoc.querySelector('meta[name="viewport"]')) {
const meta = targetDoc.createElement("meta");
meta.name = "viewport";
meta.content = "width=device-width,initial-scale=1";
targetDoc.head.appendChild(meta);
}
}
function createControl(art, toggle, alive) {
const utils = art.constructor.utils;
const releases = [];
let closed = false;
return {
mount() {
if (closed || !alive())
return;
releases.push(() => art.controls.remove("document-pip"));
art.controls.add({
name: "document-pip",
position: "right",
index: 40,
tooltip: art.i18n.get("PIP Mode"),
mounted: (control) => {
if (closed || !alive())
return;
utils.append(control, art.icons.pip);
const click = () => {
if (alive())
toggle();
};
releases.push(() => control.removeEventListener("click", click));
const unbind = art.proxy(control, "click", click);
if (closed)
unbind();
else
releases.push(unbind);
if (closed || !alive())
return;
const update = (active) => {
if (alive())
utils.tooltip(control, art.i18n.get(active ? "Exit PIP Mode" : "PIP Mode"));
};
releases.push(() => art.off("document-pip", update));
art.on("document-pip", update);
}
});
if (closed)
art.controls.remove("document-pip");
},
destroy() {
if (closed)
return;
closed = true;
const errors = releaseAll(releases.splice(0).reverse());
if (errors.length)
throw errors[0];
}
};
}
const style = ".artplayer-document-pip.art-video-player {\n width: 100% !important;\n height: 100% !important;\n}\n";
function installStyle(document2) {
const id = "artplayer-plugin-document-pip";
const existing = document2.getElementById(id);
if (existing) {
existing.textContent = style;
return;
}
const element = document2.createElement("style");
element.id = id;
element.textContent = style;
const insert = () => {
document2.removeEventListener("DOMContentLoaded", insert);
const current = document2.getElementById(id);
if (current)
current.textContent = style;
else
(document2.head || document2.documentElement).appendChild(element);
};
if (document2.readyState === "loading")
document2.addEventListener("DOMContentLoaded", insert);
else
insert();
}
function copyStyles(source, target, own, alive) {
const append = (node) => {
if (!alive())
return;
own(node);
target.head.appendChild(node);
if (!alive())
node.remove();
};
const base = target.createElement("style");
base.textContent = `
html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }
#__art_dpip_root { position:absolute; inset:0; display:flex; }
#__art_dpip_root > * { width:100% !important; height:100% !important; }
`;
append(base);
if (!target.querySelector('meta[name="viewport"]')) {
const meta = target.createElement("meta");
meta.name = "viewport";
meta.content = "width=device-width,initial-scale=1";
append(meta);
}
try {
source.querySelectorAll('link[rel="stylesheet"]').forEach((link) => {
const clone = target.createElement("link");
clone.rel = "stylesheet";
clone.href = link.href;
if (link.media)
clone.media = link.media;
if (link.crossOrigin)
clone.crossOrigin = link.crossOrigin;
if (link.referrerPolicy)
clone.referrerPolicy = link.referrerPolicy;
append(clone);
});
} catch {
}
try {
source.querySelectorAll("style").forEach((element) => {
const clone = target.createElement("style");
clone.textContent = element.textContent;
append(clone);
});
} catch {
}
}
function createProjection(player, target, text) {
const source = player.ownerDocument;
const parent = player.parentNode;
const next = player.nextSibling;
if (!parent)
throw new Error("Document Picture-in-Picture requires a mounted player");
const placeholder = source.createElement("div");
placeholder.className = "artplayer-document-pip-placeholder";
placeholder.style.cssText = "display:flex;justify-content:center;align-items:center;width:100%;height:100%;";
placeholder.textContent = text ?? "";
const root = target.createElement("div");
root.id = "__art_dpip_root";
const nodes = [];
let closed = false;
const restore = () => {
const anchor = placeholder.parentNode === parent ? placeholder : next?.parentNode === parent ? next : null;
if (player.parentNode !== parent || player.nextSibling !== anchor) {
try {
document.querySelectorAll('link[rel="stylesheet"]').forEach((link) => {
const clone = targetDoc.createElement("link");
clone.rel = "stylesheet";
clone.href = link.href;
if (link.media)
clone.media = link.media;
if (link.crossOrigin)
clone.crossOrigin = link.crossOrigin;
if (link.referrerPolicy)
clone.referrerPolicy = link.referrerPolicy;
targetDoc.head.appendChild(clone);
});
} catch {
}
try {
document.querySelectorAll("style").forEach((style2) => {
const clone = targetDoc.createElement("style");
clone.textContent = style2.textContent;
targetDoc.head.appendChild(clone);
});
} catch {
parent.insertBefore(player, anchor);
} catch (error) {
source.body.appendChild(player);
throw error;
}
}
};
const cleanup = () => {
const errors = releaseAll([restore, () => placeholder.remove(), ...nodes.splice(0).map((node) => () => node.remove()), () => root.remove()]);
if (errors.length)
throw errors[0];
};
return {
mount() {
if (closed)
return;
parent.insertBefore(placeholder, next?.parentNode === parent ? next : null);
if (!closed)
target.body.appendChild(root);
if (!closed)
copyStyles(source, target, (node) => nodes.push(node), () => !closed);
if (!closed) {
const adopted = target.adoptNode(player);
if (!closed)
root.appendChild(adopted);
}
if (closed)
cleanup();
},
destroy() {
if (closed)
return;
closed = true;
cleanup();
}
};
}
function createWindowSession(hooks) {
let destroyed = false;
let revision = 0;
let session = null;
let pending = null;
let delay = null;
const alive = () => !destroyed && hooks.alive();
const valid = (value) => value === revision && alive();
function invalidate() {
revision++;
pending?.finish();
pending = null;
delay?.cancel();
delay = null;
}
function dispose(current) {
const errors = releaseAll(current.releases.splice(0));
errors.push(...releaseAll([() => current.window.close()]));
return errors;
}
async function resizeLater(value) {
if (!valid(value))
return;
const current = createDelay();
delay = current;
await current.promise;
if (delay === current)
delay = null;
if (valid(value))
hooks.resize();
}
async function close() {
invalidate();
const value = revision;
const current = session;
session = null;
if (!current)
return;
const errors = dispose(current);
if (current.announced) {
try {
hooks.activate(false);
} catch (error) {
errors.push(error);
}
}
if (errors.length && alive())
hooks.report("close", errors[0]);
if (valid(value))
await resizeLater(value);
}
async function open() {
if (!alive() || session)
return;
if (pending)
return pending.promise;
invalidate();
const value = revision;
let finish;
let reject;
const promise = new Promise((resolve, fail) => {
finish = resolve;
reject = fail;
});
const ticket = { promise, finish };
pending = ticket;
const settle = () => {
if (pending === ticket)
pending = null;
finish();
};
const failed = (error) => {
if (valid(value)) {
const current = session;
session = null;
if (current) {
dispose(current);
if (current.announced)
releaseAll([() => hooks.activate(false)]);
}
try {
hooks.report("open", error);
} catch (noticeError) {
reject(noticeError);
}
}
};
const receive = async (window2) => {
if (!valid(value)) {
if (session?.window !== window2)
releaseAll([() => window2.close()]);
return;
}
const current = { window: window2, releases: [], announced: false };
session = current;
try {
const projection = hooks.project(window2.document);
current.releases.push(projection.destroy);
projection.mount();
if (!valid(value)) {
dispose(current);
return;
}
for (const [event, callback] of [["resize", () => {
if (valid(value))
hooks.nativeResize();
}], ["pagehide", () => {
void close();
}], ["unload", () => {
void close();
}]]) {
current.releases.unshift(() => window2.removeEventListener(event, callback));
window2.addEventListener(event, callback);
if (!valid(value)) {
dispose(current);
return;
}
}
current.announced = true;
hooks.activate(true);
await resizeLater(value);
} catch (error) {
failed(error);
}
};
try {
const request = hooks.request();
void Promise.resolve(request).then(receive, failed).then(settle, (error) => {
if (valid(value))
reject(error);
settle();
});
} catch (error) {
try {
failed(error);
} finally {
settle();
}
}
return promise;
}
return {
get active() {
return session !== null;
},
get opening() {
return pending !== null;
},
open,
close,
destroy() {
if (destroyed)
return;
destroyed = true;
void close().catch(() => {
});
}
};
}
function artplayerPluginDocumentPip(userOptions = {}) {
const options = { width: 480, height: 270, fallbackToVideoPiP: true, placeholder: "Playing in Document Picture-in-Picture", ...userOptions };
return (art) => {
const browser = window;
const isSupported = "documentPictureInPicture" in browser && typeof browser.documentPictureInPicture?.requestWindow === "function";
let host = art;
let player = art.template.$player;
let closed = art.isDestroy;
const utils = art.constructor.utils;
const alive = () => !closed && !!host && !host.isDestroy;
const session = createWindowSession({
alive,
request: () => browser.documentPictureInPicture.requestWindow({ width: options.width, height: options.height }),
project: (document2) => createProjection(player, document2, options.placeholder),
activate(active) {
if (!host || !player)
return;
if (active)
utils.addClass(player, "artplayer-document-pip");
else
utils.removeClass(player, "artplayer-document-pip");
if (!alive())
return;
host.events.bindGlobalEvents?.();
if (alive())
host.emit("document-pip", active);
},
resize: () => {
if (alive())
host.emit("resize");
},
nativeResize: () => {
if (alive())
host.resize?.();
},
report(action, error) {
if (!alive())
return;
host.notice.show = `Document Picture-in-Picture ${action} failed`;
console.warn(`[artplayer-plugin-document-pip] ${action} failed:`, error);
}
});
async function open() {
if (!alive())
return;
if (!isSupported && options.fallbackToVideoPiP) {
art.pip = true;
host.pip = true;
console.warn("[artplayer-plugin-document-pip] Document Picture-in-Picture is not supported, falling back to Video Picture-in-Picture");
return;
}
if (state.win)
return;
try {
const pipWin = await window.documentPictureInPicture.requestWindow({
width: options.width,
height: options.height
});
state.win = pipWin;
state.currentDoc = pipWin.document;
state.placeholder = document.createElement("div");
state.placeholder.className = "artplayer-document-pip-placeholder";
state.placeholder.style.cssText = `display:flex;justify-content:center;align-items:center;width:100%;height:100%;`;
state.placeholder.textContent = options.placeholder;
state.originalParent = $player.parentNode;
state.originalNext = $player.nextSibling;
state.originalParent.insertBefore(state.placeholder, state.originalNext);
const root = pipWin.document.createElement("div");
root.id = "__art_dpip_root";
pipWin.document.body.appendChild(root);
copyStylesTo(pipWin.document);
const adopted = pipWin.document.adoptNode($player);
root.appendChild(adopted);
state.currentDoc = pipWin.document;
const onResize = () => art.resize?.();
const onClose = () => close();
pipWin.addEventListener("resize", onResize);
pipWin.addEventListener("pagehide", onClose);
pipWin.addEventListener("unload", onClose);
state.cleanup = () => {
pipWin.removeEventListener("resize", onResize);
pipWin.removeEventListener("pagehide", onClose);
pipWin.removeEventListener("unload", onClose);
};
addClass($player, "artplayer-document-pip");
art.events.bindGlobalEvents?.();
art.emit("document-pip", true);
await sleep(100);
art.emit("resize");
} catch (err) {
art.notice.show = "Document Picture-in-Picture open failed";
console.warn("[artplayer-plugin-document-pip] open failed:", err);
}
}
function restoreToOriginalDocument() {
if (!state.placeholder)
return;
const backDoc = state.placeholder.ownerDocument || document;
const adoptedBack = backDoc.adoptNode($player);
state.originalParent.insertBefore(adoptedBack, state.placeholder);
state.placeholder.remove();
state.placeholder = null;
state.currentDoc = backDoc;
}
async function close() {
if (!state.win)
return;
try {
state.cleanup?.();
restoreToOriginalDocument();
state.win.close();
state.win = null;
removeClass($player, "artplayer-document-pip");
art.events.bindGlobalEvents?.();
art.emit("document-pip", false);
await sleep(100);
art.emit("resize");
} catch (err) {
art.notice.show = "Document Picture-in-Picture close failed";
console.warn("[artplayer-plugin-document-pip] close failed:", err);
}
return session.open();
}
function toggle() {
if (state.win) {
close();
} else {
open();
}
if (!alive())
return;
if (session.active || session.opening)
void session.close();
else
void open();
}
art.controls.add({
name: "document-pip",
position: "right",
index: 40,
tooltip: art.i18n.get("PIP Mode"),
mounted: ($control) => {
append($control, icons.pip);
proxy($control, "click", toggle);
art.on("document-pip", (value) => {
tooltip($control, i18n.get(value ? "Exit PIP Mode" : "PIP Mode"));
});
}
});
art.on("destroy", close);
return {
let control = createControl(art, toggle, alive);
function destroy() {
if (closed)
return;
closed = true;
const current = host;
const previousControl = control;
control = null;
const errors = releaseAll([session.destroy, () => previousControl?.destroy(), () => current?.off("destroy", destroy)]);
host = null;
player = null;
if (errors.length)
console.warn("[artplayer-plugin-document-pip] cleanup failed:", errors[0]);
}
const result = {
name: "artplayerPluginDocumentPip",
get isSupported() {
return isSupported;
},
get isActive() {
return !!state.win;
return session.active;
},
open,
close,
close: session.close,
toggle
};
if (closed) {
host = null;
player = null;
return result;
}
try {
art.on("destroy", destroy);
if (alive())
control?.mount();
else
art.off("destroy", destroy);
} catch (error) {
destroy();
throw error;
}
return result;
};
}
if (typeof document !== "undefined") {
const id = "artplayer-plugin-document-pip";
let $style = document.getElementById(id);
if (!$style) {
$style = document.createElement("style");
$style.id = id;
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", () => {
document.head.appendChild($style);
});
} else {
(document.head || document.documentElement).appendChild($style);
}
}
$style.textContent = style;
}
const index = Object.assign(artplayerPluginDocumentPip, { default: artplayerPluginDocumentPip });
if (typeof document !== "undefined")
installStyle(document);
export {
artplayerPluginDocumentPip as default
index as default
};
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-hls-control.js v1.1.0
* artplayer-plugin-hls-control.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginHlsControl=e(),define(function(){return t.artplayerPluginHlsControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginHlsControl=e()}(this,function(){"use strict";function t(t,e){const l=new Map;return t.filter(t=>{const o=t[e];return void 0===o||!l.has(o)&&l.set(o,1)})}return function(e={}){return l=>{const{$video:o}=l.template,{errorHandle:n}=l.constructor.utils;function i(){n(l.hls?.media===o,'Cannot find instance of HLS from "art.hls"'),function(o){if(!o.levels.length)return;const n=e.quality||{},i=n.auto||"Auto",s=n.title||"Quality",a=n.getName||(t=>t.name||`${t.height}P`),c=o.levels[o.currentLevel],r=c?a(c):i,u=t(o.levels.map((t,e)=>({html:a(t,e),value:e,default:o.currentLevel===e})),"html").sort((t,e)=>e.value-t.value);u.push({html:i,value:-1,default:-1===o.currentLevel});const h=t=>(o.currentLevel=t.value,l.notice.show=`${s}: ${t.html}`,n.control&&l.controls.check(t),n.setting&&l.setting.check(t),t.html);n.control&&l.controls.update({name:"hls-quality",position:"right",html:r,style:{padding:"0 10px"},selector:u,onSelect:h}),n.setting&&l.setting.update({name:"hls-quality",tooltip:r,html:s,icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>',width:200,selector:u,onSelect:h})}(l.hls),function(o){if(!o.audioTracks.length)return;const n=e.audio||{},i=n.auto||"Auto",s=n.title||"Audio",a=n.getName||(t=>t.name||t.lang||t.language),c=o.audioTracks[o.audioTrack],r=c?a(c):i,u=t(o.audioTracks.map((t,e)=>({html:a(t,e),value:t.id,default:o.audioTrack===t.id})),"html"),h=t=>(o.audioTrack=t.value,l.notice.show=`${s}: ${t.html}`,n.control&&l.controls.check(t),n.setting&&l.setting.check(t),t.html);n.control&&l.controls.update({name:"hls-audio",position:"right",html:r,style:{padding:"0 10px"},selector:u,onSelect:h}),n.setting&&l.setting.update({name:"hls-audio",tooltip:r,html:s,icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>',width:200,selector:u,onSelect:h})}(l.hls)}return l.on("ready",i),l.on("restart",i),{name:"artplayerPluginHlsControl",update:i}}}});
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginHlsControl=e(),define(function(){return t.artplayerPluginHlsControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginHlsControl=e()}(this,function(){"use strict";function t(t){const e=new Map;return t.filter(t=>{if(void 0===t.html)return!0;const o=e.get(t.html);return o?(t.default&&(o.default=!0,o.value=t.value),!1):(e.set(t.html,t),!0)})}function e(t,e,o,n,l,i){let r;const c={control:!1,setting:!1};function s(o){c[o]&&(c[o]=!1,t["control"===o?"controls":"setting"].remove(e))}function u(){r=void 0,s("control"),s("setting")}function a(e,o){for(const t of e.model.selector)t.default=t===o;e.config.control&&t.controls.check(o),e===r&&l(e.hls)&&e.config.setting&&t.setting.check(o)}return{update:function(f,d,h,m){if(!h)return void u();const g=r,v=h.selector.findIndex(t=>t.default);if(!m&&g?.hls===f&&g.model.title===h.title&&(-1!==v||!g.model.selector.some(t=>t.default)&&g.model.html===h.html)&&c.control===Boolean(d.control)&&c.setting===Boolean(d.setting)&&g.model.selector.length===h.selector.length&&g.model.selector.every((t,e)=>t.html===h.selector[e].html&&t.value===h.selector[e].value)){g.config=d;const t=g.model.selector[v];return void(!t||t.default&&g.model.html===h.html||(g.model.html=h.html,a(g,t)))}const p={hls:f,config:d,model:h};r=p;const y=()=>r===p&&l(f),T=e=>i(()=>y()?(f[o]=e.value,y()?(h.html=e.html,t.notice.show=`${h.title}: ${e.html}`,y()&&a(p,e),e.html):e.html):e.html);d.control?(c.control=!0,t.controls.update({name:e,position:"right",html:h.html,style:{padding:"0 10px"},selector:h.selector,onSelect:T})):s("control"),y()&&(d.setting?(c.setting=!0,t.setting.update({name:e,tooltip:h.html,html:h.title,icon:n,width:200,selector:h.selector,onSelect:T})):s("setting"))},clear:u,invalidate:function(){r=void 0}}}return function(o={}){return n=>{const l=n,{$video:i}=l.template,{errorHandle:r}=l.constructor.utils;let c,s,u=!1,a=0,f=()=>{},d=0;const h=new WeakSet,m=t=>!u&&!h.has(t)&&l.hls===t&&t.media===i,g=e(l,"hls-quality","currentLevel",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>',m,p),v=e(l,"hls-audio","audioTrack",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>',m,p);function p(t){d++;let e=!1;try{const o=t();return e=!0,o}finally{if(d--,!d){const t=s;s=void 0,e&&t&&y(t,!1)}}}function y(e,n){if(!m(e))return;const l=++a,i=o.quality||{},r=function(e,o){if(!e.levels.length)return null;const n=o.auto||"Auto",l=o.getName||(t=>t.name||`${t.height}P`),i=function(t){return!0===t.autoLevelEnabled?-1:t.currentLevel}(e),r=e.levels[i],c=r?l(r):n,s=t(e.levels.map((t,e)=>({html:l(t,e),value:e,default:i===e}))).sort((t,e)=>e.value-t.value);return s.push({html:n,value:-1,default:-1===i}),{html:c,title:o.title||"Quality",selector:s}}(e,i);if(!m(e)||l!==a)return;if(g.update(e,i,r,n),!m(e)||l!==a)return;const c=o.audio||{},s=function(e,o){if(!e.audioTracks.length)return null;const n=o.auto||"Auto",l=o.getName||(t=>t.name||t.lang||t.language),i=e.audioTracks[e.audioTrack],r=i?l(i):n,c=t(e.audioTracks.map((t,o)=>({html:l(t,o),value:t.id,default:e.audioTrack===t.id})));return{html:r,title:o.title||"Audio",selector:c}}(e,c);m(e)&&l===a&&v.update(e,c,s,n)}function T(){if(u)return;const t=l.hls;if(r(t?.media===i,'Cannot find instance of HLS from "art.hls"'),!h.has(t)){if(c!==t){f(),c=t;try{f=function(t,e,o){const n=t.constructor?.Events;if(!n||"function"!==typeof t.on||"function"!==typeof t.off)return()=>{};const l=t,i=[];let r=!0;function c(){if(r){r=!1;for(const[t,e]of i)l.off(t,e);i.length=0}}try{for(const t of["MANIFEST_PARSED","LEVELS_UPDATED","LEVEL_SWITCHED","AUDIO_TRACKS_UPDATED","AUDIO_TRACK_SWITCHED","DESTROYING"]){const c=n[t];if("string"!==typeof c||i.some(([t])=>t===c))continue;const s=()=>{r&&("DESTROYING"===t?o():e())};i.push([c,s]),l.on(c,s)}}catch(s){throw c(),s}return c}(t,()=>{d?s=t:y(t,!1)},()=>{h.add(t),f(),c===t&&(c=void 0,u||(g.clear(),v.clear()))})}catch(e){throw c=void 0,e}}y(t,!0)}}return l.on("ready",T),l.on("restart",T),l.on("destroy",function t(){u||(u=!0,a++,s=void 0,g.invalidate(),v.invalidate(),f(),l.offLine truncated
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-hls-control.js v1.1.0
* artplayer-plugin-hls-control.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginHlsControl=e(),define(function(){return t.artplayerPluginHlsControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginHlsControl=e()}(this,function(){"use strict";function t(t,e){const l=new Map;return t.filter(t=>{const o=t[e];return void 0===o||!l.has(o)&&l.set(o,1)})}return function(e={}){return l=>{const{$video:o}=l.template,{errorHandle:n}=l.constructor.utils;function i(){var i;n((null==(i=l.hls)?void 0:i.media)===o,'Cannot find instance of HLS from "art.hls"'),function(o){if(!o.levels.length)return;const n=e.quality||{},i=n.auto||"Auto",a=n.title||"Quality",s=n.getName||(t=>t.name||`${t.height}P`),c=o.levels[o.currentLevel],r=c?s(c):i,u=t(o.levels.map((t,e)=>({html:s(t,e),value:e,default:o.currentLevel===e})),"html").sort((t,e)=>e.value-t.value);u.push({html:i,value:-1,default:-1===o.currentLevel});const h=t=>(o.currentLevel=t.value,l.notice.show=`${a}: ${t.html}`,n.control&&l.controls.check(t),n.setting&&l.setting.check(t),t.html);n.control&&l.controls.update({name:"hls-quality",position:"right",html:r,style:{padding:"0 10px"},selector:u,onSelect:h}),n.setting&&l.setting.update({name:"hls-quality",tooltip:r,html:a,icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>',width:200,selector:u,onSelect:h})}(l.hls),function(o){if(!o.audioTracks.length)return;const n=e.audio||{},i=n.auto||"Auto",a=n.title||"Audio",s=n.getName||(t=>t.name||t.lang||t.language),c=o.audioTracks[o.audioTrack],r=c?s(c):i,u=t(o.audioTracks.map((t,e)=>({html:s(t,e),value:t.id,default:o.audioTrack===t.id})),"html"),h=t=>(o.audioTrack=t.value,l.notice.show=`${a}: ${t.html}`,n.control&&l.controls.check(t),n.setting&&l.setting.check(t),t.html);n.control&&l.controls.update({name:"hls-audio",position:"right",html:r,style:{padding:"0 10px"},selector:u,onSelect:h}),n.setting&&l.setting.update({name:"hls-audio",tooltip:r,html:a,icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>',width:200,selector:u,onSelect:h})}(l.hls)}return l.on("ready",i),l.on("restart",i),{name:"artplayerPluginHlsControl",update:i}}}});
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginHlsControl=e(),define(function(){return t.artplayerPluginHlsControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginHlsControl=e()}(this,function(){"use strict";function t(t){const e=new Map;return t.filter(t=>{if(void 0===t.html)return!0;const o=e.get(t.html);return o?(t.default&&(o.default=!0,o.value=t.value),!1):(e.set(t.html,t),!0)})}function e(t,e,o,l,n,i){let r;const c={control:!1,setting:!1};function s(o){c[o]&&(c[o]=!1,t["control"===o?"controls":"setting"].remove(e))}function u(){r=void 0,s("control"),s("setting")}function a(e,o){for(const t of e.model.selector)t.default=t===o;e.config.control&&t.controls.check(o),e===r&&n(e.hls)&&e.config.setting&&t.setting.check(o)}return{update:function(f,d,h,m){if(!h)return void u();const g=r,v=h.selector.findIndex(t=>t.default);if(!m&&(null==g?void 0:g.hls)===f&&g.model.title===h.title&&(-1!==v||!g.model.selector.some(t=>t.default)&&g.model.html===h.html)&&c.control===Boolean(d.control)&&c.setting===Boolean(d.setting)&&g.model.selector.length===h.selector.length&&g.model.selector.every((t,e)=>t.html===h.selector[e].html&&t.value===h.selector[e].value)){g.config=d;const t=g.model.selector[v];return void(!t||t.default&&g.model.html===h.html||(g.model.html=h.html,a(g,t)))}const p={hls:f,config:d,model:h};r=p;const y=()=>r===p&&n(f),T=e=>i(()=>y()?(f[o]=e.value,y()?(h.html=e.html,t.notice.show=`${h.title}: ${e.html}`,y()&&a(p,e),e.html):e.html):e.html);d.control?(c.control=!0,t.controls.update({name:e,position:"right",html:h.html,style:{padding:"0 10px"},selector:h.selector,onSelect:T})):s("control"),y()&&(d.setting?(c.setting=!0,t.setting.update({name:e,tooltip:h.html,html:h.title,icon:l,width:200,selector:h.selector,onSelect:T})):s("setting"))},clear:u,invalidate:function(){r=void 0}}}return function(o={}){return l=>{const n=l,{$video:i}=n.template,{errorHandle:r}=n.constructor.utils;let c,s,u=!1,a=0,f=()=>{},d=0;const h=new WeakSet,m=t=>!u&&!h.has(t)&&n.hls===t&&t.media===i,g=e(n,"hls-quality","currentLevel",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>',m,p),v=e(n,"hls-audio","audioTrack",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>',m,p);function p(t){d++;let e=!1;try{const o=t();return e=!0,o}finally{if(d--,!d){const t=s;s=void 0,e&&t&&y(t,!1)}}}function y(e,l){if(!m(e))return;const n=++a,i=o.quality||{},r=function(e,o){if(!e.levels.length)return null;const l=o.auto||"Auto",n=o.getName||(t=>t.name||`${t.height}P`),i=function(t){return!0===t.autoLevelEnabled?-1:t.currentLevel}(e),r=e.levels[i],c=r?n(r):l,s=t(e.levels.map((t,e)=>({html:n(t,e),value:e,default:i===e}))).sort((t,e)=>e.value-t.value);return s.push({html:l,value:-1,default:-1===i}),{html:c,title:o.title||"Quality",selector:s}}(e,i);if(!m(e)||n!==a)return;if(g.update(e,i,r,l),!m(e)||n!==a)return;const c=o.audio||{},s=function(e,o){if(!e.audioTracks.length)return null;const l=o.auto||"Auto",n=o.getName||(t=>t.name||t.lang||t.language),i=e.audioTracks[e.audioTrack],r=i?n(i):l,c=t(e.audioTracks.map((t,o)=>({html:n(t,o),value:t.id,default:e.audioTrack===t.id})));return{html:r,title:o.title||"Audio",selector:c}}(e,c);m(e)&&n===a&&v.update(e,c,s,l)}function T(){if(u)return;const t=n.hls;if(r((null==t?void 0:t.media)===i,'Cannot find instance of HLS from "art.hls"'),!h.has(t)){if(c!==t){f(),c=t;try{f=function(t,e,o){var l;const n=null==(l=t.constructor)?void 0:l.Events;if(!n||"function"!==typeof t.on||"function"!==typeof t.off)return()=>{};const i=t,r=[];let c=!0;function s(){if(c){c=!1;for(const[t,e]of r)i.off(t,e);r.length=0}}try{for(const t of["MANIFEST_PARSED","LEVELS_UPDATED","LEVEL_SWITCHED","AUDIO_TRACKS_UPDATED","AUDIO_TRACK_SWITCHED","DESTROYING"]){const l=n[t];if("string"!==typeof l||r.some(([t])=>t===l))continue;const s=()=>{c&&("DESTROYING"===t?o():e())};r.push([l,s]),i.on(l,s)}}catch(u){throw s(),u}return s}(t,()=>{d?s=t:y(t,!1)},()=>{h.add(t),f(),c===t&&(c=void 0,u||(g.clear(),v.clear()))})}catch(e){throw c=void 0,e}}y(t,!0)}}return n.on("ready",T),n.on("restart",T),n.on("destroy",function t(){u||(uLine truncated
+242 -116
View File
@@ -1,141 +1,267 @@
/*!
* artplayer-plugin-hls-control.js v1.1.0
* artplayer-plugin-hls-control.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
const $audio = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>';
const $quality = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>';
function uniqBy(array, property) {
function uniqueLabels(items) {
const seen = /* @__PURE__ */ new Map();
return array.filter((item) => {
const key = item[property];
if (key === void 0) {
return items.filter((item) => {
if (item.html === void 0)
return true;
const first = seen.get(item.html);
if (first) {
if (item.default) {
first.default = true;
first.value = item.value;
}
return false;
}
return !seen.has(key) && seen.set(key, 1);
seen.set(item.html, item);
return true;
});
}
function qualitySelection(hls) {
return hls.autoLevelEnabled === true ? -1 : hls.currentLevel;
}
function qualityModel(hls, config) {
if (!hls.levels.length)
return null;
const auto = config.auto || "Auto";
const getName = config.getName || ((level2) => level2.name || `${level2.height}P`);
const selected = qualitySelection(hls);
const level = hls.levels[selected];
const html = level ? getName(level) : auto;
const selector = uniqueLabels(hls.levels.map((item, index) => ({ html: getName(item, index), value: index, default: selected === index }))).sort((a, b) => b.value - a.value);
selector.push({ html: auto, value: -1, default: selected === -1 });
return { html, title: config.title || "Quality", selector };
}
function audioModel(hls, config) {
if (!hls.audioTracks.length)
return null;
const auto = config.auto || "Auto";
const getName = config.getName || ((track2) => track2.name || track2.lang || track2.language);
const track = hls.audioTracks[hls.audioTrack];
const html = track ? getName(track) : auto;
const selector = uniqueLabels(hls.audioTracks.map((item, index) => ({ html: getName(item, index), value: item.id, default: hls.audioTrack === item.id })));
return { html, title: config.title || "Audio", selector };
}
function createMenu(art, name, field, icon, active, select) {
let current;
const owned = { control: false, setting: false };
function remove(surface) {
if (!owned[surface])
return;
owned[surface] = false;
art[surface === "control" ? "controls" : "setting"].remove(name);
}
function clear() {
current = void 0;
remove("control");
remove("setting");
}
function check(state, item) {
for (const entry of state.model.selector)
entry.default = entry === item;
if (state.config.control)
art.controls.check(item);
if (state !== current || !active(state.hls))
return;
if (state.config.setting)
art.setting.check(item);
}
function update(hls, config, model, force) {
if (!model) {
clear();
return;
}
const previous = current;
const selectedIndex = model.selector.findIndex((item) => item.default);
const reusable = !force && previous?.hls === hls && previous.model.title === model.title && (selectedIndex !== -1 || !previous.model.selector.some((item) => item.default) && previous.model.html === model.html) && owned.control === Boolean(config.control) && owned.setting === Boolean(config.setting) && previous.model.selector.length === model.selector.length && previous.model.selector.every((item, index) => item.html === model.selector[index].html && item.value === model.selector[index].value);
if (reusable) {
previous.config = config;
const target = previous.model.selector[selectedIndex];
if (target && (!target.default || previous.model.html !== model.html)) {
previous.model.html = model.html;
check(previous, target);
}
return;
}
const state = { hls, config, model };
current = state;
const valid = () => current === state && active(hls);
const onSelect = (item) => select(() => {
if (!valid())
return item.html;
hls[field] = item.value;
if (!valid())
return item.html;
model.html = item.html;
art.notice.show = `${model.title}: ${item.html}`;
if (valid())
check(state, item);
return item.html;
});
if (config.control) {
owned.control = true;
art.controls.update({ name, position: "right", html: model.html, style: { padding: "0 10px" }, selector: model.selector, onSelect });
} else {
remove("control");
}
if (!valid())
return;
if (config.setting) {
owned.setting = true;
art.setting.update({ name, tooltip: model.html, html: model.title, icon, width: 200, selector: model.selector, onSelect });
} else {
remove("setting");
}
}
function invalidate() {
current = void 0;
}
return { update, clear, invalidate };
}
const $quality = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>';
function subscribeHls(hls, refresh, destroyed) {
const events = hls.constructor?.Events;
if (!events || typeof hls.on !== "function" || typeof hls.off !== "function")
return () => {
};
const source = hls;
const subscriptions = [];
let active = true;
function release() {
if (!active)
return;
active = false;
for (const [event, callback] of subscriptions)
source.off(event, callback);
subscriptions.length = 0;
}
try {
for (const key of ["MANIFEST_PARSED", "LEVELS_UPDATED", "LEVEL_SWITCHED", "AUDIO_TRACKS_UPDATED", "AUDIO_TRACK_SWITCHED", "DESTROYING"]) {
const event = events[key];
if (typeof event !== "string" || subscriptions.some(([name]) => name === event))
continue;
const callback = () => {
if (!active)
return;
if (key === "DESTROYING")
destroyed();
else
refresh();
};
subscriptions.push([event, callback]);
source.on(event, callback);
}
} catch (error) {
release();
throw error;
}
return release;
}
function artplayerPluginHlsControl(option = {}) {
return (art) => {
return (player) => {
const art = player;
const { $video } = art.template;
const { errorHandle } = art.constructor.utils;
function updateQuality(hls) {
if (!hls.levels.length)
return;
const config = option.quality || {};
const auto = config.auto || "Auto";
const title = config.title || "Quality";
const getName = config.getName || ((level) => level.name || `${level.height}P`);
const defaultLevel = hls.levels[hls.currentLevel];
const defaultHtml = defaultLevel ? getName(defaultLevel) : auto;
const selector = uniqBy(
hls.levels.map((item, index) => {
return {
html: getName(item, index),
value: index,
default: hls.currentLevel === index
};
}),
"html"
).sort((a, b) => b.value - a.value);
selector.push({
html: auto,
value: -1,
default: hls.currentLevel === -1
});
const onSelect = (item) => {
hls.currentLevel = item.value;
art.notice.show = `${title}: ${item.html}`;
if (config.control)
art.controls.check(item);
if (config.setting)
art.setting.check(item);
return item.html;
};
if (config.control) {
art.controls.update({
name: "hls-quality",
position: "right",
html: defaultHtml,
style: { padding: "0 10px" },
selector,
onSelect
});
}
if (config.setting) {
art.setting.update({
name: "hls-quality",
tooltip: defaultHtml,
html: title,
icon: $quality,
width: 200,
selector,
onSelect
});
let closed = false;
let revision = 0;
let engine;
let unsubscribe = () => {
};
let selecting = 0;
let pending;
const retired = /* @__PURE__ */ new WeakSet();
const active = (hls) => !closed && !retired.has(hls) && art.hls === hls && hls.media === $video;
const quality = createMenu(art, "hls-quality", "currentLevel", $quality, active, select);
const audio = createMenu(art, "hls-audio", "audioTrack", $audio, active, select);
function select(callback) {
selecting++;
let succeeded = false;
try {
const result = callback();
succeeded = true;
return result;
} finally {
selecting--;
if (!selecting) {
const hls = pending;
pending = void 0;
if (succeeded && hls)
refresh(hls, false);
}
}
}
function updateAudio(hls) {
if (!hls.audioTracks.length)
function refresh(hls, force) {
if (!active(hls))
return;
const config = option.audio || {};
const auto = config.auto || "Auto";
const title = config.title || "Audio";
const getName = config.getName || ((track) => track.name || track.lang || track.language);
const defaultTrack = hls.audioTracks[hls.audioTrack];
const defaultHtml = defaultTrack ? getName(defaultTrack) : auto;
const selector = uniqBy(
hls.audioTracks.map((item, index) => {
return {
html: getName(item, index),
value: item.id,
default: hls.audioTrack === item.id
};
}),
"html"
);
const onSelect = (item) => {
hls.audioTrack = item.value;
art.notice.show = `${title}: ${item.html}`;
if (config.control)
art.controls.check(item);
if (config.setting)
art.setting.check(item);
return item.html;
};
if (config.control) {
art.controls.update({
name: "hls-audio",
position: "right",
html: defaultHtml,
style: { padding: "0 10px" },
selector,
onSelect
});
}
if (config.setting) {
art.setting.update({
name: "hls-audio",
tooltip: defaultHtml,
html: title,
icon: $audio,
width: 200,
selector,
onSelect
});
}
const version = ++revision;
const config = option.quality || {};
const model = qualityModel(hls, config);
if (!active(hls) || version !== revision)
return;
quality.update(hls, config, model, force);
if (!active(hls) || version !== revision)
return;
const audioConfig = option.audio || {};
const audioView = audioModel(hls, audioConfig);
if (active(hls) && version === revision)
audio.update(hls, audioConfig, audioView, force);
}
function update() {
errorHandle(art.hls?.media === $video, 'Cannot find instance of HLS from "art.hls"');
updateQuality(art.hls);
updateAudio(art.hls);
if (closed)
return;
const hls = art.hls;
errorHandle(hls?.media === $video, 'Cannot find instance of HLS from "art.hls"');
if (retired.has(hls))
return;
if (engine !== hls) {
unsubscribe();
engine = hls;
try {
unsubscribe = subscribeHls(hls, () => {
if (selecting)
pending = hls;
else
refresh(hls, false);
}, () => {
retired.add(hls);
unsubscribe();
if (engine === hls) {
engine = void 0;
if (!closed) {
quality.clear();
audio.clear();
}
}
});
} catch (error) {
engine = void 0;
throw error;
}
}
refresh(hls, true);
}
function destroy() {
if (closed)
return;
closed = true;
revision++;
pending = void 0;
quality.invalidate();
audio.invalidate();
unsubscribe();
art.off("ready", update);
art.off("restart", update);
art.off("destroy", destroy);
}
art.on("ready", update);
art.on("restart", update);
return {
name: "artplayerPluginHlsControl",
update
};
art.on("destroy", destroy);
return { name: "artplayerPluginHlsControl", update };
};
}
export {
+2 -2
View File
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-jassub.js v1.1.0
* artplayer-plugin-jassub.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerPluginJassub=t(),define(function(){return t.artplayerPluginJassub})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginJassub=t()}(this,function(){"use strict";var e=Object.defineProperty,t=(t,s,i)=>((t,s,i)=>s in t?e(t,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[s]=i)(t,"symbol"!==typeof s?s+"":s,i);typeof HTMLVideoElement<"u"&&!("requestVideoFrameCallback"in HTMLVideoElement.prototype)&&"getVideoPlaybackQuality"in HTMLVideoElement.prototype&&(HTMLVideoElement.prototype._rvfcpolyfillmap={},HTMLVideoElement.prototype.requestVideoFrameCallback=function(e){const t=performance.now(),s=this.getVideoPlaybackQuality(),i=this.mozPresentedFrames||this.mozPaintedFrames||s.totalVideoFrames-s.droppedVideoFrames,a=(r,n)=>{const o=this.getVideoPlaybackQuality(),h=this.mozPresentedFrames||this.mozPaintedFrames||o.totalVideoFrames-o.droppedVideoFrames;if(h>i){const i=this.mozFrameDelay||o.totalFrameDelay-s.totalFrameDelay||0,a=n-r;e(n,{presentationTime:n+1e3*i,expectedDisplayTime:n+a,width:this.videoWidth,height:this.videoHeight,mediaTime:Math.max(0,this.currentTime||0)+a/1e3,presentedFrames:h,processingDuration:i}),delete this._rvfcpolyfillmap[t]}else this._rvfcpolyfillmap[t]=requestAnimationFrame(e=>a(n,e))};return this._rvfcpolyfillmap[t]=requestAnimationFrame(e=>a(t,e)),t},HTMLVideoElement.prototype.cancelVideoFrameCallback=function(e){cancelAnimationFrame(this._rvfcpolyfillmap[e]),delete this._rvfcpolyfillmap[e]});const s={bt709:"BT709",bt470bg:"BT601",smpte170m:"BT601"},i={BT601:{BT709:"1.0863 -0.0723 -0.014 0 0 0.0965 0.8451 0.0584 0 0 -0.0141 -0.0277 1.0418"},BT709:{BT601:"0.9137 0.0784 0.0079 0 0 -0.1049 1.1722 -0.0671 0 0 0.0096 0.0322 0.9582"},FCC:{BT709:"1.0873 -0.0736 -0.0137 0 0 0.0974 0.8494 0.0531 0 0 -0.0127 -0.0251 1.0378",BT601:"1.001 -0.0008 -0.0002 0 0 0.0009 1.005 -0.006 0 0 0.0013 0.0027 0.996"},SMPTE240M:{BT709:"0.9993 0.0006 0.0001 0 0 -0.0004 0.9812 0.0192 0 0 -0.0034 -0.0114 1.0148",BT601:"0.913 0.0774 0.0096 0 0 -0.1051 1.1508 -0.0456 0 0 0.0063 0.0207 0.973"}},a=class e extends EventTarget{constructor(t){if(super(),!globalThis.Worker)throw this.destroy("Worker not supported");if(!t)throw this.destroy("No options provided");this._loaded=new Promise(e=>{this._init=e});const s=e._test();if(this._onDemandRender="requestVideoFrameCallback"in HTMLVideoElement.prototype&&(t.onDemandRender??!0),this._offscreenRender="transferControlToOffscreen"in HTMLCanvasElement.prototype&&!t.canvas&&(t.offscreenRender??!0),this.timeOffset=t.timeOffset||0,this._video=t.video,this._videoHeight=0,this._videoWidth=0,this._videoColorSpace=null,this._canvas=t.canvas,this._video&&!this._canvas)this._canvasParent=document.createElement("div"),this._canvasParent.className="JASSUB",this._canvasParent.style.position="relative",this._canvas=this._createCanvas(),this._video.insertAdjacentElement("afterend",this._canvasParent);else if(!this._canvas)throw this.destroy("Don't know where to render: you should give video or canvas in options.");if(this._bufferCanvas=document.createElement("canvas"),this._bufferCtx=this._bufferCanvas.getContext("2d"),!this._bufferCtx)throw this.destroy("Canvas rendering not supported");this._canvasctrl=this._offscreenRender?this._canvas.transferControlToOffscreen():this._canvas,this._ctx=!this._offscreenRender&&this._canvasctrl.getContext("2d"),this._lastRenderTime=0,this.debug=!!t.debug,this.prescaleFactor=t.prescaleFactor||1,this.prescaleHeightLimit=t.prescaleHeightLimit||1080,this.maxRenderHeight=t.maxRenderHeight||0,this._boundResize=this.resize.bind(this),this._boundTimeUpdate=this._timeupdate.bind(this),this._boundSetRate=this.setRate.bind(this),this._boundUpdateColorSpace=this._updateColorSpace.bind(this),this._video&&this.setVideo(t.video),this._onDemandRender&&(this.busy=!1,this._lastDemandTime=null),this._worker=new Worker(t.workerUrl||"jassub-worker.js"),this._worker.onmessage=e=>this._onmessage(e),this._worker.onerror=e=>this._error(e),s.then(()=>{this._worker.postMessage({target:"init",wasmUrl:e._supportsSIMD&&t.modernWasmUrl?t.modernWasmUrl:t.wasmUrl??"jassub-worker.wasm",legacyWasmUrl:t.legacyWasmUrl??"jassub-worker.wasm.js",asyncRender:typeof createImageBitmap<"u"&&(t.asyncRender??!0),onDemandRender:this._onDemandRender,width:this._canvasctrl.width||0,height:this._canvasctrl.height||0,blendMode:t.blendMode||"js",subUrl:t.subUrl,subContent:t.subContent||null,fonts:t.fonts||[],availableFonts:t.availableFonts||{"liberation sans":"./default.woff2"},fallbackFont:t.fallbackFont||"liberation sans",debug:this.debug,targetFps:t.targetFps||24,dropAllAnimations:t.dropAllAnimations,dropAllBlur:t.dropAllBlur,libassMemoryLimit:t.libassMemoryLimit||0,libassGlyphLimit:t.libassGlyphLimit||0,useLocalFonts:typeof queryLocalFonts<"u"&&(t.useLocalFonts??!0),hasBitmapBug:e._hasBitmapBug}),!0===this._offscreenRender&&this.sendMessage("ofLine truncated
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginJassub=t(),define(function(){return e.artplayerPluginJassub})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginJassub=t()}(this,function(){"use strict";var e=Object.defineProperty,t=(t,s,i)=>((t,s,i)=>s in t?e(t,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[s]=i)(t,"symbol"!==typeof s?s+"":s,i);typeof HTMLVideoElement<"u"&&!("requestVideoFrameCallback"in HTMLVideoElement.prototype)&&"getVideoPlaybackQuality"in HTMLVideoElement.prototype&&(HTMLVideoElement.prototype.requestVideoFrameCallback=function(e){Object.prototype.hasOwnProperty.call(this,"_rvfcpolyfillmap")||(this._rvfcpolyfillmap={});const t=this._rvfcpolyfillid=(this._rvfcpolyfillid||0)+1,s=performance.now(),i=this.getVideoPlaybackQuality(),a=this.currentTime,r=this.mozPresentedFrames||this.mozPaintedFrames||i.totalVideoFrames-i.droppedVideoFrames,n=(o,h)=>{if(!(t in this._rvfcpolyfillmap))return;const d=this.getVideoPlaybackQuality(),l=this.mozPresentedFrames||this.mozPaintedFrames||d.totalVideoFrames-d.droppedVideoFrames,c=l>r,_=0===r&&0===l&&0===i.totalVideoFrames&&0===i.droppedVideoFrames&&0===d.totalVideoFrames&&0===d.droppedVideoFrames&&Number.isFinite(this.currentTime)&&this.currentTime!==a&&this.readyState>=2&&!this.seeking&&h-s>=1e3/30;if(c||_){const s=this.mozFrameDelay||d.totalFrameDelay-i.totalFrameDelay||0,a=h-o;delete this._rvfcpolyfillmap[t],e(h,{presentationTime:h+1e3*s,expectedDisplayTime:h+a,width:this.videoWidth,height:this.videoHeight,mediaTime:_&&!c?Math.max(0,this.currentTime):Math.max(0,this.currentTime||0)+a/1e3,presentedFrames:l,processingDuration:s})}else this._rvfcpolyfillmap[t]=requestAnimationFrame(e=>n(h,e))};return this._rvfcpolyfillmap[t]=requestAnimationFrame(e=>n(s,e)),t},HTMLVideoElement.prototype.cancelVideoFrameCallback=function(e){const t=this._rvfcpolyfillmap;t&&e in t&&(cancelAnimationFrame(t[e]),delete t[e])});const s={bt709:"BT709",bt470bg:"BT601",smpte170m:"BT601"},i={BT601:{BT709:"1.0863 -0.0723 -0.014 0 0 0.0965 0.8451 0.0584 0 0 -0.0141 -0.0277 1.0418"},BT709:{BT601:"0.9137 0.0784 0.0079 0 0 -0.1049 1.1722 -0.0671 0 0 0.0096 0.0322 0.9582"},FCC:{BT709:"1.0873 -0.0736 -0.0137 0 0 0.0974 0.8494 0.0531 0 0 -0.0127 -0.0251 1.0378",BT601:"1.001 -0.0008 -0.0002 0 0 0.0009 1.005 -0.006 0 0 0.0013 0.0027 0.996"},SMPTE240M:{BT709:"0.9993 0.0006 0.0001 0 0 -0.0004 0.9812 0.0192 0 0 -0.0034 -0.0114 1.0148",BT601:"0.913 0.0774 0.0096 0 0 -0.1051 1.1508 -0.0456 0 0 0.0063 0.0207 0.973"}},a=class e extends EventTarget{constructor(t){let s;super(),this._requests=new Set;try{if(!globalThis.Worker)throw this.destroy("Worker not supported");if(!t)throw this.destroy("No options provided");if(this._loaded=new Promise(e=>{this._init=e}),s=e._test(),this._onDemandRender="requestVideoFrameCallback"in HTMLVideoElement.prototype&&(t.onDemandRender??!0),this._offscreenRender="transferControlToOffscreen"in HTMLCanvasElement.prototype&&!t.canvas&&(t.offscreenRender??!0),this.timeOffset=t.timeOffset||0,this._video=t.video,this._videoHeight=0,this._videoWidth=0,this._videoColorSpace=null,this._canvas=t.canvas,this._video&&!this._canvas)this._canvasParent=document.createElement("div"),this._canvasParent.className="JASSUB",this._canvasParent.style.position="relative",this._canvas=this._createCanvas(),this._video.insertAdjacentElement("afterend",this._canvasParent);else if(!this._canvas)throw this.destroy("Don't know where to render: you should give video or canvas in options.");if(this._bufferCanvas=document.createElement("canvas"),this._bufferCtx=this._bufferCanvas.getContext("2d"),!this._bufferCtx)throw this.destroy("Canvas rendering not supported");this._canvasctrl=this._offscreenRender?this._canvas.transferControlToOffscreen():this._canvas,this._ctx=!this._offscreenRender&&this._canvasctrl.getContext("2d"),this._lastRenderTime=0,this.debug=!!t.debug,this.prescaleFactor=t.prescaleFactor||1,this.prescaleHeightLimit=t.prescaleHeightLimit||1080,this.maxRenderHeight=t.maxRenderHeight||0,this._boundResize=this.resize.bind(this),this._boundTimeUpdate=this._timeupdate.bind(this),this._boundSetRate=()=>{this._destroyed||this.setRate(this._video.playbackRate)},this._boundUpdateColorSpace=this._updateColorSpace.bind(this),this._video&&this.setVideo(t.video),this._onDemandRender&&(this.busy=!1,this._lastDemandTime=null),this._worker=new Worker(t.workerUrl||"jassub-worker.js"),this._worker.onmessage=e=>this._onmessage(e),this._worker.onerror=e=>this._error(e),s.then(()=>{this._destroyed||this._worker.postMessage({target:"init",wasmUrl:e._supportsSIMD&&t.modernWasmUrl?t.modernWasmUrl:t.wasmUrl??"jassub-worker.wasm",legacyWasmUrl:t.legacyWasmUrl??"jassub-worker.wasm.js",asyncRender:typeof createImageBitmap<"u"&&(t.asyncRender??!0),onDemandRender:this._onDemandRender,width:this._canvasctrl.width||0,height:this._canvasctrl.height||0,blendMode:t.blendMode||"js",subUrl:t.subLine truncated
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-jassub.js v1.1.0
* artplayer-plugin-jassub.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerPluginJassub=t(),define(function(){return t.artplayerPluginJassub})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginJassub=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,s=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable,a=(t,s,i)=>s in t?e(t,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[s]=i,r=(e,r)=>{for(var n in r||(r={}))s.call(r,n)&&a(e,n,r[n]);if(t)for(var n of t(r))i.call(r,n)&&a(e,n,r[n]);return e},n=(e,t,s)=>a(e,"symbol"!==typeof t?t+"":t,s),o=(e,t,s)=>new Promise((i,a)=>{var r=e=>{try{o(s.next(e))}catch(t){a(t)}},n=e=>{try{o(s.throw(e))}catch(t){a(t)}},o=e=>e.done?i(e.value):Promise.resolve(e.value).then(r,n);o((s=s.apply(e,t)).next())});typeof HTMLVideoElement<"u"&&!("requestVideoFrameCallback"in HTMLVideoElement.prototype)&&"getVideoPlaybackQuality"in HTMLVideoElement.prototype&&(HTMLVideoElement.prototype._rvfcpolyfillmap={},HTMLVideoElement.prototype.requestVideoFrameCallback=function(e){const t=performance.now(),s=this.getVideoPlaybackQuality(),i=this.mozPresentedFrames||this.mozPaintedFrames||s.totalVideoFrames-s.droppedVideoFrames,a=(r,n)=>{const o=this.getVideoPlaybackQuality(),h=this.mozPresentedFrames||this.mozPaintedFrames||o.totalVideoFrames-o.droppedVideoFrames;if(h>i){const i=this.mozFrameDelay||o.totalFrameDelay-s.totalFrameDelay||0,a=n-r;e(n,{presentationTime:n+1e3*i,expectedDisplayTime:n+a,width:this.videoWidth,height:this.videoHeight,mediaTime:Math.max(0,this.currentTime||0)+a/1e3,presentedFrames:h,processingDuration:i}),delete this._rvfcpolyfillmap[t]}else this._rvfcpolyfillmap[t]=requestAnimationFrame(e=>a(n,e))};return this._rvfcpolyfillmap[t]=requestAnimationFrame(e=>a(t,e)),t},HTMLVideoElement.prototype.cancelVideoFrameCallback=function(e){cancelAnimationFrame(this._rvfcpolyfillmap[e]),delete this._rvfcpolyfillmap[e]});const h={bt709:"BT709",bt470bg:"BT601",smpte170m:"BT601"},d={BT601:{BT709:"1.0863 -0.0723 -0.014 0 0 0.0965 0.8451 0.0584 0 0 -0.0141 -0.0277 1.0418"},BT709:{BT601:"0.9137 0.0784 0.0079 0 0 -0.1049 1.1722 -0.0671 0 0 0.0096 0.0322 0.9582"},FCC:{BT709:"1.0873 -0.0736 -0.0137 0 0 0.0974 0.8494 0.0531 0 0 -0.0127 -0.0251 1.0378",BT601:"1.001 -0.0008 -0.0002 0 0 0.0009 1.005 -0.006 0 0 0.0013 0.0027 0.996"},SMPTE240M:{BT709:"0.9993 0.0006 0.0001 0 0 -0.0004 0.9812 0.0192 0 0 -0.0034 -0.0114 1.0148",BT601:"0.913 0.0774 0.0096 0 0 -0.1051 1.1508 -0.0456 0 0 0.0063 0.0207 0.973"}},l=class e extends EventTarget{constructor(t){var s,i;if(super(),!globalThis.Worker)throw this.destroy("Worker not supported");if(!t)throw this.destroy("No options provided");this._loaded=new Promise(e=>{this._init=e});const a=e._test();if(this._onDemandRender="requestVideoFrameCallback"in HTMLVideoElement.prototype&&(null==(s=t.onDemandRender)||s),this._offscreenRender="transferControlToOffscreen"in HTMLCanvasElement.prototype&&!t.canvas&&(null==(i=t.offscreenRender)||i),this.timeOffset=t.timeOffset||0,this._video=t.video,this._videoHeight=0,this._videoWidth=0,this._videoColorSpace=null,this._canvas=t.canvas,this._video&&!this._canvas)this._canvasParent=document.createElement("div"),this._canvasParent.className="JASSUB",this._canvasParent.style.position="relative",this._canvas=this._createCanvas(),this._video.insertAdjacentElement("afterend",this._canvasParent);else if(!this._canvas)throw this.destroy("Don't know where to render: you should give video or canvas in options.");if(this._bufferCanvas=document.createElement("canvas"),this._bufferCtx=this._bufferCanvas.getContext("2d"),!this._bufferCtx)throw this.destroy("Canvas rendering not supported");this._canvasctrl=this._offscreenRender?this._canvas.transferControlToOffscreen():this._canvas,this._ctx=!this._offscreenRender&&this._canvasctrl.getContext("2d"),this._lastRenderTime=0,this.debug=!!t.debug,this.prescaleFactor=t.prescaleFactor||1,this.prescaleHeightLimit=t.prescaleHeightLimit||1080,this.maxRenderHeight=t.maxRenderHeight||0,this._boundResize=this.resize.bind(this),this._boundTimeUpdate=this._timeupdate.bind(this),this._boundSetRate=this.setRate.bind(this),this._boundUpdateColorSpace=this._updateColorSpace.bind(this),this._video&&this.setVideo(t.video),this._onDemandRender&&(this.busy=!1,this._lastDemandTime=null),this._worker=new Worker(t.workerUrl||"jassub-worker.js"),this._worker.onmessage=e=>this._onmessage(e),this._worker.onerror=e=>this._error(e),a.then(()=>{var s,i,a,r;this._worker.postMessage({target:"init",wasmUrl:e._supportsSIMD&&t.modernWasmUrl?t.modernWasmUrl:null!=(s=t.wasmUrl)?s:"jassub-worker.wasm",legacyWasmUrl:null!=(i=t.legacyWasmUrl)?i:"jassub-worker.wasm.js",asyncRender:typeof createImageBitmap<"u"&&(null==(a=t.asyncRender)||a),onDemandRender:this._onDemandRender,width:this._canvasctrl.width||0,height:this._canvasctrl.height||0,blendMode:t.blendMode||"js",subUrl:t.subUrl,subLine truncated
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginJassub=t(),define(function(){return e.artplayerPluginJassub})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginJassub=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,s=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable,a=(t,s,i)=>s in t?e(t,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[s]=i,r=(e,r)=>{for(var n in r||(r={}))s.call(r,n)&&a(e,n,r[n]);if(t)for(var n of t(r))i.call(r,n)&&a(e,n,r[n]);return e},n=(e,t,s)=>a(e,"symbol"!==typeof t?t+"":t,s),o=(e,t,s)=>new Promise((i,a)=>{var r=e=>{try{o(s.next(e))}catch(t){a(t)}},n=e=>{try{o(s.throw(e))}catch(t){a(t)}},o=e=>e.done?i(e.value):Promise.resolve(e.value).then(r,n);o((s=s.apply(e,t)).next())});typeof HTMLVideoElement<"u"&&!("requestVideoFrameCallback"in HTMLVideoElement.prototype)&&"getVideoPlaybackQuality"in HTMLVideoElement.prototype&&(HTMLVideoElement.prototype.requestVideoFrameCallback=function(e){Object.prototype.hasOwnProperty.call(this,"_rvfcpolyfillmap")||(this._rvfcpolyfillmap={});const t=this._rvfcpolyfillid=(this._rvfcpolyfillid||0)+1,s=performance.now(),i=this.getVideoPlaybackQuality(),a=this.currentTime,r=this.mozPresentedFrames||this.mozPaintedFrames||i.totalVideoFrames-i.droppedVideoFrames,n=(o,h)=>{if(!(t in this._rvfcpolyfillmap))return;const l=this.getVideoPlaybackQuality(),d=this.mozPresentedFrames||this.mozPaintedFrames||l.totalVideoFrames-l.droppedVideoFrames,c=d>r,_=0===r&&0===d&&0===i.totalVideoFrames&&0===i.droppedVideoFrames&&0===l.totalVideoFrames&&0===l.droppedVideoFrames&&Number.isFinite(this.currentTime)&&this.currentTime!==a&&this.readyState>=2&&!this.seeking&&h-s>=1e3/30;if(c||_){const s=this.mozFrameDelay||l.totalFrameDelay-i.totalFrameDelay||0,a=h-o;delete this._rvfcpolyfillmap[t],e(h,{presentationTime:h+1e3*s,expectedDisplayTime:h+a,width:this.videoWidth,height:this.videoHeight,mediaTime:_&&!c?Math.max(0,this.currentTime):Math.max(0,this.currentTime||0)+a/1e3,presentedFrames:d,processingDuration:s})}else this._rvfcpolyfillmap[t]=requestAnimationFrame(e=>n(h,e))};return this._rvfcpolyfillmap[t]=requestAnimationFrame(e=>n(s,e)),t},HTMLVideoElement.prototype.cancelVideoFrameCallback=function(e){const t=this._rvfcpolyfillmap;t&&e in t&&(cancelAnimationFrame(t[e]),delete t[e])});const h={bt709:"BT709",bt470bg:"BT601",smpte170m:"BT601"},l={BT601:{BT709:"1.0863 -0.0723 -0.014 0 0 0.0965 0.8451 0.0584 0 0 -0.0141 -0.0277 1.0418"},BT709:{BT601:"0.9137 0.0784 0.0079 0 0 -0.1049 1.1722 -0.0671 0 0 0.0096 0.0322 0.9582"},FCC:{BT709:"1.0873 -0.0736 -0.0137 0 0 0.0974 0.8494 0.0531 0 0 -0.0127 -0.0251 1.0378",BT601:"1.001 -0.0008 -0.0002 0 0 0.0009 1.005 -0.006 0 0 0.0013 0.0027 0.996"},SMPTE240M:{BT709:"0.9993 0.0006 0.0001 0 0 -0.0004 0.9812 0.0192 0 0 -0.0034 -0.0114 1.0148",BT601:"0.913 0.0774 0.0096 0 0 -0.1051 1.1508 -0.0456 0 0 0.0063 0.0207 0.973"}},d=class e extends EventTarget{constructor(t){var s,i;let a;super(),this._requests=new Set;try{if(!globalThis.Worker)throw this.destroy("Worker not supported");if(!t)throw this.destroy("No options provided");if(this._loaded=new Promise(e=>{this._init=e}),a=e._test(),this._onDemandRender="requestVideoFrameCallback"in HTMLVideoElement.prototype&&(null==(s=t.onDemandRender)||s),this._offscreenRender="transferControlToOffscreen"in HTMLCanvasElement.prototype&&!t.canvas&&(null==(i=t.offscreenRender)||i),this.timeOffset=t.timeOffset||0,this._video=t.video,this._videoHeight=0,this._videoWidth=0,this._videoColorSpace=null,this._canvas=t.canvas,this._video&&!this._canvas)this._canvasParent=document.createElement("div"),this._canvasParent.className="JASSUB",this._canvasParent.style.position="relative",this._canvas=this._createCanvas(),this._video.insertAdjacentElement("afterend",this._canvasParent);else if(!this._canvas)throw this.destroy("Don't know where to render: you should give video or canvas in options.");if(this._bufferCanvas=document.createElement("canvas"),this._bufferCtx=this._bufferCanvas.getContext("2d"),!this._bufferCtx)throw this.destroy("Canvas rendering not supported");this._canvasctrl=this._offscreenRender?this._canvas.transferControlToOffscreen():this._canvas,this._ctx=!this._offscreenRender&&this._canvasctrl.getContext("2d"),this._lastRenderTime=0,this.debug=!!t.debug,this.prescaleFactor=t.prescaleFactor||1,this.prescaleHeightLimit=t.prescaleHeightLimit||1080,this.maxRenderHeight=t.maxRenderHeight||0,this._boundResize=this.resize.bind(this),this._boundTimeUpdate=this._timeupdate.bind(this),this._boundSetRate=()=>{this._destroyed||this.setRate(this._video.playbackRate)},this._boundUpdateColorSpace=this._updateColorSpace.bind(this),this._video&&this.setVideo(t.video),this._onDemandRender&&(this.busy=!1,this._lastDemandTime=null),this._worker=new Worker(t.workerUrl||"jassub-worker.js"),this._worker.onmessage=e=>this._onmessage(e),this._Line truncated
+284 -99
View File
@@ -1,5 +1,5 @@
/*!
* artplayer-plugin-jassub.js v1.1.0
* artplayer-plugin-jassub.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
@@ -7,27 +7,46 @@
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
typeof HTMLVideoElement < "u" && !("requestVideoFrameCallback" in HTMLVideoElement.prototype) && "getVideoPlaybackQuality" in HTMLVideoElement.prototype && (HTMLVideoElement.prototype._rvfcpolyfillmap = {}, HTMLVideoElement.prototype.requestVideoFrameCallback = function(c) {
const e = performance.now(), t = this.getVideoPlaybackQuality(), s = this.mozPresentedFrames || this.mozPaintedFrames || t.totalVideoFrames - t.droppedVideoFrames, r = (n, a) => {
const i = this.getVideoPlaybackQuality(), h = this.mozPresentedFrames || this.mozPaintedFrames || i.totalVideoFrames - i.droppedVideoFrames;
if (h > s) {
const d = this.mozFrameDelay || i.totalFrameDelay - t.totalFrameDelay || 0, l = a - n;
c(a, {
presentationTime: a + d * 1e3,
expectedDisplayTime: a + l,
width: this.videoWidth,
height: this.videoHeight,
mediaTime: Math.max(0, this.currentTime || 0) + l / 1e3,
presentedFrames: h,
processingDuration: d
}), delete this._rvfcpolyfillmap[e];
} else
this._rvfcpolyfillmap[e] = requestAnimationFrame((d) => r(a, d));
if (typeof HTMLVideoElement < "u" && !("requestVideoFrameCallback" in HTMLVideoElement.prototype) && "getVideoPlaybackQuality" in HTMLVideoElement.prototype) {
HTMLVideoElement.prototype.requestVideoFrameCallback = function(callback) {
if (!Object.prototype.hasOwnProperty.call(this, "_rvfcpolyfillmap"))
this._rvfcpolyfillmap = {};
const id = this._rvfcpolyfillid = (this._rvfcpolyfillid || 0) + 1;
const started = performance.now(), initial = this.getVideoPlaybackQuality(), initialTime = this.currentTime;
const initialFrames = this.mozPresentedFrames || this.mozPaintedFrames || initial.totalVideoFrames - initial.droppedVideoFrames;
const poll = (previous, now) => {
if (!(id in this._rvfcpolyfillmap)) return;
const quality = this.getVideoPlaybackQuality();
const frames = this.mozPresentedFrames || this.mozPaintedFrames || quality.totalVideoFrames - quality.droppedVideoFrames;
const advanced = frames > initialFrames;
const mediaFallback = initialFrames === 0 && frames === 0 && initial.totalVideoFrames === 0 && initial.droppedVideoFrames === 0 && quality.totalVideoFrames === 0 && quality.droppedVideoFrames === 0 && Number.isFinite(this.currentTime) && this.currentTime !== initialTime && this.readyState >= 2 && !this.seeking && now - started >= 1e3 / 30;
if (advanced || mediaFallback) {
const delay = this.mozFrameDelay || quality.totalFrameDelay - initial.totalFrameDelay || 0;
const elapsed = now - previous;
delete this._rvfcpolyfillmap[id];
callback(now, {
presentationTime: now + delay * 1e3,
expectedDisplayTime: now + elapsed,
width: this.videoWidth,
height: this.videoHeight,
mediaTime: mediaFallback && !advanced ? Math.max(0, this.currentTime) : Math.max(0, this.currentTime || 0) + elapsed / 1e3,
presentedFrames: frames,
processingDuration: delay
});
} else {
this._rvfcpolyfillmap[id] = requestAnimationFrame((time) => poll(now, time));
}
};
this._rvfcpolyfillmap[id] = requestAnimationFrame((time) => poll(started, time));
return id;
};
return this._rvfcpolyfillmap[e] = requestAnimationFrame((n) => r(e, n)), e;
}, HTMLVideoElement.prototype.cancelVideoFrameCallback = function(c) {
cancelAnimationFrame(this._rvfcpolyfillmap[c]), delete this._rvfcpolyfillmap[c];
});
HTMLVideoElement.prototype.cancelVideoFrameCallback = function(id) {
const callbacks = this._rvfcpolyfillmap;
if (!callbacks || !(id in callbacks)) return;
cancelAnimationFrame(callbacks[id]);
delete callbacks[id];
};
}
const _ = {
bt709: "BT709",
// these might not be exactly correct? oops?
@@ -82,47 +101,65 @@ const _o = class _o extends EventTarget {
* @param {Number} [options.libassGlyphLimit] libass glyph cache memory limit in MiB (approximate).
*/
constructor(e) {
if (super(), !globalThis.Worker)
throw this.destroy("Worker not supported");
if (!e)
throw this.destroy("No options provided");
this._loaded = /** @type {Promise<void>} */
new Promise((s) => {
this._init = s;
});
const t = _o._test();
if (this._onDemandRender = "requestVideoFrameCallback" in HTMLVideoElement.prototype && (e.onDemandRender ?? true), this._offscreenRender = "transferControlToOffscreen" in HTMLCanvasElement.prototype && !e.canvas && (e.offscreenRender ?? true), this.timeOffset = e.timeOffset || 0, this._video = e.video, this._videoHeight = 0, this._videoWidth = 0, this._videoColorSpace = null, this._canvas = e.canvas, this._video && !this._canvas)
this._canvasParent = document.createElement("div"), this._canvasParent.className = "JASSUB", this._canvasParent.style.position = "relative", this._canvas = this._createCanvas(), this._video.insertAdjacentElement("afterend", this._canvasParent);
else if (!this._canvas)
throw this.destroy("Don't know where to render: you should give video or canvas in options.");
if (this._bufferCanvas = document.createElement("canvas"), this._bufferCtx = this._bufferCanvas.getContext("2d"), !this._bufferCtx)
throw this.destroy("Canvas rendering not supported");
this._canvasctrl = this._offscreenRender ? this._canvas.transferControlToOffscreen() : this._canvas, this._ctx = !this._offscreenRender && this._canvasctrl.getContext("2d"), this._lastRenderTime = 0, this.debug = !!e.debug, this.prescaleFactor = e.prescaleFactor || 1, this.prescaleHeightLimit = e.prescaleHeightLimit || 1080, this.maxRenderHeight = e.maxRenderHeight || 0, this._boundResize = this.resize.bind(this), this._boundTimeUpdate = this._timeupdate.bind(this), this._boundSetRate = this.setRate.bind(this), this._boundUpdateColorSpace = this._updateColorSpace.bind(this), this._video && this.setVideo(e.video), this._onDemandRender && (this.busy = false, this._lastDemandTime = null), this._worker = new Worker(e.workerUrl || "jassub-worker.js"), this._worker.onmessage = (s) => this._onmessage(s), this._worker.onerror = (s) => this._error(s), t.then(() => {
this._worker.postMessage({
target: "init",
wasmUrl: _o._supportsSIMD && e.modernWasmUrl ? e.modernWasmUrl : e.wasmUrl ?? "jassub-worker.wasm",
legacyWasmUrl: e.legacyWasmUrl ?? "jassub-worker.wasm.js",
asyncRender: typeof createImageBitmap < "u" && (e.asyncRender ?? true),
onDemandRender: this._onDemandRender,
width: this._canvasctrl.width || 0,
height: this._canvasctrl.height || 0,
blendMode: e.blendMode || "js",
subUrl: e.subUrl,
subContent: e.subContent || null,
fonts: e.fonts || [],
availableFonts: e.availableFonts || { "liberation sans": "./default.woff2" },
fallbackFont: e.fallbackFont || "liberation sans",
debug: this.debug,
targetFps: e.targetFps || 24,
dropAllAnimations: e.dropAllAnimations,
dropAllBlur: e.dropAllBlur,
libassMemoryLimit: e.libassMemoryLimit || 0,
libassGlyphLimit: e.libassGlyphLimit || 0,
// @ts-ignore
useLocalFonts: typeof queryLocalFonts < "u" && (e.useLocalFonts ?? true),
hasBitmapBug: _o._hasBitmapBug
}), this._offscreenRender === true && this.sendMessage("offscreenCanvas", null, [this._canvasctrl]);
});
super();
this._requests = /* @__PURE__ */ new Set();
let t;
try {
if (!globalThis.Worker)
throw this.destroy("Worker not supported");
if (!e)
throw this.destroy("No options provided");
this._loaded = /** @type {Promise<void>} */
new Promise((s) => {
this._init = s;
});
t = _o._test();
if (this._onDemandRender = "requestVideoFrameCallback" in HTMLVideoElement.prototype && (e.onDemandRender ?? true), this._offscreenRender = "transferControlToOffscreen" in HTMLCanvasElement.prototype && !e.canvas && (e.offscreenRender ?? true), this.timeOffset = e.timeOffset || 0, this._video = e.video, this._videoHeight = 0, this._videoWidth = 0, this._videoColorSpace = null, this._canvas = e.canvas, this._video && !this._canvas)
this._canvasParent = document.createElement("div"), this._canvasParent.className = "JASSUB", this._canvasParent.style.position = "relative", this._canvas = this._createCanvas(), this._video.insertAdjacentElement("afterend", this._canvasParent);
else if (!this._canvas)
throw this.destroy("Don't know where to render: you should give video or canvas in options.");
if (this._bufferCanvas = document.createElement("canvas"), this._bufferCtx = this._bufferCanvas.getContext("2d"), !this._bufferCtx)
throw this.destroy("Canvas rendering not supported");
this._canvasctrl = this._offscreenRender ? this._canvas.transferControlToOffscreen() : this._canvas, this._ctx = !this._offscreenRender && this._canvasctrl.getContext("2d"), this._lastRenderTime = 0, this.debug = !!e.debug, this.prescaleFactor = e.prescaleFactor || 1, this.prescaleHeightLimit = e.prescaleHeightLimit || 1080, this.maxRenderHeight = e.maxRenderHeight || 0, this._boundResize = this.resize.bind(this), this._boundTimeUpdate = this._timeupdate.bind(this), this._boundSetRate = () => {
if (!this._destroyed) this.setRate(this._video.playbackRate);
}, this._boundUpdateColorSpace = this._updateColorSpace.bind(this), this._video && this.setVideo(e.video), this._onDemandRender && (this.busy = false, this._lastDemandTime = null), this._worker = new Worker(e.workerUrl || "jassub-worker.js"), this._worker.onmessage = (s) => this._onmessage(s), this._worker.onerror = (s) => this._error(s), t.then(() => {
if (this._destroyed) return;
this._worker.postMessage({
target: "init",
wasmUrl: _o._supportsSIMD && e.modernWasmUrl ? e.modernWasmUrl : e.wasmUrl ?? "jassub-worker.wasm",
legacyWasmUrl: e.legacyWasmUrl ?? "jassub-worker.wasm.js",
asyncRender: typeof createImageBitmap < "u" && (e.asyncRender ?? true),
onDemandRender: this._onDemandRender,
width: this._canvasctrl.width || 0,
height: this._canvasctrl.height || 0,
blendMode: e.blendMode || "js",
subUrl: e.subUrl,
subContent: e.subContent || null,
fonts: e.fonts || [],
availableFonts: e.availableFonts || { "liberation sans": "./default.woff2" },
fallbackFont: e.fallbackFont || "liberation sans",
debug: this.debug,
targetFps: e.targetFps || 24,
dropAllAnimations: e.dropAllAnimations,
dropAllBlur: e.dropAllBlur,
libassMemoryLimit: e.libassMemoryLimit || 0,
libassGlyphLimit: e.libassGlyphLimit || 0,
// @ts-ignore
useLocalFonts: typeof queryLocalFonts < "u" && (e.useLocalFonts ?? true),
hasBitmapBug: _o._hasBitmapBug
});
}).catch((error) => {
if (!this._destroyed) this.destroy(error);
});
} catch (error) {
t?.catch(() => {
});
try {
this.destroy();
} catch {
}
throw error;
}
}
_createCanvas() {
return this._canvas = document.createElement("canvas"), this._canvas.style.display = "block", this._canvas.style.position = "absolute", this._canvas.style.pointerEvents = "none", this._canvasParent.appendChild(this._canvas), this._canvas;
@@ -183,6 +220,7 @@ const _o = class _o extends EventTarget {
* @param {Boolean} [force=false]
*/
resize(e = 0, t = 0, s = 0, r = 0, n = this._video?.paused) {
if (this._destroyed) return;
if ((!e || !t) && this._video) {
const a = this._getVideoPosition();
let i = null;
@@ -193,7 +231,7 @@ const _o = class _o extends EventTarget {
i = this._computeCanvasSize(a.width || 0, a.height || 0);
e = i.width, t = i.height, this._canvasParent && (s = a.y - (this._canvasParent.getBoundingClientRect().top - this._video.getBoundingClientRect().top), r = a.x), this._canvas.style.width = a.width + "px", this._canvas.style.height = a.height + "px";
}
this._canvas.style.top = s + "px", this._canvas.style.left = r + "px", n && this.busy === false ? this.busy = true : n = false, this.sendMessage("canvas", { width: e, height: t, videoWidth: this._videoWidth || this._video.videoWidth, videoHeight: this._videoHeight || this._video.videoHeight, force: n });
this._canvas.style.top = s + "px", this._canvas.style.left = r + "px", n && this.busy === false ? this.busy = true : n = false, this.sendMessage("canvas", { width: e, height: t, videoWidth: this._videoWidth || this._video?.videoWidth || e, videoHeight: this._videoHeight || this._video?.videoHeight || t, force: n });
}
_getVideoPosition(e = this._video.videoWidth, t = this._video.videoHeight) {
const s = e / t, { offsetWidth: r, offsetHeight: n } = this._video, a = r / n;
@@ -213,6 +251,7 @@ const _o = class _o extends EventTarget {
return { width: e, height: t };
}
_timeupdate({ type: e }) {
if (this._destroyed) return;
const s = {
seeking: true,
waiting: true,
@@ -225,7 +264,34 @@ const _o = class _o extends EventTarget {
* @param {HTMLVideoElement} video
*/
setVideo(e) {
e instanceof HTMLVideoElement ? (this._removeListeners(), this._video = e, this._onDemandRender ? this._video.requestVideoFrameCallback(this._handleRVFC.bind(this)) : (this._playstate = e.paused, e.addEventListener("timeupdate", this._boundTimeUpdate, false), e.addEventListener("progress", this._boundTimeUpdate, false), e.addEventListener("waiting", this._boundTimeUpdate, false), e.addEventListener("seeking", this._boundTimeUpdate, false), e.addEventListener("playing", this._boundTimeUpdate, false), e.addEventListener("ratechange", this._boundSetRate, false), e.addEventListener("resize", this._boundResize, false)), "VideoFrame" in window && (e.addEventListener("loadedmetadata", this._boundUpdateColorSpace, false), e.readyState > 2 && this._updateColorSpace()), e.videoWidth > 0 && this.resize(), typeof ResizeObserver < "u" && (this._ro || (this._ro = new ResizeObserver(() => this.resize())), this._ro.observe(e))) : this._error("Video element invalid!");
if (this._destroyed) return;
if (!(e instanceof HTMLVideoElement)) {
this._error("Video element invalid!");
return;
}
this._removeListeners();
this._video = e;
this._videoWidth = this._videoHeight = 0;
this._videoColorSpace = null;
if (this._canvasParent && this._canvasParent.parentNode !== e.parentNode)
e.insertAdjacentElement("afterend", this._canvasParent);
if (this._onDemandRender) this._requestFrame();
else {
this._playstate = e.paused;
for (const name of ["timeupdate", "progress", "waiting", "seeking", "playing"])
e.addEventListener(name, this._boundTimeUpdate, false);
e.addEventListener("ratechange", this._boundSetRate, false);
e.addEventListener("resize", this._boundResize, false);
}
if ("VideoFrame" in window) {
e.addEventListener("loadedmetadata", this._boundUpdateColorSpace, false);
if (e.readyState > 2) this._updateColorSpace();
}
if (e.videoWidth > 0) this.resize();
if (typeof ResizeObserver < "u") {
this._ro || (this._ro = new ResizeObserver(() => this.resize()));
this._ro.observe(e);
}
}
runBenchmark() {
this.sendMessage("runBenchmark");
@@ -317,7 +383,7 @@ const _o = class _o extends EventTarget {
getEvents(e) {
this._fetchFromWorker({
target: "getEvents"
}, (t, { events: s }) => {
}, (t, { events: s } = {}) => {
e(t, s);
});
}
@@ -392,7 +458,7 @@ const _o = class _o extends EventTarget {
getStyles(e) {
this._fetchFromWorker({
target: "getStyles"
}, (t, { styles: s }) => {
}, (t, { styles: s } = {}) => {
e(t, s);
});
}
@@ -434,12 +500,22 @@ const _o = class _o extends EventTarget {
}
}
_unbusy() {
if (this._destroyed) return;
this._lastDemandTime ? this._demandRender(this._lastDemandTime) : this.busy = false;
}
_handleRVFC(e, { mediaTime: t, width: s, height: r }) {
if (this._destroyed)
return null;
this.busy ? this._lastDemandTime = { mediaTime: t, width: s, height: r } : (this.busy = true, this._demandRender({ mediaTime: t, width: s, height: r })), this._video.requestVideoFrameCallback(this._handleRVFC.bind(this));
this.busy ? this._lastDemandTime = { mediaTime: t, width: s, height: r } : (this.busy = true, this._demandRender({ mediaTime: t, width: s, height: r })), this._requestFrame();
}
_requestFrame() {
if (this._destroyed || !this._video || this._frameCallback != null) return;
const video = this._video, generation = this._videoGeneration;
this._frameCallback = video.requestVideoFrameCallback((time, metadata) => {
if (this._destroyed || generation !== this._videoGeneration || video !== this._video) return;
this._frameCallback = null;
this._handleRVFC(time, metadata);
});
}
_demandRender({ mediaTime: e, width: t, height: s }) {
this._lastDemandTime = null, (t !== this._videoWidth || s !== this._videoHeight) && (this._videoWidth = t, this._videoHeight = s, this.resize()), this.sendMessage("demand", { time: e + this.timeOffset });
@@ -452,17 +528,25 @@ const _o = class _o extends EventTarget {
}
// if the video or track changed, we need to re-attach the offscreen canvas
_reAttachOffscreen() {
if (!this._offscreenRender || !this._ctx)
if (this._destroyed || !this._offscreenRender || !this._ctx)
return null;
this._canvas.remove(), this._createCanvas(), this._canvasctrl = this._canvas.transferControlToOffscreen(), this._ctx = false, this.sendMessage("offscreenCanvas", null, [this._canvasctrl]), this.resize(0, 0, 0, 0, true);
this._canvas.remove(), this._createCanvas(), this._canvasctrl = this._canvas.transferControlToOffscreen(), this._ctx = false, this.busy = false, this._lastDemandTime = null, this.sendMessage("offscreenCanvas", null, [this._canvasctrl]), this.resize(0, 0, 0, 0, true);
}
_updateColorSpace() {
this._video.requestVideoFrameCallback(() => {
if (this._destroyed || this._colorCallback != null) return;
const video = this._video, generation = this._videoGeneration;
this._colorCallback = video.requestVideoFrameCallback(() => {
if (this._destroyed || generation !== this._videoGeneration || video !== this._video) return;
this._colorCallback = null;
let frame;
try {
const e = new VideoFrame(this._video);
this._videoColorSpace = _[e.colorSpace.matrix], e.close(), this.sendMessage("getColorSpace");
frame = new VideoFrame(video);
this._videoColorSpace = _[frame.colorSpace.matrix];
this.sendMessage("getColorSpace");
} catch (e) {
console.warn(e);
} finally {
frame?.close();
}
});
}
@@ -476,9 +560,17 @@ const _o = class _o extends EventTarget {
!e || !t || e !== t && (this._detachOffscreen(), this._ctx.filter = `url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'><filter id='f'><feColorMatrix type='matrix' values='${f[e][t]} 0 0 0 0 0 1 0'/></filter></svg>#f")`);
}
_render({ images: e, asyncRender: t, times: s, width: r, height: n, colorSpace: a }) {
this._unbusy(), this.debug && (s.IPCTime = Date.now() - s.JSRenderTime), (this._canvasctrl.width !== r || this._canvasctrl.height !== n) && (this._canvasctrl.width = r, this._canvasctrl.height = n, this._verifyColorSpace({ subtitleColorSpace: a })), this._ctx.clearRect(0, 0, this._canvasctrl.width, this._canvasctrl.height);
for (const i of e)
i.image && (t ? (this._ctx.drawImage(i.image, i.x, i.y), i.image.close()) : (this._bufferCanvas.width = i.w, this._bufferCanvas.height = i.h, this._bufferCtx.putImageData(new ImageData(this._fixAlpha(new Uint8ClampedArray(i.image)), i.w, i.h), 0, 0), this._ctx.drawImage(this._bufferCanvas, i.x, i.y)));
if (!this._ctx) {
for (const image of e) image.image?.close?.();
return;
}
try {
this._unbusy(), this.debug && (s.IPCTime = Date.now() - s.JSRenderTime), (this._canvasctrl.width !== r || this._canvasctrl.height !== n) && (this._canvasctrl.width = r, this._canvasctrl.height = n, this._verifyColorSpace({ subtitleColorSpace: a })), this._ctx.clearRect(0, 0, this._canvasctrl.width, this._canvasctrl.height);
for (const i of e)
i.image && (t ? this._ctx.drawImage(i.image, i.x, i.y) : (this._bufferCanvas.width = i.w, this._bufferCanvas.height = i.h, this._bufferCtx.putImageData(new ImageData(this._fixAlpha(new Uint8ClampedArray(i.image)), i.w, i.h), 0, 0), this._ctx.drawImage(this._bufferCanvas, i.x, i.y)));
} finally {
if (t) for (const i of e) i.image?.close();
}
if (this.debug) {
s.JSRenderTime = Date.now() - s.JSRenderTime - s.IPCTime;
let i = 0;
@@ -496,6 +588,11 @@ const _o = class _o extends EventTarget {
return e;
}
_ready() {
if (this._destroyed) return;
if (this._offscreenRender === true && !this._initialOffscreenSent) {
this._initialOffscreenSent = true;
this._worker.postMessage({ target: "offscreenCanvas", transferable: [this._canvasctrl] }, [this._canvasctrl]);
}
this._init(), this.dispatchEvent(new CustomEvent("ready"));
}
/**
@@ -505,7 +602,10 @@ const _o = class _o extends EventTarget {
* @param {Transferable[]} [transferable] Array of transferables.
*/
async sendMessage(e, t = {}, s) {
await this._loaded, s ? this._worker.postMessage({
if (this._destroyed) return;
await this._loaded;
if (this._destroyed) return;
s ? this._worker.postMessage({
target: e,
transferable: s,
...t
@@ -515,23 +615,53 @@ const _o = class _o extends EventTarget {
});
}
_fetchFromWorker(e, t) {
if (this._destroyed) {
t(new Error("JASSUB instance destroyed"));
return;
}
const worker = this._worker;
let timer, settled = false;
const cleanup = () => {
worker.removeEventListener("message", onMessage);
worker.removeEventListener("error", onError);
clearTimeout(timer);
this._requests.delete(cancel);
};
const finish = (error, data) => {
if (settled) return;
settled = true;
cleanup();
t(error, data);
};
const onMessage = ({ data }) => {
if (data.target === e.target) finish(null, data);
};
const onError = (error) => finish(error);
const cancel = () => {
if (settled) return;
settled = true;
cleanup();
return () => t(new Error("JASSUB instance destroyed"));
};
try {
const s = e.target, r = setTimeout(() => {
a(new Error("Error: Timeout while try to fetch " + s));
}, 5e3), n = ({ data: i }) => {
i.target === s && (t(null, i), this._worker.removeEventListener("message", n), this._worker.removeEventListener("error", a), clearTimeout(r));
}, a = (i) => {
t(i), this._worker.removeEventListener("message", n), this._worker.removeEventListener("error", a), clearTimeout(r);
};
this._worker.addEventListener("message", n), this._worker.addEventListener("error", a), this._worker.postMessage(e);
this._requests.add(cancel);
worker.addEventListener("message", onMessage);
worker.addEventListener("error", onError);
timer = setTimeout(() => onError(new Error("Error: Timeout while try to fetch " + e.target)), 5e3);
worker.postMessage(e);
} catch (s) {
this._error(s);
if (settled) throw s;
finish(s);
}
}
_console({ content: e, command: t }) {
console[t].apply(console, JSON.parse(e));
}
_onmessage({ data: e }) {
if (this._destroyed) {
for (const image of e.images || []) image.image?.close?.();
return;
}
this["_" + e.target] && this["_" + e.target](e);
}
_error(e) {
@@ -539,6 +669,12 @@ const _o = class _o extends EventTarget {
return this.dispatchEvent(s), console.error(t), t;
}
_removeListeners() {
this._videoGeneration = (this._videoGeneration || 0) + 1;
for (const id of [this._frameCallback, this._colorCallback])
if (id != null) this._video?.cancelVideoFrameCallback?.(id);
this._frameCallback = this._colorCallback = null;
this._lastDemandTime = null;
if (this._onDemandRender) this.busy = false;
this._video && (this._ro && this._ro.unobserve(this._video), this._ctx && (this._ctx.filter = "none"), this._video.removeEventListener("timeupdate", this._boundTimeUpdate), this._video.removeEventListener("progress", this._boundTimeUpdate), this._video.removeEventListener("waiting", this._boundTimeUpdate), this._video.removeEventListener("seeking", this._boundTimeUpdate), this._video.removeEventListener("playing", this._boundTimeUpdate), this._video.removeEventListener("ratechange", this._boundSetRate), this._video.removeEventListener("resize", this._boundResize), this._video.removeEventListener("loadedmetadata", this._boundUpdateColorSpace));
}
/**
@@ -546,7 +682,38 @@ const _o = class _o extends EventTarget {
* @param {String|Error} [err] Error to throw when destroying.
*/
destroy(e) {
return e && (e = this._error(e)), this._video && this._canvasParent && this._video.parentNode?.removeChild(this._canvasParent), this._destroyed = true, this._removeListeners(), this.sendMessage("destroy"), this._worker?.terminate(), e;
if (this._destroyed) return e && this._error(e);
this._destroyed = true;
let failure, failed = false;
const attempt = (callback) => {
try {
callback();
} catch (error) {
if (!failed) {
failure = error;
failed = true;
}
}
};
if (e) attempt(() => {
e = this._error(e);
});
attempt(() => this._removeListeners());
attempt(() => this._ro?.disconnect());
attempt(() => this._canvasParent?.remove());
this._init?.();
const callbacks = [];
for (const cancel of [...this._requests || []]) attempt(() => {
const notify = cancel();
if (notify) callbacks.push(notify);
});
for (const notify of callbacks) attempt(notify);
if (this._worker) {
this._worker.onmessage = this._worker.onerror = null;
attempt(() => this._worker.terminate());
}
if (failed) throw failure;
return e;
}
};
// test support for WASM, ImageData, alphaBug, but only once, on init so it doesn't run when first running the page
@@ -557,21 +724,39 @@ __publicField(_o, "_hasAlphaBug", null);
/** @type {boolean|null} */
__publicField(_o, "_hasBitmapBug", null);
let o = _o;
function artplayerPluginJassub(option) {
return (art) => {
const instance = new o({
video: art.video,
...option
});
instance._canvasParent.style.zIndex = 20;
art.on("destroy", () => {
function registerJassub(art, option) {
const instance = new o({ video: art.video, ...option });
let disposed = false;
const dispose = () => {
if (disposed || instance._destroyed)
return;
disposed = true;
try {
instance.destroy();
});
return {
name: "artplayerPluginJassub",
instance
};
} catch (error) {
disposed = false;
throw error;
}
};
try {
if (instance._canvasParent)
instance._canvasParent.style.zIndex = 20;
art.on("destroy", dispose);
} catch (error) {
try {
art.off("destroy", dispose);
} catch {
}
try {
dispose();
} catch {
}
throw error;
}
return { name: "artplayerPluginJassub", instance };
}
function artplayerPluginJassub(option) {
return (art) => registerJassub(art, option);
}
export {
artplayerPluginJassub as default
@@ -1,7 +1,58 @@
/*!
* artplayer-plugin-multiple-subtitles.js v1.2.0
* artplayer-plugin-multiple-subtitles.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*
* This package includes WebVTT parser and serializer code from w3c/webvtt.js.
* Reference revision: 380cfcce34ba8b472d3a31474874eb72a0e5f460
* https://github.com/w3c/webvtt.js/tree/380cfcce34ba8b472d3a31474874eb72a0e5f460
* The parser has a CC0 public-domain dedication. Local adaptations replace
* the IIFE/global exports with named ESM exports and format the code.
* The ArtPlayer plugin wrapper remains MIT licensed.
*
* ## creative commons
*
* # CC0 1.0 Universal
*
* CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER.
*
* ### Statement of Purpose
*
* The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
*
* Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
*
* For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
*
* 1. __Copyright and Related Rights.__ A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
*
* i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
*
* ii. moral rights retained by the original author(s) and/or performer(s);
*
* iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
*
* iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
*
* v. rights protecting the extraction, dissemination, use and reuse of data in a Work;
*
* vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
*
* vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
*
* 2. __Waiver.__ To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
*
* 3. __Public License Fallback.__ Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
*
* 4. __Limitations and Disclaimers.__
*
* a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
*
* b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
*
* c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
*
* d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerPluginMultipleSubtitles=t(),define(function(){return t.artplayerPluginMultipleSubtitles})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginMultipleSubtitles=t()}(this,function(){"use strict";var e={direction:"horizontal",snapToLines:!0,linePosition:"auto",lineAlign:"start",textPosition:"auto",positionAlign:"auto",size:100,alignment:"center"},t=function(t){t||(t={"&amp":"&","&lt":"<","&gt":">","&lrm":"\u200e","&rlm":"\u200f","&nbsp":"\xa0"}),this.entities=t,this.parse=function(a,s){a=a.replace(/\0/g,"\ufffd");var r=Date.now(),o=0,l=a.split(/\r\n|\r|\n/),f=!1,c=[],u=[],d=[];function p(e,t){d.push({message:e,line:o+1,col:t})}var m=l[o],g=m.length,h="WEBVTT",v=0,b=6;for("\ufeff"===m[0]&&(v=1,b+=1),(g<b||m.indexOf(h)!==0+v||g>b&&" "!==m[b]&&"\t"!==m[b])&&p('No valid signature. (File needs to start with "WEBVTT".)'),o++;""!=l[o]&&void 0!=l[o];){if(p("No blank line after the signature."),-1!=l[o].indexOf("--\x3e")){f=!0;break}o++}for(;void 0!=l[o];){for(var x;!f&&""==l[o];)o++;if(!f&&void 0==l[o])break;x=Object.assign({},e,{id:"",startTime:0,endTime:0,pauseOnExit:!1,direction:"horizontal",snapToLines:!0,linePosition:"auto",lineAlign:"start",textPosition:"auto",positionAlign:"auto",size:100,alignment:"center",text:"",tree:null});var T=!0;if(-1==l[o].indexOf("--\x3e")){if(x.id=l[o],/^NOTE($|[ \t])/.test(x.id)){for(o++;""!=l[o]&&void 0!=l[o];)-1!=l[o].indexOf("--\x3e")&&p("Cannot have timestamp in a comment."),o++;continue}if(/^STYLE($|[ \t])/.test(x.id)){var y=[],w=!1;for(o++;""!=l[o]&&void 0!=l[o];)-1!=l[o].indexOf("--\x3e")&&(p("Cannot have timestamp in a style block."),w=!0),y.push(l[o]),o++;if(u.length){p("Style blocks cannot appear after the first cue.");continue}w||c.push(y.join("\n"));continue}if(""==l[++o]||void 0==l[o]){p("Cue identifier cannot be standalone.");continue}if(-1==l[o].indexOf("--\x3e")){T=!1,p("Cue identifier needs to be followed by timestamp.");continue}}f=!1;var O=new n(l[o],p),L=0;if(u.length>0&&(L=u[u.length-1].startTime),!T||O.parse(x,L)){for(o++;""!=l[o]&&void 0!=l[o];){if(-1!=l[o].indexOf("--\x3e")){p("Blank line missing before cue."),f=!0;break}""!=x.text&&(x.text+="\n"),x.text+=l[o],o++}var I=new i(x.text,p,s,t);x.tree=I.parse(x.startTime,x.endTime),u.push(x)}else for(x=null,o++;""!=l[o]&&void 0!=l[o];){if(-1!=l[o].indexOf("--\x3e")){f=!0;break}o++}}return u.sort(function(e,t){return e.startTime<t.startTime?-1:e.startTime>t.startTime?1:e.endTime>t.endTime?-1:e.endTime<t.endTime?1:0}),{cues:u,errors:d,time:Date.now()-r,styles:c}}},n=function(e,t){var n=/[\u0020\t\f]/,i=/[^\u0020\t\f]/,a=(e=e,0),s=function(e){t(e,a+1)};function r(t){for(;void 0!=e[a]&&t.test(e[a]);)a++}function o(t){for(var n="";void 0!=e[a]&&t.test(e[a]);)n+=e[a],a++;return n}function l(){var t,n,i,r,l="minutes";if(void 0!=e[a])if(/\d/.test(e[a]))if(((t=o(/\d/)).length>2||parseInt(t,10)>59)&&(l="hours"),":"==e[a])if(a++,2==(n=o(/\d/)).length){if("hours"==l||":"==e[a]){if(":"!=e[a])return void s("No seconds found or minutes is greater than 59.");if(a++,2!=(i=o(/\d/)).length)return void s("Must be exactly two digits.")}else{if(2!=t.length)return void s("Must be exactly two digits.");i=n,n=t,t="0"}if("."==e[a])if(a++,3==(r=o(/\d/)).length)if(parseInt(n,10)>59)s("You cannot have more than 59 minutes.");else{if(!(parseInt(i,10)>59))return 60*parseInt(t,10)*60+60*parseInt(n,10)+parseInt(i,10)+parseInt(r,10)/1e3;s("You cannot have more than 59 seconds.")}else s("Milliseconds must be given in three digits.");else s('No decimal separator (".") found.')}else s("Must be exactly two digits.");else s("No time unit separator found.");else s("Timestamp must start with a character in the range 0-9.");else s("No timestamp found.")}this.parse=function(t,o){if(r(n),t.startTime=l(),void 0!=t.startTime)if(t.startTime<o&&s("Start timestamp is not greater than or equal to start timestamp of previous cue."),i.test(e[a])&&s("Timestamp not separated from '--\x3e' by whitespace."),r(n),"-"==e[a])if(a++,"-"==e[a])if(a++,">"==e[a]){if(a++,i.test(e[a])&&s("'--\x3e' not separated from timestamp by whitespace."),r(n),t.endTime=l(),void 0!=t.endTime)return t.endTime<=t.startTime&&s("End timestamp is not greater than start timestamp."),i.test(e[a]),r(n),function(e,t){for(var i=e.split(n),a=[],r=0;r<i.length;r++)if(""!=i[r]){var o=i[r].indexOf(":"),l=i[r].slice(0,o),f=i[r].slice(o+1);if(-1!=a.indexOf(l)&&s("Duplicate setting."),a.push(l),""==f)return void s("No value for setting defined.");if("vertical"==l){if("rl"!=f&&"lr"!=f){s("Writing direction can only be set to 'rl' or 'rl'.");continue}t.direction=f}else if("line"==l){if(/,/.test(f)){var c=f.split(",");f=c[0];var u=c[1]}if(!/^[-\d](\d*)(\.\d+)?%?$/.test(f)){s("Line position takes a number or percentage.");continue}if(-1!=f.indexOf("-",1)){s("Line position can only have '-' at the start.");continue}if(-1!=f.indexOf("%")&&f.indexOf("%")!=f.Line truncated
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginMultipleSubtitles=t(),define(function(){return e.artplayerPluginMultipleSubtitles})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginMultipleSubtitles=t()}(this,function(){"use strict";var e={direction:"horizontal",snapToLines:!0,linePosition:"auto",lineAlign:"start",textPosition:"auto",positionAlign:"auto",size:100,alignment:"center"},t=function(t){t||(t={"&amp":"&","&lt":"<","&gt":">","&lrm":"\u200e","&rlm":"\u200f","&nbsp":"\xa0"}),this.entities=t,this.parse=function(s,a){s=s.replace(/\0/g,"\ufffd");var r=Date.now(),o=0,l=s.split(/\r\n|\r|\n/),c=!1,f=[],u=[],d=[];function p(e,t){d.push({message:e,line:o+1,col:t})}var m=l[o],g=m.length,h="WEBVTT",v=0,b=6;for("\ufeff"===m[0]&&(v=1,b+=1),(g<b||m.indexOf(h)!==0+v||g>b&&" "!==m[b]&&"\t"!==m[b])&&p('No valid signature. (File needs to start with "WEBVTT".)'),o++;""!=l[o]&&void 0!=l[o];){if(p("No blank line after the signature."),-1!=l[o].indexOf("--\x3e")){c=!0;break}o++}for(;void 0!=l[o];){for(var x;!c&&""==l[o];)o++;if(!c&&void 0==l[o])break;x=Object.assign({},e,{id:"",startTime:0,endTime:0,pauseOnExit:!1,direction:"horizontal",snapToLines:!0,linePosition:"auto",lineAlign:"start",textPosition:"auto",positionAlign:"auto",size:100,alignment:"center",text:"",tree:null});var T=!0;if(-1==l[o].indexOf("--\x3e")){if(x.id=l[o],/^NOTE($|[ \t])/.test(x.id)){for(o++;""!=l[o]&&void 0!=l[o];)-1!=l[o].indexOf("--\x3e")&&p("Cannot have timestamp in a comment."),o++;continue}if(/^STYLE($|[ \t])/.test(x.id)){var y=[],w=!1;for(o++;""!=l[o]&&void 0!=l[o];)-1!=l[o].indexOf("--\x3e")&&(p("Cannot have timestamp in a style block."),w=!0),y.push(l[o]),o++;if(u.length){p("Style blocks cannot appear after the first cue.");continue}w||f.push(y.join("\n"));continue}if(""==l[++o]||void 0==l[o]){p("Cue identifier cannot be standalone.");continue}if(-1==l[o].indexOf("--\x3e")){T=!1,p("Cue identifier needs to be followed by timestamp.");continue}}c=!1;var $=new n(l[o],p),A=0;if(u.length>0&&(A=u[u.length-1].startTime),!T||$.parse(x,A)){for(o++;""!=l[o]&&void 0!=l[o];){if(-1!=l[o].indexOf("--\x3e")){p("Blank line missing before cue."),c=!0;break}""!=x.text&&(x.text+="\n"),x.text+=l[o],o++}var O=new i(x.text,p,a,t);x.tree=O.parse(x.startTime,x.endTime),u.push(x)}else for(x=null,o++;""!=l[o]&&void 0!=l[o];){if(-1!=l[o].indexOf("--\x3e")){c=!0;break}o++}}return u.sort(function(e,t){return e.startTime<t.startTime?-1:e.startTime>t.startTime?1:e.endTime>t.endTime?-1:e.endTime<t.endTime?1:0}),{cues:u,errors:d,time:Date.now()-r,styles:f}}},n=function(e,t){var n=/[\u0020\t\f]/,i=/[^\u0020\t\f]/,s=(e=e,0),a=function(e){t(e,s+1)};function r(t){for(;void 0!=e[s]&&t.test(e[s]);)s++}function o(t){for(var n="";void 0!=e[s]&&t.test(e[s]);)n+=e[s],s++;return n}function l(){var t,n,i,r,l="minutes";if(void 0!=e[s])if(/\d/.test(e[s]))if(((t=o(/\d/)).length>2||parseInt(t,10)>59)&&(l="hours"),":"==e[s])if(s++,2==(n=o(/\d/)).length){if("hours"==l||":"==e[s]){if(":"!=e[s])return void a("No seconds found or minutes is greater than 59.");if(s++,2!=(i=o(/\d/)).length)return void a("Must be exactly two digits.")}else{if(2!=t.length)return void a("Must be exactly two digits.");i=n,n=t,t="0"}if("."==e[s])if(s++,3==(r=o(/\d/)).length)if(parseInt(n,10)>59)a("You cannot have more than 59 minutes.");else{if(!(parseInt(i,10)>59))return 60*parseInt(t,10)*60+60*parseInt(n,10)+parseInt(i,10)+parseInt(r,10)/1e3;a("You cannot have more than 59 seconds.")}else a("Milliseconds must be given in three digits.");else a('No decimal separator (".") found.')}else a("Must be exactly two digits.");else a("No time unit separator found.");else a("Timestamp must start with a character in the range 0-9.");else a("No timestamp found.")}this.parse=function(t,o){if(r(n),t.startTime=l(),void 0!=t.startTime)if(t.startTime<o&&a("Start timestamp is not greater than or equal to start timestamp of previous cue."),i.test(e[s])&&a("Timestamp not separated from '--\x3e' by whitespace."),r(n),"-"==e[s])if(s++,"-"==e[s])if(s++,">"==e[s]){if(s++,i.test(e[s])&&a("'--\x3e' not separated from timestamp by whitespace."),r(n),t.endTime=l(),void 0!=t.endTime)return t.endTime<=t.startTime&&a("End timestamp is not greater than start timestamp."),i.test(e[s]),r(n),function(e,t){for(var i=e.split(n),s=[],r=0;r<i.length;r++)if(""!=i[r]){var o=i[r].indexOf(":"),l=i[r].slice(0,o),c=i[r].slice(o+1);if(-1!=s.indexOf(l)&&a("Duplicate setting."),s.push(l),""==c)return void a("No value for setting defined.");if("vertical"==l){if("rl"!=c&&"lr"!=c){a("Writing direction can only be set to 'rl' or 'rl'.");continue}t.direction=c}else if("line"==l){if(/,/.test(c)){var f=c.split(",");c=f[0];var u=f[1]}if(!/^[-\d](\d*)(\.\d+)?%?$/.test(c)){a("Line position takes a number or percentage.");continue}if(-1!=c.indexOf("-",1)){a("Line position can only have '-' at the start.");continue}if(-1!=c.indexOf("%")&&c.indexOf("%")!=c.Line truncated
@@ -1,7 +1,58 @@
/*!
* artplayer-plugin-multiple-subtitles.js v1.2.0
* artplayer-plugin-multiple-subtitles.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*
* This package includes WebVTT parser and serializer code from w3c/webvtt.js.
* Reference revision: 380cfcce34ba8b472d3a31474874eb72a0e5f460
* https://github.com/w3c/webvtt.js/tree/380cfcce34ba8b472d3a31474874eb72a0e5f460
* The parser has a CC0 public-domain dedication. Local adaptations replace
* the IIFE/global exports with named ESM exports and format the code.
* The ArtPlayer plugin wrapper remains MIT licensed.
*
* ## creative commons
*
* # CC0 1.0 Universal
*
* CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER.
*
* ### Statement of Purpose
*
* The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
*
* Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
*
* For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
*
* 1. __Copyright and Related Rights.__ A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
*
* i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
*
* ii. moral rights retained by the original author(s) and/or performer(s);
*
* iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
*
* iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
*
* v. rights protecting the extraction, dissemination, use and reuse of data in a Work;
*
* vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
*
* vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
*
* 2. __Waiver.__ To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
*
* 3. __Public License Fallback.__ Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
*
* 4. __Limitations and Disclaimers.__
*
* a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
*
* b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
*
* c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
*
* d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerPluginMultipleSubtitles=t(),define(function(){return t.artplayerPluginMultipleSubtitles})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginMultipleSubtitles=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.defineProperties,n=Object.getOwnPropertyDescriptors,i=Object.getOwnPropertySymbols,a=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,r=(t,n,i)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[n]=i,o=(e,t)=>{for(var n in t||(t={}))a.call(t,n)&&r(e,n,t[n]);if(i)for(var n of i(t))s.call(t,n)&&r(e,n,t[n]);return e},l=(e,t,n)=>new Promise((i,a)=>{var s=e=>{try{o(n.next(e))}catch(t){a(t)}},r=e=>{try{o(n.throw(e))}catch(t){a(t)}},o=e=>e.done?i(e.value):Promise.resolve(e.value).then(s,r);o((n=n.apply(e,t)).next())}),f={direction:"horizontal",snapToLines:!0,linePosition:"auto",lineAlign:"start",textPosition:"auto",positionAlign:"auto",size:100,alignment:"center"},c=function(e){e||(e={"&amp":"&","&lt":"<","&gt":">","&lrm":"\u200e","&rlm":"\u200f","&nbsp":"\xa0"}),this.entities=e,this.parse=function(t,n){t=t.replace(/\0/g,"\ufffd");var i=Date.now(),a=0,s=t.split(/\r\n|\r|\n/),r=!1,o=[],l=[],c=[];function p(e,t){c.push({message:e,line:a+1,col:t})}var m=s[a],g=m.length,h="WEBVTT",v=0,b=6;for("\ufeff"===m[0]&&(v=1,b+=1),(g<b||m.indexOf(h)!==0+v||g>b&&" "!==m[b]&&"\t"!==m[b])&&p('No valid signature. (File needs to start with "WEBVTT".)'),a++;""!=s[a]&&void 0!=s[a];){if(p("No blank line after the signature."),-1!=s[a].indexOf("--\x3e")){r=!0;break}a++}for(;void 0!=s[a];){for(var x;!r&&""==s[a];)a++;if(!r&&void 0==s[a])break;x=Object.assign({},f,{id:"",startTime:0,endTime:0,pauseOnExit:!1,direction:"horizontal",snapToLines:!0,linePosition:"auto",lineAlign:"start",textPosition:"auto",positionAlign:"auto",size:100,alignment:"center",text:"",tree:null});var T=!0;if(-1==s[a].indexOf("--\x3e")){if(x.id=s[a],/^NOTE($|[ \t])/.test(x.id)){for(a++;""!=s[a]&&void 0!=s[a];)-1!=s[a].indexOf("--\x3e")&&p("Cannot have timestamp in a comment."),a++;continue}if(/^STYLE($|[ \t])/.test(x.id)){var y=[],w=!1;for(a++;""!=s[a]&&void 0!=s[a];)-1!=s[a].indexOf("--\x3e")&&(p("Cannot have timestamp in a style block."),w=!0),y.push(s[a]),a++;if(l.length){p("Style blocks cannot appear after the first cue.");continue}w||o.push(y.join("\n"));continue}if(""==s[++a]||void 0==s[a]){p("Cue identifier cannot be standalone.");continue}if(-1==s[a].indexOf("--\x3e")){T=!1,p("Cue identifier needs to be followed by timestamp.");continue}}r=!1;var O=new u(s[a],p),P=0;if(l.length>0&&(P=l[l.length-1].startTime),!T||O.parse(x,P)){for(a++;""!=s[a]&&void 0!=s[a];){if(-1!=s[a].indexOf("--\x3e")){p("Blank line missing before cue."),r=!0;break}""!=x.text&&(x.text+="\n"),x.text+=s[a],a++}var I=new d(x.text,p,n,e);x.tree=I.parse(x.startTime,x.endTime),l.push(x)}else for(x=null,a++;""!=s[a]&&void 0!=s[a];){if(-1!=s[a].indexOf("--\x3e")){r=!0;break}a++}}return l.sort(function(e,t){return e.startTime<t.startTime?-1:e.startTime>t.startTime?1:e.endTime>t.endTime?-1:e.endTime<t.endTime?1:0}),{cues:l,errors:c,time:Date.now()-i,styles:o}}},u=function(e,t){var n=/[\u0020\t\f]/,i=/[^\u0020\t\f]/,a=(e=e,0),s=function(e){t(e,a+1)};function r(t){for(;void 0!=e[a]&&t.test(e[a]);)a++}function o(t){for(var n="";void 0!=e[a]&&t.test(e[a]);)n+=e[a],a++;return n}function l(){var t,n,i,r,l="minutes";if(void 0!=e[a])if(/\d/.test(e[a]))if(((t=o(/\d/)).length>2||parseInt(t,10)>59)&&(l="hours"),":"==e[a])if(a++,2==(n=o(/\d/)).length){if("hours"==l||":"==e[a]){if(":"!=e[a])return void s("No seconds found or minutes is greater than 59.");if(a++,2!=(i=o(/\d/)).length)return void s("Must be exactly two digits.")}else{if(2!=t.length)return void s("Must be exactly two digits.");i=n,n=t,t="0"}if("."==e[a])if(a++,3==(r=o(/\d/)).length)if(parseInt(n,10)>59)s("You cannot have more than 59 minutes.");else{if(!(parseInt(i,10)>59))return 60*parseInt(t,10)*60+60*parseInt(n,10)+parseInt(i,10)+parseInt(r,10)/1e3;s("You cannot have more than 59 seconds.")}else s("Milliseconds must be given in three digits.");else s('No decimal separator (".") found.')}else s("Must be exactly two digits.");else s("No time unit separator found.");else s("Timestamp must start with a character in the range 0-9.");else s("No timestamp found.")}this.parse=function(t,o){if(r(n),t.startTime=l(),void 0!=t.startTime)if(t.startTime<o&&s("Start timestamp is not greater than or equal to start timestamp of previous cue."),i.test(e[a])&&s("Timestamp not separated from '--\x3e' by whitespace."),r(n),"-"==e[a])if(a++,"-"==e[a])if(a++,">"==e[a]){if(a++,i.test(e[a])&&s("'--\x3e' not separated from timestamp by whitespace."),r(n),t.endTime=l(),void 0!=t.endTime)return t.endTime<=t.startTime&&s("End timestamp is not greater than start timestamp."),i.test(e[a]),r(n),function(e,t){for(var i=e.split(n),a=[],r=0;r<i.length;r++)ifLine truncated
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginMultipleSubtitles=t(),define(function(){return e.artplayerPluginMultipleSubtitles})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginMultipleSubtitles=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.defineProperties,n=Object.getOwnPropertyDescriptors,i=Object.getOwnPropertySymbols,r=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,o=(t,n,i)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[n]=i,a=(e,t)=>{for(var n in t||(t={}))r.call(t,n)&&o(e,n,t[n]);if(i)for(var n of i(t))s.call(t,n)&&o(e,n,t[n]);return e},l=(e,i)=>t(e,n(i)),c=(e,t,n)=>new Promise((i,r)=>{var s=e=>{try{a(n.next(e))}catch(t){r(t)}},o=e=>{try{a(n.throw(e))}catch(t){r(t)}},a=e=>e.done?i(e.value):Promise.resolve(e.value).then(s,o);a((n=n.apply(e,t)).next())});var u={direction:"horizontal",snapToLines:!0,linePosition:"auto",lineAlign:"start",textPosition:"auto",positionAlign:"auto",size:100,alignment:"center"},f=function(e){e||(e={"&amp":"&","&lt":"<","&gt":">","&lrm":"\u200e","&rlm":"\u200f","&nbsp":"\xa0"}),this.entities=e,this.parse=function(t,n){t=t.replace(/\0/g,"\ufffd");var i=Date.now(),r=0,s=t.split(/\r\n|\r|\n/),o=!1,a=[],l=[],c=[];function f(e,t){c.push({message:e,line:r+1,col:t})}var m=s[r],g=m.length,h="WEBVTT",v=0,b=6;for("\ufeff"===m[0]&&(v=1,b+=1),(g<b||m.indexOf(h)!==0+v||g>b&&" "!==m[b]&&"\t"!==m[b])&&f('No valid signature. (File needs to start with "WEBVTT".)'),r++;""!=s[r]&&void 0!=s[r];){if(f("No blank line after the signature."),-1!=s[r].indexOf("--\x3e")){o=!0;break}r++}for(;void 0!=s[r];){for(var y;!o&&""==s[r];)r++;if(!o&&void 0==s[r])break;y=Object.assign({},u,{id:"",startTime:0,endTime:0,pauseOnExit:!1,direction:"horizontal",snapToLines:!0,linePosition:"auto",lineAlign:"start",textPosition:"auto",positionAlign:"auto",size:100,alignment:"center",text:"",tree:null});var x=!0;if(-1==s[r].indexOf("--\x3e")){if(y.id=s[r],/^NOTE($|[ \t])/.test(y.id)){for(r++;""!=s[r]&&void 0!=s[r];)-1!=s[r].indexOf("--\x3e")&&f("Cannot have timestamp in a comment."),r++;continue}if(/^STYLE($|[ \t])/.test(y.id)){var T=[],w=!1;for(r++;""!=s[r]&&void 0!=s[r];)-1!=s[r].indexOf("--\x3e")&&(f("Cannot have timestamp in a style block."),w=!0),T.push(s[r]),r++;if(l.length){f("Style blocks cannot appear after the first cue.");continue}w||a.push(T.join("\n"));continue}if(""==s[++r]||void 0==s[r]){f("Cue identifier cannot be standalone.");continue}if(-1==s[r].indexOf("--\x3e")){x=!1,f("Cue identifier needs to be followed by timestamp.");continue}}o=!1;var O=new d(s[r],f),$=0;if(l.length>0&&($=l[l.length-1].startTime),!x||O.parse(y,$)){for(r++;""!=s[r]&&void 0!=s[r];){if(-1!=s[r].indexOf("--\x3e")){f("Blank line missing before cue."),o=!0;break}""!=y.text&&(y.text+="\n"),y.text+=s[r],r++}var j=new p(y.text,f,n,e);y.tree=j.parse(y.startTime,y.endTime),l.push(y)}else for(y=null,r++;""!=s[r]&&void 0!=s[r];){if(-1!=s[r].indexOf("--\x3e")){o=!0;break}r++}}return l.sort(function(e,t){return e.startTime<t.startTime?-1:e.startTime>t.startTime?1:e.endTime>t.endTime?-1:e.endTime<t.endTime?1:0}),{cues:l,errors:c,time:Date.now()-i,styles:a}}},d=function(e,t){var n=/[\u0020\t\f]/,i=/[^\u0020\t\f]/,r=(e=e,0),s=function(e){t(e,r+1)};function o(t){for(;void 0!=e[r]&&t.test(e[r]);)r++}function a(t){for(var n="";void 0!=e[r]&&t.test(e[r]);)n+=e[r],r++;return n}function l(){var t,n,i,o,l="minutes";if(void 0!=e[r])if(/\d/.test(e[r]))if(((t=a(/\d/)).length>2||parseInt(t,10)>59)&&(l="hours"),":"==e[r])if(r++,2==(n=a(/\d/)).length){if("hours"==l||":"==e[r]){if(":"!=e[r])return void s("No seconds found or minutes is greater than 59.");if(r++,2!=(i=a(/\d/)).length)return void s("Must be exactly two digits.")}else{if(2!=t.length)return void s("Must be exactly two digits.");i=n,n=t,t="0"}if("."==e[r])if(r++,3==(o=a(/\d/)).length)if(parseInt(n,10)>59)s("You cannot have more than 59 minutes.");else{if(!(parseInt(i,10)>59))return 60*parseInt(t,10)*60+60*parseInt(n,10)+parseInt(i,10)+parseInt(o,10)/1e3;s("You cannot have more than 59 seconds.")}else s("Milliseconds must be given in three digits.");else s('No decimal separator (".") found.')}else s("Must be exactly two digits.");else s("No time unit separator found.");else s("Timestamp must start with a character in the range 0-9.");else s("No timestamp found.")}this.parse=function(t,a){if(o(n),t.startTime=l(),void 0!=t.startTime)if(t.startTime<a&&s("Start timestamp is not greater than or equal to start timestamp of previous cue."),i.test(e[r])&&s("Timestamp not separated from '--\x3e' by whitespace."),o(n),"-"==e[r])if(r++,"-"==e[r])if(r++,">"==e[r]){if(r++,i.test(e[r])&&s("'--\x3e' not separated from timestamp by whitespace."),o(n),t.endTime=l(),void 0!=t.endTime)return t.endTime<=t.startTime&&s("End timestamp is not greater than start timestamp."),i.test(e[r]),o(n),function(e,t){for(var i=e.split(n),r=[Line truncated
@@ -1,9 +1,80 @@
/*!
* artplayer-plugin-multiple-subtitles.js v1.2.0
* artplayer-plugin-multiple-subtitles.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*
* This package includes WebVTT parser and serializer code from w3c/webvtt.js.
* Reference revision: 380cfcce34ba8b472d3a31474874eb72a0e5f460
* https://github.com/w3c/webvtt.js/tree/380cfcce34ba8b472d3a31474874eb72a0e5f460
* The parser has a CC0 public-domain dedication. Local adaptations replace
* the IIFE/global exports with named ESM exports and format the code.
* The ArtPlayer plugin wrapper remains MIT licensed.
*
* ## creative commons
*
* # CC0 1.0 Universal
*
* CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER.
*
* ### Statement of Purpose
*
* The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
*
* Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
*
* For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
*
* 1. __Copyright and Related Rights.__ A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
*
* i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
*
* ii. moral rights retained by the original author(s) and/or performer(s);
*
* iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
*
* iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
*
* v. rights protecting the extraction, dissemination, use and reuse of data in a Work;
*
* vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
*
* vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
*
* 2. __Waiver.__ To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
*
* 3. __Public License Fallback.__ Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
*
* 4. __Limitations and Disclaimers.__
*
* a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
*
* b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
*
* c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
*
* d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
*/
function renderLegacyCaptions(art) {
const cues = art.subtitle?.textTrack?.activeCues;
if (!cues || cues.length < 2)
return;
const texts = Array.from(cues, (cue) => "text" in cue && typeof cue.text === "string" ? cue.text : "");
const target = art.template.$subtitle;
if (art.option?.subtitle?.escape) {
target.innerHTML = "";
for (const text of texts) {
for (const line of text.split(/\r?\n/)) {
const element = target.ownerDocument.createElement("div");
element.className = "art-subtitle-line";
element.textContent = line;
target.appendChild(element);
}
}
} else {
target.innerHTML = texts.join("");
}
}
var defaultCueSettings = {
direction: "horizontal",
snapToLines: true,
@@ -242,7 +313,7 @@ var WebVTTCueTimingsAndSettingsParser = function(line, errorHandler) {
var settings = input.split(SPACE), seen = [];
for (var i = 0; i < settings.length; i++) {
if (settings[i] == "") continue;
var index = settings[i].indexOf(":"), setting = settings[i].slice(0, index), value = settings[i].slice(index + 1);
var index2 = settings[i].indexOf(":"), setting = settings[i].slice(0, index2), value = settings[i].slice(index2 + 1);
if (seen.indexOf(setting) != -1) {
err("Duplicate setting.");
}
@@ -748,87 +819,301 @@ var WebVTTSerializer = function() {
return result;
};
};
async function loadVtt(option, { getExt, srtToVtt, assToVtt }) {
const response = await fetch(option.url);
const buffer = await response.arrayBuffer();
const decoder = new TextDecoder(option.encoding || "utf-8");
const text = decoder.decode(buffer);
switch (option.type || getExt(option.url)) {
case "srt": {
return srtToVtt(text);
}
case "ass": {
return assToVtt(text);
}
case "vtt": {
return text;
}
default:
return "";
}
const cueEntities = {
"&amp": "&",
"&amp;": "&",
"&lt": "<",
"&lt;": "<",
"&gt": ">",
"&gt;": ">",
"&lrm": "‎",
"&lrm;": "‎",
"&rlm": "‏",
"&rlm;": "‏",
"&nbsp": " ",
"&nbsp;": " "
};
function escapeCueText(value) {
return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
}
function mergeTrees(trees) {
const parser = new WebVTTParser();
const result = parser.parse("", "metadata");
for (let i = 0; i < trees.length; i++) {
const tree = trees[i];
if (!tree.updated) {
tree.updated = true;
for (let j = 0; j < tree.cues.length; j++) {
const cue = tree.cues[j];
for (let k = 0; k < cue.tree.children.length; k++) {
const children = cue.tree.children[k];
children.value = `<div class="art-subtitle-${tree.name}">${children.value}</div>`;
const TIMESTAMP_CLASS = "artplayer-multiple-subtitles-timestamp";
function markTimestamp(node) {
return { type: "object", name: "c", classes: [TIMESTAMP_CLASS], children: [node] };
}
function prepareCueNode(node) {
if (node.type === "timestamp")
return markTimestamp(node);
if (node.type === "object")
return { ...node, children: node.children.map(prepareCueNode) };
return { ...node, value: escapeCueText(node.value) };
}
function parseTracks(vtts, subtitles) {
const parser = new WebVTTParser(cueEntities);
return vtts.map((vtt, index2) => {
const tree = parser.parse(vtt, "metadata");
return { ...tree, url: subtitles[index2].url, name: subtitles[index2].name };
});
}
function serializeTracks(trees) {
const cues = [];
for (const selected of trees) {
const tree = selected;
for (const cue of tree.cues) {
const children = [];
for (const child of cue.tree.children) {
if (child.type === "timestamp") {
children.push(markTimestamp(child));
} else {
children.push(
{ type: "text", value: `<div class="art-subtitle-${tree.name}">` },
prepareCueNode(child),
{ type: "text", value: "</div>" }
);
}
}
cues.push({
...cue,
tree: {
...cue.tree,
children
}
});
}
result.cues.push(...tree.cues);
}
return result;
return new WebVTTSerializer().serialize(cues);
}
function installCaptionView(art, lifetime) {
const legacy = !!art.subtitle && "activeCue" in art.subtitle && !("activeCues" in art.subtitle);
const event = legacy ? "subtitleUpdate" : "subtitleAfterUpdate";
function update() {
if (lifetime.closed)
return;
if (legacy)
renderLegacyCaptions(art);
for (const marker of Array.from(art.template.$subtitle.getElementsByTagName(`c.${TIMESTAMP_CLASS}`))) {
const first = marker.firstChild;
if (first?.nodeType === 3)
first.nodeValue = (first.nodeValue || "").replace(/^<(?:\d+:)?\d{2}:\d{2}\.\d{3}>/, "");
marker.replaceWith(...Array.from(marker.childNodes));
}
}
if (lifetime.closed)
return;
lifetime.own(() => art.off(event, update));
art.on(event, update);
}
function createLifetime(art) {
let closed = Boolean(art.isDestroy);
const cleanups = /* @__PURE__ */ new Set();
let cancel;
const cancelled = new Promise((resolve) => {
cancel = resolve;
});
function run(cleanup) {
try {
cleanup();
} catch (error) {
console.warn("Failed to clean up multiple subtitles:", error);
}
}
const lifetime = {
get closed() {
return closed;
},
own(cleanup) {
if (closed)
run(cleanup);
else
cleanups.add(cleanup);
return () => cleanups.delete(cleanup);
},
wait(value) {
return Promise.race([value, cancelled]);
},
dispose() {
if (closed)
return;
closed = true;
cancel();
const pending = [...cleanups].reverse();
cleanups.clear();
for (const cleanup of pending)
run(cleanup);
}
};
if (!closed) {
lifetime.own(() => art.off("destroy", lifetime.dispose));
try {
art.on("destroy", lifetime.dispose);
} catch (error) {
lifetime.dispose();
throw error;
}
}
return lifetime;
}
function createRenderer(art, lifetime, unescape) {
let current = null;
function own(url) {
let freed = false;
let release = () => {
};
const entry = {
free() {
if (freed)
return;
freed = true;
release();
URL.revokeObjectURL(url);
}
};
release = lifetime.own(entry.free);
return entry;
}
return (vtt) => {
if (lifetime.closed)
return;
const url = URL.createObjectURL(new Blob([vtt], { type: "text/vtt" }));
const entry = own(url);
if (lifetime.closed)
return;
const previous = current;
let option;
let escape;
let configured = false;
current = entry;
try {
option = art.option.subtitle;
escape = option.escape;
if (lifetime.closed || current !== entry)
return;
option.escape = false;
configured = true;
const config = { ...option, url, type: "vtt", onVttLoad: unescape };
if (lifetime.closed || current !== entry)
return;
const pending = art.subtitle.init(config);
Promise.resolve(pending).catch((error) => {
if (current === entry) {
current = null;
entry.free();
}
if (!lifetime.closed)
console.warn("Failed to initialize multiple subtitles:", error);
});
} catch (error) {
if (current === entry) {
current = previous;
if (configured && option.escape === false)
option.escape = escape;
}
entry.free();
throw error;
} finally {
if (previous !== current)
previous?.free();
if (entry !== current)
entry.free();
}
};
}
function convertAss(text, converter) {
const converted = converter(text);
if (!/^WEBVTT \d+ \d+:/.test(converted))
return converted;
const cues = [];
for (const line of text.split(/\r?\n/)) {
const match = line.match(/Dialogue:\s\d,(\d+:\d{2}:\d{2}\.\d{2}),(\d+:\d{2}:\d{2}\.\d{2}),(?:[^,]*,){6}([\s\S]*)$/i);
if (!match)
continue;
const [, start = "", end = "", content = ""] = match;
cues.push({
start: `${start.replace(/^(\d):/, "0$1:")}0`,
end: `${end.replace(/^(\d):/, "0$1:")}0`,
text: content.replace(/\{[\s\S]*?\}/g, "").replace(/\\N/g, "\n").trim().split(/\r?\n/).map((line2) => line2.trim()).join("\n")
});
}
const collapsed = `WEBVTT ${cues.map((cue, index2) => `${index2 + 1} ${cue.start} --> ${cue.end} ${cue.text}`).join("\n\n")}`;
if (converted !== collapsed)
return converted;
return `WEBVTT
${cues.map((cue, index2) => `${index2 + 1}
${cue.start} --> ${cue.end}
${cue.text}`).join("\n\n")}`;
}
async function loadVtt(option, { getExt, srtToVtt, assToVtt }, lifetime) {
if (lifetime.closed)
return;
const controller = typeof AbortController === "function" ? new AbortController() : null;
const release = lifetime.own(() => controller?.abort());
try {
const url = option.url;
if (lifetime.closed)
return;
const response = await lifetime.wait(controller ? fetch(url, { signal: controller.signal }) : fetch(url));
if (lifetime.closed)
return;
if (response.ok === false)
throw new Error(`Failed to fetch multiple subtitles: HTTP ${response.status}`);
const buffer = await lifetime.wait(response.arrayBuffer());
if (lifetime.closed)
return;
const text = new TextDecoder(option.encoding || "utf-8").decode(buffer);
switch (option.type || getExt(option.url)) {
case "srt":
return srtToVtt(text);
case "ass":
return convertAss(text, assToVtt);
case "vtt":
return text;
default:
return "";
}
} catch (error) {
controller?.abort();
throw error;
} finally {
release();
}
}
function artplayerPluginMultipleSubtitles({ subtitles = [] }) {
return async (art) => {
const { unescape, getExt, srtToVtt, assToVtt } = art.constructor.utils;
const parser = new WebVTTParser();
const seri = new WebVTTSerializer();
const vtts = await Promise.all(
subtitles.map((option) => {
return loadVtt(option, { getExt, srtToVtt, assToVtt });
})
);
const trees = vtts.map((vtt, index) => {
const tree = parser.parse(vtt, "metadata");
tree.url = subtitles[index].url;
tree.name = subtitles[index].name;
return tree;
});
let lastUrl = "";
function setTracks(trees2 = []) {
const tree = mergeTrees(trees2);
const vtt = seri.serialize(tree.cues);
URL.revokeObjectURL(lastUrl);
const url = URL.createObjectURL(new Blob([vtt], { type: "text/vtt" }));
lastUrl = url;
art.option.subtitle.escape = false;
art.subtitle.init({
...art.option.subtitle,
url,
type: "vtt",
onVttLoad: unescape
});
const lifetime = createLifetime(art);
const render = createRenderer(art, lifetime, unescape);
let trees = [];
function setTracks(selected) {
if (!lifetime.closed)
render(serializeTracks(selected));
}
setTracks(trees);
return {
const result = {
name: "multipleSubtitles",
tracks(names = []) {
return setTracks(names.map((name) => trees.find((tree) => tree.name === name)));
if (!lifetime.closed)
setTracks(names.map((name) => trees.find((tree) => tree.name === name)));
},
reset() {
return setTracks(trees);
setTracks(trees);
}
};
try {
if (lifetime.closed)
return result;
const vtts = await Promise.all(subtitles.map((option) => loadVtt(option, { getExt, srtToVtt, assToVtt }, lifetime)));
if (lifetime.closed)
return result;
trees = parseTracks(vtts, subtitles);
installCaptionView(art, lifetime);
setTracks(trees);
return result;
} catch (error) {
lifetime.dispose();
throw error;
}
};
}
const index = Object.assign(artplayerPluginMultipleSubtitles, { default: artplayerPluginMultipleSubtitles });
export {
artplayerPluginMultipleSubtitles as default
index as default
};
+2 -2
View File
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-vast.js v1.2.0
* artplayer-plugin-vast.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVast=e(),define(function(){return t.artplayerPluginVast})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVast=e()}(this,function(){"use strict";var t=null,e=function(){t=null};function i(t,e,i){return e&&function(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}(t.prototype,e),t}function n(){return n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n])}return t},n.apply(this,arguments)}function s(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,o(t,e)}function r(t){return(r=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,e){return(o=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function a(t,e,i){return(a=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}()?Reflect.construct:function(t,e,i){var n=[null];n.push.apply(n,e);var s=new(Function.bind.apply(t,n));return i&&o(s,i.prototype),s}).apply(null,arguments)}function d(t){var e="function"==typeof Map?new Map:void 0;return d=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,i)}function i(){return a(t,arguments,r(this).constructor)}return i.prototype=Object.create(t.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),o(i,t)},d(t)}function h(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function u(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i<e;i++)n[i]=t[i];return n}var l=0;function c(t){return"__private_"+l+++"_"+t}function f(t,e){if(!Object.prototype.hasOwnProperty.call(t,e))throw new TypeError("attempted to use private field on non-instance");return t}var v={};v.CustomEvent="function"==typeof CustomEvent?CustomEvent:function(t){return e[t]=new e("").constructor[t],e;function e(t,e){e||(e={});var i=document.createEvent("CustomEvent");return i.initCustomEvent(t,!!e.bubbles,!!e.cancelable,e.detail),i}}("prototype");var p,E,y,A=v.CustomEvent,m=c("mediaElement"),b=c("currentTime"),g=c("enabled"),O=function(){function t(t){Object.defineProperty(this,m,{writable:!0,value:void 0}),Object.defineProperty(this,b,{writable:!0,value:void 0}),Object.defineProperty(this,g,{writable:!0,value:void 0}),this.seeking=void 0,f(this,m)[m]=t,f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.t=this.t.bind(this),this.i=this.i.bind(this),this.h=this.h.bind(this),this.enable()}var e=t.prototype;return e.i=function(){this.seeking=!0},e.h=function(){this.seeking=!1},e.t=function(){var t,e;this.seeking||null!=(t=f(this,m)[m])&&t.paused||(f(this,b)[b]=null==(e=f(this,m)[m])?void 0:e.currentTime)},e.enable=function(){var t,e,i;f(this,g)[g]||(null==(t=f(this,m)[m])||t.addEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.addEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.addEventListener("timeupdate",this.t),f(this,g)[g]=!0)},e.disable=function(){var t,e,i;f(this,g)[g]&&(null==(t=f(this,m)[m])||t.removeEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.removeEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.removeEventListener("timeupdate",this.t),f(this,g)[g]=!1)},e.play=function(){var t=this;return new Promise(function(e){var i;e(null==(i=f(t,m)[m])?void 0:i.play())})},e.pause=function(){var t;null==(t=f(this,m)[m])||t.pause()},e.reset=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.enable()},e.destroy=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.disable(),f(this,m)[m]=void 0},i(t,[{key:"enabled",get:function(){return f(this,g)[g]}},{key:"currentTime",get:function(){return f(this,b)[b]}},{key:"duration",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.duration}},{key:"muted",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.muted}},{key:"volume",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.volume}}]),t}(),w=function(){function t(){this.delegate=document.createDocumentFragment()}var e=t.prototype;return e.addEventListener=function(){this.delegate.addEventListener.apply(this.delegate,[].slice.call(arguments))},e.dispatchEvent=function(){return this.delegate.dispatchEvent.apply(this.delegate,[].slice.call(arguments))},e.removeEventListener=function(){return this.delegate.removeEventListener.apply(this.delegate,[].slicLine truncated
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVast=e(),define(function(){return t.artplayerPluginVast})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVast=e()}(this,function(){"use strict";var t=null,e=function(){t=null};function i(t,e,i){return e&&function(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}(t.prototype,e),t}function n(){return n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n])}return t},n.apply(this,arguments)}function r(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,o(t,e)}function s(t){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,e){return(o=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function a(t,e,i){return(a=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}()?Reflect.construct:function(t,e,i){var n=[null];n.push.apply(n,e);var r=new(Function.bind.apply(t,n));return i&&o(r,i.prototype),r}).apply(null,arguments)}function u(t){var e="function"==typeof Map?new Map:void 0;return u=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,i)}function i(){return a(t,arguments,s(this).constructor)}return i.prototype=Object.create(t.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),o(i,t)},u(t)}function d(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function h(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i<e;i++)n[i]=t[i];return n}var l=0;function c(t){return"__private_"+l+++"_"+t}function f(t,e){if(!Object.prototype.hasOwnProperty.call(t,e))throw new TypeError("attempted to use private field on non-instance");return t}var p={};p.CustomEvent="function"==typeof CustomEvent?CustomEvent:function(t){return e[t]=new e("").constructor[t],e;function e(t,e){e||(e={});var i=document.createEvent("CustomEvent");return i.initCustomEvent(t,!!e.bubbles,!!e.cancelable,e.detail),i}}("prototype");var v,y,E,A=p.CustomEvent,m=c("mediaElement"),b=c("currentTime"),g=c("enabled"),O=function(){function t(t){Object.defineProperty(this,m,{writable:!0,value:void 0}),Object.defineProperty(this,b,{writable:!0,value:void 0}),Object.defineProperty(this,g,{writable:!0,value:void 0}),this.seeking=void 0,f(this,m)[m]=t,f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.t=this.t.bind(this),this.i=this.i.bind(this),this.h=this.h.bind(this),this.enable()}var e=t.prototype;return e.i=function(){this.seeking=!0},e.h=function(){this.seeking=!1},e.t=function(){var t,e;this.seeking||null!=(t=f(this,m)[m])&&t.paused||(f(this,b)[b]=null==(e=f(this,m)[m])?void 0:e.currentTime)},e.enable=function(){var t,e,i;f(this,g)[g]||(null==(t=f(this,m)[m])||t.addEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.addEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.addEventListener("timeupdate",this.t),f(this,g)[g]=!0)},e.disable=function(){var t,e,i;f(this,g)[g]&&(null==(t=f(this,m)[m])||t.removeEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.removeEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.removeEventListener("timeupdate",this.t),f(this,g)[g]=!1)},e.play=function(){var t=this;return new Promise(function(e){var i;e(null==(i=f(t,m)[m])?void 0:i.play())})},e.pause=function(){var t;null==(t=f(this,m)[m])||t.pause()},e.reset=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.enable()},e.destroy=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.disable(),f(this,m)[m]=void 0},i(t,[{key:"enabled",get:function(){return f(this,g)[g]}},{key:"currentTime",get:function(){return f(this,b)[b]}},{key:"duration",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.duration}},{key:"muted",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.muted}},{key:"volume",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.volume}}]),t}(),w=function(){function t(){this.delegate=document.createDocumentFragment()}var e=t.prototype;return e.addEventListener=function(){this.delegate.addEventListener.apply(this.delegate,[].slice.call(arguments))},e.dispatchEvent=function(){return this.delegate.dispatchEvent.apply(this.delegate,[].slice.call(arguments))},e.removeEventListener=function(){return this.delegate.removeEventListener.apply(this.delegate,[].slicLine truncated
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-vast.js v1.2.0
* artplayer-plugin-vast.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVast=e(),define(function(){return t.artplayerPluginVast})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVast=e()}(this,function(){"use strict";var t=null,e=function(){t=null};function i(t,e,i){return e&&function(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}(t.prototype,e),t}function n(){return n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n])}return t},n.apply(this,arguments)}function s(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,o(t,e)}function r(t){return(r=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,e){return(o=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function a(t,e,i){return(a=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}()?Reflect.construct:function(t,e,i){var n=[null];n.push.apply(n,e);var s=new(Function.bind.apply(t,n));return i&&o(s,i.prototype),s}).apply(null,arguments)}function d(t){var e="function"==typeof Map?new Map:void 0;return d=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,i)}function i(){return a(t,arguments,r(this).constructor)}return i.prototype=Object.create(t.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),o(i,t)},d(t)}function h(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function u(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i<e;i++)n[i]=t[i];return n}var l=0;function c(t){return"__private_"+l+++"_"+t}function v(t,e){if(!Object.prototype.hasOwnProperty.call(t,e))throw new TypeError("attempted to use private field on non-instance");return t}var f={};f.CustomEvent="function"==typeof CustomEvent?CustomEvent:function(t){return e[t]=new e("").constructor[t],e;function e(t,e){e||(e={});var i=document.createEvent("CustomEvent");return i.initCustomEvent(t,!!e.bubbles,!!e.cancelable,e.detail),i}}("prototype");var p,y,E,A=f.CustomEvent,m=c("mediaElement"),b=c("currentTime"),g=c("enabled"),O=function(){function t(t){Object.defineProperty(this,m,{writable:!0,value:void 0}),Object.defineProperty(this,b,{writable:!0,value:void 0}),Object.defineProperty(this,g,{writable:!0,value:void 0}),this.seeking=void 0,v(this,m)[m]=t,v(this,b)[b]=0,v(this,g)[g]=!1,this.seeking=!1,this.t=this.t.bind(this),this.i=this.i.bind(this),this.h=this.h.bind(this),this.enable()}var e=t.prototype;return e.i=function(){this.seeking=!0},e.h=function(){this.seeking=!1},e.t=function(){var t,e;this.seeking||null!=(t=v(this,m)[m])&&t.paused||(v(this,b)[b]=null==(e=v(this,m)[m])?void 0:e.currentTime)},e.enable=function(){var t,e,i;v(this,g)[g]||(null==(t=v(this,m)[m])||t.addEventListener("seeking",this.i),null==(e=v(this,m)[m])||e.addEventListener("seeked",this.h),null==(i=v(this,m)[m])||i.addEventListener("timeupdate",this.t),v(this,g)[g]=!0)},e.disable=function(){var t,e,i;v(this,g)[g]&&(null==(t=v(this,m)[m])||t.removeEventListener("seeking",this.i),null==(e=v(this,m)[m])||e.removeEventListener("seeked",this.h),null==(i=v(this,m)[m])||i.removeEventListener("timeupdate",this.t),v(this,g)[g]=!1)},e.play=function(){var t=this;return new Promise(function(e){var i;e(null==(i=v(t,m)[m])?void 0:i.play())})},e.pause=function(){var t;null==(t=v(this,m)[m])||t.pause()},e.reset=function(){v(this,b)[b]=0,v(this,g)[g]=!1,this.seeking=!1,this.enable()},e.destroy=function(){v(this,b)[b]=0,v(this,g)[g]=!1,this.seeking=!1,this.disable(),v(this,m)[m]=void 0},i(t,[{key:"enabled",get:function(){return v(this,g)[g]}},{key:"currentTime",get:function(){return v(this,b)[b]}},{key:"duration",get:function(){var t;return null==(t=v(this,m)[m])?void 0:t.duration}},{key:"muted",get:function(){var t;return null==(t=v(this,m)[m])?void 0:t.muted}},{key:"volume",get:function(){var t;return null==(t=v(this,m)[m])?void 0:t.volume}}]),t}(),w=function(){function t(){this.delegate=document.createDocumentFragment()}var e=t.prototype;return e.addEventListener=function(){this.delegate.addEventListener.apply(this.delegate,[].slice.call(arguments))},e.dispatchEvent=function(){return this.delegate.dispatchEvent.apply(this.delegate,[].slice.call(arguments))},e.removeEventListener=function(){return this.delegate.removeEventListener.apply(this.delegate,[].slicLine truncated
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVast=e(),define(function(){return t.artplayerPluginVast})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVast=e()}(this,function(){"use strict";var t=null,e=function(){t=null};function i(t,e,i){return e&&function(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}(t.prototype,e),t}function n(){return n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n])}return t},n.apply(this,arguments)}function r(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,o(t,e)}function s(t){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,e){return(o=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function a(t,e,i){return(a=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}()?Reflect.construct:function(t,e,i){var n=[null];n.push.apply(n,e);var r=new(Function.bind.apply(t,n));return i&&o(r,i.prototype),r}).apply(null,arguments)}function u(t){var e="function"==typeof Map?new Map:void 0;return u=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,i)}function i(){return a(t,arguments,s(this).constructor)}return i.prototype=Object.create(t.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),o(i,t)},u(t)}function l(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function d(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i<e;i++)n[i]=t[i];return n}var h=0;function c(t){return"__private_"+h+++"_"+t}function f(t,e){if(!Object.prototype.hasOwnProperty.call(t,e))throw new TypeError("attempted to use private field on non-instance");return t}var p={};p.CustomEvent="function"==typeof CustomEvent?CustomEvent:function(t){return e[t]=new e("").constructor[t],e;function e(t,e){e||(e={});var i=document.createEvent("CustomEvent");return i.initCustomEvent(t,!!e.bubbles,!!e.cancelable,e.detail),i}}("prototype");var v,y,E,A=p.CustomEvent,m=c("mediaElement"),b=c("currentTime"),g=c("enabled"),O=function(){function t(t){Object.defineProperty(this,m,{writable:!0,value:void 0}),Object.defineProperty(this,b,{writable:!0,value:void 0}),Object.defineProperty(this,g,{writable:!0,value:void 0}),this.seeking=void 0,f(this,m)[m]=t,f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.t=this.t.bind(this),this.i=this.i.bind(this),this.h=this.h.bind(this),this.enable()}var e=t.prototype;return e.i=function(){this.seeking=!0},e.h=function(){this.seeking=!1},e.t=function(){var t,e;this.seeking||null!=(t=f(this,m)[m])&&t.paused||(f(this,b)[b]=null==(e=f(this,m)[m])?void 0:e.currentTime)},e.enable=function(){var t,e,i;f(this,g)[g]||(null==(t=f(this,m)[m])||t.addEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.addEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.addEventListener("timeupdate",this.t),f(this,g)[g]=!0)},e.disable=function(){var t,e,i;f(this,g)[g]&&(null==(t=f(this,m)[m])||t.removeEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.removeEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.removeEventListener("timeupdate",this.t),f(this,g)[g]=!1)},e.play=function(){var t=this;return new Promise(function(e){var i;e(null==(i=f(t,m)[m])?void 0:i.play())})},e.pause=function(){var t;null==(t=f(this,m)[m])||t.pause()},e.reset=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.enable()},e.destroy=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.disable(),f(this,m)[m]=void 0},i(t,[{key:"enabled",get:function(){return f(this,g)[g]}},{key:"currentTime",get:function(){return f(this,b)[b]}},{key:"duration",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.duration}},{key:"muted",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.muted}},{key:"volume",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.volume}}]),t}(),w=function(){function t(){this.delegate=document.createDocumentFragment()}var e=t.prototype;return e.addEventListener=function(){this.delegate.addEventListener.apply(this.delegate,[].slice.call(arguments))},e.dispatchEvent=function(){return this.delegate.dispatchEvent.apply(this.delegate,[].slice.call(arguments))},e.removeEventListener=function(){return this.delegate.removeEventListener.apply(this.delegate,[].slicLine truncated
+232 -105
View File
@@ -1,5 +1,5 @@
/*!
* artplayer-plugin-vast.js v1.2.0
* artplayer-plugin-vast.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
@@ -436,117 +436,244 @@ var S = b("mediaElement"), M = b("adElement"), x = b("customPlayhead"), I = b("a
return [].concat(w(this, $)[$]);
} }]), i2;
})(C);
function artplayerPluginVast(callback) {
return async (art) => {
const { template, constructor } = art;
const { createElement, setStyles } = constructor.utils;
const { $video, $player } = template;
await e();
const google = window.google;
const ima = google.ima;
const adsRenderingSettings = new ima.AdsRenderingSettings();
function createRequest(ima, field, value, config) {
const request = new ima.AdsRequest();
request[field] = value;
const fields = request;
for (const key in config)
fields[key] = config[key];
return request;
}
let nextId = 0;
function createContainer(utils, workspaceMode) {
const container = utils.createElement("div");
container.id = `${workspaceMode ? "art-vast-" : "art-"}${Date.now()}-${++nextId}`;
utils.setStyles(container, {
position: "absolute",
inset: "0",
width: "100%",
height: "100%",
zIndex: "150",
display: "none"
});
if (workspaceMode)
utils.setStyles(container, { backgroundColor: "black", pointerEvents: "auto" });
return container;
}
function createSession(art, ima, utils, closed, workspaceMode) {
const { $video, $player } = art.template;
const adsRenderingSettings = new ima.AdsRenderingSettings();
if (workspaceMode) {
adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;
adsRenderingSettings.enablePreloading = true;
const playerOptions = new E();
let isAdPlaying = false;
let imaPlayer = null;
let $container = null;
function createContainer() {
const container = createElement("div");
const id = `art-vast-${Date.now()}`;
container.id = id;
setStyles(container, {
position: "absolute",
inset: "0",
width: "100%",
height: "100%",
zIndex: "150",
backgroundColor: "black",
display: "none",
pointerEvents: "auto"
});
return container;
}
const playerOptions = new E();
let current = null;
let initializing = false;
let releasing = 0;
const context = {
art,
playUrl: (url, config = {}) => play("adTagUrl", url, config),
playRes: (response, config = {}) => play("adsResponse", response, config),
init,
ima,
adsRenderingSettings,
playerOptions,
imaPlayer: null,
id: null,
$container: null,
get container() {
return current?.container || null;
}
function initPlayer() {
if (imaPlayer)
return imaPlayer;
$container = createContainer();
$player.appendChild($container);
imaPlayer = new nt(ima, $video, $container, adsRenderingSettings, playerOptions);
imaPlayer.addEventListener("AdContentPauseRequested", () => {
isAdPlaying = true;
$container.style.display = "block";
});
imaPlayer.addEventListener("AdContentResumeRequested", () => {
isAdPlaying = false;
$container.style.display = "none";
});
imaPlayer.addEventListener("AdStarted", () => {
isAdPlaying = true;
$container.style.display = "block";
});
imaPlayer.addEventListener("AdError", (event) => {
console.error("VAST Ad Error:", event.detail);
isAdPlaying = false;
$container.style.display = "none";
});
return imaPlayer;
}
function destroyPlayer() {
if (imaPlayer?.destroy)
imaPlayer.destroy();
if ($container?.parentNode)
$container.parentNode.removeChild($container);
$container = null;
imaPlayer = null;
}
function playUrl(url, config = {}) {
if (isAdPlaying)
return;
if (!imaPlayer)
initPlayer();
const request = new ima.AdsRequest();
request.adTagUrl = url;
for (const key in config) {
request[key] = config[key];
}
imaPlayer.playAds(request);
}
function playRes(res, config = {}) {
if (isAdPlaying)
return;
if (!imaPlayer)
initPlayer();
const request = new ima.AdsRequest();
request.adsResponse = res;
for (const key in config) {
request[key] = config[key];
}
imaPlayer.playAds(request);
}
if (typeof callback === "function") {
await callback({
art,
playUrl,
playRes,
init: initPlayer,
ima,
adsRenderingSettings,
playerOptions,
get imaPlayer() {
return imaPlayer;
},
get container() {
return $container;
};
if (workspaceMode) {
Object.defineProperties(context, {
imaPlayer: { get: () => current?.player || null },
id: { get: () => current?.container.id || null },
$container: { get: () => current?.container || null }
});
}
const live = (owner) => current === owner && !owner.released && !closed();
function release(owner) {
if (current === owner)
current = null;
owner.released = true;
owner.playing = false;
const player = owner.player;
owner.player = null;
const listeners = owner.listeners.splice(0);
let failed = false;
let failure;
const attempt = (cleanup) => {
try {
cleanup();
} catch (error) {
if (!failed) {
failed = true;
failure = error;
} else {
console.error("VAST cleanup error:", error);
}
});
}
return {
name: "artplayerPluginVast",
destroy: destroyPlayer
}
};
releasing++;
try {
if (player) {
for (const [name, callback] of listeners)
attempt(() => player.removeEventListener(name, callback));
attempt(() => player.destroy());
}
attempt(() => {
if (owner.container.parentNode)
owner.container.parentNode.removeChild(owner.container);
});
} finally {
releasing--;
}
if (failed)
throw failure;
}
function init() {
if (closed() || releasing)
return null;
if (initializing)
throw new Error("VAST initialization is already in progress");
if (current?.player)
return current.player;
initializing = true;
let owner;
try {
owner = { container: createContainer(utils, workspaceMode), player: null, listeners: [], playing: false, released: false };
current = owner;
if (!live(owner)) {
release(owner);
return null;
}
$player.appendChild(owner.container);
if (!live(owner)) {
release(owner);
return null;
}
owner.player = new nt(ima, $video, owner.container, adsRenderingSettings, playerOptions);
if (!live(owner)) {
release(owner);
return null;
}
const allocated = owner;
const events = workspaceMode ? [
["AdContentPauseRequested", true],
["AdContentResumeRequested", false],
["AdStarted", true],
["AdError", false]
] : [];
for (const [name, playing] of events) {
const callback = (event) => {
if (!live(allocated))
return;
if (name === "AdError")
console.error("VAST Ad Error:", event.detail);
allocated.playing = playing;
allocated.container.style.display = playing ? "block" : "none";
};
owner.listeners.push([name, callback]);
owner.player.addEventListener(name, callback);
if (!live(owner)) {
release(owner);
return null;
}
}
if (!workspaceMode) {
Object.defineProperties(context, {
imaPlayer: { value: owner.player },
id: { value: owner.container.id },
$container: { value: owner.container }
});
}
return owner.player;
} catch (error) {
if (owner) {
try {
release(owner);
} catch (cleanupError) {
console.error("VAST cleanup error:", cleanupError);
}
}
throw error;
} finally {
initializing = false;
}
}
function play(field, value, config) {
if (closed() || workspaceMode && current?.playing)
return;
const player = init();
const owner = current;
if (!player || !owner)
return;
const request = createRequest(ima, field, value, config);
if (live(owner) && owner.player === player)
player.playAds(request);
}
function destroy() {
if (current)
release(current);
}
return { context, destroy };
}
function artplayerPluginVast(callback, options = {}) {
const compatibility = options.compatibility;
if (compatibility !== void 0 && compatibility !== "workspace-1.2")
throw new TypeError("Unsupported VAST compatibility mode");
const workspaceMode = compatibility === "workspace-1.2";
return async (art) => {
let disposed = false;
let session;
const closed = () => disposed || art.isDestroy;
const result = { name: "artplayerPluginVast", destroy: () => session?.destroy() };
function dispose() {
if (disposed)
return;
disposed = true;
try {
art.off("destroy", dispose);
} finally {
session?.destroy();
}
}
if (closed())
return result;
art.on("destroy", dispose);
try {
if (closed())
return result;
const ima = await e();
if (closed())
return result;
const utils = art.constructor.utils;
session = createSession(art, ima, utils, closed, workspaceMode);
if (closed()) {
dispose();
return result;
}
if (!workspaceMode) {
session.context.init();
if (closed())
return result;
}
if (typeof callback === "function")
await callback(session.context);
return result;
} catch (error) {
try {
dispose();
} catch (cleanupError) {
console.error("VAST cleanup error:", cleanupError);
}
throw error;
}
};
}
artplayerPluginVast.default = artplayerPluginVast;
export {
artplayerPluginVast as default
};
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-vtt-thumbnail.js v1.1.0
* artplayer-plugin-vtt-thumbnail.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVttThumbnail=e(),define(function(){return t.artplayerPluginVttThumbnail})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVttThumbnail=e()}(this,function(){"use strict";function t(t){const e=t.split("."),n=e[0].split(":")||[],i=(l=e[1]||"0",o=3,s="0",l.length>o?String(l):((o-=l.length)>s.length&&(s+=s.repeat(o/s.length)),String(l)+s.slice(0,o)));var l,o,s;const r=Number(i)/1e3;return 3600*Number(n[n.length-3]||0)+60*Number(n[n.length-2]||0)+Number(n[n.length-1]||0)+r}return function(e){return async n=>{const{constructor:{utils:{setStyle:i,isMobile:l,addClass:o}},template:{$progress:s}}=n;let r=null;const a=await async function(e=""){const n=(await(await fetch(e)).text()).split(/[\n\r]/g).filter(t=>t.trim()),i=[];for(let l=1;l<n.length;l+=2){const o=n[l],s=n[l+1];if(!s.trim())continue;const r=/((?:\d{2}:)?(?:\d{2}:)?\d{2}(?:.\d{3})?) ?--> ?((?:\d{2}:)?(?:\d{2}:)?\d{2}(?:.\d{3})?)/,a=o.match(r),u=/(.*)#(\w{4})=(.*)/,c=s.match(u),d=Math.floor(t(a[1])),p=Math.floor(t(a[2]));let f=c[1];if(!/^\/|(?:https?|ftp|file):\/\//i.test(f)){const t=e.split("/");t.pop(),t.push(f),f=t.join("/")}const h={start:d,end:p,url:f},m=c[2].split(""),g=c[3].split(",");for(let t=0;t<m.length;t++)h[m[t]]=g[t];i.push(h)}return i}(e.vtt);return n.controls.add({name:"vtt-thumbnail",position:"top",index:20,style:e.style||{},mounted(t){o(t,"art-control-thumbnails"),n.on("setBar",async(e,o,u)=>{const c="played"===e&&u&&l;if("hover"===e||c){const e=s.clientWidth*o,u=o*n.duration;i(t,"display","flex");const d=a.find(t=>u>=t.start&&u<=t.end);if(!d)return i(t,"display","none");e>0&&e<s.clientWidth?function(t,e,n){i(t,"backgroundImage",`url(${e.url})`),i(t,"height",`${e.h}px`),i(t,"width",`${e.w}px`),i(t,"backgroundPosition",`-${e.x}px -${e.y}px`),n<=e.w/2?i(t,"left",0):n>s.clientWidth-e.w/2?i(t,"left",s.clientWidth-e.w+"px"):i(t,"left",n-e.w/2+"px")}(t,d,e):l||i(t,"display","none"),c&&(clearTimeout(r),r=setTimeout(()=>{i(t,"display","none")},500))}})}}),{name:"artplayerPluginVttThumbnail"}}}});
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVttThumbnail=e(),define(function(){return t.artplayerPluginVttThumbnail})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVttThumbnail=e()}(this,function(){"use strict";function t(t,e){throw new TypeError(`Invalid VTT thumbnail at line ${t}: ${e}`)}function e(e,n){/^\d{2,}(?::\d{2}){0,2}(?:\.\d{3})?$/.test(e)||t(n,"invalid timestamp");const[i,o="0"]=e.split("."),r=i.split(":").reduce((t,e)=>60*t+Number(e),0)+Number(o)/1e3;return Number.isSafeInteger(Math.floor(r))||t(n,"timestamp exceeds the supported numeric range"),r}function n(e,n,i){const o=e.match(/^(.+)#([xywh]{4})=(.*)$/);o&&4===new Set(o[2]).size||t(i,"expected an image URL and four distinct xywh keys");const r=o[3].split(",").map(t=>t.trim());4!==r.length&&t(i,"expected four rectangle coordinates");const s={};for(let c=0;c<4;c++){const e=o[2][c],n=r[c];/^(?:\d+(?:\.\d+)?|\.\d+)$/.test(n)&&Number.isFinite(Number(n))||t(i,"rectangle coordinates must be finite non-negative decimals"),"w"!==e&&"h"!==e||0!==Number(n)||t(i,"rectangle width and height must be positive"),s[e]=n}let l=o[1];if(!/^\/|(?:https?|ftp|file):\/\//i.test(l)){const t=n.split("/");t.pop(),t.push(l),l=t.join("/")}return{url:l,...s}}function i({lifetime:t,thumbnails:e,progress:n,duration:i,setStyle:o,isMobile:r}){let s=null,l=0;function c(e,n,i){t.closed||o(e,n,i)}return t.own(()=>{if(l++,null!==s){const t=s;s=null,clearTimeout(t)}}),o=>async(u,a,d)=>{if(t.closed)return;const f="played"===u&&d&&r;if("hover"!==u&&!f)return;const m=n.clientWidth*a,h=a*i();if(c(o,"display","flex"),t.closed)return;const p=function(t,e){return t.find(t=>e>=t.start&&e<=t.end)}(e,h);if(!p)return c(o,"display","none");if(m>0&&m<n.clientWidth?function(t,e,i){c(t,"backgroundImage",`url(${e.url})`),c(t,"height",`${e.h}px`),c(t,"width",`${e.w}px`),c(t,"backgroundPosition",`-${e.x}px -${e.y}px`),i<=Number(e.w)/2?c(t,"left",0):i>n.clientWidth-Number(e.w)/2?c(t,"left",n.clientWidth-Number(e.w)+"px"):c(t,"left",i-Number(e.w)/2+"px")}(o,p,m):r||c(o,"display","none"),f&&!t.closed){const e=++l;if(null!==s&&clearTimeout(s),t.closed)return;const n=setTimeout(()=>{e!==l||t.closed||(s=null,c(o,"display","none"))},500);t.closed||e!==l?clearTimeout(n):s=n}}}function o(o){return async r=>{const{setStyle:s,isMobile:l,addClass:c}=r.constructor.utils,{$progress:u}=r.template,a=function(t){let e=Boolean(t.isDestroy);const n=new Set;let i;const o=new Promise(t=>{i=t}),r={get closed(){return e},own:t=>(e?s(t):n.add(t),()=>n.delete(t)),listen(n,i){e||(r.own(()=>t.off(n,i)),t.on(n,i))},wait:t=>Promise.race([t,o]),dispose(){if(e)return;e=!0,i();const t=[...n].reverse();n.clear();for(const e of t)s(e)}};function s(t){try{t()}catch(e){console.warn("Failed to clean up VTT thumbnails:",e)}}try{r.listen("destroy",r.dispose)}catch(l){throw r.dispose(),l}return r}(r),d={name:"artplayerPluginVttThumbnail"};try{if(a.closed)return d;const f=o.vtt,m=await async function(t="",e){if(e.closed)return;const n="function"===typeof AbortController?new AbortController:null,i=e.own(()=>n?.abort());try{if(e.closed)return;const i=await e.wait(n?fetch(t,{signal:n.signal}):fetch(t));if(e.closed)return;if(!1===i.ok)throw new Error(`Failed to fetch VTT thumbnails: HTTP ${i.status}`);if(e.closed)return;return await e.wait(i.text())}finally{i()}}(f,a);if(a.closed)return d;const h=function(i,o=""){"string"!==typeof i&&t(1,"expected text");const r=i.replace(/^\uFEFF/,"").split(/\r\n|\r|\n/);let s=0;function l(){for(;s<r.length&&!r[s].trim();)s++}if(l(),s===r.length)return[];/^WEBVTT(?:[\t ].*)?$/.test(r[s].trim())&&!r[s].includes("--\x3e")||t(s+1,"expected WEBVTT header"),s++;const c=[];for(;s<r.length&&(l(),s!==r.length);){const i=r[s].trim();if(/^NOTE(?:[\t ]|$)/.test(i)||"STYLE"===i||"REGION"===i){for(;s<r.length&&r[s].trim();)s++;continue}const u=s+1;i.includes("--\x3e")||(s++,s!==r.length&&r[s].trim()||t(u,"cue identifier must be followed by timing"));const a=s+1,d=r[s].trim().match(/^([\d:.]+)[\t ]*-->[\t ]*([\d:.]+)(?:[\t ].*)?$/);d||t(a,"invalid cue timing");const f=e(d[1],a),m=e(d[2],a);m<f&&t(a,"cue end precedes its start"),s++,l(),s===r.length&&t(a,"missing sprite image");const h=n(r[s].trim(),o,s+1);c.push({start:Math.floor(f),end:Math.floor(m),...h}),s++}return c}(m,f),p=i({lifetime:a,thumbnails:h,progress:u,duration:()=>r.duration,setStyle:s,isMobile:l}),b=o.style||{};return a.closed||r.controls.add({name:"vtt-thumbnail",position:"top",index:20,style:b,mounted(t){a.own(()=>{r.controls["vtt-thumbnail"]===t&&r.controls.remove("vtt-thumbnail")}),a.closed||(c(t,"art-control-thumbnails"),a.listen("setBar",p(t)))}}),d}catch(f){throw a.dispose(),f}}}return Object.assign(o,{default:o})});
@@ -1,7 +1,7 @@
/*!
* artplayer-plugin-vtt-thumbnail.js v1.1.0
* artplayer-plugin-vtt-thumbnail.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVttThumbnail=e(),define(function(){return t.artplayerPluginVttThumbnail})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVttThumbnail=e()}(this,function(){"use strict";var t=(t,e,n)=>new Promise((l,i)=>{var o=t=>{try{s(n.next(t))}catch(e){i(e)}},r=t=>{try{s(n.throw(t))}catch(e){i(e)}},s=t=>t.done?l(t.value):Promise.resolve(t.value).then(o,r);s((n=n.apply(t,e)).next())});function e(t){const e=t.split("."),n=e[0].split(":")||[],l=(i=e[1]||"0",o=3,r="0",i.length>o?String(i):((o-=i.length)>r.length&&(r+=r.repeat(o/r.length)),String(i)+r.slice(0,o)));var i,o,r;const s=Number(l)/1e3;return 3600*Number(n[n.length-3]||0)+60*Number(n[n.length-2]||0)+Number(n[n.length-1]||0)+s}return function(n){return l=>t(null,null,function*(){const{constructor:{utils:{setStyle:i,isMobile:o,addClass:r}},template:{$progress:s}}=l;let u=null;const a=yield function(n=""){return t(this,null,function*(){const t=(yield(yield fetch(n)).text()).split(/[\n\r]/g).filter(t=>t.trim()),l=[];for(let i=1;i<t.length;i+=2){const o=t[i],r=t[i+1];if(!r.trim())continue;const s=/((?:\d{2}:)?(?:\d{2}:)?\d{2}(?:.\d{3})?) ?--> ?((?:\d{2}:)?(?:\d{2}:)?\d{2}(?:.\d{3})?)/,u=o.match(s),a=/(.*)#(\w{4})=(.*)/,c=r.match(a),d=Math.floor(e(u[1])),h=Math.floor(e(u[2]));let p=c[1];if(!/^\/|(?:https?|ftp|file):\/\//i.test(p)){const t=n.split("/");t.pop(),t.push(p),p=t.join("/")}const f={start:d,end:h,url:p},m=c[2].split(""),g=c[3].split(",");for(let t=0;t<m.length;t++)f[m[t]]=g[t];l.push(f)}return l})}(n.vtt);return l.controls.add({name:"vtt-thumbnail",position:"top",index:20,style:n.style||{},mounted(e){r(e,"art-control-thumbnails"),l.on("setBar",(n,r,c)=>t(null,null,function*(){const t="played"===n&&c&&o;if("hover"===n||t){const n=s.clientWidth*r,c=r*l.duration;i(e,"display","flex");const d=a.find(t=>c>=t.start&&c<=t.end);if(!d)return i(e,"display","none");n>0&&n<s.clientWidth?function(t,e,n){i(t,"backgroundImage",`url(${e.url})`),i(t,"height",`${e.h}px`),i(t,"width",`${e.w}px`),i(t,"backgroundPosition",`-${e.x}px -${e.y}px`),n<=e.w/2?i(t,"left",0):n>s.clientWidth-e.w/2?i(t,"left",s.clientWidth-e.w+"px"):i(t,"left",n-e.w/2+"px")}(e,d,n):o||i(e,"display","none"),t&&(clearTimeout(u),u=setTimeout(()=>{i(e,"display","none")},500))}}))}}),{name:"artplayerPluginVttThumbnail"}})}});
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVttThumbnail=e(),define(function(){return t.artplayerPluginVttThumbnail})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVttThumbnail=e()}(this,function(){"use strict";var t=Object.defineProperty,e=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,r=(e,n,o)=>n in e?t(e,n,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[n]=o,i=(t,i)=>{for(var l in i||(i={}))n.call(i,l)&&r(t,l,i[l]);if(e)for(var l of e(i))o.call(i,l)&&r(t,l,i[l]);return t},l=(t,e,n)=>new Promise((o,r)=>{var i=t=>{try{s(n.next(t))}catch(e){r(e)}},l=t=>{try{s(n.throw(t))}catch(e){r(e)}},s=t=>t.done?o(t.value):Promise.resolve(t.value).then(i,l);s((n=n.apply(t,e)).next())});function s(t,e){throw new TypeError(`Invalid VTT thumbnail at line ${t}: ${e}`)}function c(t,e){/^\d{2,}(?::\d{2}){0,2}(?:\.\d{3})?$/.test(t)||s(e,"invalid timestamp");const[n,o="0"]=t.split("."),r=n.split(":").reduce((t,e)=>60*t+Number(e),0)+Number(o)/1e3;return Number.isSafeInteger(Math.floor(r))||s(e,"timestamp exceeds the supported numeric range"),r}function u(t,e,n){const o=t.match(/^(.+)#([xywh]{4})=(.*)$/);o&&4===new Set(o[2]).size||s(n,"expected an image URL and four distinct xywh keys");const r=o[3].split(",").map(t=>t.trim());4!==r.length&&s(n,"expected four rectangle coordinates");const l={};for(let i=0;i<4;i++){const t=o[2][i],e=r[i];/^(?:\d+(?:\.\d+)?|\.\d+)$/.test(e)&&Number.isFinite(Number(e))||s(n,"rectangle coordinates must be finite non-negative decimals"),"w"!==t&&"h"!==t||0!==Number(e)||s(n,"rectangle width and height must be positive"),l[t]=e}let c=o[1];if(!/^\/|(?:https?|ftp|file):\/\//i.test(c)){const t=e.split("/");t.pop(),t.push(c),c=t.join("/")}return i({url:c},l)}function a({lifetime:t,thumbnails:e,progress:n,duration:o,setStyle:r,isMobile:i}){let s=null,c=0;function u(e,n,o){t.closed||r(e,n,o)}return t.own(()=>{if(c++,null!==s){const t=s;s=null,clearTimeout(t)}}),r=>(a,d,f)=>l(null,null,function*(){if(t.closed)return;const l="played"===a&&f&&i;if("hover"!==a&&!l)return;const m=n.clientWidth*d,p=d*o();if(u(r,"display","flex"),t.closed)return;const h=function(t,e){return t.find(t=>e>=t.start&&e<=t.end)}(e,p);if(!h)return u(r,"display","none");if(m>0&&m<n.clientWidth?function(t,e,o){u(t,"backgroundImage",`url(${e.url})`),u(t,"height",`${e.h}px`),u(t,"width",`${e.w}px`),u(t,"backgroundPosition",`-${e.x}px -${e.y}px`),o<=Number(e.w)/2?u(t,"left",0):o>n.clientWidth-Number(e.w)/2?u(t,"left",n.clientWidth-Number(e.w)+"px"):u(t,"left",o-Number(e.w)/2+"px")}(r,h,m):i||u(r,"display","none"),l&&!t.closed){const e=++c;if(null!==s&&clearTimeout(s),t.closed)return;const n=setTimeout(()=>{e!==c||t.closed||(s=null,u(r,"display","none"))},500);t.closed||e!==c?clearTimeout(n):s=n}})}function d(t){return e=>l(null,null,function*(){const{setStyle:n,isMobile:o,addClass:r}=e.constructor.utils,{$progress:d}=e.template,f=function(t){let e=Boolean(t.isDestroy);const n=new Set;let o;const r=new Promise(t=>{o=t}),i={get closed(){return e},own:t=>(e?l(t):n.add(t),()=>n.delete(t)),listen(n,o){e||(i.own(()=>t.off(n,o)),t.on(n,o))},wait:t=>Promise.race([t,r]),dispose(){if(e)return;e=!0,o();const t=[...n].reverse();n.clear();for(const e of t)l(e)}};function l(t){try{t()}catch(e){console.warn("Failed to clean up VTT thumbnails:",e)}}try{i.listen("destroy",i.dispose)}catch(s){throw i.dispose(),s}return i}(e),m={name:"artplayerPluginVttThumbnail"};try{if(f.closed)return m;const p=t.vtt,h=yield function(t="",e){return l(this,null,function*(){if(e.closed)return;const n="function"===typeof AbortController?new AbortController:null,o=e.own(()=>null==n?void 0:n.abort());try{if(e.closed)return;const o=yield e.wait(n?fetch(t,{signal:n.signal}):fetch(t));if(e.closed)return;if(!1===o.ok)throw new Error(`Failed to fetch VTT thumbnails: HTTP ${o.status}`);if(e.closed)return;return yield e.wait(o.text())}finally{o()}})}(p,f);if(f.closed)return m;const b=function(t,e=""){"string"!==typeof t&&s(1,"expected text");const n=t.replace(/^\uFEFF/,"").split(/\r\n|\r|\n/);let o=0;function r(){for(;o<n.length&&!n[o].trim();)o++}if(r(),o===n.length)return[];/^WEBVTT(?:[\t ].*)?$/.test(n[o].trim())&&!n[o].includes("--\x3e")||s(o+1,"expected WEBVTT header"),o++;const l=[];for(;o<n.length&&(r(),o!==n.length);){const t=n[o].trim();if(/^NOTE(?:[\t ]|$)/.test(t)||"STYLE"===t||"REGION"===t){for(;o<n.length&&n[o].trim();)o++;continue}const a=o+1;t.includes("--\x3e")||(o++,o!==n.length&&n[o].trim()||s(a,"cue identifier must be followed by timing"));const d=o+1,f=n[o].trim().match(/^([\d:.]+)[\t ]*-->[\t ]*([\d:.]+)(?:[\t ].*)?$/);f||s(d,"invalid cue timing");const m=c(f[1],d),p=c(f[2],d);p<m&&s(d,"cue end precedes its start"),o++,r(),o===n.length&&s(d,"missing sprite image");const h=u(n[o].trim(),e,o+1);l.push(i({start:Math.floor(m),end:Math.floor(p)},h)),o++}return l}(h,p),y=a({lifetime:f,thuLine truncated
+258 -103
View File
@@ -1,124 +1,279 @@
/*!
* artplayer-plugin-vtt-thumbnail.js v1.1.0
* artplayer-plugin-vtt-thumbnail.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
function padEnd(str, targetLength, padString) {
if (str.length > targetLength) {
return String(str);
} else {
targetLength = targetLength - str.length;
if (targetLength > padString.length) {
padString += padString.repeat(targetLength / padString.length);
function createLifetime(art) {
let closed = Boolean(art.isDestroy);
const cleanups = /* @__PURE__ */ new Set();
let cancel;
const cancelled = new Promise((resolve) => {
cancel = resolve;
});
const lifetime = {
get closed() {
return closed;
},
own(cleanup) {
if (closed)
run(cleanup);
else
cleanups.add(cleanup);
return () => cleanups.delete(cleanup);
},
listen(name, callback) {
if (closed)
return;
lifetime.own(() => art.off(name, callback));
art.on(name, callback);
},
wait(value) {
return Promise.race([value, cancelled]);
},
dispose() {
if (closed)
return;
closed = true;
cancel();
const pending = [...cleanups].reverse();
cleanups.clear();
for (const cleanup of pending)
run(cleanup);
}
};
function run(cleanup) {
try {
cleanup();
} catch (error) {
console.warn("Failed to clean up VTT thumbnails:", error);
}
return String(str) + padString.slice(0, targetLength);
}
try {
lifetime.listen("destroy", lifetime.dispose);
} catch (error) {
lifetime.dispose();
throw error;
}
return lifetime;
}
function t2d(time) {
const arr = time.split(".");
const left = arr[0].split(":") || [];
const right = padEnd(arr[1] || "0", 3, "0");
const ms = Number(right) / 1e3;
const h = Number(left[left.length - 3] || 0) * 3600;
const m = Number(left[left.length - 2] || 0) * 60;
const s = Number(left[left.length - 1] || 0);
return h + m + s + ms;
function invalid(line, message) {
throw new TypeError(`Invalid VTT thumbnail at line ${line}: ${message}`);
}
async function getVttArray(vttUrl = "") {
const vttString = await (await fetch(vttUrl)).text();
const lines = vttString.split(/[\n\r]/g).filter((item) => item.trim());
const vttArray = [];
for (let i = 1; i < lines.length; i += 2) {
const time = lines[i];
const text = lines[i + 1];
if (!text.trim())
function timestamp(value, line) {
if (!/^\d{2,}(?::\d{2}){0,2}(?:\.\d{3})?$/.test(value))
invalid(line, "invalid timestamp");
const [whole, fraction = "0"] = value.split(".");
const seconds = whole.split(":").reduce((total, part) => total * 60 + Number(part), 0) + Number(fraction) / 1e3;
if (!Number.isSafeInteger(Math.floor(seconds)))
invalid(line, "timestamp exceeds the supported numeric range");
return seconds;
}
function rectangle(text, vttUrl, line) {
const match = text.match(/^(.+)#([xywh]{4})=(.*)$/);
if (!match || new Set(match[2]).size !== 4)
invalid(line, "expected an image URL and four distinct xywh keys");
const values = match[3].split(",").map((value) => value.trim());
if (values.length !== 4)
invalid(line, "expected four rectangle coordinates");
const rect = {};
for (let index2 = 0; index2 < 4; index2++) {
const key = match[2][index2];
const value = values[index2];
if (!/^(?:\d+(?:\.\d+)?|\.\d+)$/.test(value) || !Number.isFinite(Number(value)))
invalid(line, "rectangle coordinates must be finite non-negative decimals");
if ((key === "w" || key === "h") && Number(value) === 0)
invalid(line, "rectangle width and height must be positive");
rect[key] = value;
}
let url = match[1];
if (!/^\/|(?:https?|ftp|file):\/\//i.test(url)) {
const segments = vttUrl.split("/");
segments.pop();
segments.push(url);
url = segments.join("/");
}
return { url, ...rect };
}
function findThumbnail(thumbnails, second) {
return thumbnails.find((item) => second >= item.start && second <= item.end);
}
function parseVtt(text, vttUrl = "") {
if (typeof text !== "string")
invalid(1, "expected text");
const lines = text.replace(/^\uFEFF/, "").split(/\r\n|\r|\n/);
let index2 = 0;
function skipEmpty() {
while (index2 < lines.length && !lines[index2].trim())
index2++;
}
skipEmpty();
if (index2 === lines.length)
return [];
if (!/^WEBVTT(?:[\t ].*)?$/.test(lines[index2].trim()) || lines[index2].includes("-->"))
invalid(index2 + 1, "expected WEBVTT header");
index2++;
const thumbnails = [];
while (index2 < lines.length) {
skipEmpty();
if (index2 === lines.length)
break;
const first = lines[index2].trim();
if (/^NOTE(?:[\t ]|$)/.test(first) || first === "STYLE" || first === "REGION") {
while (index2 < lines.length && lines[index2].trim())
index2++;
continue;
const timeReg = /((?:\d{2}:)?(?:\d{2}:)?\d{2}(?:.\d{3})?) ?--> ?((?:\d{2}:)?(?:\d{2}:)?\d{2}(?:.\d{3})?)/;
const timeMatch = time.match(timeReg);
const textReg = /(.*)#(\w{4})=(.*)/;
const textMatch = text.match(textReg);
const start = Math.floor(t2d(timeMatch[1]));
const end = Math.floor(t2d(timeMatch[2]));
let url = textMatch[1];
const isAbsoluteUrl = /^\/|(?:https?|ftp|file):\/\//i.test(url);
if (!isAbsoluteUrl) {
const urlArr = vttUrl.split("/");
urlArr.pop();
urlArr.push(url);
url = urlArr.join("/");
}
const result = { start, end, url };
const keys = textMatch[2].split("");
const values = textMatch[3].split(",");
for (let j = 0; j < keys.length; j++) {
result[keys[j]] = values[j];
const identifierLine = index2 + 1;
if (!first.includes("-->")) {
index2++;
if (index2 === lines.length || !lines[index2].trim())
invalid(identifierLine, "cue identifier must be followed by timing");
}
vttArray.push(result);
const timingLine = index2 + 1;
const timing = lines[index2].trim().match(/^([\d:.]+)[\t ]*-->[\t ]*([\d:.]+)(?:[\t ].*)?$/);
if (!timing)
invalid(timingLine, "invalid cue timing");
const start = timestamp(timing[1], timingLine);
const end = timestamp(timing[2], timingLine);
if (end < start)
invalid(timingLine, "cue end precedes its start");
index2++;
skipEmpty();
if (index2 === lines.length)
invalid(timingLine, "missing sprite image");
const image = rectangle(lines[index2].trim(), vttUrl, index2 + 1);
thumbnails.push({ start: Math.floor(start), end: Math.floor(end), ...image });
index2++;
}
return thumbnails;
}
function createPreview({ lifetime, thumbnails, progress, duration, setStyle, isMobile }) {
let timer = null;
let generation = 0;
lifetime.own(() => {
generation++;
if (timer !== null) {
const previous = timer;
timer = null;
clearTimeout(previous);
}
});
function style(control, key, value) {
if (!lifetime.closed)
setStyle(control, key, value);
}
function show(control, cue, width) {
style(control, "backgroundImage", `url(${cue.url})`);
style(control, "height", `${cue.h}px`);
style(control, "width", `${cue.w}px`);
style(control, "backgroundPosition", `-${cue.x}px -${cue.y}px`);
if (width <= Number(cue.w) / 2)
style(control, "left", 0);
else if (width > progress.clientWidth - Number(cue.w) / 2)
style(control, "left", `${progress.clientWidth - Number(cue.w)}px`);
else
style(control, "left", `${width - Number(cue.w) / 2}px`);
}
return (control) => async (type, percentage, event) => {
if (lifetime.closed)
return;
const dragging = type === "played" && event && isMobile;
if (type !== "hover" && !dragging)
return;
const width = progress.clientWidth * percentage;
const second = percentage * duration();
style(control, "display", "flex");
if (lifetime.closed)
return;
const cue = findThumbnail(thumbnails, second);
if (!cue)
return style(control, "display", "none");
if (width > 0 && width < progress.clientWidth)
show(control, cue, width);
else if (!isMobile)
style(control, "display", "none");
if (dragging && !lifetime.closed) {
const current = ++generation;
if (timer !== null)
clearTimeout(timer);
if (lifetime.closed)
return;
const id = setTimeout(() => {
if (current !== generation || lifetime.closed)
return;
timer = null;
style(control, "display", "none");
}, 500);
if (lifetime.closed || current !== generation)
clearTimeout(id);
else
timer = id;
}
};
}
async function requestVtt(url = "", lifetime) {
if (lifetime.closed)
return;
const controller = typeof AbortController === "function" ? new AbortController() : null;
const release = lifetime.own(() => controller?.abort());
try {
if (lifetime.closed)
return;
const response = await lifetime.wait(controller ? fetch(url, { signal: controller.signal }) : fetch(url));
if (lifetime.closed)
return;
if (response.ok === false)
throw new Error(`Failed to fetch VTT thumbnails: HTTP ${response.status}`);
if (lifetime.closed)
return;
return await lifetime.wait(response.text());
} finally {
release();
}
return vttArray;
}
function artplayerPluginVttThumbnail(option) {
return async (art) => {
const {
constructor: {
utils: { setStyle, isMobile, addClass }
},
template: { $progress }
} = art;
let timer = null;
const thumbnails = await getVttArray(option.vtt);
function showThumbnails($control, find, width) {
setStyle($control, "backgroundImage", `url(${find.url})`);
setStyle($control, "height", `${find.h}px`);
setStyle($control, "width", `${find.w}px`);
setStyle($control, "backgroundPosition", `-${find.x}px -${find.y}px`);
if (width <= find.w / 2) {
setStyle($control, "left", 0);
} else if (width > $progress.clientWidth - find.w / 2) {
setStyle($control, "left", `${$progress.clientWidth - find.w}px`);
} else {
setStyle($control, "left", `${width - find.w / 2}px`);
}
const { setStyle, isMobile, addClass } = art.constructor.utils;
const { $progress } = art.template;
const lifetime = createLifetime(art);
const result = { name: "artplayerPluginVttThumbnail" };
try {
if (lifetime.closed)
return result;
const url = option.vtt;
const text = await requestVtt(url, lifetime);
if (lifetime.closed)
return result;
const thumbnails = parseVtt(text, url);
const preview = createPreview({ lifetime, thumbnails, progress: $progress, duration: () => art.duration, setStyle, isMobile });
const style = option.style || {};
if (lifetime.closed)
return result;
art.controls.add({
name: "vtt-thumbnail",
position: "top",
index: 20,
style,
mounted(control) {
lifetime.own(() => {
if (art.controls["vtt-thumbnail"] === control)
art.controls.remove("vtt-thumbnail");
});
if (lifetime.closed)
return;
addClass(control, "art-control-thumbnails");
lifetime.listen("setBar", preview(control));
}
});
return result;
} catch (error) {
lifetime.dispose();
throw error;
}
art.controls.add({
name: "vtt-thumbnail",
position: "top",
index: 20,
style: option.style || {},
mounted($control) {
addClass($control, "art-control-thumbnails");
art.on("setBar", async (type, percentage, event) => {
const isMobileDroging = type === "played" && event && isMobile;
if (type === "hover" || isMobileDroging) {
const width = $progress.clientWidth * percentage;
const second = percentage * art.duration;
setStyle($control, "display", "flex");
const find = thumbnails.find((item) => second >= item.start && second <= item.end);
if (!find)
return setStyle($control, "display", "none");
if (width > 0 && width < $progress.clientWidth) {
showThumbnails($control, find, width);
} else {
if (!isMobile) {
setStyle($control, "display", "none");
}
}
if (isMobileDroging) {
clearTimeout(timer);
timer = setTimeout(() => {
setStyle($control, "display", "none");
}, 500);
}
}
});
}
});
return {
name: "artplayerPluginVttThumbnail"
};
};
}
const index = Object.assign(artplayerPluginVttThumbnail, { default: artplayerPluginVttThumbnail });
export {
artplayerPluginVttThumbnail as default
index as default
};
+2 -2
View File
@@ -1,7 +1,7 @@
/*!
* artplayer-proxy-canvas.js v1.1.0
* artplayer-proxy-canvas.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerProxyCanvas=t(),define(function(){return t.artplayerProxyCanvas})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyCanvas=t()}(this,function(){"use strict";return function(e){return t=>{const{constructor:n}=t,{createElement:i}=n.utils,o=i("canvas"),a=i("video"),r=o.getContext("2d");let c=null;const d={};for(const e in o)"function"===typeof o[e]&&(d[e]=o[e].bind(o));for(const e in a)e in o||Object.defineProperty(o,e,{get(){const t=a[e];return"function"===typeof t?t.bind(a):t},set(t){a[e]=t},configurable:!0,enumerable:!0});for(const e in d)o[e]=function(...t){return e in d?d[e](...t):a[e](...t)};return function(){const{events:e}=n.config;setTimeout(()=>{e.forEach(e=>{t.proxy(a,e,e=>{t.emit(`video:${e.type}`,e)})})})}(),t.on("video:loadedmetadata",()=>{o.width=a.videoWidth,o.height=a.videoHeight}),t.on("video:play",()=>{cancelAnimationFrame(c),f()}),t.on("video:pause",()=>{cancelAnimationFrame(c)}),t.on("resize",()=>{!function(){const e=t.template?.$player;if(!e||t.option.autoSize)return;const n=a.videoWidth/a.videoHeight,i=e.clientWidth,r=e.clientHeight;let c,d;i/r>n?(d=r,c=d*n):(c=i,d=c/n),o.width=c,o.height=d;const s=(i-c)/2,f=(r-d)/2;Object.assign(o.style,{padding:`${f}px ${s}px`})}(),s()}),t.on("destroy",()=>{cancelAnimationFrame(c)}),o;async function s(){try{if("undefined"!==typeof createImageBitmap){const e=await createImageBitmap(a);r.drawImage(e,0,0,o.width,o.height),e.close()}else r.drawImage(a,0,0,o.width,o.height);e&&e(r,a),t.emit("artplayerProxyCanvas:draw",r,a)}catch(n){t.emit("artplayerProxyCanvas:error",n)}}async function f(){await s(),c=requestAnimationFrame(f)}}}});
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerProxyCanvas=t(),define(function(){return e.artplayerProxyCanvas})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyCanvas=t()}(this,function(){"use strict";function e(e){return Number.isFinite(e.videoWidth)&&Number.isFinite(e.videoHeight)&&e.videoWidth>0&&e.videoHeight>0}function t(e,t){let n=!1,i=!1,o=!1,r=!1,a=0,l=null;function s(){null!==l&&cancelAnimationFrame(l),l=null}function c(){if(!o&&!i&&t())if(r){r=!1,o=!0;const n=a,l=()=>{o=!1,c()};e(()=>!i&&t()&&a===n).then(l,l)}else n&&null===l&&(l=requestAnimationFrame(()=>{l=null,r=!0,c()}))}function u(){!i&&t()&&(a++,r=!0,s(),c())}function d(){n=!1,r=!1,a++,s()}return{request:u,start(){n||i||!t()||(n=!0,u())},stop:d,destroy(){i=!0,d()}}}function n(n){return i=>{const o=i.constructor,r=o.utils.createElement("canvas"),a=o.utils.createElement("video");let l=i,s=i.isDestroy,c=null;const u=[],d=()=>!s&&!l?.isDestroy,f=function(e,t,n){let i=!1;return{mount(){if(i||!n())return;const o=t();o&&(e.setAttribute("aria-hidden","true"),e.tabIndex=-1,e.playsInline=!0,Object.assign(e.style,{position:"absolute",width:"auto",height:"auto",opacity:"0",pointerEvents:"none",left:"0",top:"0"}),o.appendChild(e),i=!0,n()||e.remove())},destroy(){const t=[],n=()=>{e.srcObject=null};for(const i of[()=>e.pause(),()=>e.removeAttribute("src"),n,()=>e.load(),()=>e.remove()])try{i()}catch(o){t.push(o)}if(i=!1,t.length)throw t[0]}}}(a,()=>l?.template?.$player,d),p=function(t,n,i,o,r){const a=t.getContext("2d");let l=!1;return{available:()=>!!a||(l||(l=!0,r(new Error("Canvas 2D context is unavailable"))),!1),async draw(l){const s=()=>l()&&n.readyState>=2&&!n.seeking;if(!a||!s()||!e(n)||!t.width||!t.height)return;let c=!1;try{if("undefined"!==typeof createImageBitmap){c=!0;const e=await createImageBitmap(n);c=!1;try{s()&&a.drawImage(e,0,0,t.width,t.height)}finally{e.close()}}else a.drawImage(n,0,0,t.width,t.height);if(!s())return;i&&i(a,n),s()&&o(a,n)}catch(u){const e=c&&"object"===typeof u&&null!==u&&"name"in u&&"InvalidStateError"===u.name&&0===n.currentTime&&"function"===typeof n.getVideoPlaybackQuality&&0===n.getVideoPlaybackQuality().totalVideoFrames;s()&&!e&&r(u)}}}}(r,a,n,(e,t)=>l?.emit("artplayerProxyCanvas:draw",e,t),e=>l?.emit("artplayerProxyCanvas:error",e)),h=t(p.draw,d);if(function(e,t,n,i,o){const r=new Map;for(const a in e){const t=Reflect.get(e,a);"function"===typeof t&&r.set(a,(...n)=>Reflect.apply(t,e,n))}for(const a in t)a in e||Object.defineProperty(e,a,{get(){const e=Reflect.get(t,a);return"function"!==typeof e?e:(...r)=>n()?("load"===a&&i(),"play"===a&&o(),Reflect.apply(e,t,r)):"play"===a?Promise.resolve():void 0},set(e){n()&&("src"!==a&&"srcObject"!==a||i(),Reflect.set(t,a,e))},configurable:!0,enumerable:!0});for(const[a,l]of r)Reflect.set(e,a,l)}(r,a,d,h.stop,f.mount),s)return l=null,r;function y(){if(s)return;s=!0,h.destroy(),null!==c&&clearTimeout(c),c=null;const e=[];for(const n of[...u.splice(0).reverse(),f.destroy])try{n()}catch(t){e.push(t)}if(l=null,r.width=0,r.height=0,e.length)throw e[0]}function m(e,t){if(!d())return;const n=()=>{("destroy"===e||d())&&t()},o=()=>i.off(e,n);u.push(o),i.on(e,n),s&&o()}function v(){p.available()&&h.request()}try{!function(e,t,n,i){if(!i())return;const o=e.appendChild;n.kind="metadata",n.default=!0,t.appendChild(n),e.appendChild=r=>i()&&1===r.nodeType&&"TRACK"===r.nodeName&&"namespaceURI"in r&&"http://www.w3.org/1999/xhtml"===r.namespaceURI?(n.remove(),t.appendChild(r)):o.call(e,r)}(r,a,o.utils.createElement("track"),d),m("destroy",y),m("video:loadedmetadata",()=>{e(a)&&(r.width=a.videoWidth,r.height=a.videoHeight)}),m("video:play",()=>{f.mount(),p.available()&&h.start()}),m("video:pause",h.stop),m("video:emptied",h.stop),m("video:seeked",v),m("resize",()=>{!function(t,n,i,o){if(!i||o||!e(n))return;const r=i.clientWidth,a=i.clientHeight;if(!Number.isFinite(r)||!Number.isFinite(a)||r<=0||a<=0)return;const l=n.videoWidth/n.videoHeight,s=r/a>l?a*l:r,c=r/a>l?a:r/l;t.width=s,t.height=c,t.style.padding=`${(a-c)/2}px ${(r-s)/2}px`}(r,a,l?.template?.$player,l?.option.autoSize),v()}),d()&&(c=setTimeout(()=>{if(c=null,d())try{f.mount();for(const e of o.config.events){if(!d())break;const t=e=>{d()&&l?.emit(`video:${e.type}`,e)},n=()=>a.removeEventListener(e,t);u.push(n);const o=i.proxy(a,e,t);d()?u.push(o):o()}}catch(e){try{y()}catch{}i.emit("artplayerProxyCanvas:error",e)}}))}catch(g){try{y()}catch{}throw g}return r}}return Object.assign(n,{default:n})});
@@ -1,7 +1,7 @@
/*!
* artplayer-proxy-canvas.js v1.1.0
* artplayer-proxy-canvas.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerProxyCanvas=t(),define(function(){return t.artplayerProxyCanvas})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyCanvas=t()}(this,function(){"use strict";var e=(e,t,n)=>new Promise((i,o)=>{var r=e=>{try{c(n.next(e))}catch(t){o(t)}},a=e=>{try{c(n.throw(e))}catch(t){o(t)}},c=e=>e.done?i(e.value):Promise.resolve(e.value).then(r,a);c((n=n.apply(e,t)).next())});return function(t){return n=>{const{constructor:i}=n,{createElement:o}=i.utils,r=o("canvas"),a=o("video"),c=r.getContext("2d");let d=null;const l={};for(const e in r)"function"===typeof r[e]&&(l[e]=r[e].bind(r));for(const e in a)e in r||Object.defineProperty(r,e,{get(){const t=a[e];return"function"===typeof t?t.bind(a):t},set(t){a[e]=t},configurable:!0,enumerable:!0});for(const e in l)r[e]=function(...t){return e in l?l[e](...t):a[e](...t)};return function(){const{events:e}=i.config;setTimeout(()=>{e.forEach(e=>{n.proxy(a,e,e=>{n.emit(`video:${e.type}`,e)})})})}(),n.on("video:loadedmetadata",()=>{r.width=a.videoWidth,r.height=a.videoHeight}),n.on("video:play",()=>{cancelAnimationFrame(d),u()}),n.on("video:pause",()=>{cancelAnimationFrame(d)}),n.on("resize",()=>{!function(){var e;const t=null==(e=n.template)?void 0:e.$player;if(!t||n.option.autoSize)return;const i=a.videoWidth/a.videoHeight,o=t.clientWidth,c=t.clientHeight;let d,l;o/c>i?(l=c,d=l*i):(d=o,l=d/i),r.width=d,r.height=l;const s=(o-d)/2,u=(c-l)/2;Object.assign(r.style,{padding:`${u}px ${s}px`})}(),s()}),n.on("destroy",()=>{cancelAnimationFrame(d)}),r;function s(){return e(this,null,function*(){try{if("undefined"!==typeof createImageBitmap){const e=yield createImageBitmap(a);c.drawImage(e,0,0,r.width,r.height),e.close()}else c.drawImage(a,0,0,r.width,r.height);t&&t(c,a),n.emit("artplayerProxyCanvas:draw",c,a)}catch(e){n.emit("artplayerProxyCanvas:error",e)}})}function u(){return e(this,null,function*(){yield s(),d=requestAnimationFrame(u)})}}}});
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerProxyCanvas=t(),define(function(){return e.artplayerProxyCanvas})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyCanvas=t()}(this,function(){"use strict";function e(e){return Number.isFinite(e.videoWidth)&&Number.isFinite(e.videoHeight)&&e.videoWidth>0&&e.videoHeight>0}function t(t,n,i,o,r){const a=t.getContext("2d");let l=!1;return{available:()=>!!a||(l||(l=!0,r(new Error("Canvas 2D context is unavailable"))),!1),draw(l){return s=this,u=null,c=function*(){const s=()=>l()&&n.readyState>=2&&!n.seeking;if(!a||!s()||!e(n)||!t.width||!t.height)return;let u=!1;try{if("undefined"!==typeof createImageBitmap){u=!0;const e=yield createImageBitmap(n);u=!1;try{s()&&a.drawImage(e,0,0,t.width,t.height)}finally{e.close()}}else a.drawImage(n,0,0,t.width,t.height);if(!s())return;i&&i(a,n),s()&&o(a,n)}catch(c){const e=u&&"object"===typeof c&&null!==c&&"name"in c&&"InvalidStateError"===c.name&&0===n.currentTime&&"function"===typeof n.getVideoPlaybackQuality&&0===n.getVideoPlaybackQuality().totalVideoFrames;s()&&!e&&r(c)}},new Promise((e,t)=>{var n=e=>{try{o(c.next(e))}catch(n){t(n)}},i=e=>{try{o(c.throw(e))}catch(n){t(n)}},o=t=>t.done?e(t.value):Promise.resolve(t.value).then(n,i);o((c=c.apply(s,u)).next())});var s,u,c}}}function n(e,t){let n=!1,i=!1,o=!1,r=!1,a=0,l=null;function s(){null!==l&&cancelAnimationFrame(l),l=null}function u(){if(!o&&!i&&t())if(r){r=!1,o=!0;const n=a,l=()=>{o=!1,u()};e(()=>!i&&t()&&a===n).then(l,l)}else n&&null===l&&(l=requestAnimationFrame(()=>{l=null,r=!0,u()}))}function c(){!i&&t()&&(a++,r=!0,s(),u())}function d(){n=!1,r=!1,a++,s()}return{request:c,start(){n||i||!t()||(n=!0,c())},stop:d,destroy(){i=!0,d()}}}function i(i){return o=>{const r=o.constructor,a=r.utils.createElement("canvas"),l=r.utils.createElement("video");let s=o,u=o.isDestroy,c=null;const d=[],f=()=>!u&&!(null==s?void 0:s.isDestroy),p=function(e,t,n){let i=!1;return{mount(){if(i||!n())return;const o=t();o&&(e.setAttribute("aria-hidden","true"),e.tabIndex=-1,e.playsInline=!0,Object.assign(e.style,{position:"absolute",width:"auto",height:"auto",opacity:"0",pointerEvents:"none",left:"0",top:"0"}),o.appendChild(e),i=!0,n()||e.remove())},destroy(){const t=[],n=()=>{e.srcObject=null};for(const i of[()=>e.pause(),()=>e.removeAttribute("src"),n,()=>e.load(),()=>e.remove()])try{i()}catch(o){t.push(o)}if(i=!1,t.length)throw t[0]}}}(l,()=>{var e;return null==(e=null==s?void 0:s.template)?void 0:e.$player},f),h=t(a,l,i,(e,t)=>null==s?void 0:s.emit("artplayerProxyCanvas:draw",e,t),e=>null==s?void 0:s.emit("artplayerProxyCanvas:error",e)),y=n(h.draw,f);if(function(e,t,n,i,o){const r=new Map;for(const a in e){const t=Reflect.get(e,a);"function"===typeof t&&r.set(a,(...n)=>Reflect.apply(t,e,n))}for(const a in t)a in e||Object.defineProperty(e,a,{get(){const e=Reflect.get(t,a);return"function"!==typeof e?e:(...r)=>n()?("load"===a&&i(),"play"===a&&o(),Reflect.apply(e,t,r)):"play"===a?Promise.resolve():void 0},set(e){n()&&("src"!==a&&"srcObject"!==a||i(),Reflect.set(t,a,e))},configurable:!0,enumerable:!0});for(const[a,l]of r)Reflect.set(e,a,l)}(a,l,f,y.stop,p.mount),u)return s=null,a;function m(){if(u)return;u=!0,y.destroy(),null!==c&&clearTimeout(c),c=null;const e=[];for(const n of[...d.splice(0).reverse(),p.destroy])try{n()}catch(t){e.push(t)}if(s=null,a.width=0,a.height=0,e.length)throw e[0]}function v(e,t){if(!f())return;const n=()=>{("destroy"===e||f())&&t()},i=()=>o.off(e,n);d.push(i),o.on(e,n),u&&i()}function g(){h.available()&&y.request()}try{!function(e,t,n,i){if(!i())return;const o=e.appendChild;n.kind="metadata",n.default=!0,t.appendChild(n),e.appendChild=r=>i()&&1===r.nodeType&&"TRACK"===r.nodeName&&"namespaceURI"in r&&"http://www.w3.org/1999/xhtml"===r.namespaceURI?(n.remove(),t.appendChild(r)):o.call(e,r)}(a,l,r.utils.createElement("track"),f),v("destroy",m),v("video:loadedmetadata",()=>{e(l)&&(a.width=l.videoWidth,a.height=l.videoHeight)}),v("video:play",()=>{p.mount(),h.available()&&y.start()}),v("video:pause",y.stop),v("video:emptied",y.stop),v("video:seeked",g),v("resize",()=>{var t;!function(t,n,i,o){if(!i||o||!e(n))return;const r=i.clientWidth,a=i.clientHeight;if(!Number.isFinite(r)||!Number.isFinite(a)||r<=0||a<=0)return;const l=n.videoWidth/n.videoHeight,s=r/a>l?a*l:r,u=r/a>l?a:r/l;t.width=s,t.height=u,t.style.padding=`${(a-u)/2}px ${(r-s)/2}px`}(a,l,null==(t=null==s?void 0:s.template)?void 0:t.$player,null==s?void 0:s.option.autoSize),g()}),f()&&(c=setTimeout(()=>{if(c=null,f())try{p.mount();for(const e of r.config.events){if(!f())break;const t=e=>{f()&&(null==s||s.emit(`video:${e.type}`,e))},n=()=>l.removeEventListener(e,t);d.push(n);const i=o.proxy(l,e,t);f()?d.push(i):i()}}catch(e){try{m()}catch(t){}o.emit("artplayerProxyCanvas:error",e)}}))}catch(b){try{m()}catch(w){}throw b}return a}}return Object.assign(i,{default:i})});
+332 -112
View File
@@ -1,124 +1,344 @@
/*!
* artplayer-proxy-canvas.js v1.1.0
* artplayer-proxy-canvas.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
function artplayerProxyCanvas(callback) {
return (art) => {
const { constructor } = art;
const { createElement } = constructor.utils;
const canvas = createElement("canvas");
const video = createElement("video");
const ctx = canvas.getContext("2d");
let animationId = null;
const originalCanvasMethods = {};
for (const prop in canvas) {
if (typeof canvas[prop] === "function") {
originalCanvasMethods[prop] = canvas[prop].bind(canvas);
}
}
for (const prop in video) {
if (!(prop in canvas)) {
Object.defineProperty(canvas, prop, {
get() {
const value = video[prop];
return typeof value === "function" ? value.bind(video) : value;
},
set(value) {
video[prop] = value;
},
configurable: true,
enumerable: true
});
}
}
for (const prop in originalCanvasMethods) {
canvas[prop] = function(...args) {
if (prop in originalCanvasMethods) {
return originalCanvasMethods[prop](...args);
}
return video[prop](...args);
};
}
setupEventListeners();
setupArtPlayerEvents();
return canvas;
function setupEventListeners() {
const { events } = constructor.config;
setTimeout(() => {
events.forEach((event) => {
art.proxy(video, event, (event2) => {
art.emit(`video:${event2.type}`, event2);
});
});
});
}
async function draw() {
try {
if (typeof createImageBitmap !== "undefined") {
const bitmap = await createImageBitmap(video);
ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
bitmap.close();
} else {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
}
callback && callback(ctx, video);
art.emit("artplayerProxyCanvas:draw", ctx, video);
} catch (error) {
art.emit("artplayerProxyCanvas:error", error);
}
}
async function animation() {
await draw();
animationId = requestAnimationFrame(animation);
}
function resize() {
const player = art.template?.$player;
if (!player || art.option.autoSize)
function forwardMedia(canvas, video, active, invalidate, mount) {
const methods = /* @__PURE__ */ new Map();
for (const name in canvas) {
const value = Reflect.get(canvas, name);
if (typeof value === "function")
methods.set(name, (...args) => Reflect.apply(value, canvas, args));
}
for (const name in video) {
if (name in canvas)
continue;
Object.defineProperty(canvas, name, {
get() {
const value = Reflect.get(video, name);
if (typeof value !== "function")
return value;
return (...args) => {
if (!active())
return name === "play" ? Promise.resolve() : void 0;
if (name === "load")
invalidate();
if (name === "play")
mount();
return Reflect.apply(value, video, args);
};
},
set(value) {
if (!active())
return;
if (name === "src" || name === "srcObject")
invalidate();
Reflect.set(video, name, value);
},
configurable: true,
enumerable: true
});
}
for (const [name, method] of methods)
Reflect.set(canvas, name, method);
}
function hasDimensions(video) {
return Number.isFinite(video.videoWidth) && Number.isFinite(video.videoHeight) && video.videoWidth > 0 && video.videoHeight > 0;
}
function resizeCanvas(canvas, video, player, autoSize) {
if (!player || autoSize || !hasDimensions(video))
return;
const width = player.clientWidth;
const height = player.clientHeight;
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0)
return;
const aspect = video.videoWidth / video.videoHeight;
const canvasWidth = width / height > aspect ? height * aspect : width;
const canvasHeight = width / height > aspect ? height : width / aspect;
canvas.width = canvasWidth;
canvas.height = canvasHeight;
canvas.style.padding = `${(height - canvasHeight) / 2}px ${(width - canvasWidth) / 2}px`;
}
function ownMedia(video, parent, active) {
let mounted = false;
return {
mount() {
if (mounted || !active())
return;
const aspectRatio = video.videoWidth / video.videoHeight;
const containerWidth = player.clientWidth;
const containerHeight = player.clientHeight;
const containerRatio = containerWidth / containerHeight;
let canvasWidth, canvasHeight;
if (containerRatio > aspectRatio) {
canvasHeight = containerHeight;
canvasWidth = canvasHeight * aspectRatio;
} else {
canvasWidth = containerWidth;
canvasHeight = canvasWidth / aspectRatio;
const target = parent();
if (!target)
return;
video.setAttribute("aria-hidden", "true");
video.tabIndex = -1;
video.playsInline = true;
Object.assign(video.style, { position: "absolute", width: "auto", height: "auto", opacity: "0", pointerEvents: "none", left: "0", top: "0" });
target.appendChild(video);
mounted = true;
if (!active())
video.remove();
},
destroy() {
const failures = [];
const clearObject = () => {
video.srcObject = null;
};
for (const release of [() => video.pause(), () => video.removeAttribute("src"), clearObject, () => video.load(), () => video.remove()]) {
try {
release();
} catch (error) {
failures.push(error);
}
}
canvas.width = canvasWidth;
canvas.height = canvasHeight;
const paddingLeft = (containerWidth - canvasWidth) / 2;
const paddingTop = (containerHeight - canvasHeight) / 2;
Object.assign(canvas.style, {
padding: `${paddingTop}px ${paddingLeft}px`
});
}
function setupArtPlayerEvents() {
art.on("video:loadedmetadata", () => {
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
});
art.on("video:play", () => {
cancelAnimationFrame(animationId);
animation();
});
art.on("video:pause", () => {
cancelAnimationFrame(animationId);
});
art.on("resize", () => {
resize();
draw();
});
art.on("destroy", () => {
cancelAnimationFrame(animationId);
});
mounted = false;
if (failures.length)
throw failures[0];
}
};
}
function createRenderer(canvas, video, callback, notify, error) {
const context = canvas.getContext("2d");
let reported = false;
return {
available() {
if (context)
return true;
if (!reported) {
reported = true;
error(new Error("Canvas 2D context is unavailable"));
}
return false;
},
async draw(valid) {
const usable = () => valid() && video.readyState >= 2 && !video.seeking;
if (!context || !usable() || !hasDimensions(video) || !canvas.width || !canvas.height)
return;
let acquiring = false;
try {
if (typeof createImageBitmap !== "undefined") {
acquiring = true;
const bitmap = await createImageBitmap(video);
acquiring = false;
try {
if (usable())
context.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
} finally {
bitmap.close();
}
} else {
context.drawImage(video, 0, 0, canvas.width, canvas.height);
}
if (!usable())
return;
if (callback)
callback(context, video);
if (usable())
notify(context, video);
} catch (failure) {
const awaitingFirstFrame = acquiring && typeof failure === "object" && failure !== null && "name" in failure && failure.name === "InvalidStateError" && video.currentTime === 0 && typeof video.getVideoPlaybackQuality === "function" && video.getVideoPlaybackQuality().totalVideoFrames === 0;
if (usable() && !awaitingFirstFrame)
error(failure);
}
}
};
}
function createFrameScheduler(draw, active) {
let running = false;
let closed = false;
let busy = false;
let pending = false;
let generation = 0;
let frame = null;
function cancel() {
if (frame !== null)
cancelAnimationFrame(frame);
frame = null;
}
function drain() {
if (busy || closed || !active())
return;
if (pending) {
pending = false;
busy = true;
const version = generation;
const valid = () => !closed && active() && generation === version;
const complete = () => {
busy = false;
drain();
};
void draw(valid).then(complete, complete);
} else if (running && frame === null) {
frame = requestAnimationFrame(() => {
frame = null;
pending = true;
drain();
});
}
}
function request() {
if (closed || !active())
return;
generation++;
pending = true;
cancel();
drain();
}
function stop() {
running = false;
pending = false;
generation++;
cancel();
}
return {
request,
start() {
if (running || closed || !active())
return;
running = true;
request();
},
stop,
destroy() {
closed = true;
stop();
}
};
}
function forwardSubtitleTrack(canvas, video, initialTrack, active) {
if (!active())
return;
const append = canvas.appendChild;
initialTrack.kind = "metadata";
initialTrack.default = true;
video.appendChild(initialTrack);
canvas.appendChild = (node) => {
if (active() && node.nodeType === 1 && node.nodeName === "TRACK" && "namespaceURI" in node && node.namespaceURI === "http://www.w3.org/1999/xhtml") {
initialTrack.remove();
return video.appendChild(node);
}
return append.call(canvas, node);
};
}
function artplayerProxyCanvas(callback) {
return (art) => {
const constructor = art.constructor;
const canvas = constructor.utils.createElement("canvas");
const video = constructor.utils.createElement("video");
let host = art;
let closed = art.isDestroy;
let timer = null;
const releases = [];
const active = () => !closed && !host?.isDestroy;
const media = ownMedia(video, () => host?.template?.$player, active);
const renderer = createRenderer(canvas, video, callback, (context, source) => host?.emit("artplayerProxyCanvas:draw", context, source), (error) => host?.emit("artplayerProxyCanvas:error", error));
const scheduler = createFrameScheduler(renderer.draw, active);
forwardMedia(canvas, video, active, scheduler.stop, media.mount);
if (closed) {
host = null;
return canvas;
}
function destroy() {
if (closed)
return;
closed = true;
scheduler.destroy();
if (timer !== null)
clearTimeout(timer);
timer = null;
const failures = [];
for (const release of [...releases.splice(0).reverse(), media.destroy]) {
try {
release();
} catch (error) {
failures.push(error);
}
}
host = null;
canvas.width = 0;
canvas.height = 0;
if (failures.length)
throw failures[0];
}
function listen(name, handler) {
if (!active())
return;
const listener = () => {
if (name === "destroy" || active())
handler();
};
const release = () => art.off(name, listener);
releases.push(release);
art.on(name, listener);
if (closed)
release();
}
function request() {
if (renderer.available())
scheduler.request();
}
try {
forwardSubtitleTrack(canvas, video, constructor.utils.createElement("track"), active);
listen("destroy", destroy);
listen("video:loadedmetadata", () => {
if (hasDimensions(video)) {
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
}
});
listen("video:play", () => {
media.mount();
if (renderer.available())
scheduler.start();
});
listen("video:pause", scheduler.stop);
listen("video:emptied", scheduler.stop);
listen("video:seeked", request);
listen("resize", () => {
resizeCanvas(canvas, video, host?.template?.$player, host?.option.autoSize);
request();
});
if (active()) {
timer = setTimeout(() => {
timer = null;
if (!active())
return;
try {
media.mount();
for (const name of constructor.config.events) {
if (!active())
break;
const forward = (event) => {
if (active())
host?.emit(`video:${event.type}`, event);
};
const remove = () => video.removeEventListener(name, forward);
releases.push(remove);
const release = art.proxy(video, name, forward);
if (active())
releases.push(release);
else
release();
}
} catch (error) {
try {
destroy();
} catch {
}
art.emit("artplayerProxyCanvas:error", error);
}
});
}
} catch (error) {
try {
destroy();
} catch {
}
throw error;
}
return canvas;
};
}
const index = Object.assign(artplayerProxyCanvas, { default: artplayerProxyCanvas });
export {
artplayerProxyCanvas as default
index as default
};
+2 -2
View File
@@ -1,7 +1,7 @@
/*!
* artplayer-proxy-mediabunny.js v1.1.0
* artplayer-proxy-mediabunny.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerProxyMediabunny=t(),define(function(){return t.artplayerProxyMediabunny})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyMediabunny=t()}(this,function(){"use strict";class e{constructor(){this.listeners=new Map}addEventListener(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t)}removeEventListener(e,t){const r=this.listeners.get(e);if(!r)return;const i=r.indexOf(t);i>=0&&r.splice(i,1)}emit(e,t){const r=new Event(e);r.detail=t;const i=this.listeners.get(e);i&&i.forEach(e=>e(r))}}function t(e){if(!e)throw new Error("Assertion failed.")}const r=e=>{const t=(e%360+360)%360;if(0===t||90===t||180===t||270===t)return t;throw new Error(`Invalid rotation ${e}.`)},i=e=>e&&e[e.length-1];class a{constructor(e){this.bytes=e,this.pos=0}seekToByte(e){this.pos=8*e}readBit(){const e=Math.floor(this.pos/8),t=this.bytes[e]??0,r=7-(7&this.pos),i=(t&1<<r)>>r;return this.pos++,i}readBits(e){if(1===e)return this.readBit();let t=0;for(let r=0;r<e;r++)t<<=1,t|=this.readBit();return t}writeBits(e,t){const r=this.pos+e;for(let i=this.pos;i<r;i++){const e=Math.floor(i/8);let a=this.bytes[e];const s=7-(7&i);a&=~(1<<s),a|=(t&1<<r-i-1)>>r-i-1<<s,this.bytes[e]=a}this.pos=r}readAlignedByte(){if(this.pos%8!==0)throw new Error("Bitstream is not byte-aligned.");const e=this.pos/8,t=this.bytes[e]??0;return this.pos+=8,t}skipBits(e){this.pos+=e}getBitsLeft(){return 8*this.bytes.length-this.pos}clone(){const e=new a(this.bytes);return e.pos=this.pos,e}}const s=e=>{let t=0;for(;0===e.readBits(1)&&t<32;)t++;if(t>=32)throw new Error("Invalid exponential-Golomb code.");return(1<<t)-1+e.readBits(t)},n=e=>{const t=s(e);return 0===(1&t)?-(t>>1):t+1>>1},o=e=>e.constructor===Uint8Array?e:ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e),c=e=>e.constructor===DataView?e:ArrayBuffer.isView(e)?new DataView(e.buffer,e.byteOffset,e.byteLength):new DataView(e),l=new TextDecoder,d=e=>Object.fromEntries(Object.entries(e).map(([e,t])=>[t,e])),u={bt709:1,bt470bg:5,smpte170m:6,bt2020:9,smpte432:12},h=d(u),m={bt709:1,smpte170m:6,linear:8,"iec61966-2-1":13,pq:16,hlg:18},f=d(m),p={rgb:0,bt709:1,bt470bg:5,smpte170m:6,"bt2020-ncl":9},g=d(p),k=e=>e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e);class b{constructor(){this.currentPromise=Promise.resolve()}async acquire(){let e;const t=new Promise(t=>{e=t}),r=this.currentPromise;return this.currentPromise=t,await r,e}}const T=e=>[...e].map(e=>e.toString(16).padStart(2,"0")).join(""),y=e=>(e=(e=(e=(e=(e=e>>1&1431655765|(1431655765&e)<<1)>>2&858993459|(858993459&e)<<2)>>4&252645135|(252645135&e)<<4)>>8&16711935|(16711935&e)<<8)>>16&65535|(65535&e)<<16)>>>0,w=(e,t,r)=>{let i=0,a=e.length-1,s=-1;for(;i<=a;){const n=i+a>>1,o=r(e[n]);o===t?(s=n,a=n-1):o<t?i=n+1:a=n-1}return s},S=(e,t,r)=>{let i=0,a=e.length-1,s=-1;for(;i<=a;){const n=i+(a-i+1)/2|0;r(e[n])<=t?(s=n,i=n+1):a=n-1}return s},I=(e,t,r)=>{const i=S(e,r(t),r);e.splice(i+1,0,t)},v=()=>{let e,t;return{promise:new Promise((r,i)=>{e=r,t=i}),resolve:e,reject:t}},P=(e,t)=>{for(let r=e.length-1;r>=0;r--)if(t(e[r]))return e[r]},x=(e,t)=>{for(let r=e.length-1;r>=0;r--)if(t(e[r]))return r;return-1},C=e=>{throw new Error(`Unexpected value: ${e}`)},_=(e,t,r)=>{const i=e.getUint8(t),a=e.getUint8(t+1),s=e.getUint8(t+2);return r?i|a<<8|s<<16:i<<16|a<<8|s},B=(e,t,r,i)=>{r>>>=0,r&=16777215,e.setUint8(t,r>>>16&255),e.setUint8(t+1,r>>>8&255),e.setUint8(t+2,255&r)},E=(e,t)=>({async next(){const r=await e.next();return r.done?{value:void 0,done:!0}:{value:t(r.value),done:!1}},return:()=>e.return(),throw:t=>e.throw(t),[Symbol.asyncIterator](){return this}}),F=(e,t,r)=>Math.max(t,Math.min(r,e)),D="und",A=e=>{const t=Math.round(e);return Math.abs(e/t-1)<10*Number.EPSILON?t:e},R=/^[a-z]{3}$/,M=e=>R.test(e),N=1e6*(1+Number.EPSILON),z=(e,t)=>{const r={...e,...t};if(e.headers||t.headers){const i=e.headers?O(e.headers):{},a=t.headers?O(t.headers):{},s={...i};Object.entries(a).forEach(([e,t])=>{const r=Object.keys(s).find(t=>t.toLowerCase()===e.toLowerCase());r&&delete s[r],s[e]=t}),r.headers=s}return r},O=e=>{if(e instanceof Headers){const t={};return e.forEach((e,r)=>{t[r]=e}),t}if(Array.isArray(e)){const t={};return e.forEach(([e,r])=>{t[e]=r}),t}return e},L=async(e,t,r,i,a)=>{let s=0;for(;;)try{return await e(t,r)}catch(n){if(a())throw n;s++;const e=i(s,n,t);if(null===e)throw n;if(console.error("Retrying failed fetch. Error:",n),!Number.isFinite(e)||e<0)throw new TypeError("Retry delay must be a non-negative finite number.");if(e>0&&await new Promise(t=>setTimeout(t,1e3*e)),a())throw n}};class U{constructor(){this.currentPromise=Promise.resolve()}call(e){return this.currentPromise=this.currentPromise.then(e)}}let V=null;const q=()=>null!==V?V:V=!("undefined"===typeof navigator||!(navigator.vendor?Line truncated
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerProxyMediabunny=t(),define(function(){return e.artplayerProxyMediabunny})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyMediabunny=t()}(this,function(){"use strict";var e,t,i,r,a,s,n,o,c,l,u,h,d,f,m,p,g,k,y,b,w,T,S,v,P,I,x,C,B,E,_,R,F,A=e=>{throw TypeError(e)},M=(e,t,i)=>t.has(e)||A("Cannot "+i),D=(e,t,i)=>(M(e,t,"read from private field"),i?i.call(e):t.get(e)),N=(e,t,i)=>t.has(e)?A("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,i),O=(e,t,i,r)=>(M(e,t,"write to private field"),r?r.call(e,i):t.set(e,i),i),L=(e,t,i)=>(M(e,t,"access private method"),i),z=(e,t,i,r)=>({set _(r){O(e,t,r,i)},get _(){return D(e,t,r)}});function U(e){const t=[];for(const r of e)try{r()}catch(i){t.push(i)}if(t.length)throw t[0]}function q(e,t,i){const r={control:!1,setting:!1};let a=null;function s(i){r[i]&&(r[i]=!1,"control"===i?e.controls.cache.has(t)&&e.controls.remove(t):e.setting.find(t)&&e.setting.remove(t))}function n(){a=null,U([()=>s("control"),()=>s("setting")])}return{update:function(o,c,l,u){if(!o)return void n();a=o;const h=()=>a===o&&l(),d=async e=>h()&&o.selector.some(t=>t.value===e.value)?u(e,o.title):e.html;c.control?(r.control=!0,e.controls.update({name:t,position:"right",html:o.html,style:{padding:"0 10px"},selector:o.selector,onSelect:d})):s("control"),h()&&(c.setting?(r.setting=!0,e.setting.update({name:t,tooltip:o.html,html:o.title,icon:i,width:200,selector:o.selector,onSelect:d})):s("setting"))},clear:n}}function W(e){const t=new Map,i=[];for(const r of e){const e=t.get(r.html);void 0!==r.html&&void 0!==e?r.default&&(i[e]=r):(t.set(r.html,i.length),i.push(r))}return i}function H({art:e,shim:t,option:i}){if(!i.m3u8)return;let r=!1,a=0,s=0;const n=q(e,"mediabunny-quality",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>'),o=q(e,"mediabunny-audio",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>'),c=e=>!r&&!t.engine.destroyed&&t.engine.loadSeq===e;async function l(){if(r||t.engine.destroyed)return;const e=++a,s=t.engine.loadSeq,l=()=>e===a&&c(s);try{const e=await t.getM3u8State();if(!l())return;const r=i.m3u8?.quality||{},a=function(e,t,i){if(!t.control&&!t.setting||!e?.levels.length)return null;const r=t.auto||"Auto",a=t.getName||(e=>e.name||`${e.height}P`),s=e.currentLevel?a(e.currentLevel):r,n=[];for(const l of e.levels){if(!i())return null;n.push({html:a(l),value:l.id,default:e.currentLevel?.id===l.id})}const o=new Map(e.levels.map(e=>[e.id,e.height])),c=W(n).sort((e,t)=>("auto"===t.value?0:o.get(t.value)||0)-("auto"===e.value?0:o.get(e.value)||0));return c.push({html:r,value:"auto",default:!e.currentLevel}),{title:t.title||"Quality",html:s,selector:c}}(e,r,l);if(!l())return;if(n.update(a,r,()=>c(s),(e,t)=>u("quality",e,t)),!l())return;const h=i.m3u8?.audio||{},d=function(e,t,i){if(!t.control&&!t.setting||!e||e.audios.length<2)return null;const r=t.auto||"Auto",a=t.getName||(e=>e.name||e.lang||e.language),s=e.currentAudio?a(e.currentAudio):r,n=[];for(const c of e.audios){if(!i())return null;n.push({html:a(c),value:c.id,default:e.currentAudio?.id===c.id})}const o=W(n);return o.push({html:r,value:"auto",default:!e.currentAudio}),{title:t.title||"Audio",html:s,selector:o}}(e,h,l);l()&&o.update(d,h,()=>c(s),(e,t)=>u("audio",e,t))}catch(h){if(l())throw h}}async function u(i,r,n){const o=++s,u=t.engine.loadSeq;a++;const d=()=>o===s&&c(u);try{"quality"===i?await t.switchM3u8Quality(r.value):await t.switchM3u8Audio(r.value),d()&&(await l(),d()&&(e.notice.show=`${n}: ${r.html}`))}catch(f){if(d()&&(await h(),d()))throw f}return r.html}function h(){return l().catch(e=>console.warn("MediaBunny HLS menu update:",e))}function d(){a++,s++;try{U([n.clear,o.clear])}catch(e){console.warn("MediaBunny HLS menu cleanup:",e)}}function f(){if(!r){r=!0,d();try{U([()=>e.off("video:loadedmetadata",h),()=>e.off("restart",h),()=>e.off("video:loadstart",d),()=>e.off("video:error",d),()=>e.off("destroy",f)])}catch(t){console.warn("MediaBunny HLS listener cleanup:",t)}}}try{e.on("video:loadedmetadata",h),e.on("restarLine truncated
@@ -1,7 +1,7 @@
/*!
* artplayer-proxy-mediabunny.js v1.1.0
* artplayer-proxy-mediabunny.js v2.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerProxyMediabunny=t(),define(function(){return t.artplayerProxyMediabunny})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyMediabunny=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.defineProperties,r=Object.getOwnPropertyDescriptors,i=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,a=(e,t)=>(t=Symbol[e])?t:Symbol.for("Symbol."+e),o=Math.pow,l=(t,r,i)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[r]=i,c=(e,t)=>{for(var r in t||(t={}))n.call(t,r)&&l(e,r,t[r]);if(i)for(var r of i(t))s.call(t,r)&&l(e,r,t[r]);return e},u=(e,t,r)=>new Promise((i,n)=>{var s=e=>{try{o(r.next(e))}catch(t){n(t)}},a=e=>{try{o(r.throw(e))}catch(t){n(t)}},o=e=>e.done?i(e.value):Promise.resolve(e.value).then(s,a);o((r=r.apply(e,t)).next())}),d=function(e,t){this[0]=e,this[1]=t},h=e=>{var t,r=e[a("asyncIterator")],i=!1,n={};return null==r?(r=e[a("iterator")](),t=e=>n[e]=t=>r[e](t)):(r=r.call(e),t=e=>n[e]=t=>{if(i){if(i=!1,"throw"===e)throw t;return t}return i=!0,{done:!1,value:new d(new Promise(i=>{var n=r[e](t);n instanceof Object||(e=>{throw TypeError(e)})("Object expected"),i(n)}),1)}}),n[a("iterator")]=()=>n,t("next"),"throw"in r?t("throw"):n.throw=e=>{throw e},"return"in r&&t("return"),n},m=(e,t,r)=>(t=e[a("asyncIterator")])?t.call(e):(e=e[a("iterator")](),t={},(r=(r,i)=>(i=e[r])&&(t[r]=t=>new Promise((r,n,s)=>(t=i.call(e,t),s=t.done,Promise.resolve(t.value).then(e=>r({value:e,done:s}),n)))))("next"),r("return"),t);class f{constructor(){this.listeners=new Map}addEventListener(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t)}removeEventListener(e,t){const r=this.listeners.get(e);if(!r)return;const i=r.indexOf(t);i>=0&&r.splice(i,1)}emit(e,t){const r=new Event(e);r.detail=t;const i=this.listeners.get(e);i&&i.forEach(e=>e(r))}}function p(e){if(!e)throw new Error("Assertion failed.")}const g=e=>{const t=(e%360+360)%360;if(0===t||90===t||180===t||270===t)return t;throw new Error(`Invalid rotation ${e}.`)},k=e=>e&&e[e.length-1];class b{constructor(e){this.bytes=e,this.pos=0}seekToByte(e){this.pos=8*e}readBit(){var e;const t=Math.floor(this.pos/8),r=null!=(e=this.bytes[t])?e:0,i=7-(7&this.pos),n=(r&1<<i)>>i;return this.pos++,n}readBits(e){if(1===e)return this.readBit();let t=0;for(let r=0;r<e;r++)t<<=1,t|=this.readBit();return t}writeBits(e,t){const r=this.pos+e;for(let i=this.pos;i<r;i++){const e=Math.floor(i/8);let n=this.bytes[e];const s=7-(7&i);n&=~(1<<s),n|=(t&1<<r-i-1)>>r-i-1<<s,this.bytes[e]=n}this.pos=r}readAlignedByte(){var e;if(this.pos%8!==0)throw new Error("Bitstream is not byte-aligned.");const t=this.pos/8,r=null!=(e=this.bytes[t])?e:0;return this.pos+=8,r}skipBits(e){this.pos+=e}getBitsLeft(){return 8*this.bytes.length-this.pos}clone(){const e=new b(this.bytes);return e.pos=this.pos,e}}const y=e=>{let t=0;for(;0===e.readBits(1)&&t<32;)t++;if(t>=32)throw new Error("Invalid exponential-Golomb code.");return(1<<t)-1+e.readBits(t)},T=e=>{const t=y(e);return 0===(1&t)?-(t>>1):t+1>>1},S=e=>e.constructor===Uint8Array?e:ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e),v=e=>e.constructor===DataView?e:ArrayBuffer.isView(e)?new DataView(e.buffer,e.byteOffset,e.byteLength):new DataView(e),w=new TextDecoder,I=e=>Object.fromEntries(Object.entries(e).map(([e,t])=>[t,e])),P={bt709:1,bt470bg:5,smpte170m:6,bt2020:9,smpte432:12},x=I(P),C={bt709:1,smpte170m:6,linear:8,"iec61966-2-1":13,pq:16,hlg:18},_=I(C),B={rgb:0,bt709:1,bt470bg:5,smpte170m:6,"bt2020-ncl":9},E=I(B),F=e=>e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e);class D{constructor(){this.currentPromise=Promise.resolve()}acquire(){return u(this,null,function*(){let e;const t=new Promise(t=>{e=t}),r=this.currentPromise;return this.currentPromise=t,yield r,e})}}const A=e=>[...e].map(e=>e.toString(16).padStart(2,"0")).join(""),R=e=>(e=(e=(e=(e=(e=e>>1&1431655765|(1431655765&e)<<1)>>2&858993459|(858993459&e)<<2)>>4&252645135|(252645135&e)<<4)>>8&16711935|(16711935&e)<<8)>>16&65535|(65535&e)<<16)>>>0,M=(e,t,r)=>{let i=0,n=e.length-1,s=-1;for(;i<=n;){const a=i+n>>1,o=r(e[a]);o===t?(s=a,n=a-1):o<t?i=a+1:n=a-1}return s},N=(e,t,r)=>{let i=0,n=e.length-1,s=-1;for(;i<=n;){const a=i+(n-i+1)/2|0;r(e[a])<=t?(s=a,i=a+1):n=a-1}return s},z=(e,t,r)=>{const i=N(e,r(t),r);e.splice(i+1,0,t)},O=()=>{let e,t;return{promise:new Promise((r,i)=>{e=r,t=i}),resolve:e,reject:t}},L=(e,t)=>{for(let r=e.length-1;r>=0;r--)if(t(e[r]))return e[r]},U=(e,t)=>{for(let r=e.length-1;r>=0;r--)if(t(e[r]))return r;return-1},V=function(e){return((e,t,r)=>{var i=(e,t,n,s)=>{try{var a=r[e](t),o=(t=a.value)instanceof d,l=a.done;Promise.resolve(o?t[0]:t).then(r=>o?i("return"===e?e:"next",t[1]?{done:r.done,value:r.value}:r,n,s):n({vaLine truncated
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerProxyMediabunny=t(),define(function(){return e.artplayerProxyMediabunny})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyMediabunny=t()}(this,function(){"use strict";var e,t,i,r,n,s,a,o,l,c,u,d,h,f,m,p,g,k,y,b,T,v,w,S,P,I,x,C,B,E,_,R,F,A=Object.defineProperty,M=Object.defineProperties,D=Object.getOwnPropertyDescriptors,N=Object.getOwnPropertySymbols,O=Object.prototype.hasOwnProperty,L=Object.prototype.propertyIsEnumerable,z=(e,t)=>(t=Symbol[e])?t:Symbol.for("Symbol."+e),U=e=>{throw TypeError(e)},q=Math.pow,W=(e,t,i)=>t in e?A(e,t,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[t]=i,H=(e,t)=>{for(var i in t||(t={}))O.call(t,i)&&W(e,i,t[i]);if(N)for(var i of N(t))L.call(t,i)&&W(e,i,t[i]);return e},V=(e,t)=>M(e,D(t)),j=(e,t,i)=>t.has(e)||U("Cannot "+i),K=(e,t,i)=>(j(e,t,"read from private field"),i?i.call(e):t.get(e)),X=(e,t,i)=>t.has(e)?U("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,i),$=(e,t,i,r)=>(j(e,t,"write to private field"),r?r.call(e,i):t.set(e,i),i),G=(e,t,i)=>(j(e,t,"access private method"),i),Q=(e,t,i,r)=>({set _(r){$(e,t,r,i)},get _(){return K(e,t,r)}}),Y=(e,t,i)=>new Promise((r,n)=>{var s=e=>{try{o(i.next(e))}catch(t){n(t)}},a=e=>{try{o(i.throw(e))}catch(t){n(t)}},o=e=>e.done?r(e.value):Promise.resolve(e.value).then(s,a);o((i=i.apply(e,t)).next())}),J=function(e,t){this[0]=e,this[1]=t},Z=(e,t,i)=>{var r,n=(e,t,r,s)=>{try{var a=i[e](t),o=(t=a.value)instanceof J,l=a.done;Promise.resolve(o?t[0]:t).then(i=>o?n("return"===e?e:"next",t[1]?{done:i.done,value:i.value}:i,r,s):r({value:i,done:l})).catch(e=>n("throw",e,r,s))}catch(c){s(c)}},s=(e,t,i,s)=>a[e]=a=>(t=new Promise((t,i,s)=>(s=()=>n(e,a,t,i),r?r.then(s):s())),s=()=>r===i&&(r=0),r=i=t.then(s,s),t),a={};return i=i.apply(e,t),a[z("asyncIterator")]=()=>a,s("next"),s("throw"),s("return"),a},ee=e=>{var t,i=e[z("asyncIterator")],r=!1,n={};return null==i?(i=e[z("iterator")](),t=e=>n[e]=t=>i[e](t)):(i=i.call(e),t=e=>n[e]=t=>{if(r){if(r=!1,"throw"===e)throw t;return t}return r=!0,{done:!1,value:new J(new Promise(r=>{var n=i[e](t);n instanceof Object||U("Object expected"),r(n)}),1)}}),n[z("iterator")]=()=>n,t("next"),"throw"in i?t("throw"):n.throw=e=>{throw e},"return"in i&&t("return"),n},te=(e,t,i)=>(t=e[z("asyncIterator")])?t.call(e):(e=e[z("iterator")](),t={},(i=(i,r)=>(r=e[i])&&(t[i]=t=>new Promise((i,n,s)=>(t=r.call(e,t),s=t.done,Promise.resolve(t.value).then(e=>i({value:e,done:s}),n)))))("next"),i("return"),t);function ie(e){const t=[];for(const r of e)try{r()}catch(i){t.push(i)}if(t.length)throw t[0]}function re(e,t,i){const r={control:!1,setting:!1};let n=null;function s(i){r[i]&&(r[i]=!1,"control"===i?e.controls.cache.has(t)&&e.controls.remove(t):e.setting.find(t)&&e.setting.remove(t))}function a(){n=null,ie([()=>s("control"),()=>s("setting")])}return{update:function(o,l,c,u){if(!o)return void a();n=o;const d=()=>n===o&&c(),h=e=>Y(null,null,function*(){return d()&&o.selector.some(t=>t.value===e.value)?u(e,o.title):e.html});l.control?(r.control=!0,e.controls.update({name:t,position:"right",html:o.html,style:{padding:"0 10px"},selector:o.selector,onSelect:h})):s("control"),d()&&(l.setting?(r.setting=!0,e.setting.update({name:t,tooltip:o.html,html:o.title,icon:i,width:200,selector:o.selector,onSelect:h})):s("setting"))},clear:a}}function ne(e){const t=new Map,i=[];for(const r of e){const e=t.get(r.html);void 0!==r.html&&void 0!==e?r.default&&(i[e]=r):(t.set(r.html,i.length),i.push(r))}return i}function se({art:e,shim:t,option:i}){if(!i.m3u8)return;let r=!1,n=0,s=0;const a=re(e,"mediabunny-quality",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>'),o=re(e,"mediabunny-audio",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>'),l=e=>!r&&!t.engine.destroyed&&t.engine.loadSeq===e;function c(){return Y(this,null,function*(){var e,s;if(r||t.engine.destroyed)return;const c=++n,d=t.engine.loadSeq,h=()=>c===n&&l(d);try{const r=yield t.getM3u8State();if(!h())return;const n=(null==(e=i.m3u8)?void 0:e.quality)||{},c=function(e,t,i){vaLine truncated
File diff suppressed because it is too large. Load diff
Loaded 100 of 3716 files, more files were not shown because too many files have changed in this diff. Show more