test(multiple-subtitles): [PKG-MULTI-SUB-05] checkpoint native core combination gaps

This commit is contained in:
Harvey Zhao committed 2026-09-14 12:30:42 +08:00
1 parent 675b095b27
commit b5dee252d4
12 files changed
+3437 -7

No files matched your search

@@ -143,4 +143,15 @@ check both factory-assignment directions and accurate asynchronous runtime metho
seven compiler modes, including classic CommonJS without interop. Removing suppression
comments must reject all 16 invalid statements at their exact lines in every mode.
Tasks 05/06 still own complete core/device combinations and demo acceptance.
The task05 matrix in `test/browser/multiple-subtitles-combinations.spec.js` adds
core5.1.2/5.1.7/5.3.0/5.4.0/candidate and actual plugin1.0.0/1.1.0/1.2.0.
Read native `template.$track.track.cues` for old-core probes: older hosts do not
provide the later `subtitle.cues` getter. Core5.1.2/5.1.7 only render their first
active cue; the matrix explicitly records lost simultaneous languages for1.1.0+
and candidate, while1.0.0's index-merged cue displays both. This remains an open
compatibility issue, not an approved limitation. Firefox paused offset assertions
currently fail on old and candidate cores; a WebKit5.3.0 source-switch failure is
intermittent. See the task05 change and validation JSON for exact failed runs.
The matrix is runnable with `yarn test:browser test/browser/multiple-subtitles-combinations.spec.js`;
do not replace these failures with skips or count boundary observations as acceptance.
See `../../refactor/baselines/multiple-subtitles-contract.md` for exact historical differences.
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,255 @@
{
"schemaVersion": 1,
"task": "PKG-MULTI-SUB-05",
"sourceCommit": "675b095b27e50832c4468096502e936422ea689a",
"capturedAt": "2026-09-14T04:18:32.057Z",
"association": "5.1.2/5.1.7/5.3.1 are historical plugin gitHead core associations, not a declared minimum range. Missing 5.3.1 must remain absent; 5.3.0 is only an adjacent stable comparison.",
"observations": [
{
"url": "https://registry.npmjs.org/artplayer/5.1.2",
"status": 200,
"sha256": "d9f823551c9d149e9cf1aa9ad1fe923f35cf78f8060e3c3efab0f389a4383eee"
},
{
"url": "https://registry.npmjs.org/artplayer/5.3.1",
"status": 404,
"sha256": "cb85b239f6d43e568f1a54eeac640ca05397450355d18994fe3719fed61dfd8b"
}
],
"releases": [
{
"name": "artplayer",
"version": "5.1.2",
"metadataUrl": "https://registry.npmjs.org/artplayer/5.1.2",
"tarball": "https://registry.npmjs.org/artplayer/-/artplayer-5.1.2.tgz",
"integrity": "sha512-eIWlxiP2ghgftaZWIGnclkOpXGFZTOf5xrm6sGZCGx5A8wGbTHRSMe+ZiyPFpbNhBVupi/QObSjX/FcD+YbS1Q==",
"sha256": "cb06570fb55f28577e702b15e011f79293a1378b429b0acb542caeda49ab6c00",
"files": {
"package/README.md": "2070b94087839a80dc01616a3114cbe2d3a4950018188f433752880daf7843f8",
"package/dist/artplayer.js": "3dfd035b4cde34c9d9dd1b303f95bfbb42bde105bcb3e5671a8d375a719290b1",
"package/dist/artplayer.legacy.js": "eedce04975dcf9a78a166ca3038d2b2bd06ce39696ce90f32ed39c8356132c4d",
"package/dist/i18n/cs.js": "0e353e313076ab5bc812c69d95c65dd4f41304be8cd3248b4fb1e66cc96361ef",
"package/dist/i18n/es.js": "e95e0c3d9e67d9aa9560a1d4ad34d7e524bb654573af63b583b0e230f397a918",
"package/dist/i18n/fa.js": "9e491847bacba5115af6c436461cce7b62b27913d73201a25f1ab33357fac820",
"package/dist/i18n/fr.js": "47f8c2741b8c65a71d02061b4d9659d5c9634c9b4670d16852d649fe5ca3674c",
"package/dist/i18n/id.js": "eb485192730c9a23aafb6b82b71cb3440e66790b9527fa735e1a23e132597170",
"package/dist/i18n/pl.js": "1ca2be239bda3d652431e8d4d8e41170d737b90193c151bbbfe9c1716d67c4f8",
"package/dist/i18n/ru.js": "ff7d1323f5fb21ead2834ae140da9e4a35cc2f80070f213623795b63daad79e6",
"package/dist/i18n/tr.js": "3981931b76ade9f8b8c6a862a18e702aed2644445b18a338bf2b58f9b16cde87",
"package/dist/i18n/zh-tw.js": "e6ed01c7cf38d47f36027ee916181aa5a243de4872d2fbcb2bca91668df84aa3",
"package/package.json": "aaf3ba9c7beaaea31170cc50e3958c0bb5d779ab4f90b6a213994ce8c9aace36",
"package/src/config/index.js": "6419ff29300032a0c3535a396d7c977cf4ac09d9edc6b3a04eeec7256ea5f6d4",
"package/src/contextmenu/aspectRatio.js": "2e880ea29ed71d6e05192f10de246e0646754817f8135ac71bc4f082c7f60ec1",
"package/src/contextmenu/close.js": "4df0e913b1755409f034cbb54027b4518f05490ef66ad84b6f0e995899f41bc4",
"package/src/contextmenu/flip.js": "6f7574f7b5dfb0464e86e5910cc7b6f64ae06cbbef8d9a2a30086050a3952404",
"package/src/contextmenu/index.js": "836c353eddc3e638d0ca43c3065809b5967ac1ec83e2ccf59e1ea11bc8cb67ee",
"package/src/contextmenu/info.js": "b7286de4d650d115493ef98891b77ff0deddb7e6c5725d93c8874890304885c1",
"package/src/contextmenu/playbackRate.js": "2b470a632bba8c40ffc46c00374e80bd3ea2325cf0c9e5ddfad81a03fd149847",
"package/src/contextmenu/version.js": "d15f750e2af7c9de92ce85fd765541cd0deb00dbff6fa7544b90ba2e00354f40",
"package/src/control/airplay.js": "3f5a5c82edfd8e0104311d1bc6224a216e8823d977f4d3d2efd2230232f1096e",
"package/src/control/fullscreen.js": "fab9bd25ace5b85b643207cc781fc1ccf73bdc6abdeeb35d7863cfe21ce25da3",
"package/src/control/fullscreenWeb.js": "c4e8f2ed78556ed5a1fef61477d4fd4acd2bbf2226b0969604cabea3b8cf8152",
"package/src/control/index.js": "bc669b48b55f4bda20f2eff31a3afe744be072a751924b78d28ac8bff2f7659f",
"package/src/control/pip.js": "abf03561ccf8209e58b961c32d013a24e190b275f5c420f237eb5c9eea836de7",
"package/src/control/playAndPause.js": "e29d017f0c629a583b970d08ffe91169d43c573e2fa50e5467182a3e2ca06d34",
"package/src/control/progress.js": "afde20e842fc10fcc71dc58f3821f82e4e27c51d79fcdbabd28bc9f7156ad734",
"package/src/control/screenshot.js": "66d1baddda0e7aeecfa13b345b95c388e9b030e56ed41b6ab5bd7fd65305fb8c",
"package/src/control/setting.js": "5aafdb3a26b0526d38c1de2a721d818a61ea06c1c3ef9fce54aa467cb3999c7e",
"package/src/control/thumbnails.js": "d8781caff5bce02529877061042968accedb35c88096f67285ed76ddcf54c616",
"package/src/control/time.js": "b29e4abdab8a52a120534d268b56ea502e7394a1d0a3ce0986b5f90a4251dded",
"package/src/control/volume.js": "0835f417e11cadf3b845a6e84666afb649fc055d23951291d4526a3f35466cdf",
"package/src/events/clickInit.js": "c71e5709da54b6dbd650744c3cfea43f74cbad39080da4db5c049452e4a8c595",
"package/src/events/documentInit.js": "3588e34c434555ac474c92519f1aba8d8f9b442b9cf32d15a12e136bcbca0ae2",
"package/src/events/gestureInit.js": "cc1af487be679f629b9a5084dba0497816cc06277464cc5250699775a1e116fb",
"package/src/events/hoverInit.js": "e7ad02a7b3a2fa654b29d6016cc8b70950185a9fae422fa259b443046c9f0b5d",
"package/src/events/index.js": "9e89b16e3082c9d4c74accd8e58b8e5229bfd07a29e63018be1c3ce81f18ecda",
"package/src/events/moveInit.js": "396c374c161a62c7b74fc52ff8e8efe99016eac2b3ce9fa4f2476751b8f46d51",
"package/src/events/resizeInit.js": "c1cfb19f57bab631d5a6fe0691c4b1c26e1cc9d7f412069368aa2a467ecd9c1f",
"package/src/events/updateInit.js": "40cd0fd049e660ff58c83e20823409b9461077924a9a777406866c3aa345296e",
"package/src/events/viewInit.js": "b04b1356495e5edc19c435b3263665d8b0906a21329391a2e24051d1b5943868",
"package/src/hotkey.js": "ca9ecd041f2d2081fdc8f6bc2ba13c9eddc90afb1cdddef3bdb9907866efaa94",
"package/src/i18n/cs.js": "ebf7b10a0c1eab982935047019016e1e4e639c3184cf01805c651fa5473caf42",
"package/src/i18n/es.js": "90f2acedb4387b323ce57de3d693361caa130aa85f979f748ff3e5126b849b62",
"package/src/i18n/fa.js": "5b97bc2a038a4e75b56c2e5408412355c0eb54efae3033dcebce889442b3bb55",
"package/src/i18n/fr.js": "91901814ebcffc0c282e817fe7467c59406eb2d7c388fe5d6513078dd06db3a8",
"package/src/i18n/id.js": "7207ba2e88336d6342665ab8037e1ef1710c1ee09ac9d7c040237e4a3d5b8c5b",
"package/src/i18n/index.js": "5408964b30ab298ebfa8bdaa4c45a1bc5f517682a0032c15ac98fb11867b8855",
"package/src/i18n/pl.js": "1f0b0849c3de39faebcf5a14c068374344cfb9de5745f6e5abedc5d569aea529",
"package/src/i18n/ru.js": "44ec0ab1ba6794315069adf178ab9ac645922ba408aedfe09ef8b79daf70e776",
"package/src/i18n/tr.js": "f94e874dbe8e4a7aacbd4444a7040e9bf9ac140e442f33fed31e376ce8f52a41",
"package/src/i18n/zh-cn.js": "10707cf170c062e3450587d21cc12156cb88843a6766c61eedafed0d2cf34a12",
"package/src/i18n/zh-tw.js": "b7dedc5616f12345b17c8ec185853b08d0ef572fb7460df79fc0206f0c8b6d97",
"package/src/icons/airplay.svg": "095f71bbac1aabde07963c645cb2071f790873fb2730363224e004321a01242a",
"package/src/icons/arrow-left.svg": "ac8cb60bf1f9436b9fc27eef2c65787dd879f01fb7ed2070b74be8a4d3167e0e",
"package/src/icons/arrow-right.svg": "9e2aa8a84ee9879bb70fb4fbae8eeb2a020e9a02c7bde14dede819d33acdff3c",
"package/src/icons/aspect-ratio.svg": "a71df3064cba45f402698b4c11fe21798b9af9aa6c5d0d689262889ffa386ab1",
"package/src/icons/check.svg": "672230ecd40c42b5354aad702ba6b018a9b765655bc96a53ba003fee41d8413a",
"package/src/icons/close.svg": "bb9e23e5305d11ec3d8f75a50ecdf3150deab8614c7df2af588873f2d78f06c2",
"package/src/icons/config.svg": "adbe547dfde4b44399da319ccdfc29fca57bcdbec8c6af5e36a2eeb97ecc2041",
"package/src/icons/error.svg": "d85a72e27ceaa38221637405cb0a5be270a297da58f1b0428498f568fab7570a",
"package/src/icons/fast-forward.svg": "709887f67e76e76d17fec37025c7405d85e9be28466d49602c1aa18732c89cef",
"package/src/icons/flip.svg": "ea6d9328823bb8454af65250030f02584239fcf8fbc2fb937dd1a1bac7602c28",
"package/src/icons/fullscreen-off.svg": "612577a443da55433bef698f1f4a426d0223c70cf1bcec3b27221bff753ae621",
"package/src/icons/fullscreen-on.svg": "bbec64253a42ef5ea26f6289d58254a7e86af3c0d627b2eb2ae357ef47cd04db",
"package/src/icons/fullscreen-web-off.svg": "57fa0e8780baa7f27befdeeb9ec2e772a1185a469a5f7ce05ed760d93ac8c434",
"package/src/icons/fullscreen-web-on.svg": "c6283f3ef124ea47e27b725ef5757a0b586dd5371cbefcdf2180dfabfe6375a9",
"package/src/icons/index.js": "b0107676f57ad6d04e507976f5582e64d4dd71309ae395897f608f2591896320",
"package/src/icons/loading.svg": "ffcf5d814e6f3931a370bb4f0d2675381c2adb8f6d29dd1ee8f5df33d8175e75",
"package/src/icons/lock.svg": "1acb0566c08175200cdd47f0ce7f72ca1ae2761962cc3b134be4d44398cfcee2",
"package/src/icons/pause.svg": "9efe05ebf5610befddebcac51b3c9a491001189ff86204cb47928eb1617f6c7a",
"package/src/icons/pip.svg": "52d1e150d1364aed20917d83a2f7ab7589fb9df9655f3d3afaea3c4387800812",
"package/src/icons/play.svg": "c35562d20028d52ce329f35f90496a06d4dc5b6dc39df7ebcfb027f6f2393958",
"package/src/icons/playback-rate.svg": "cbc025c7780a5e5c31160182d70131202fa41a661d20ec2933e0bb1f488f1cd8",
"package/src/icons/screenshot.svg": "49f7d90198fb0bcbc29848f40b0a8c042b78c07ecef1cfc5184e2e84a61b4bd4",
"package/src/icons/setting.svg": "7f6454d1c7f037d5a7144a898abedc89ca339534166d620dfa45efcd4c74ee3c",
"package/src/icons/state.svg": "9d777729e9287c6dc7f8d0687a257ffd40bd817fa84f24eb98dfebb3256b6e35",
"package/src/icons/switch-off.svg": "0bf5803437823035b816fb8bec148c06b4e01f85ea987cedda87269da6aab412",
"package/src/icons/switch-on.svg": "1d87b42af5e7141f9defdc790567534288d84858d5068dd15093d5ef12f37f9c",
"package/src/icons/unlock.svg": "f341e80530c2b6b218495c7ed3b9e4f268d70d2c931c0bf76efed1add8bab745",
"package/src/icons/volume-close.svg": "b9dbeaf9043c8014cd29d0e4a21a82ce567bc6b85497c310cca5f68bceeb31b2",
"package/src/icons/volume.svg": "baebc4ede3013202a4b13202a8d961cb0e5e065ee03733816022b2541d13884f",
"package/src/index.js": "01ac24c9cc37f788995b0072769a46532bb569271ffdf4e3f734bab3fae2da67",
"package/src/info.js": "7fc50f9549ab4cc91422dea5182fe6250cf8273501425cb371a5870393bc39c1",
"package/src/layer.js": "ed576b5a805684852de55b56e65bf295ef8422e51e58a7f0fb7ad9987639f262",
"package/src/libs/screenfull.js": "3ff8b0abec9b100b4c25476627f7bd505466ae77a0700c95347e9e6e05f45bc6",
"package/src/loading.js": "f47a310ae4acfbd45bf34786901377844a08b4acc40d169f99b1af7ab02e4988",
"package/src/mask.js": "c28ab44ab96255f9357d39e184a048aa12f0822073d38a82c63d59b6cd2a0936",
"package/src/notice.js": "ef17bef61d6ff1e67f5e722a100ab5f5f9e4779f1297b06e16b5a9a32168cd67",
"package/src/player/airplayMix.js": "83346ea049d0a17b6943926f67e6c3a1e7242bcd978933dd77cd16ae3dca39ef",
"package/src/player/aspectRatioMix.js": "9f262f3fb47d23dc784aa31ea3264980567dcecdbfed592f2a26251d9473bdac",
"package/src/player/attrMix.js": "ae4103f3ede68f9ae87a16fa2c1e2b3bd3b03ec6190eb0ea8ace0c4b61216a29",
"package/src/player/autoHeightMix.js": "3c24c9b2a8ccc95f0b6b682e506565c0616f1b96f3d98bd20d219616d2dc4234",
"package/src/player/autoSizeMix.js": "c1da497f2a8232f5a107c9a5bed1eac7261db3938208b4e1c21e5bf69f6b7419",
"package/src/player/cssVarMix.js": "ea05acb553183ae60d42829ccf96deef06fbdb400424071777bd39c6ed6e683c",
"package/src/player/currentTimeMix.js": "41e5a6ac03d0dcd6883d5b08e2c74e0421b3d68e819f2b9c1e7f27aaf26bd7e8",
"package/src/player/durationMix.js": "87922cfb4a55db593e1c0187bf1912cf5b7c9b3b0136341723692a60f95efe01",
"package/src/player/eventInit.js": "f5f7412e652e8b2709443e2e2833d949e3563c002794d78cf466200e27af7be1",
"package/src/player/flipMix.js": "416485570461e7ef3c0346b528bedd8846bd24473d51ce6e33ac7abf61a24dfd",
"package/src/player/fullscreenMix.js": "648c5339b6a49ee16dac10848ce414636c39781cc3ad71f955c1e1923bd74e32",
"package/src/player/fullscreenWebMix.js": "168aa2b5ddf6b0305a565bacb73ade7c49942d7e8abcbe3198d4089e071d17b3",
"package/src/player/index.js": "518d54576f7cf1a7cec6031743a19ad1a475df54e539546a722c174ee4c2cf1b",
"package/src/player/loadedMix.js": "cd984138d0bee78d8e822ae424a4f61adc5530327283e2db72b1942f6b464f22",
"package/src/player/miniMix.js": "d051921e521178c14fd9a3cd28823a0de62ffdbc35936cf3d745700263841ed4",
"package/src/player/optionInit.js": "ca8978d55edd199a8ea6ccffdafa6d5ee0b1eebc818333b73d81574daadb0493",
"package/src/player/pauseMix.js": "f96b7d2f17a01144bb5299612a794b4e971d7e389444f3769a272fa164f82886",
"package/src/player/pipMix.js": "f6c1970557258374f1007b16eaea05a2ceaf4319ad1cc6c7c0e4971b080775a8",
"package/src/player/playMix.js": "1e37d4ff7d5a5508c9f656d391993ec28a5a4627aca7917d4601164f6fdc5d63",
"package/src/player/playbackRateMix.js": "51f862cfec9744b7414a75fd1cd2aaaaf41d240300a21d024320ca85ede71415",
"package/src/player/playedMix.js": "0d345bac5914a3403cc2b7f5c8d68ab61a4c53e9085602d8e28950dab7175936",
"package/src/player/playingMix.js": "2ba6c2c9e495bcabb91da43d0c8162742c80f9fe39ee60e15eb01e7c5761348f",
"package/src/player/posterMix.js": "b50ee061fa1ded74b77a2e0b0e7306d9f8f87854d8b72368e2e84f2a89568850",
"package/src/player/qualityMix.js": "3e43a8a6e0c0004e8f88a42457db61c20bb2184203675d19cd5761f936ae15a3",
"package/src/player/rectMix.js": "9eb0a052fce5cb4e6fa1999221155407842275dc022f18a713e3e71ac7c22187",
"package/src/player/screenshotMix.js": "40bb2ae541ba41a60bdfe315c9fe35da25954132ad8c52f184281dc341e6af24",
"package/src/player/seekMix.js": "2bb1f1923aad7a989b4cadb3fe79e02176adb123425a356a93541eb8cd0885d4",
"package/src/player/stateMix.js": "ff8618ab6424f9d34337ebf5294449d2eea5cf76307b654cfff1e53e71c3ae54",
"package/src/player/subtitleOffsetMix.js": "5dfc80bce7921ce305259fe0a6f92a79f6bb09c1c7ca00132e3595a25fcdfca7",
"package/src/player/switchMix.js": "34bcc9d0c55ccb4b859583e22c0516171c719fa95c2b9b0af3232ad2455d789e",
"package/src/player/themeMix.js": "4f5394da3fc6fae0b5996a4d0a9d875fd8f9a9def759e946fc6a64af595dc3de",
"package/src/player/toggleMix.js": "9ec0e69ade2445e8e583eb94d226825efe2c109274eeed244c1e035e39b024a9",
"package/src/player/typeMix.js": "2a2284a7c1368c33054c8f8df473fa2cac71bb97dced04b3c61097854e05351e",
"package/src/player/urlMix.js": "f30f285ab3b071a47c3f82b6150f89664ab03fc8c403a8c953e197a7d457e5fd",
"package/src/player/volumeMix.js": "9847e9cdd994023db1ab1df7f71177ec52b9eea16105f9297cc0cfab0d5fe040",
"package/src/plugins/autoOrientation.js": "0b5885a7113d3d93724ebfe5713708a2e2c79d5a426f215af13db5367db565a5",
"package/src/plugins/autoPlayback.js": "9aaf05c22f7ca3c36fe4f8adcb1cc0374d4aceeef0e22d0f11b1c2cb99aebf35",
"package/src/plugins/fastForward.js": "77f2bf8f4d3b81328da0ca95bc74eb5f8b36ab70b0f0fa406d90ee5448ada697",
"package/src/plugins/index.js": "5a25986996ffa174cfd7678a072d2b703c4ab903b357c4635678703defdd03ef",
"package/src/plugins/lock.js": "e3aa7dfe8380cec6ff8f64fc6b97211dc3a2f6d0b6fd67d40cc6ecc176c8db0d",
"package/src/plugins/miniProgressBar.js": "8d22005b3a42820c7b6c53f0abaaed38f94a5fa12239e27f28efccd379c2c5eb",
"package/src/scheme/index.js": "42f14c584e0e663f8f0a111954fdb26e56ebabd4c5e45c455fa740f03d268b47",
"package/src/setting/aspectRatio.js": "b1cf508b7806776ac7e952cd1791da8dabce4177219f8c59e9fe4784be5aa1fa",
"package/src/setting/flip.js": "1ecf3b33579f8fb564763a83b2aaca1949fa582816f185b58684cc341aa39dee",
"package/src/setting/index.js": "900905c0ee9b38a67a07a703dc06b4dc6a2eea132c0762582859645cdf318181",
"package/src/setting/playbackRate.js": "77826765484758cafab1d000baab857d856d38caca80d25cacfc52988d3a1259",
"package/src/setting/subtitleOffset.js": "7112aa437e203b4449eba9a95a5885fce9bb09c15c879bceb79536b3f152823b",
"package/src/storage.js": "416f090c331fa27ff49838e58967c77f334bff4bb000cdc116d2579f5ac56021",
"package/src/style/artplayer.less": "662cfc3f079e75e50c18199511d533f4e35f7eac21aaf8f1171cfc93dcca243d",
"package/src/style/aspectRatio.less": "5ab50ae065c4a21734f17a32f5838b940f97070083143dabe1070d45630a3aca",
"package/src/style/backdrop.less": "8530dcc3e390b7a1cd767463023aab2ca410478792dd5b4f00b24ae55967ed33",
"package/src/style/bottom.less": "447283e979e53e6c777dc8f513d0b42488ab98afb8f5f5bb8cb0d645df47a085",
"package/src/style/contextmenu.less": "3aca4d6f32e5fa7022b22bd2f7bc81d8b17224158a7de41ca9e6b8ed84837252",
"package/src/style/controls.less": "89d35e4154a82a99096df18bc01b1f7939a54b1823c12bd2c43e0ce67e91fa0c",
"package/src/style/danmuku.less": "e75aae6ff39b1d255d250486562e9db8324dada097552d62a0a85f2de7035caa",
"package/src/style/flip.less": "7b7be6602d1672c7d17a726051273c320eec83a925be509e2545df7a387123b7",
"package/src/style/fullscreen.less": "0ba5cddcd264a2750281a309916ab0f3d8b01131666e052a24bc0ec89e870e76",
"package/src/style/fullscreenWeb.less": "1e0bac3295e5269ac28888cdc9060f6720983792dead34bfad897e2d33f499bd",
"package/src/style/hideCursor.less": "fcf26ad3ca2ce28486594975a045304048bdd98996bc80ac74e36740fd7ef4e7",
"package/src/style/hint.less": "e29017145d831b23337b500b9ed5ff3706ce56f31dc4ac2720615c6ea3a9d97d",
"package/src/style/icon.less": "a75dcb23a859cb42fa50cadada36508ce752aed6ea03984a8f5947d8584d10b7",
"package/src/style/index.less": "1d9cecc59fe0d0b7f2d057c91998e3a2492ea52999369512ef355fc166781474",
"package/src/style/info.less": "ba577cbe605cd541d0171d4e0b2fe15333963da4bc040d466bfb347f9be79bcc",
"package/src/style/layers.less": "93791f5e52176a166835e1f4b3d24a07d305531f91647cc8aea75496ec72b8ab",
"package/src/style/loading.less": "7f211e95694e0d3aa64b6f8e25deb6f60c2c65303dff9df44b1acab6cbc30bcd",
"package/src/style/mask.less": "251ea4a6b4ca20de2baaa8b13b420a77180fb570ca1744a7bd757d646b5b3664",
"package/src/style/mini.less": "de25c47271e807fc311f33110e651ea0ee143e61b15ae92cdcbe4ea8d2e78683",
"package/src/style/mixins.less": "3bb2205bf2b2ff9c224010fc1a170f1e56614f6e710b222f2e8807747f772c04",
"package/src/style/mobile.less": "088a21666ebf5b631f2d15527c2a283890b25285d0d31ea5f60adfaf3689d936",
"package/src/style/notice.less": "98baf3481e7269bb8b4d399d561a15f6f5189e45f50225adf41aabb64d0e94d1",
"package/src/style/plugins.less": "97b4baef8a0493f152ae73ce1b988cab0d7eebbe4a6c119e944247d19bcfd2bc",
"package/src/style/poster.less": "939f33aa2a48806eb1da3bc4b49a8f9ab541ff2a53796260f475b2c7a98cba60",
"package/src/style/progress.less": "396183b508c937b17a92f3713b4a80d911c0f04ab39e7eaf29e26aafff391199",
"package/src/style/selector.less": "5320e35c670912a57534fdf4122aef566c9ca273e14b52af5d882c8cd4591f74",
"package/src/style/setting.less": "1951153c3fa2ae6541c0a046404db043a1287b80847a499c6386c49c3e929695",
"package/src/style/subtitle.less": "b26cdc6aa6e5a113a0197f08e895ce73f0557e54d0e4d1dc4cac03a2fd48b5c0",
"package/src/style/variables.less": "585d2d19f2763087c578a9d90a853db7c236b0d3768f502e46eee27dd51b7ef5",
"package/src/style/video.less": "a2a7ca14711238c18acdfa7d094c5223f269618cbb884866a6cdc22af7579b8d",
"package/src/style/volume.less": "7593ef9f5e34713b30b5d690182c6510a0912dd659f3405f7f38242398fbdfcb",
"package/src/subtitle.js": "7847d732cbecd3fabb0683b69d22972d9c47b1b13a991fa6b46e2b95d3ba4a65",
"package/src/template.js": "6561ac281682a65f3423dffd232b56e14f10d88713743d6505e1fbe0cf5402a9",
"package/src/utils/compatibility.js": "079c4621b7856d2f34bfba27376048c47b538cfc3e07c9d019701bd05a8b62c8",
"package/src/utils/component.js": "1a96e1ce80fab7a2c88e0849bf8519edd2554e332a4d3461eb7de8d3c709d638",
"package/src/utils/dom.js": "3b989e4073efc94a30b967ec3f9015565ee0d0895acea779d53611890d3af3b9",
"package/src/utils/emitter.js": "637c2b65c89a34ca3208335a892258540eefc49cb8f87f981c69496fe49efa89",
"package/src/utils/error.js": "3b395e07922fb3fcbb7de34e662ada1914b3499dac6f109e522c432bd705f3d1",
"package/src/utils/file.js": "c02139c54e569bf635f90d32b7ccb9d6cb8ba5ff126071e6c79b34a134b11cb2",
"package/src/utils/format.js": "318a9e844fdbb64168a1d076c45697e35b0f907103089bce94b414f132ab3e9c",
"package/src/utils/index.js": "585394c7bfda8e8548cfb92c73ae1e45cccc55c48d683ca9a48099debdf4b98e",
"package/src/utils/property.js": "48faa8d72daf7bea824146ecf9ccec0575fd32995d482cb94731d859b1f9a437",
"package/src/utils/subtitle.js": "2f932f5812f7cf9e5684d10da81c40f757de7fdfe0175da3b24da84c08befe1b",
"package/src/utils/time.js": "d471d1cbde1a108b908a083005a3af1e17a3df55b084cec1f1866368f1f3d07b",
"package/tsconfig.json": "bf1616499e177df22713d30f25dd255295c43d34310185403b2dfb1c4970c793",
"package/types/artplayer.d.ts": "ae6877ec208b09c9538e46b33eb80230690d7a3e04c69f14ea33a57557039143",
"package/types/component.d.ts": "7a4ea13e3f6400918190d2f34992b7de96e6145b4ebdf2030976594d5673f50d",
"package/types/config.d.ts": "3e2e3294802653fbab62f05d5d656411c657641d8f7a3ce64295eef44b37ef62",
"package/types/cssVar.d.ts": "a83429be37936c98850975c1a3a6896bb8a113a270b8cbe3994967f1d41458a3",
"package/types/events.d.ts": "d5de098edc263858f10e29c34c2beb68dc55192d7e8251ecc74bd7e60988e996",
"package/types/i18n.d.ts": "75a61026bbc08cf29498700d1ed73b115734d9284085ab1ea0769d3d1a3c3d8b",
"package/types/icons.d.ts": "a4d2fa1a85755cc40d0ac9d0dadb7bedae1872b3306ba434f0fd817c0b2ac3b6",
"package/types/option.d.ts": "a336ee6381415fa7141edc1a1967db12e353b1cfad3af6f390a3c47f146faa3a",
"package/types/player.d.ts": "94dfcb837326954195cf38363ef8d8b909243549579c59fdde344cd8d8f1886f",
"package/types/quality.d.ts": "b07e6525dcadbbb6fcd7c5ccb5e24eca87d25b24b8a23b49891c032a479fe660",
"package/types/setting.d.ts": "fbf66bb3fd75e4d57052aafc41f752f8fca1c801ad502ff06ef11a6ab6b86200",
"package/types/subtitle.d.ts": "76d899e4f72aeafedfd8f063f9dcbe2ada9e367d0bb2dc6a01b9929d3ebbd58f",
"package/types/template.d.ts": "a6065449803fc0adca1b39a2588c01c4d82e4b2e3be73bb66f601d579aa2a583",
"package/types/utils.d.ts": "570ef62a8524999af0ec1018cad7c0446703dae319ddbe15ee3f917a7240b2ed"
},
"manifest": {
"license": "MIT",
"name": "artplayer",
"version": "5.1.2",
"main": "dist/artplayer.js",
"legacy": "dist/artplayer.legacy.js",
"types": "types/artplayer.d.ts",
"homepage": "https://artplayer.org",
"author": "Harvey Zack <laozhaochaguan@gmail.com>",
"browserslist": "last 1 Chrome version",
"description": "ArtPlayer.js is a modern and full featured HTML5 video player",
"repository": {
"type": "git",
"url": "git+https://github.com/zhw2590582/ArtPlayer.git"
},
"bugs": {
"url": "https://github.com/zhw2590582/ArtPlayer/issues"
},
"keywords": [
"html5",
"video",
"player"
],
"dependencies": {
"option-validator": "^2.0.6"
}
}
}
]
}
@@ -0,0 +1,73 @@
# PKG-MULTI-SUB-05: core combinations checkpoint
Baseline: 675b095b27e50832c4468096502e936422ea689a. Task05 remains doing.
This checkpoint adds executable integration evidence, not a completed package or
release acceptance. Source implementation, public types and generated bundles do
not change. No dependencies, versions, lockfile, push or publication changes.
## Inputs and tests
`multiple-subtitles-cores.json` freezes real npm core5.1.2 metadata, SHA-512 archive
integrity, SHA-256 archive/member inventory and manifest. It corresponds to the
plugin1.0.0 historical gitHead association. Core5.1.7 is already frozen for VAST;
5.3.0 is an adjacent stable comparison only. The actual registry request for5.3.1
returns404, matching the earlier investigation; it is not silently substituted.
Existing published5.4.0 and candidate core source complete the five-core set.
These associations are not a declared minimum support range.
The browser server verifies5.1.2 bytes before serving them. The new combination
suite uses actual1.0.0/1.1.0/1.2.0 main bytes and the candidate source bundle.
It verifies video playback/seeks, native VTT/SRT timing, track selection, offsets,
web/native fullscreen, source change, multiple players and plugin-owned Blob URLs.
The fixture uses native track.cues rather than the later subtitle.cues getter.
Removal assertions use destroy(); destroy(false) intentionally retains HTML.
Both mistakes were exposed and corrected in the initial test run; neither was a
production defect. The original failed reports remain in the evidence manifest.
## Actual findings and limits
- Core5.1.2/5.1.7 only display activeCue, the first native active cue. Plugin1.0.0
combines languages into one cue and displays both. Plugin1.1.0/1.2.0/candidate
retain separately timed cues and display only the first language. All three
engines reproduce this exact distinction. Native tracks contain both languages;
selecting the second language alone still works. The24 boundary observations
include18 defect observations, not24 successful compatibility acceptances.
MULTI-SUB-MERGE-01 remains open for a compatible old-host solution.
- Firefox155 at paused time1.5 still reports cues with start2/end4 as active after
subtitleOffset=1. HTML retains both captions. This occurs on5.3.0,5.4.0 and the
candidate, twice. The second run records native cues, active list, time, pause
state and rendered text. The candidate failure remains a real failing assertion,
not an expected-failure annotation, skip or timeout increase.
- Windows WebKit26.6 on5.3.0 once lost the selected caption after source change;
the diagnostic rerun passed. This is an unresolved intermittent observation,
not proof of a fixed issue or a reproducible production root cause.
- The full three-engine run:57 cases,53 passing assertions,4 failures,0 skips.
It includes the24 explicitly labelled boundary observations above. The targeted
diagnostic rerun:9 cases,6 pass,3 Firefox failures,0 skips. Earlier Chromium
runs had7 failures from fixture assumptions, then2 real overlap failures after
those assumptions were corrected. Current test adds final-state attachments;
the full run predates that diagnostic-only hook and formatting cleanup.
Detailed input hashes, browser versions, reports, failure messages and selected
native-state observations are stored in
[multiple-subtitles-combinations-validation.json](../baselines/multiple-subtitles-combinations-validation.json).
Local reports/traces are archived under refactor/.cache; their original attachment
paths can be resolved relative to each named archive. The JSON retains small
observations in Git so findings do not rely solely on those local archives.
## Next actions and maintenance
Fix the paused-offset candidate defect with an independent implementation task,
first reducing it to a native-text-track probe and a controlled regression. Keep
old release defects explicit. Resolve the old-core overlap behavior without
changing legal public calls; investigate the intermittent old-WebKit switch loss.
Then complete remaining ASS/encoding, overlap/offset transitions, lifecycle,
core/device and distribution evidence. Do not mark05 done on this checkpoint.
Run `yarn test:browser test/browser/multiple-subtitles-combinations.spec.js` to
rerun the matrix. Its currently failing offset assertions intentionally prevent a
green compatibility claim until corrected. The test supports the existing
ARTPLAYER_MULTIPLE_SUBTITLES_ARTIFACT override for actual bundle verification;
this checkpoint used source builds. No package rebuild is required for test/server
changes. Revert this task05 checkpoint to remove the added tests and frozen core
route; do not revert the independent task08 implementation commit with it.
+3 -2
View File
@@ -4,7 +4,7 @@
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 247 项,范围 22 个包及工作区/示例。
状态:todo 56 / doing 16 / blocked 0 / done 175 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
状态:todo 55 / doing 17 / blocked 0 / done 175 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
@@ -227,7 +227,7 @@
| PKG-MULTI-SUB-04 | artplayer-plugin-multiple-subtitles<br>迁移自有源码和公开类型 | PKG-MULTI-SUB-03, ENG-04, ENG-06, CORE-07 | 准确 parser/cue/tree/result 类型与真实异步形状 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | done |
| PKG-MULTI-SUB-07 | artplayer-plugin-multiple-subtitles<br>修复字幕内嵌时间戳序列化 | PKG-MULTI-SUB-03 | 保留数字时间戳节点、修正无效 NaN 输出、明确旧/新字幕输出差异 | 旧九份实现可复现,候选有效内嵌时间戳及文字/CSS/原生字幕通过,公开工厂与选择接口不变 | H | done |
| PKG-MULTI-SUB-08 | artplayer-plugin-multiple-subtitles<br>修复字幕实体解码与嵌套标签包装 | PKG-MULTI-SUB-04, PKG-MULTI-SUB-07 | 使用解析器既有实体表入口修复多余分号;保护字面文本并以兄弟节点包装标签,保留CSS钩子和时间戳 | 冻结旧实现复现、实体/双重编码/标签/选择重置回归、新旧核心真实字幕显示通过;vendor原文与来源校验不变,类型/分发兼容 | M | done |
| PKG-MULTI-SUB-05 | artplayer-plugin-multiple-subtitles<br>验证新旧核心和组合 | PKG-MULTI-SUB-04, CORE-22, PKG-MULTI-SUB-07, PKG-MULTI-SUB-08 | 与核心字幕/偏移/全屏组合,旧名称调用不变 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo |
| PKG-MULTI-SUB-05 | artplayer-plugin-multiple-subtitles<br>验证新旧核心和组合 | PKG-MULTI-SUB-04, CORE-22, PKG-MULTI-SUB-07, PKG-MULTI-SUB-08 | 与核心字幕/偏移/全屏组合,旧名称调用不变 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | doing |
| PKG-MULTI-SUB-06 | artplayer-plugin-multiple-subtitles<br>验证分发并同步文档 | PKG-MULTI-SUB-05, ENG-07 | multiple.subtitles.js、parser 来源许可及打包边界 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo |
## 5 包迁移:artplayer-plugin-jassub
@@ -554,6 +554,7 @@
- PKG-MULTI-SUB-04: [记录](baselines/multiple-subtitles-runtime-types.json) [记录](changes/2026-09-13-PKG-MULTI-SUB-04-runtime-types.md) [记录](baselines/multiple-subtitles-public-types.json) [记录](changes/2026-09-13-PKG-MULTI-SUB-04-public-types.md) [记录](type-compatibility-policy.md) [记录](baselines/multiple-subtitles-approved-types.json) [记录](changes/2026-09-13-PKG-MULTI-SUB-04-approved-types.md)
- PKG-MULTI-SUB-07: [记录](baselines/multiple-subtitles-timestamps.json) [记录](changes/2026-09-13-PKG-MULTI-SUB-07-timestamps.md)
- PKG-MULTI-SUB-08: [记录](changes/2026-09-14-PKG-MULTI-SUB-08-entities.md) [记录](baselines/multiple-subtitles-entities-validation.json)
- PKG-MULTI-SUB-05: [记录](changes/2026-09-14-PKG-MULTI-SUB-05-combinations.md) [记录](baselines/multiple-subtitles-combinations-validation.json) [记录](baselines/multiple-subtitles-cores.json)
- PKG-JASSUB-01: [记录](baselines/jassub-release.json) [记录](baselines/jassub-vendor.json) [记录](baselines/jassub-font-metadata.json) [记录](baselines/jassub-contract.md) [记录](baselines/jassub-contract-validation.json) [记录](changes/2026-09-13-PKG-JASSUB-01-baseline.md) [记录](baselines/jassub-provenance.json) [记录](baselines/jassub-provenance-validation.json) [记录](changes/2026-09-14-PKG-JASSUB-01-provenance.md)
- PKG-JASSUB-02: [记录](changes/2026-09-14-PKG-JASSUB-02-failure-baseline.md) [记录](baselines/jassub-failures-validation.json)
- PKG-JASSUB-03: [记录](changes/2026-09-14-PKG-JASSUB-03-registration.md) [记录](baselines/jassub-registration-validation.json)
+16
View File
@@ -1,5 +1,21 @@
# 进度与证据
## PKG-MULTI-SUB-05 新旧核心组合检查点(未完成)
任务08已独立提交675b095b2,提交审计175 done/171专属提交/4初始例外通过。
任务05现进入doing:补取并冻结真实npm核心5.1.2,5.3.1查询404保持缺失;与
现有5.1.7/5.3.0/5.4.0/候选组成矩阵,旧插件1.0.0/1.1.0/1.2.0也实际运行。
57项三引擎检查53通过、4失败、0跳过,其中24项是边界观察,18项确认双语
缺失而非兼容通过。旧5.1.2/5.1.7仅显示首个active cue,候选和旧1.1.0/1.2.0
均受影响;1.0.0按索引合并后能显示双语。Firefox暂停偏移在三种核心上持续失败,
原生cue时间已经变为2至4秒,但播放时间1.5秒时仍列为active并显示。9项定向
复跑6通过3失败;WebKit5.3.0切源丢字幕首次失败后通过,保留待定位记录。
CI50项和测试/服务脚本lint通过;无生产代码、依赖、声明或产物改动。
见[检查点](changes/2026-09-14-PKG-MULTI-SUB-05-combinations.md)和
[证据](baselines/multiple-subtitles-combinations-validation.json)。247项中175 done、
17 doing、55 todo;两项新风险保持open,任务05不能完成。下一步先最小化并修复
暂停偏移缺陷,再解决旧核心双语与切源边界;ASS/编码/真机及分发仍未验收。
## PKG-MULTI-SUB-08 字幕实体与标签包装完成
通过解析器既有实体表入口修复标准命名实体后多余分号,保留原始vendor文件与
+2
View File
@@ -265,3 +265,5 @@
| DEV-SERVOR-PORT-01 | resolved / 已复现 | Servor exits the entire dev process with status zero when the requested port is occupied | MOD-DEV-01 |
| AUTO-THUMB-ENCODE-TIMEOUT-01 | resolved / 源码/产物事实 | Pending JPEG encoding has no bounded lifetime after frame readiness finishes | PKG-AUTO-THUMB-10 |
| MULTI-SUB-MARKUP-01 | resolved / 已复现 | Semantic cue nodes receive HTML wrappers inside their annotation fields | PKG-MULTI-SUB-08 |
| MULTI-SUB-OFFSET-01 | open / 已复现 | Paused Firefox subtitle offset leaves out-of-time native cues active and captions visible | PKG-MULTI-SUB-05 |
| MULTI-SUB-SWITCH-01 | open / 待取证 | Intermittent WebKit core5.3.0 caption loss after selected-track source switch | PKG-MULTI-SUB-05 |
+39 -2
View File
@@ -4367,11 +4367,14 @@
"refactor/changes/2026-09-13-PKG-MULTI-SUB-03-resources.md",
"test/multiple-subtitles-lifecycle.test.js",
"test/multiple-subtitles-merge.test.js",
"test/browser/multiple-subtitles-lifecycle.spec.js"
"test/browser/multiple-subtitles-lifecycle.spec.js",
"refactor/changes/2026-09-14-PKG-MULTI-SUB-05-combinations.md",
"refactor/baselines/multiple-subtitles-combinations-validation.json",
"test/browser/multiple-subtitles-combinations.spec.js"
],
"compatibleResolution": "Keep historical merge profiles explicit and test real overlap/timing before choosing compatibility behavior.",
"closureCriteria": "Unaligned lengths, overlap, sorting, names and real subtitle display across supported cores are verified.",
"workspaceState": "Candidate resource fixes and serialization parity are verified in task 03. This risk remains open for the complete supported-core/device coverage owned by task 05."
"workspaceState": "Native three-engine comparisons on cores5.1.2/5.1.7 show only first active cue displayed for actual plugin1.1.0/1.2.0/candidate; plugin1.0.0 index-merges both languages into one visible cue. Native tracks hold both languages and selecting either alone works. Compatible old-host overlap resolution and complete device coverage remain open."
},
{
"id": "MULTI-SUB-LIFE-01",
@@ -5993,6 +5996,40 @@
"refactor/baselines/multiple-subtitles-entities-validation.json"
],
"resolutionRationale": "Historical regressions retain old output; corrected b/c/v/ruby and text cases plus actual b/literal-tag native/HTML display pass. Immutable trees, timestamps and lifecycle tests remain green."
},
{
"id": "MULTI-SUB-OFFSET-01",
"title": "Paused Firefox subtitle offset leaves out-of-time native cues active and captions visible",
"confirmation": "reproduced",
"workspaceState": "Two runs on Firefox155 with cores5.3.0/5.4.0/candidate: paused at1.5, subtitleOffset=1 changes start/end to2/4 but native activeCues and HTML still contain both captions after the assertion timeout. Candidate assertion remains failing. No production correction yet.",
"compatibleResolution": "Reduce native timing invalidation and ensure offset updates render the correct active captions without seeking media or changing public timing and event contracts.",
"closureCriteria": "Candidate paused positive/negative/reset offsets refresh correctly, transitions and lifecycle regressions pass; historical behavior and actual old-core compatibility are separately documented.",
"status": "open",
"owners": [
"PKG-MULTI-SUB-05"
],
"evidence": [
"refactor/changes/2026-09-14-PKG-MULTI-SUB-05-combinations.md",
"refactor/baselines/multiple-subtitles-combinations-validation.json",
"test/browser/multiple-subtitles-combinations.spec.js"
]
},
{
"id": "MULTI-SUB-SWITCH-01",
"title": "Intermittent WebKit core5.3.0 caption loss after selected-track source switch",
"confirmation": "unverified",
"workspaceState": "One Windows WebKit26.6 run lost Translation after switchUrl and seek1.5; diagnostic rerun passed without a production change. Root cause and reproducibility are unresolved; do not mark accepted or fixed.",
"compatibleResolution": "Inspect native track loading and source-switch ordering with deterministic state evidence; distinguish historical host failure from fixture ordering and candidate regression.",
"closureCriteria": "Root cause classified with targeted evidence, any required fix validated, and changed candidate/old-core combination rerun without hiding the original failure.",
"status": "open",
"owners": [
"PKG-MULTI-SUB-05"
],
"evidence": [
"refactor/changes/2026-09-14-PKG-MULTI-SUB-05-combinations.md",
"refactor/baselines/multiple-subtitles-combinations-validation.json",
"test/browser/multiple-subtitles-combinations.spec.js"
]
}
]
}
+6 -2
View File
@@ -2410,11 +2410,15 @@
"PKG-MULTI-SUB-07",
"PKG-MULTI-SUB-08"
],
"status": "todo",
"status": "doing",
"risk": "H",
"deliverable": "与核心字幕/偏移/全屏组合,旧名称调用不变",
"acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成",
"evidence": []
"evidence": [
"changes/2026-09-14-PKG-MULTI-SUB-05-combinations.md",
"baselines/multiple-subtitles-combinations-validation.json",
"baselines/multiple-subtitles-cores.json"
]
},
{
"id": "PKG-MULTI-SUB-06",
+14
View File
@@ -210,3 +210,17 @@ ordering, library/compiler failures, FileReader settlement and storage denial.
vendor assets for typed Run, Ctrl-S, imports, preferences, declaration failure,
language readiness and model disposal. Console Error objects are inspected through
their arguments: Firefox may serialize their display text as only `Error`.
## Multiple subtitles core combinations
`test/browser/multiple-subtitles-combinations.spec.js` uses verified old core and
plugin bytes plus candidate source builds. It covers native caption timing,
VTT/SRT selection, offsets/fullscreen/source changes and multi-instance URL
ownership. Old1.0.0/1.1.0/1.2.0 factories run unchanged on the candidate core.
Explicit single-active-cue probes record historical and candidate overlap defects;
their passing assertions do not mean simultaneous captions are compatible.
Paused Firefox offset checks remain failing pending a production fix, and the
original WebKit source-switch failure is retained despite a passing rerun.
See `refactor/changes/2026-09-14-PKG-MULTI-SUB-05-combinations.md` before changing
expectations. Reports include native active cues and rendered text. The new frozen
5.1.2 core route verifies archive integrity and member hashes before serving.
@@ -0,0 +1,208 @@
import { hash } from '../../refactor/scripts/releases.mjs'
import { multipleSubtitlesCandidate, multipleSubtitlesHistorical } from '../helpers/multiple-subtitles.js'
import { expect, test } from './fixtures.js'
const candidate = await multipleSubtitlesCandidate()
const historical = (await multipleSubtitlesHistorical()).filter(item => /^published-.*-main$/.test(item.name))
const cores = ['published-5.1.2', 'published-5.1.7', 'published-5.3.0', 'published', 'candidate']
const vtt = 'WEBVTT\n\n00:01.000 --> 00:03.000\nFirst\n\n00:04.000 --> 00:06.000\nSecond\n'
const srt = '1\n00:00:01,000 --> 00:00:03,000\nTranslation\n'
test.afterEach(async ({ page }, testInfo) => {
const state = await page.evaluate(() => {
const art = window.art
if (!art)
return null
const track = art.template.$track?.track
const read = cue => ({ start: cue.startTime, end: cue.endTime, text: cue.text })
return { destroyed: art.isDestroy, paused: art.video.paused, time: art.currentTime, offset: art.subtitleOffset, cues: Array.from(track?.cues || [], read), active: Array.from(track?.activeCues || [], read), displayed: art.template.$subtitle?.textContent }
})
await testInfo.attach('multiple-combination-final-state', { contentType: 'application/json', body: JSON.stringify(state) })
})
async function prepare(page, core, implementation, browser, testInfo) {
await page.route('**/test/combination.vtt', route => route.fulfill({ contentType: 'text/vtt', body: vtt }))
await page.route('**/test/combination.srt', route => route.fulfill({ contentType: 'text/plain', body: srt }))
await page.goto(`/test/player.html?core=${core}`)
await page.addScriptTag({ content: `(() => { const module = { exports: {} }; const exports = module.exports; ${implementation.code}; window.multipleFactory = module.exports.default || module.exports; })();` })
await page.evaluate(() => window.createPlayer('/test/pattern.mp4'))
await expect.poll(() => page.evaluate(() => window.art.isReady)).toBe(true)
await testInfo.attach('multiple-combination-inputs', { contentType: 'application/json', body: JSON.stringify({ core, plugin: implementation.name, pluginSha256: hash(implementation.code), browser: browser.version(), scope: 'Desktop engines; 5.3.0 is adjacent stable, not the unavailable 5.3.1 release; no minimum-version or physical-device claim' }) })
}
async function seek(page, time) {
await page.evaluate(time => new Promise((resolve) => {
window.art.once('video:seeked', resolve)
window.art.seek = time
}), time)
}
for (const core of cores.filter(core => !['published-5.1.2', 'published-5.1.7'].includes(core))) {
test(`Multiple subtitles candidate / ${core}: timed VTT and SRT, offsets, fullscreen and source change`, async ({ page, browser }, testInfo) => {
await prepare(page, core, candidate, browser, testInfo)
await page.evaluate(async () => {
await window.art.plugins.add(window.multipleFactory({ subtitles: [{ name: 'a', url: '/test/combination.vtt' }, { name: 'b', url: '/test/combination.srt' }] }))
})
await expect.poll(() => page.evaluate(() => window.art.template.$track.track.cues?.length)).toBe(3)
await page.locator('#play').click()
await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(0.1)
await page.locator('#pause').click()
await seek(page, 1.5)
await expect(page.locator('.art-subtitle-a')).toHaveText('First')
await expect(page.locator('.art-subtitle-b')).toHaveText('Translation')
await page.evaluate(() => {
window.art.subtitleOffset = 1
})
expect(await page.evaluate(() => Array.from(window.art.template.$track.track.cues, cue => [cue.startTime, cue.endTime]))).toEqual([[2, 4], [2, 4], [5, 7]])
await expect(page.locator('.art-subtitle-a')).toHaveCount(0)
await seek(page, 2.5)
await expect(page.locator('.art-subtitle-a')).toHaveText('First')
await page.evaluate(() => {
window.art.subtitleOffset = -1
})
expect(await page.evaluate(() => Array.from(window.art.template.$track.track.cues, cue => [cue.startTime, cue.endTime]))).toEqual([[0, 2], [0, 2], [3, 5]])
await expect(page.locator('.art-subtitle-a')).toHaveCount(0)
await page.evaluate(() => {
window.art.subtitleOffset = 0
})
await expect(page.locator('.art-subtitle-a')).toHaveText('First')
await page.evaluate(() => {
window.art.fullscreenWeb = true
})
await expect.poll(() => page.evaluate(() => window.art.fullscreenWeb)).toBe(true)
await expect(page.locator('.art-subtitle-a')).toBeVisible()
await page.evaluate(() => {
window.art.fullscreenWeb = false
window.fullscreenEvents = []
window.art.on('fullscreen', value => window.fullscreenEvents.push(value))
document.querySelector('#play').onclick = () => {
window.art.fullscreen = true
}
})
await page.locator('#play').click()
await expect.poll(() => page.evaluate(() => (document.fullscreenElement || document.webkitFullscreenElement) === window.art.template.$player)).toBe(true)
await expect(page.locator('.art-subtitle-a')).toBeVisible()
expect(await page.evaluate(() => (document.fullscreenElement || document.webkitFullscreenElement).contains(window.art.template.$subtitle))).toBe(true)
await page.evaluate(() => {
window.art.fullscreen = false
})
await expect.poll(() => page.evaluate(() => window.fullscreenEvents)).toEqual([true, false])
await page.evaluate(() => window.art.plugins.multipleSubtitles.tracks(['b']))
await expect(page.locator('.art-subtitle-a')).toHaveCount(0)
await expect(page.locator('.art-subtitle-b')).toHaveText('Translation')
await page.evaluate(() => window.art.switchUrl('/test/pattern.mp4?subtitles-combination'))
await seek(page, 1.5)
await expect(page.locator('.art-subtitle-b')).toHaveText('Translation')
await page.evaluate(() => window.art.plugins.multipleSubtitles.reset())
await expect(page.locator('.art-subtitle-a')).toHaveText('First')
await seek(page, 4.5)
await expect(page.locator('.art-subtitle-a')).toHaveText('Second')
await expect(page.locator('.art-subtitle-b')).toHaveCount(0)
await page.evaluate(() => window.art.destroy())
await expect(page.locator('.art-subtitle-a')).toHaveCount(0)
})
}
for (const core of cores) {
test(`Multiple subtitles candidate / ${core}: destroying one player preserves another player's captions and URLs`, async ({ page, browser }, testInfo) => {
await prepare(page, core, candidate, browser, testInfo)
await page.evaluate(async () => {
const container = document.createElement('div')
container.style.cssText = 'width:320px;height:180px'
document.body.append(container)
window.other = new window.Artplayer({ container, url: '/test/pattern.mp4', muted: true, mutex: false })
window.owned = [[], []]
window.revoked = []
const revoke = URL.revokeObjectURL.bind(URL)
URL.revokeObjectURL = (url) => {
window.revoked.push(url)
revoke(url)
}
for (const [index, art] of [window.art, window.other].entries()) {
const init = art.subtitle.init.bind(art.subtitle)
art.subtitle.init = (option) => {
window.owned[index].push(option.url)
return init(option)
}
await art.plugins.add(window.multipleFactory({ subtitles: [{ name: `p${index}`, url: '/test/combination.vtt' }] }))
}
})
await expect.poll(() => page.evaluate(() => window.other.isReady && window.other.template.$track.track.cues?.length === 2 && window.art.template.$track.track.cues?.length === 2)).toBe(true)
await page.locator('#play').click()
await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(0.1)
await page.locator('#pause').click()
await seek(page, 1.5)
await expect(page.locator('.art-subtitle-p0')).toHaveText('First')
await page.evaluate(() => {
window.art.destroy(false)
document.querySelector('#play').onclick = () => window.other.play()
document.querySelector('#pause').onclick = () => window.other.pause()
})
expect(await page.evaluate(() => window.owned[0].every(url => window.revoked.includes(url)))).toBe(true)
expect(await page.evaluate(() => window.owned[1].some(url => window.revoked.includes(url)))).toBe(false)
await page.locator('#play').click()
await expect.poll(() => page.evaluate(() => window.other.currentTime)).toBeGreaterThan(0.1)
await page.locator('#pause').click()
await page.evaluate(() => {
window.other.seek = 1.5
})
await expect(page.locator('.art-subtitle-p1')).toHaveText('First')
await page.evaluate(() => window.other.plugins.multipleSubtitles.tracks([]))
await expect(page.locator('.art-subtitle-p1')).toHaveCount(0)
await page.evaluate(() => window.other.plugins.multipleSubtitles.reset())
await expect(page.locator('.art-subtitle-p1')).toHaveText('First')
await page.evaluate(() => window.other.destroy(false))
expect(await page.evaluate(() => window.owned.flat().every(url => window.revoked.includes(url)))).toBe(true)
})
}
for (const core of ['published-5.1.2', 'published-5.1.7']) {
for (const implementation of [...historical, candidate]) {
test(`Multiple subtitles ${implementation.name} / ${core}: record single-active-cue overlap boundary`, async ({ page, browser }, testInfo) => {
await prepare(page, core, implementation, browser, testInfo)
await page.route('**/test/combination.vtt', route => route.fulfill({ contentType: 'text/vtt', body: 'WEBVTT\n\n00:01.000 --> 00:03.000\nFirst\n' }))
await page.evaluate(async () => {
await window.art.plugins.add(window.multipleFactory({ subtitles: [{ name: 'a', url: '/test/combination.vtt' }, { name: 'b', url: '/test/combination.srt' }] }))
})
const indexMerge = implementation.version === '1.0.0'
await expect.poll(() => page.evaluate(() => window.art.template.$track.track.cues?.length)).toBe(indexMerge ? 1 : 2)
await page.locator('#play').click()
await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(0.1)
await page.locator('#pause').click()
await seek(page, 1.5)
await expect(page.locator('.art-subtitle-a')).toHaveText('First')
// This is a deficiency probe, not successful simultaneous-caption acceptance.
await expect(page.locator('.art-subtitle-b')).toHaveCount(indexMerge ? 1 : 0)
const state = await page.evaluate(() => ({ native: Array.from(window.art.template.$track.track.activeCues, cue => cue.getCueAsHTML().textContent), displayed: window.art.template.$subtitle.textContent }))
expect(state.native).toEqual(indexMerge ? ['FirstTranslation'] : ['First', 'Translation'])
expect(state.displayed).toBe(indexMerge ? 'FirstTranslation' : 'First')
await testInfo.attach('single-active-cue-boundary', { contentType: 'application/json', body: JSON.stringify({ core, implementation: implementation.name, state, simultaneousCaptionsAccepted: indexMerge, unresolvedCandidateGap: !indexMerge, explanation: '1.0.0 combines by array index; 1.1.0 onward retains separately timed cues. Old core displays only its first active cue. Candidate gap remains open, even when this observation test passes.' }) })
await page.evaluate(() => window.art.plugins.multipleSubtitles.tracks(['b']))
await expect(page.locator('.art-subtitle-b')).toHaveText('Translation')
await expect(page.locator('.art-subtitle-a')).toHaveCount(0)
await page.evaluate(() => window.art.destroy())
})
}
}
for (const implementation of historical) {
test(`Multiple subtitles ${implementation.name} / candidate core: unchanged old factory and selection calls`, async ({ page, browser }, testInfo) => {
await prepare(page, 'candidate', implementation, browser, testInfo)
await page.evaluate(async () => {
await window.art.plugins.add(window.multipleFactory({ subtitles: [{ name: 'old', url: '/test/combination.vtt' }] }))
})
await expect.poll(() => page.evaluate(() => window.art.subtitle.cues.length)).toBe(2)
await page.locator('#play').click()
await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(0.1)
await page.locator('#pause').click()
await seek(page, 1.5)
await expect(page.locator('.art-subtitle-old')).toHaveText('First')
expect(await page.evaluate(() => window.art.plugins.multipleSubtitles.tracks([]) === undefined)).toBe(true)
await expect(page.locator('.art-subtitle-old')).toHaveCount(0)
expect(await page.evaluate(() => window.art.plugins.multipleSubtitles.reset() === undefined)).toBe(true)
await expect(page.locator('.art-subtitle-old')).toHaveText('First')
await seek(page, 4.5)
await expect(page.locator('.art-subtitle-old')).toHaveText('Second')
await page.evaluate(() => window.art.destroy(false))
})
}
+7 -1
View File
@@ -84,6 +84,12 @@ const vttCoreMember = `package/${vttCore.manifest.main.replace(/^\.\//, '')}`
const vttCoreBytes = readMember(await ensureArchive(vttCore), vttCoreMember)
assert.equal(hash(vttCoreBytes), vttCore.files[vttCoreMember], 'Historical VTT core differs from frozen archive')
add('/published-5.1.6/artplayer.js', vttCoreBytes, { kind: 'npm-release', version: vttCore.version, integrity: vttCore.integrity, member: vttCoreMember })
for (const release of JSON.parse(fs.readFileSync(path.join(workspace, 'refactor/baselines/multiple-subtitles-cores.json'), 'utf8')).releases) {
const member = `package/${release.manifest.main.replace(/^\.\//, '')}`
const bytes = readMember(await ensureArchive(release), member)
assert.equal(hash(bytes), release.files[member], 'Historical multiple subtitles core differs from frozen release')
add(`/published-${release.version}/artplayer.js`, bytes, { kind: 'npm-release', version: release.version, integrity: release.integrity, member })
}
add('/test/audio-tone.m4a', fs.readFileSync(path.join(workspace, 'test/browser/media/audio-tone.m4a')), { kind: 'generated-media', file: 'test/browser/media/audio-tone.m4a' })
add('/test/thumbnail-pattern.mp4', fs.readFileSync(path.join(workspace, 'test/browser/media/thumbnail-pattern.mp4')), { kind: 'generated-media', file: 'test/browser/media/thumbnail-pattern.mp4' })
add('/test/auto-thumbnail-timeline.mp4', fs.readFileSync(path.join(workspace, 'test/browser/media/auto-thumbnail-timeline.mp4')), { kind: 'generated-media', file: 'test/browser/media/auto-thumbnail-timeline.mp4' })
@@ -170,7 +176,7 @@ const server = http.createServer((req, res) => {
if (url.pathname === '/test/player.html') {
const core = url.searchParams.get('core') || 'candidate'
const chapter = url.searchParams.get('chapter') || 'candidate'
assert(['candidate', 'published', 'published-4.5.5', 'published-4.5.9', 'published-5.1.6', 'published-5.1.7', 'published-5.3.0', 'published-5.3.1-beta.1'].includes(core) && ['candidate', 'published'].includes(chapter), 'Invalid test combination')
assert(['candidate', 'published', 'published-4.5.5', 'published-4.5.9', 'published-5.1.2', 'published-5.1.6', 'published-5.1.7', 'published-5.3.0', 'published-5.3.1-beta.1'].includes(core) && ['candidate', 'published'].includes(chapter), 'Invalid test combination')
const html = fs.readFileSync(path.join(workspace, 'test/browser/player.html'), 'utf8')
.replace('__CORE__', core)
.replace('__CHAPTER__', chapter)