mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-08 10:56:15 -08:00
test(thumbnail): [PKG-TOOL-THUMB-05] verify generated sheets across core versions
This commit is contained in:
1 parent
fb78328c43
commit
8aa99ef03f
13 files changed
+15502
-9
No files matched your search
@@ -134,6 +134,27 @@ The [public type guide](types/README.md)
|
||||
documents declaration ownership, module entries, events and installed consumers.
|
||||
See [task plan](../../refactor/plan.md) and [risk ledger](../../refactor/risks.json).
|
||||
|
||||
## Generated sheets consumed by ArtPlayer
|
||||
|
||||
The tool owns both `videoUrl` and `thumbnailUrl`. Destroy the player borrowing
|
||||
those URLs before generating a replacement sheet or destroying the tool. Pass
|
||||
the same `number`, `column`, `width` and `height` to the player's thumbnails
|
||||
option; the PNG includes a 30px attribution footer, so do not infer cell height
|
||||
from the full image height. The integration suite uses `scale: 1`.
|
||||
|
||||
Run `yarn test:browser:source thumbnail-core.spec.js --workers=1` for native file
|
||||
extraction, two generated sheets, real mouse hover, screenshot pixels and URL
|
||||
ownership against associated core 3.5.31, published 5.4.0 and the candidate core.
|
||||
`ARTPLAYER_THUMBNAIL_ARTIFACT` selects the installed tool main. Historical cores'
|
||||
first-cell/row-boundary defects have explicit expectations; the candidate must
|
||||
use the correct cell. The old tool uses its original 300ms delay, while the
|
||||
candidate still exercises 20ms. Recovered 3.5.31 at 20ms produced black cells in
|
||||
Firefox because it draws after a timer without awaiting seek completion.
|
||||
|
||||
Windows WebKit Blob controls do not validate extraction. See the
|
||||
[combination checkpoint](../../refactor/changes/2026-09-16-PKG-TOOL-THUMB-05-core-combinations.md)
|
||||
for exact passing scopes and remaining Safari/device/archive evidence.
|
||||
|
||||
## Type and provenance boundaries
|
||||
|
||||
All nine executable source modules and the shared type module are checked with
|
||||
|
||||
@@ -35,6 +35,12 @@ BASE-01 于 2026-09-10 固定核心与 chapter 的 npm 发布内容,数据在
|
||||
|
||||
## 公共 API 报告
|
||||
|
||||
Thumbnail 工具的关联历史核心 3.5.31 已单独恢复完整 npm 归档,见
|
||||
[144 个文件与来源](thumbnail-core.json) 和
|
||||
[三代核心组合结果](thumbnail-core-validation.json)。运行
|
||||
`node --test refactor/scripts/thumbnail-core.test.mjs` 校验归档和历史关联。
|
||||
工具本身的旧 3.5.31 完整归档仍未恢复;不能将核心归档当成工具分发证据。
|
||||
|
||||
Audio Track 的后续包基线由 PKG-AUDIO-01 独立冻结,见
|
||||
[契约和重跑](audio-track-contract.md) 及 [1.1.0 归档来源](audio-track-release.json)。
|
||||
它不改写本目录初始 BASE 快照,媒体/类型/设备通过范围由后续任务提供。
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,347 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "PKG-TOOL-THUMB-05",
|
||||
"sourceCommit": "fb78328c4355042b578091e1236c2ce71a68e5c2",
|
||||
"capturedAt": "2026-09-16T02:00:14.335Z",
|
||||
"metadata": {
|
||||
"url": "https://registry.npmjs.org/artplayer/3.5.31",
|
||||
"status": 200,
|
||||
"sha256": "d57dc330fd334660fe892c56b5f552f435cea6f5e86e68a16d0ee32a551ee17e"
|
||||
},
|
||||
"association": {
|
||||
"commit": "af1a116a31b088efdd77afa81c4b6565d12bd162",
|
||||
"file": "packages/artplayer/package.json",
|
||||
"version": "3.5.31"
|
||||
},
|
||||
"scope": "Original core release associated with recovered tool 3.5.31; not a minimum-version claim or recovery of the missing original tool archive.",
|
||||
"release": {
|
||||
"name": "artplayer",
|
||||
"version": "3.5.31",
|
||||
"metadataUrl": "https://registry.npmjs.org/artplayer/3.5.31",
|
||||
"tarball": "https://registry.npmjs.org/artplayer/-/artplayer-3.5.31.tgz",
|
||||
"integrity": "sha512-xuuU8+NKdurlAxjHzZmesve/WKAz4PRCpwREDsZAyhxKeSknDbVDs1QwWiBrGhRQrQJs/qDEMV5y860imtv2ig==",
|
||||
"sha256": "6295c423883980f9e2e2e1281c33de09af5b95e2f9caeaf17ba4914a7908dd33",
|
||||
"manifest": {
|
||||
"name": "artplayer",
|
||||
"version": "3.5.31",
|
||||
"expose": "Artplayer",
|
||||
"description": "ArtPlayer.js is a modern and full featured HTML5 video player",
|
||||
"main": "dist/artplayer.js",
|
||||
"types": "types/artplayer.d.ts",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zhw2590582/ArtPlayer.git"
|
||||
},
|
||||
"keywords": [
|
||||
"video",
|
||||
"player"
|
||||
],
|
||||
"author": "Harvey Zack <laozhaochaguan@gmail.com>",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/zhw2590582/ArtPlayer/issues"
|
||||
},
|
||||
"homepage": "https://github.com/zhw2590582/ArtPlayer#readme",
|
||||
"dependencies": {
|
||||
"option-validator": "^2.0.6",
|
||||
"screenfull": "^5.1.0"
|
||||
},
|
||||
"gitHead": "af1a116a31b088efdd77afa81c4b6565d12bd162"
|
||||
},
|
||||
"files": {
|
||||
"package/LICENSE": "e10af0b158a3cd8d923fd524b234cc2ee7219f08746ec3851e71e59d5061f2c2",
|
||||
"package/README.md": "e59e7d43e0bdc774f9f1c6192d30de5c0d475240dd834c46ca8e68f5e058515b",
|
||||
"package/dist/artplayer.js": "f6e6c4f5885ce62e17c7955a95db399a734ea715cb7891c20639d325e3da4de3",
|
||||
"package/package.json": "cba20e72d58ccb2ca435b485223eb66e1a52647f6128f61eccd5526395821b1f",
|
||||
"package/src/config/index.js": "1141882b3efb492d0a77ccb3777bdedb462b450eaa31fdc1ab09991dd4aff2e5",
|
||||
"package/src/contextmenu/aspectRatio.js": "9941303fc7b842baab4baf3a1a4f5ba768ee17862ccb5c36b49a41544d940042",
|
||||
"package/src/contextmenu/close.js": "e1d9cda75b2b2ed469772d77130d78e7cf98fe368d2798dbc0753f842aa3f8f2",
|
||||
"package/src/contextmenu/index.js": "aa8170c46b2a6ebdd84018af823cce8307c18e252b844f7e60cbeabba7cd8915",
|
||||
"package/src/contextmenu/info.js": "0f0a7a215d74fb5698467c6dad175b5c58a29710fa148d9205e4a8c35e23b900",
|
||||
"package/src/contextmenu/light.js": "f65b064948da8d4173aeeaf4ff318c7133913fb22f30c778b5663d4ef4790cda",
|
||||
"package/src/contextmenu/playbackRate.js": "c3c7d9a87475d130066141be2d3cc5c528791e7aec99d89c853eaed5a6d69a48",
|
||||
"package/src/contextmenu/version.js": "b1a3f58c3b5e54fb8b4a3a19d884839dc168f4a0d35a6e89779f9fadcb1076e3",
|
||||
"package/src/control/fullscreen.js": "480b88414c9a68c2410983a5428bd8b34250264ff678249277adcae9966ce85d",
|
||||
"package/src/control/fullscreenWeb.js": "4e1b40b7a9165ff025f0b3a5197b05a46e135aa54c726cf632d8df53ccdd9e6a",
|
||||
"package/src/control/index.js": "98cd156158337d8f638fa53a19bf43d65ff1796b06fe14204b2a654e507c743a",
|
||||
"package/src/control/loop.js": "074804c86398b8706d70392f38aec5a5c9cf9dbef116ef4660533caa36b5f8da",
|
||||
"package/src/control/pip.js": "9bca1805ac5e722207f2d4c2ea8eb066b23acaa300c50261bd64bcf19aaf4cd2",
|
||||
"package/src/control/playAndPause.js": "1e737a76786146e7e16fec704651a2e80284cc796154b100f6cf342ac0474d62",
|
||||
"package/src/control/progress.js": "869294624065ba755e97d8dbfa918a2d7b14df6bc21182ebf910a0d0cc9b99cd",
|
||||
"package/src/control/quality.js": "7b83a706f922ca6332bb00be8a84f3f74f970f39b88ed308f99a4384f81e1da8",
|
||||
"package/src/control/screenshot.js": "56358d7c49b98f43b463b7150bb917b3828089fb3461dc596b4462bd56b90a4d",
|
||||
"package/src/control/setting.js": "57edc60a847cda957709ce077309530bdb7580c4139cac648be88a44d8697fee",
|
||||
"package/src/control/subtitle.js": "296f582aa364e36f6980102a52bb05f72cffd990dc3cc3bbc25142ec76d84235",
|
||||
"package/src/control/thumbnails.js": "941d9e620d90f460b97a2fad16c018e1160ac04c61caf9f4ec13b897e8e7012e",
|
||||
"package/src/control/time.js": "1f0b7c37c0f9f5f6f62826b7fcf4e6c1b403a532cfbeed4491ddb8cd0cf93d8d",
|
||||
"package/src/control/volume.js": "1f74dc0a9c46596d9bb67e5c5b0826724d757b608b205d64176f3d2df266fad0",
|
||||
"package/src/events/clickInit.js": "2d1677389199b167c669b6eaa1ba9a1b322c25a0118b4f80122ff96097222225",
|
||||
"package/src/events/gestureInit.js": "59b69dd52d7adb8714e310f1b4fdab31f6c8ff7cc1b51654353c1fcdd638f2fa",
|
||||
"package/src/events/hoverInit.js": "efc52a3efa115bb9bf40eb98f9b6f5eb62bcc5f1a6f536b8d31e21070d05f2e9",
|
||||
"package/src/events/index.js": "1de72910e10231955226030ceeaf83612c5b8784cc7dd170c95eb1f1eefcdc36",
|
||||
"package/src/events/mousemoveInit.js": "99383ba26bfb723f90fd0b068de4042c874bc630f20881b2ef0986bb0d353dd2",
|
||||
"package/src/events/resizeInit.js": "3e1a968b609bfdd6900864b7addedc06aaaa0b3938b49db2fd976eaf95eb67f4",
|
||||
"package/src/events/viewInit.js": "f0b6b13dec7cb6589ac7a5292ccb0adfbc86233c3e5a2f6ed632e2d8b269863a",
|
||||
"package/src/hotkey.js": "0ff31f8398dae512d9cab66cb6c3a81b17ad82ca79027a0d404d8ea6a960faad",
|
||||
"package/src/i18n/index.js": "10b3af2a0c676cd216ef4e3354b301336d3579cb91a2e5344c0d19497ea4a6e1",
|
||||
"package/src/i18n/zh-cn.json": "87e759a3d555abf9d6a7c980dedf965b2557d715ca0e67f8b6928d4ffc46d5a0",
|
||||
"package/src/i18n/zh-tw.json": "a76993ab9077a848ca0cebfb9e94ff18b3301aacd7f2cd9d453f2900345eeaaa",
|
||||
"package/src/icons/fullscreen-web.svg": "82d3ebc7ac89283a3dcdaea606e518ca0775df71c062d3e07bfc8e4e11bce93b",
|
||||
"package/src/icons/fullscreen.svg": "26e83a9ac001d0710d064963a56a34afde309503873c3bc9d588b8807ec8015c",
|
||||
"package/src/icons/index.js": "26ddf832d241e4dbbb525b41b37af3e8da9e2d51c0a5404328916566673f69cb",
|
||||
"package/src/icons/loading.svg": "ffcf5d814e6f3931a370bb4f0d2675381c2adb8f6d29dd1ee8f5df33d8175e75",
|
||||
"package/src/icons/next.svg": "9967c458a78032a3be130cd4ea59b70b8324878468cade18361d50567a8c9618",
|
||||
"package/src/icons/pause.svg": "9efe05ebf5610befddebcac51b3c9a491001189ff86204cb47928eb1617f6c7a",
|
||||
"package/src/icons/pip.svg": "52d1e150d1364aed20917d83a2f7ab7589fb9df9655f3d3afaea3c4387800812",
|
||||
"package/src/icons/play.svg": "c35562d20028d52ce329f35f90496a06d4dc5b6dc39df7ebcfb027f6f2393958",
|
||||
"package/src/icons/prev.svg": "5be9100d186dfd629e88afa25b0f5fd120ce90d47efcc970a00436c458319692",
|
||||
"package/src/icons/screenshot.svg": "49f7d90198fb0bcbc29848f40b0a8c042b78c07ecef1cfc5184e2e84a61b4bd4",
|
||||
"package/src/icons/setting.svg": "7f6454d1c7f037d5a7144a898abedc89ca339534166d620dfa45efcd4c74ee3c",
|
||||
"package/src/icons/state.svg": "271a80268957209b2455ccccf4a42e89fafe990d04b2bcbe22624fcd63e43411",
|
||||
"package/src/icons/subtitle.svg": "b28a64d59b2eca9bde9357b50ff6701452dffe62e8c568c514b2e36542f83f9c",
|
||||
"package/src/icons/volume-close.svg": "b9dbeaf9043c8014cd29d0e4a21a82ce567bc6b85497c310cca5f68bceeb31b2",
|
||||
"package/src/icons/volume.svg": "baebc4ede3013202a4b13202a8d961cb0e5e065ee03733816022b2541d13884f",
|
||||
"package/src/index.js": "0099495a167656c3af9408d4559cbdb2d573f480a0807698bc5c22f316be5ade",
|
||||
"package/src/info.js": "0ac75176efb8c1626bd0f08831a009b4b7b478582aff4f06247512b85f410f22",
|
||||
"package/src/layer.js": "d801f40fd34425fbe347cfec353c40a0286e569590b3c9beb262936eb512f266",
|
||||
"package/src/loading.js": "f47a310ae4acfbd45bf34786901377844a08b4acc40d169f99b1af7ab02e4988",
|
||||
"package/src/mask.js": "945e8d45b9f1a683d47e2981fce45441da3fe399d09de0829781a486d9ee513a",
|
||||
"package/src/mobile.js": "362b4a3be51eeed87c5953a5a70df250d12144a1359b1f639de39e0409088e6d",
|
||||
"package/src/notice.js": "84a8fbb2035c8c12b80ae43a2fe4abb76152c936acdec9a3ff6a6d918bd53c29",
|
||||
"package/src/player/aspectRatioMix.js": "d6de0761fdc46e5235dcee296859549174819d24528912940052f266536fc89f",
|
||||
"package/src/player/attrInit.js": "3802cfb908fd333f6d7a34be2fe5f19760271a953a54f7eceb9d32caf5e93e8a",
|
||||
"package/src/player/autoSizeMix.js": "1337da3bd01d317690c2e9ea0b9e582818c0b2a6b02f475001bfe9bd09049b91",
|
||||
"package/src/player/currentTimeMix.js": "8b23cf52262284e1a974007a2d61bf7c30cb4bdb25405e1380d47649e86f4d1e",
|
||||
"package/src/player/durationMix.js": "3a8efa85852b53e1a22231a858bc05e32e7a08c138d16fd6a8b279fa67d74183",
|
||||
"package/src/player/eventInit.js": "08a551bb724f3886bdb33450e280c5964ce7521dc5247fcf068eeadb7b95a3a5",
|
||||
"package/src/player/exclusiveInit.js": "f21f07d70779192039160cd5e1e404263bca4080f97a23ded8893bce937e6e7f",
|
||||
"package/src/player/flipMix.js": "b7d4e456695a6114536b77e21a2b8c9ea61129a8b9c62a24a8fbe3c764c27a54",
|
||||
"package/src/player/fullscreenMix.js": "f62d862ab451e4e1c9f82841f8bb88f989840bbd2b51e776c1d8e34578196f9d",
|
||||
"package/src/player/fullscreenRotateMix.js": "ac7060b12d0d828681776348d5cfa48cf3256eee0473c392ff96bd50941d03b8",
|
||||
"package/src/player/fullscreenWebMix.js": "3cad9355a0e6a09e470f30fb2de34131fbbb4ad815a12bc6d3dfeea897877b96",
|
||||
"package/src/player/index.js": "14ff2741482c6a459bb24ed0372005100403736a0800c9aae9176294fad7c28b",
|
||||
"package/src/player/lightMix.js": "4f49ecdec4bc95451721b7df40b3eb95540d26297bb91868a91d09713ee33ec4",
|
||||
"package/src/player/loadedMix.js": "772169f97e31be3ad1d45c29056a68c6de3f172921d19bc0f430fa2edb188475",
|
||||
"package/src/player/loopMin.js": "61f89a6cee6ce773e6a2319ac99e01c264781d2f6720f9b9cfb74bcfe66754c5",
|
||||
"package/src/player/miniMix.js": "96c3e297641b46e2ebfd6e6ad01369dfcf48c2566f43c4587c4006f2694ef313",
|
||||
"package/src/player/pauseMix.js": "7abbfd904d55a322e76dfebabb43dabe2fd91b1ef32840d0cd18b64f4e229fb2",
|
||||
"package/src/player/pipMix.js": "32a22db1c33dcd096d067cdf939ed3c70f393441b18f7c8fe53e9a64dbd9675b",
|
||||
"package/src/player/playMix.js": "b5a413eac658912f5a10311c3d2a656829f5d8c28a14a172955d44b2b16ca0be",
|
||||
"package/src/player/playbackRateMix.js": "8b6150375f636ea5917fbb311807ab705882f52df9a24dd9e3f99925df6901fc",
|
||||
"package/src/player/playedMix.js": "5516d2fecfd048320544cda28ebe368459816bf2201eaf6be7b756630afee3a6",
|
||||
"package/src/player/playingMix.js": "dc9bc49920c20e7504f8adab7b4c50ffa9d2f65ad078d62c492a19505abb192d",
|
||||
"package/src/player/posterMix.js": "6551399ec68e90ec0dca5d154df234aae550eacbe8cc6e8b13555ef719db02c0",
|
||||
"package/src/player/rectMix.js": "46354ef4ed7fa0c737bf5de9c96825491a78b65932d5a488798ae0cb9e3a88e1",
|
||||
"package/src/player/rotateMix.js": "e96eb474484aa45472a6c1c97d877a46d2414b831568e7b76c1d6de60299d5c8",
|
||||
"package/src/player/screenshotMix.js": "a30ba49d23817ad7cbc0b76189ccaf168e2c253058574a850acdb948659f29c0",
|
||||
"package/src/player/seekMix.js": "1be19f1ee0a502327d158ed2b35da8c5a78750bf779558d058b565fc0643aa7b",
|
||||
"package/src/player/switchMix.js": "a2b78e2ab7b100bd36af27408ae59255c58e271ea065aef2c48e98b0c24b7203",
|
||||
"package/src/player/toggleMix.js": "af06c80fd60a89eb453c4d9dc54416f8782a840e9f30f8dafac203ce0cd2e7cc",
|
||||
"package/src/player/urlMix.js": "c79c779438d442cf4fe6ab6f73229fa7cebc1bfdbee4e434a54303db658a9bf6",
|
||||
"package/src/player/volumeMix.js": "676f4c05459f8cd6e788d24f16614e48a34ae0def957832c925da7c53744ba77",
|
||||
"package/src/plugins/index.js": "4a929c4bd20141dc7c96674aa29e38217fbab2ae8decbc65fdcdda27f3aa3338",
|
||||
"package/src/plugins/localSubtitle.js": "faa70fe2aa7d46e62d991d8cefb09ac4f6b361919f4a5ef5b68ef03737ec1c60",
|
||||
"package/src/plugins/localVideo.js": "629062e7d2018fc899265b5f84921d7d2168cee1b8eda04ca589e86ed1bb3dad",
|
||||
"package/src/plugins/log.js": "c1effb811e1112763c7c99f99d5f489078ced11ab898a0a019a41c6cde739edd",
|
||||
"package/src/plugins/miniProgressBar.js": "98be20eba83482a1fb7469f4228b5916a9f6b5cae88f73de461cea453b2419e7",
|
||||
"package/src/plugins/networkMonitor.js": "4ef263c21b29e47098fab7bf98374036578daefb5854855190077a088af9e65d",
|
||||
"package/src/plugins/subtitleOffset.js": "f76806d0c21698f5b44d7a9d0ae89083cbb15888f6b462d199d22d7b4850e837",
|
||||
"package/src/scheme/index.js": "93127f49ccf4f1d6643594be2368a2d7529ad6498e7518fd49c88b63c2189aab",
|
||||
"package/src/setting/aspectRatio.js": "68783962408a11adb8fa01cf0dabeb68374438fa7e9a116024714a4999691eda",
|
||||
"package/src/setting/flip.js": "e541d8c4990875bf37dc06e240da887c2869286216b319e7ffcff493f1a56378",
|
||||
"package/src/setting/index.js": "1cb2d855bc6da6212bee11c4827e98a57203b7d22d21d25ab6e38dd60aa1729f",
|
||||
"package/src/setting/playbackRate.js": "54ccbac34711894c28ac48d39497c8ff22d30aa3a83ef90485dff0cc71d08c44",
|
||||
"package/src/setting/rotate.js": "a38dfdbae6cf6f3c8a83f7b55bb5d03fbe4422e805a79849d8ceb9232dc8e622",
|
||||
"package/src/storage.js": "6ce11595322cef50346c95c511d3968ed31bd0a90af64d83f13e12f841881c5c",
|
||||
"package/src/style/artplayer.scss": "37676394ef97246b9fcb62bd0188efd37cc79ec50585032caf29f7af9c5bdd3a",
|
||||
"package/src/style/aspectRatio.scss": "c2e5a5c0d4f4a740f8bbe30cbbdc71650ec0790e05bdba3929ef5d08a86ea9c6",
|
||||
"package/src/style/autoSize.scss": "35f482ca46bf9d12e8a1430b18502d7466468539bf642f686a46650f86fa7817",
|
||||
"package/src/style/balloon.scss": "c8186155a7dd804b3df9490b19cd426f1d8429cb67d11551e0c27bbc2724a1ff",
|
||||
"package/src/style/bottom.scss": "dd69ddb97cf0347f03500b4fdb1381cf065fb0011436e2227988be91ae8c92d1",
|
||||
"package/src/style/contextmenu.scss": "eb1e488e46c43f6188e0a3d4914b8faeba6fb777f8265501078e77d516d3572c",
|
||||
"package/src/style/danmuku.scss": "f2f488c5140ee5cc09226784e1222fcd0b9b917f7e86179ff9922abf4a90edd8",
|
||||
"package/src/style/flip.scss": "d18c9c258041d7dc2128f709cacfbcf3a93cd498deed0a733ed90631a352b148",
|
||||
"package/src/style/fullscreenRotate.scss": "9be8d1340d4d25cdf76eab1eab550ead89cbc655628e0d4cc9231d98de73ff86",
|
||||
"package/src/style/fullscreenWeb.scss": "cc1a35fb81507faae404d08ed3bd52cc4fc15243937c992c23a3ab443719bb31",
|
||||
"package/src/style/hideCursor.scss": "e05a85e4c0afd202a0becc2f0f5fb4bb1b49f56802c495f2a816099416d9c22b",
|
||||
"package/src/style/index.scss": "02eeddf75b25f3635aba0851d15386ceee7398dfc54c0596149520db6b32f016",
|
||||
"package/src/style/info.scss": "d40b6a710550d3cb46e5fda9fc3fad8aca617a56872a5c1d8ab59154fa185806",
|
||||
"package/src/style/layers.scss": "db19d955e243da2a888204115001d6f1567d7203427d9975613fb9a5d617802d",
|
||||
"package/src/style/loading.scss": "fd1411beb6390c71ba4f7a812e32c8e28c2fb7b3dac54a02d20f3278cd2892f8",
|
||||
"package/src/style/mask.scss": "7ebc125d3dcf69fd0e6635502028447334d04a395fcc50a86e0ba9307a36703a",
|
||||
"package/src/style/mini.scss": "2d1d35a24f2bebb801f9c13f18f141286fa5fc9908ddfce5a16f65eee18c74f1",
|
||||
"package/src/style/notice.scss": "2793a0f603c049df0ca5cec62682ab6136b249a31a53fd8caa04dd250409e4dc",
|
||||
"package/src/style/plugins.scss": "4fee8cc639e3efd8e9910a9d15a4ee80e5adeffae38aac52a5474ef02c0b92c0",
|
||||
"package/src/style/poster.scss": "3039b30d18bcae180f51a166f01f8a331d417bea4df900d44fec3006167ddc65",
|
||||
"package/src/style/selector.scss": "d834f5e0450331096c33eb055b10bfcf7aeea3bf51b9df5ccdb33b5077274569",
|
||||
"package/src/style/setting.scss": "0c05f8c5a7d895d6521fb73c36931121f5892c510e06b352f247206643fd4740",
|
||||
"package/src/style/subtitle.scss": "2372ca5120da184d487e5f1c4d3a8a5eb5a5be1c7172a76fe11c10c9d0a417e6",
|
||||
"package/src/style/video.scss": "c8a4fcdf7070a70b724e6d39d78b9c243ff18d8f8b6fbb8700d647799ff9756b",
|
||||
"package/src/subtitle.js": "2b09bd8b2e5d8bb4ff6736470de9cc0d7f0817bc317860722b5aeb2a39082e9b",
|
||||
"package/src/template.js": "f76586b89c11e9435ff1d457d9af4351d81397160ae8251d90adadd24179824c",
|
||||
"package/src/utils/compatibility.js": "e0f6f697d258867d997a02743281037a2b543190fdd3a2f15b2a771073fe4f20",
|
||||
"package/src/utils/component.js": "705b656bf8029c059b74d29df8d1f5748f3bfc9d7bc05a4c9368d10490a3f06e",
|
||||
"package/src/utils/dom.js": "de97d2b717b763f9cddcc5f4d6886e9f53ded5343a58f6f7f9318a73ef745fac",
|
||||
"package/src/utils/emitter.js": "637c2b65c89a34ca3208335a892258540eefc49cb8f87f981c69496fe49efa89",
|
||||
"package/src/utils/error.js": "3b395e07922fb3fcbb7de34e662ada1914b3499dac6f109e522c432bd705f3d1",
|
||||
"package/src/utils/file.js": "c02139c54e569bf635f90d32b7ccb9d6cb8ba5ff126071e6c79b34a134b11cb2",
|
||||
"package/src/utils/format.js": "64e22ffdd2bc27808847e118db413c4274bb8c33da21071fb535f0751848db9d",
|
||||
"package/src/utils/index.js": "585394c7bfda8e8548cfb92c73ae1e45cccc55c48d683ca9a48099debdf4b98e",
|
||||
"package/src/utils/property.js": "a78e476a111010d0760ca64e95d692736ca91c245a1eefd004603ed51b740f0a",
|
||||
"package/src/utils/subtitle.js": "7d4f67bedab5c32ef4c4b8c2b8d61c2d25d76c79acd236f88d7113b314d7c9d3",
|
||||
"package/src/utils/time.js": "905f0abb54088ea9320f00e7668efe65a398efa3f1a66d5f79f9d15eacebc2d6",
|
||||
"package/src/whitelist.js": "04dbac182814dc575707682bc48f723f4a0746f76ae185694837f3b4dc273bc6",
|
||||
"package/tsconfig.json": "2a93a271339a5b743f4b42090b9a633b79ba3657a5e429e00d9e3f5dd1ce6e30",
|
||||
"package/types/artplayer.d.ts": "3782fa31d484433976f464e44e15d2dce1be6c2b4cb45cc727d0e2b92e53f4d6"
|
||||
}
|
||||
},
|
||||
"archiveMembers": [
|
||||
"package/LICENSE",
|
||||
"package/README.md",
|
||||
"package/dist/artplayer.js",
|
||||
"package/package.json",
|
||||
"package/src/config/index.js",
|
||||
"package/src/contextmenu/aspectRatio.js",
|
||||
"package/src/contextmenu/close.js",
|
||||
"package/src/contextmenu/index.js",
|
||||
"package/src/contextmenu/info.js",
|
||||
"package/src/contextmenu/light.js",
|
||||
"package/src/contextmenu/playbackRate.js",
|
||||
"package/src/contextmenu/version.js",
|
||||
"package/src/control/fullscreen.js",
|
||||
"package/src/control/fullscreenWeb.js",
|
||||
"package/src/control/index.js",
|
||||
"package/src/control/loop.js",
|
||||
"package/src/control/pip.js",
|
||||
"package/src/control/playAndPause.js",
|
||||
"package/src/control/progress.js",
|
||||
"package/src/control/quality.js",
|
||||
"package/src/control/screenshot.js",
|
||||
"package/src/control/setting.js",
|
||||
"package/src/control/subtitle.js",
|
||||
"package/src/control/thumbnails.js",
|
||||
"package/src/control/time.js",
|
||||
"package/src/control/volume.js",
|
||||
"package/src/events/clickInit.js",
|
||||
"package/src/events/gestureInit.js",
|
||||
"package/src/events/hoverInit.js",
|
||||
"package/src/events/index.js",
|
||||
"package/src/events/mousemoveInit.js",
|
||||
"package/src/events/resizeInit.js",
|
||||
"package/src/events/viewInit.js",
|
||||
"package/src/hotkey.js",
|
||||
"package/src/i18n/index.js",
|
||||
"package/src/i18n/zh-cn.json",
|
||||
"package/src/i18n/zh-tw.json",
|
||||
"package/src/icons/fullscreen-web.svg",
|
||||
"package/src/icons/fullscreen.svg",
|
||||
"package/src/icons/index.js",
|
||||
"package/src/icons/loading.svg",
|
||||
"package/src/icons/next.svg",
|
||||
"package/src/icons/pause.svg",
|
||||
"package/src/icons/pip.svg",
|
||||
"package/src/icons/play.svg",
|
||||
"package/src/icons/prev.svg",
|
||||
"package/src/icons/screenshot.svg",
|
||||
"package/src/icons/setting.svg",
|
||||
"package/src/icons/state.svg",
|
||||
"package/src/icons/subtitle.svg",
|
||||
"package/src/icons/volume-close.svg",
|
||||
"package/src/icons/volume.svg",
|
||||
"package/src/index.js",
|
||||
"package/src/info.js",
|
||||
"package/src/layer.js",
|
||||
"package/src/loading.js",
|
||||
"package/src/mask.js",
|
||||
"package/src/mobile.js",
|
||||
"package/src/notice.js",
|
||||
"package/src/player/aspectRatioMix.js",
|
||||
"package/src/player/attrInit.js",
|
||||
"package/src/player/autoSizeMix.js",
|
||||
"package/src/player/currentTimeMix.js",
|
||||
"package/src/player/durationMix.js",
|
||||
"package/src/player/eventInit.js",
|
||||
"package/src/player/exclusiveInit.js",
|
||||
"package/src/player/flipMix.js",
|
||||
"package/src/player/fullscreenMix.js",
|
||||
"package/src/player/fullscreenRotateMix.js",
|
||||
"package/src/player/fullscreenWebMix.js",
|
||||
"package/src/player/index.js",
|
||||
"package/src/player/lightMix.js",
|
||||
"package/src/player/loadedMix.js",
|
||||
"package/src/player/loopMin.js",
|
||||
"package/src/player/miniMix.js",
|
||||
"package/src/player/pauseMix.js",
|
||||
"package/src/player/pipMix.js",
|
||||
"package/src/player/playMix.js",
|
||||
"package/src/player/playbackRateMix.js",
|
||||
"package/src/player/playedMix.js",
|
||||
"package/src/player/playingMix.js",
|
||||
"package/src/player/posterMix.js",
|
||||
"package/src/player/rectMix.js",
|
||||
"package/src/player/rotateMix.js",
|
||||
"package/src/player/screenshotMix.js",
|
||||
"package/src/player/seekMix.js",
|
||||
"package/src/player/switchMix.js",
|
||||
"package/src/player/toggleMix.js",
|
||||
"package/src/player/urlMix.js",
|
||||
"package/src/player/volumeMix.js",
|
||||
"package/src/plugins/index.js",
|
||||
"package/src/plugins/localSubtitle.js",
|
||||
"package/src/plugins/localVideo.js",
|
||||
"package/src/plugins/log.js",
|
||||
"package/src/plugins/miniProgressBar.js",
|
||||
"package/src/plugins/networkMonitor.js",
|
||||
"package/src/plugins/subtitleOffset.js",
|
||||
"package/src/scheme/index.js",
|
||||
"package/src/setting/aspectRatio.js",
|
||||
"package/src/setting/flip.js",
|
||||
"package/src/setting/index.js",
|
||||
"package/src/setting/playbackRate.js",
|
||||
"package/src/setting/rotate.js",
|
||||
"package/src/storage.js",
|
||||
"package/src/style/artplayer.scss",
|
||||
"package/src/style/aspectRatio.scss",
|
||||
"package/src/style/autoSize.scss",
|
||||
"package/src/style/balloon.scss",
|
||||
"package/src/style/bottom.scss",
|
||||
"package/src/style/contextmenu.scss",
|
||||
"package/src/style/danmuku.scss",
|
||||
"package/src/style/flip.scss",
|
||||
"package/src/style/fullscreenRotate.scss",
|
||||
"package/src/style/fullscreenWeb.scss",
|
||||
"package/src/style/hideCursor.scss",
|
||||
"package/src/style/index.scss",
|
||||
"package/src/style/info.scss",
|
||||
"package/src/style/layers.scss",
|
||||
"package/src/style/loading.scss",
|
||||
"package/src/style/mask.scss",
|
||||
"package/src/style/mini.scss",
|
||||
"package/src/style/notice.scss",
|
||||
"package/src/style/plugins.scss",
|
||||
"package/src/style/poster.scss",
|
||||
"package/src/style/selector.scss",
|
||||
"package/src/style/setting.scss",
|
||||
"package/src/style/subtitle.scss",
|
||||
"package/src/style/video.scss",
|
||||
"package/src/subtitle.js",
|
||||
"package/src/template.js",
|
||||
"package/src/utils/compatibility.js",
|
||||
"package/src/utils/component.js",
|
||||
"package/src/utils/dom.js",
|
||||
"package/src/utils/emitter.js",
|
||||
"package/src/utils/error.js",
|
||||
"package/src/utils/file.js",
|
||||
"package/src/utils/format.js",
|
||||
"package/src/utils/index.js",
|
||||
"package/src/utils/property.js",
|
||||
"package/src/utils/subtitle.js",
|
||||
"package/src/utils/time.js",
|
||||
"package/src/whitelist.js",
|
||||
"package/tsconfig.json",
|
||||
"package/types/artplayer.d.ts"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
# PKG-TOOL-THUMB-05 三代核心组合验证检查点
|
||||
|
||||
起点 `fb78328c4355042b578091e1236c2ce71a68e5c2`。本批补齐真实文件抽帧后由
|
||||
新旧核心显示图片的证据,没有改变生产实现、公开类型或依赖。05 保持 doing:
|
||||
Windows WebKit 的 Blob 解码限制与实际 Safari/设备证据仍未关闭。
|
||||
|
||||
## 实现和兼容
|
||||
|
||||
冻结关联核心 artplayer 3.5.31 的完整 npm 归档,逐个验证 144 个成员 SHA256、
|
||||
registry integrity、归档 SHA256 和 manifest。历史 Git 核心版本关联一致,见
|
||||
[归档](../baselines/thumbnail-core.json)。这是历史关联版本,不是最低支持版本,
|
||||
也不代表找回了原始 thumbnail 工具的完整归档或声明。浏览器服务新增独立路由,
|
||||
保留原 published 5.4.0 路由,每次读取先校验归档和 main。
|
||||
|
||||
`thumbnail-core.spec.js` 将恢复的 CDN 3.5.31、冻结工作区工具和重构工具的
|
||||
默认/workspace 策略分别接入核心 3.5.31、5.4.0 和重构核心。原生文件选择、
|
||||
实际解码、工具生成 PNG、真实鼠标悬停,每组两次生成并重建播放器,检查图片
|
||||
640×300、12 个样本中心、5 个取格位置、预览像素、URL 更新和销毁。
|
||||
截图比较上部未被时间提示遮挡的区域,排除圆角,平均 RGB 通道误差上限为 3;
|
||||
没有隐藏提示或修改产品样式。
|
||||
|
||||
旧核心在行边界取上一行最后一格、返回首格时保留上次位置,是已有缺陷;旧结果
|
||||
明确断言,重构核心必须显示正确格子。核心 5.4.0 初始化会撤销空的前一媒体 URL,
|
||||
两次初始化精确记录两个空值;所有非空创建/撤销仍精确匹配。
|
||||
|
||||
图片有 30px 页脚,应显式传入与生成配置一致的 number/column/width/height;
|
||||
本组合 scale=1。工具持有图片和媒体 Blob URL,先销毁引用它们的播放器,再生成
|
||||
下一张或销毁工具;播放器不得撤销外借 URL。包内架构和测试文档同步补充。
|
||||
|
||||
## 验证
|
||||
|
||||
Node 24.21.0 / Yarn Classic 1.22.22 / Windows。逐例记录和哈希见
|
||||
[组合证据](../baselines/thumbnail-core-validation.json)。
|
||||
|
||||
| 范围 | 结果 | 实际证明 |
|
||||
| --- | --- | --- |
|
||||
| 关联核心归档测试 | 1 通过 | 144 个文件、完整归档和历史版本关联 |
|
||||
| 源码三引擎组合 | 36 通过,144.262s | Chromium/Firefox 24 个抽帧组合;WebKit 12 个能力控制 |
|
||||
| 已安装 main 三引擎组合 | 18 通过,53.185s | Chromium/Firefox 12 个抽帧组合;WebKit 6 个能力控制 |
|
||||
| 最终通知等待改动 | 源码 WebKit 12 通过 | 等待精确一次原生错误通知 |
|
||||
| 只读 scoped ESLint | 通过 | 浏览器用例、服务、归档测试 |
|
||||
| 计划与风险台账 | 通过;风险回归 2 项通过 | 285 项任务、依赖、证据链接和风险关闭规则 |
|
||||
|
||||
以上最终运行没有失败/跳过/重试。安装工具来自先前独立 Yarn pack/install,
|
||||
main 与当前 dist SHA256 一致:
|
||||
`a254d9d66943bd302719edae040d6ee5e0a32f7c9f1ae0727be8cb6c5a335511`。
|
||||
组合中的重构核心来自源码编译,不冒充全套安装产物或最新全项目候选验收。
|
||||
共享测试输入变化后,REL-02 仍须刷新完整候选指纹。
|
||||
|
||||
Windows WebKit 26.6 原生 HTTP MP4 成功,同一内容 Blob URL 报 media error 4。
|
||||
控制用例确认原生和工具一致、通知与清理正确,没有产生缩略图,不能计作 Safari
|
||||
抽帧成功。Chromium 153.0.8010.12 / Firefox 155.0 验证实际图片和预览。
|
||||
|
||||
## 失败调查和修正
|
||||
|
||||
- 初次将另一素材的末格红色预期错误套用到本素材,12 项失败。独立 FFmpeg 在
|
||||
1、3、…、23 秒解码确认所有中心蓝色,修正预期并保存原报告。
|
||||
- 随后 12 项整图比较失败,截图确认时间提示遮挡下部。改比较未遮挡区域,
|
||||
没有扩大误差阈值。一次已发布核心空 URL 撤销差异改为按实际代码精确断言。
|
||||
- 统一 delay=20 时,Firefox 三个恢复版 3.5.31 组合生成黑格:0/4/8 格中心蓝色,
|
||||
其余黑色。历史源码只等计时器后 drawImage,不等 seeked。正常组合使用旧版原
|
||||
默认 delay=300 后通过;重构工具仍使用 delay=20。保留失败,不声称旧版短延时通过。
|
||||
- 安装产物首次 17 通过/1 失败:video.error 已设置,排队的 error 事件尚未送达。
|
||||
改为在原超时内等待精确一次通知;安装 18 项和源码 WebKit 12 项通过。源码完整
|
||||
36 项在这次等待改动之前运行,其测试文件另存哈希;跟进结果单独记录。
|
||||
- 归档测试纠正错误的 Vitest 导入,使用项目原有 Node 运行器,没有新增依赖。
|
||||
|
||||
## 交接与回退
|
||||
|
||||
225 done /23 doing /37 todo。THUMB-LIFE-01 增加组合证据但保持开放;原生 Blob
|
||||
风险仍保留。05/06 的 Safari/真机和完整历史工具分发证据不足,不结束任务,
|
||||
不进入用户保留的正式复盘,不推送或发布。回退仅撤销本批测试路由、归档/证据、
|
||||
用例和文档,不改变生产 API。
|
||||
+3
-2
@@ -4,7 +4,7 @@
|
||||
|
||||
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 285 项,范围 22 个包及工作区/示例。
|
||||
|
||||
状态:todo 38 / doing 22 / blocked 0 / done 225 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||
状态:todo 37 / doing 23 / blocked 0 / done 225 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||
|
||||
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
|
||||
|
||||
@@ -400,7 +400,7 @@
|
||||
| PKG-TOOL-THUMB-02 | artplayer-tool-thumbnail<br>建立特有行为与错误测试 | PKG-TOOL-THUMB-01, ENG-03, ENG-05 | 文件输入/拖放、抽帧网格、begin/end、进度/失败/重复任务 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | done |
|
||||
| PKG-TOOL-THUMB-03 | artplayer-tool-thumbnail<br>整理内部职责与资源 | PKG-TOOL-THUMB-02, CORE-01 | 输入、抽帧队列、网格导出、URL/监听清理分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | done |
|
||||
| PKG-TOOL-THUMB-04 | artplayer-tool-thumbnail<br>迁移自有源码和公开类型 | PKG-TOOL-THUMB-03, ENG-04, ENG-06, CORE-07, PKG-TOOL-THUMB-07 | 补齐真实 API 声明,自有 emitter/utils TS 化 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容;为 BASE-DIST-01 提供兼容入口/声明及消费者验证 | H | done |
|
||||
| PKG-TOOL-THUMB-05 | artplayer-tool-thumbnail<br>验证新旧核心和组合 | PKG-TOOL-THUMB-04, CORE-22 | 工具独立浏览器使用,生成缩略图在核心中显示 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo |
|
||||
| PKG-TOOL-THUMB-05 | artplayer-tool-thumbnail<br>验证新旧核心和组合 | PKG-TOOL-THUMB-04, CORE-22 | 工具独立浏览器使用,生成缩略图在核心中显示 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | doing |
|
||||
| PKG-TOOL-THUMB-06 | artplayer-tool-thumbnail<br>验证分发并同步文档 | PKG-TOOL-THUMB-05, ENG-07 | tool.thumbnail.js、历史 ESM 兼容文件、types 路径和 tarball | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo |
|
||||
| PKG-TOOL-THUMB-07 | artplayer-tool-thumbnail<br>恢复清理和销毁中的原始异常传播 | PKG-TOOL-THUMB-03 | 清理记录与异常值分离,保留首个 falsy 抛出值并继续释放资源;历史对照、真实DOM、分发验证及维护记录 | 恢复旧 destroy 监听器同步异常语义,0/false/undefined/NaN等不被吞掉或覆盖;后续清理、重复销毁与正常抽帧回归通过,默认兼容决策不受影响 | M | done |
|
||||
|
||||
@@ -677,6 +677,7 @@
|
||||
- PKG-TOOL-THUMB-02: [记录](baselines/thumbnail-behavior-validation.json) [记录](changes/2026-09-13-PKG-TOOL-THUMB-02-behavior.md)
|
||||
- PKG-TOOL-THUMB-03: [记录](changes/2026-09-13-PKG-TOOL-THUMB-03-input-checkpoint.md) [记录](baselines/thumbnail-input-checkpoint.json) [记录](changes/2026-09-13-PKG-TOOL-THUMB-03-lifecycle.md) [记录](baselines/thumbnail-lifecycle-validation.json)
|
||||
- PKG-TOOL-THUMB-04: [记录](changes/2026-09-13-PKG-TOOL-THUMB-04-runtime-types.md) [记录](baselines/thumbnail-runtime-types-validation.json) [记录](changes/2026-09-13-PKG-TOOL-THUMB-04-public-types.md) [记录](baselines/thumbnail-public-types-validation.json) [记录](changes/2026-09-13-PKG-TOOL-THUMB-04-emitter.md) [记录](baselines/thumbnail-emitter-validation.json) [记录](thumbnail-compatibility-decision.md) [记录](changes/2026-09-15-PKG-TOOL-THUMB-04-policy-proposal.md) [记录](changes/2026-09-15-PKG-TOOL-THUMB-04-approved-policy.md) [记录](baselines/thumbnail-policy-validation.json)
|
||||
- PKG-TOOL-THUMB-05: [记录](changes/2026-09-16-PKG-TOOL-THUMB-05-core-combinations.md) [记录](baselines/thumbnail-core-validation.json) [记录](baselines/thumbnail-core.json)
|
||||
- SITE-01: [记录](site-inventory.md) [记录](baselines/site-inventory.json) [记录](baselines/site-provenance.json) [记录](baselines/demo-additions.json) [记录](changes/2026-09-14-SITE-01-site-inventory.md) [记录](baselines/site-inventory-validation.json)
|
||||
- SITE-SMOKE-01: [记录](changes/2026-09-14-SITE-SMOKE-01-documentation-smoke.md) [记录](baselines/docs-smoke-validation.json) [记录](scripts/docs-smoke.test.mjs)
|
||||
- SITE-02: [记录](changes/2026-09-14-SITE-02-editor-declarations.md) [记录](baselines/editor-declarations-validation.json) [记录](changes/2026-09-14-SITE-SMOKE-01-documentation-smoke.md)
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# 进度与证据
|
||||
|
||||
## PKG-TOOL-THUMB-05 三代核心组合检查点
|
||||
|
||||
新增关联核心 3.5.31 完整归档校验和真实文件抽帧/核心预览组合,见
|
||||
[记录](changes/2026-09-16-PKG-TOOL-THUMB-05-core-combinations.md)。源码36项、
|
||||
已安装main18项通过,其中分别24/12项实际抽帧,12/6项为Windows WebKit能力控制。
|
||||
错误通知等待修正后源码WebKit12项跟进通过。旧工具短延时黑格和旧核心取格缺陷
|
||||
明确记录;重构工具在两种策略、三代核心下通过实际截图与URL释放检查。
|
||||
05保持doing,Safari/设备及完整历史工具分发缺口保留。225 done /23 doing /37 todo。
|
||||
共享输入对应候选仍待REL-02刷新;不进入用户保留的正式复盘,不推送或发布。
|
||||
|
||||
## SITE-05 本地链接、编辑器与远端缺口
|
||||
|
||||
新增check:site-links并接入CI:67生成页面/5766本地引用/942搜索结果全部有效。
|
||||
|
||||
+13
-4
@@ -2,7 +2,7 @@
|
||||
"schemaVersion": 1,
|
||||
"task": "BASE-07",
|
||||
"sourceCommit": "e01f39ff",
|
||||
"updatedAt": "2026-09-15T17:18:32.442Z",
|
||||
"updatedAt": "2026-09-16T02:27:53.896Z",
|
||||
"note": "Open means closure evidence is outstanding; source-observed and unverified are not reproduced runtime bugs. A source issue already mitigated in the workspace still requires candidate regression evidence. No accepted-with-scope item is implied by baseline task completion.",
|
||||
"items": [
|
||||
{
|
||||
@@ -4182,8 +4182,13 @@
|
||||
"refactor/baselines/thumbnail-input-checkpoint.json",
|
||||
"refactor/changes/2026-09-13-PKG-TOOL-THUMB-03-lifecycle.md",
|
||||
"test/thumbnail-lifecycle.test.js",
|
||||
"refactor/baselines/thumbnail-lifecycle-validation.json"
|
||||
]
|
||||
"refactor/baselines/thumbnail-lifecycle-validation.json",
|
||||
"refactor/changes/2026-09-16-PKG-TOOL-THUMB-05-core-combinations.md",
|
||||
"refactor/baselines/thumbnail-core-validation.json",
|
||||
"refactor/baselines/thumbnail-core.json",
|
||||
"test/browser/thumbnail-core.spec.js"
|
||||
],
|
||||
"workspaceState": "04 strict types and approved default/workspace policy are complete. 05 source and installed tool main pass actual Chromium/Firefox extraction, two generated sheets, preview pixels and exact URL ownership against core 3.5.31/5.4.0/candidate. Windows WebKit native Blob error 4 and physical Safari/device evidence remain open."
|
||||
},
|
||||
{
|
||||
"id": "THUMB-PROVENANCE-01",
|
||||
@@ -4225,7 +4230,11 @@
|
||||
"refactor/baselines/thumbnail-behavior-validation.json",
|
||||
"refactor/changes/2026-09-13-PKG-TOOL-THUMB-02-behavior.md",
|
||||
"test/thumbnail.test.js",
|
||||
"test/browser/thumbnail-tool.spec.js"
|
||||
"test/browser/thumbnail-tool.spec.js",
|
||||
"refactor/changes/2026-09-16-PKG-TOOL-THUMB-05-core-combinations.md",
|
||||
"refactor/baselines/thumbnail-core-validation.json",
|
||||
"refactor/baselines/thumbnail-core.json",
|
||||
"test/browser/thumbnail-core.spec.js"
|
||||
],
|
||||
"compatibleResolution": "Preserve independent HTTP/Blob capability controls; obtain actual supported WebKit/Safari file extraction evidence before release acceptance. Do not count the 12 unavailable controls as successful thumbnail generation or silently replace local files with HTTP media.",
|
||||
"closureCriteria": "Actual generated PNG/extraction and lifecycle proof in supported Safari/WebKit environments, or explicit supported-environment decision with migration documentation; Windows limitation stays identifiable."
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
// eslint-disable-next-line test/no-import-node-test -- Node frozen release-contract runner.
|
||||
import test from 'node:test'
|
||||
import { archiveFiles, ensureArchive, hash, readMember } from './releases.mjs'
|
||||
|
||||
test('Thumbnail associated core 3.5.31 is a complete verified npm archive', async () => {
|
||||
const baseline = JSON.parse(fs.readFileSync(new URL('../baselines/thumbnail-core.json', import.meta.url)))
|
||||
const tool = JSON.parse(fs.readFileSync(new URL('../baselines/thumbnail-release.json', import.meta.url)))
|
||||
assert.deepEqual(baseline.association, tool.coreAssociations.historical)
|
||||
assert.equal(baseline.release.name, 'artplayer')
|
||||
assert.equal(baseline.release.version, baseline.association.version)
|
||||
const archive = await ensureArchive(baseline.release)
|
||||
assert.deepEqual(archiveFiles(archive), baseline.archiveMembers)
|
||||
assert.deepEqual(Object.keys(baseline.release.files).sort(), baseline.archiveMembers)
|
||||
for (const [member, expected] of Object.entries(baseline.release.files))
|
||||
assert.equal(hash(readMember(archive, member)), expected, member)
|
||||
assert.deepEqual(JSON.parse(readMember(archive, 'package/package.json')), baseline.release.manifest)
|
||||
})
|
||||
+6
-2
@@ -4274,11 +4274,15 @@
|
||||
"PKG-TOOL-THUMB-04",
|
||||
"CORE-22"
|
||||
],
|
||||
"status": "todo",
|
||||
"status": "doing",
|
||||
"risk": "H",
|
||||
"deliverable": "工具独立浏览器使用,生成缩略图在核心中显示",
|
||||
"acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成",
|
||||
"evidence": []
|
||||
"evidence": [
|
||||
"changes/2026-09-16-PKG-TOOL-THUMB-05-core-combinations.md",
|
||||
"baselines/thumbnail-core-validation.json",
|
||||
"baselines/thumbnail-core.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "PKG-TOOL-THUMB-06",
|
||||
|
||||
@@ -535,6 +535,18 @@ The first immediate-pixel WebKit failure remains in the refactor evidence.
|
||||
This is native desktop media playback, not physical audibility or full devices.
|
||||
`document-site.spec.js` also checks generated guide links and Run Code parameters.
|
||||
|
||||
## Standalone thumbnail sheets
|
||||
|
||||
The standalone tool's `thumbnail-core.spec.js` generates actual PNG sheets from
|
||||
a selected local MP4 and displays them in core 3.5.31, 5.4.0 and the candidate.
|
||||
It checks two generations, real hover, unobscured screenshot pixels and exact
|
||||
Blob URL ownership. Historical grid defects are asserted separately from the
|
||||
correct candidate layout. Tool main can be selected with
|
||||
`ARTPLAYER_THUMBNAIL_ARTIFACT`. Windows WebKit's HTTP-success/Blob-error-4 branch
|
||||
is explicitly a capability control, not successful extraction. Full evidence:
|
||||
`refactor/baselines/thumbnail-core-validation.json`; run
|
||||
`yarn test:browser:source thumbnail-core.spec.js --workers=1`.
|
||||
|
||||
## Auto-thumbnail delayed registration
|
||||
|
||||
Auto-thumbnail's `auto-thumbnail-registration.spec.js` separately checks direct
|
||||
|
||||
@@ -95,6 +95,11 @@ 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 })
|
||||
const thumbnailCore = JSON.parse(fs.readFileSync(path.join(workspace, 'refactor/baselines/thumbnail-core.json'), 'utf8')).release
|
||||
const thumbnailCoreMember = `package/${thumbnailCore.manifest.main}`
|
||||
const thumbnailCoreBytes = readMember(await ensureArchive(thumbnailCore), thumbnailCoreMember)
|
||||
assert.equal(hash(thumbnailCoreBytes), thumbnailCore.files[thumbnailCoreMember], 'Historical Thumbnail core differs from frozen archive')
|
||||
add('/published-3.5.31/artplayer.js', thumbnailCoreBytes, { kind: 'npm-release', version: thumbnailCore.version, integrity: thumbnailCore.integrity, member: thumbnailCoreMember })
|
||||
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)
|
||||
@@ -199,7 +204,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.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')
|
||||
assert(['candidate', 'published', 'published-3.5.31', '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)
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
import { Buffer } from 'node:buffer'
|
||||
import fs from 'node:fs'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { PNG } from 'pngjs'
|
||||
import { hash } from '../../refactor/scripts/releases.mjs'
|
||||
import { thumbnailCandidate, thumbnailHistorical } from '../helpers/thumbnail.js'
|
||||
import { expect, test } from './fixtures.js'
|
||||
|
||||
const sample = fileURLToPath(new URL('./media/thumbnail-pattern.mp4', import.meta.url))
|
||||
const candidate = await thumbnailCandidate()
|
||||
const implementations = [
|
||||
...thumbnailHistorical().filter(item => item.name !== 'workspace.legacy.js'),
|
||||
{ ...candidate, lifecycle: true },
|
||||
{ ...candidate, name: `${candidate.name}-workspace-policy`, compatibility: 'workspace-4.4', lifecycle: true },
|
||||
]
|
||||
|
||||
for (const core of ['published-3.5.31', 'published', 'candidate']) {
|
||||
for (const implementation of implementations) {
|
||||
test(`Thumbnail ${implementation.name} sheets display and refresh in ${core} core`, async ({ page, browserName }, testInfo) => {
|
||||
test.setTimeout(45000)
|
||||
await page.goto(`/test/player.html?core=${core}`)
|
||||
await page.addScriptTag({ content: implementation.code })
|
||||
const native = await page.evaluate(async () => {
|
||||
const bytes = await (await fetch('/test/thumbnail-pattern.mp4')).blob()
|
||||
const source = URL.createObjectURL(bytes)
|
||||
const result = {}
|
||||
for (const [transport, url] of [['http', '/test/thumbnail-pattern.mp4'], ['blob', source]]) {
|
||||
const video = document.createElement('video')
|
||||
video.muted = true
|
||||
document.body.append(video)
|
||||
result[transport] = await new Promise((resolve, reject) => {
|
||||
const timer = setTimeout(() => reject(new Error('Native media control did not settle')), 5000)
|
||||
video.onloadeddata = () => {
|
||||
clearTimeout(timer)
|
||||
resolve({ loaded: true, width: video.videoWidth })
|
||||
}
|
||||
video.onerror = () => {
|
||||
clearTimeout(timer)
|
||||
resolve({ loaded: false, code: video.error.code })
|
||||
}
|
||||
video.src = url
|
||||
})
|
||||
video.removeAttribute('src')
|
||||
video.load()
|
||||
video.remove()
|
||||
}
|
||||
URL.revokeObjectURL(source)
|
||||
return result
|
||||
})
|
||||
const delay = implementation.legacy ? 300 : 20
|
||||
await page.evaluate(({ compatibility, delay }) => {
|
||||
const input = document.createElement('input')
|
||||
input.id = 'thumbnail-file'
|
||||
input.type = 'file'
|
||||
document.body.append(input)
|
||||
window.createdThumbnailUrls = []
|
||||
window.revokedThumbnailUrls = []
|
||||
const create = URL.createObjectURL.bind(URL)
|
||||
const revoke = URL.revokeObjectURL.bind(URL)
|
||||
URL.createObjectURL = (blob) => {
|
||||
const url = create(blob)
|
||||
window.createdThumbnailUrls.push(url)
|
||||
return url
|
||||
}
|
||||
URL.revokeObjectURL = (url) => {
|
||||
window.revokedThumbnailUrls.push(url)
|
||||
revoke(url)
|
||||
}
|
||||
window.tool = new window.ArtplayerToolThumbnail({ fileInput: input, number: 12, column: 4, width: 160, height: 90, delay, compatibility })
|
||||
window.toolErrors = []
|
||||
window.tool.on('error', error => window.toolErrors.push(String(error)))
|
||||
}, { compatibility: implementation.compatibility, delay })
|
||||
await page.locator('#thumbnail-file').setInputFiles(sample)
|
||||
await testInfo.attach('thumbnail-core-inputs', { contentType: 'application/json', body: JSON.stringify({ core, implementation: implementation.name, delay, toolSha256: hash(implementation.code), mediaSha256: hash(fs.readFileSync(sample)), native, originalToolArchiveAvailable: false }) })
|
||||
if (!native.blob.loaded) {
|
||||
expect(browserName).toBe('webkit')
|
||||
expect(native).toEqual({ http: { loaded: true, width: 320 }, blob: { loaded: false, code: 4 } })
|
||||
await expect.poll(() => page.evaluate(() => window.tool.video.error?.code)).toBe(4)
|
||||
// Native error state can be set before the queued error event is dispatched.
|
||||
await expect.poll(() => page.evaluate(() => window.toolErrors.length)).toBe(implementation.lifecycle ? 1 : 0)
|
||||
await page.evaluate(() => window.tool.destroy())
|
||||
testInfo.annotations.push({ type: 'capability-control', description: 'Native HTTP works; native Blob and tool Blob fail with media error 4. This case does not validate extraction or core thumbnail display.' })
|
||||
return
|
||||
}
|
||||
await expect.poll(() => page.evaluate(() => window.tool.video.readyState)).toBeGreaterThanOrEqual(2)
|
||||
const generations = []
|
||||
for (let generation = 0; generation < 2; generation++) {
|
||||
const sheet = await page.evaluate(async () => {
|
||||
await window.tool.start()
|
||||
const image = new Image()
|
||||
image.src = window.tool.thumbnailUrl
|
||||
await image.decode()
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = image.width
|
||||
canvas.height = image.height
|
||||
const context = canvas.getContext('2d')
|
||||
context.drawImage(image, 0, 0)
|
||||
const cells = Array.from({ length: 12 }, (_, index) => [...context.getImageData(index % 4 * 160 + 80, Math.floor(index / 4) * 90 + 45, 1, 1).data])
|
||||
window.art = new window.Artplayer({
|
||||
container: '.player',
|
||||
url: window.tool.videoUrl,
|
||||
muted: true,
|
||||
thumbnails: { url: window.tool.thumbnailUrl, number: 12, column: 4, width: 160, height: 90, scale: 1 },
|
||||
})
|
||||
return { url: window.tool.thumbnailUrl, width: image.width, height: image.height, cells, png: canvas.toDataURL('image/png').split(',')[1] }
|
||||
})
|
||||
const sheetPng = PNG.sync.read(Buffer.from(sheet.png, 'base64'))
|
||||
await testInfo.attach(`sheet-${generation}`, { contentType: 'image/png', body: Buffer.from(sheet.png, 'base64') })
|
||||
delete sheet.png
|
||||
expect([sheet.width, sheet.height]).toEqual([640, 300])
|
||||
// Independent FFmpeg decoding confirms all twelve sample centers are blue.
|
||||
for (const pixel of sheet.cells)
|
||||
expect(pixel[2] - Math.max(pixel[0], pixel[1])).toBeGreaterThan(80)
|
||||
await expect.poll(() => page.evaluate(() => window.art.template.$video.readyState)).toBeGreaterThanOrEqual(2)
|
||||
const progress = page.locator('.art-control-progress')
|
||||
const preview = page.locator('.art-control-thumbnails')
|
||||
const bounds = await progress.boundingBox()
|
||||
const observed = []
|
||||
// The old core's first-cell/row-boundary defect is independently characterized.
|
||||
for (const [index, oldIndex] of [[1, 1], [4, 3], [5, 5], [0, 5], [11, 11]]) {
|
||||
const x = bounds.x + bounds.width * (index + 0.5) / 12
|
||||
const y = bounds.y + bounds.height / 2
|
||||
await page.mouse.move(x, y)
|
||||
await expect.poll(async () => {
|
||||
await page.mouse.move(x, y)
|
||||
return preview.evaluate(element => element.style.backgroundImage)
|
||||
}).toContain('blob:')
|
||||
const cell = core === 'candidate' ? index : oldIndex
|
||||
await expect(preview).toHaveCSS('background-position', `${-(cell % 4) * 160}px ${-Math.floor(cell / 4) * 90}px`)
|
||||
await expect(preview).toBeVisible()
|
||||
let screenshot
|
||||
await expect.poll(async () => {
|
||||
screenshot = await preview.screenshot()
|
||||
const png = PNG.sync.read(screenshot)
|
||||
expect([png.width, png.height]).toEqual([160, 90])
|
||||
let difference = 0
|
||||
let channels = 0
|
||||
// The progress time tooltip covers the lower part of the preview.
|
||||
// Compare the unobscured interior, excluding rounded border pixels.
|
||||
for (let py = 8; py < 60; py++) {
|
||||
for (let px = 8; px < 152; px++) {
|
||||
const actual = (py * png.width + px) * 4
|
||||
const expected = ((Math.floor(cell / 4) * 90 + py) * sheetPng.width + cell % 4 * 160 + px) * 4
|
||||
for (let channel = 0; channel < 3; channel++) {
|
||||
difference += Math.abs(png.data[actual + channel] - sheetPng.data[expected + channel])
|
||||
channels++
|
||||
}
|
||||
}
|
||||
}
|
||||
return difference / channels
|
||||
}).toBeLessThanOrEqual(3)
|
||||
observed.push({ requestedIndex: index, displayedIndex: cell })
|
||||
await testInfo.attach(`sheet-${generation}-cell-${index}`, { contentType: 'image/png', body: screenshot })
|
||||
}
|
||||
const beforeDestroy = await page.evaluate(() => window.revokedThumbnailUrls.slice())
|
||||
await page.evaluate(() => window.art.destroy(true))
|
||||
expect(await page.evaluate(() => window.revokedThumbnailUrls)).toEqual(beforeDestroy)
|
||||
expect(await page.evaluate(() => window.tool.video.isConnected)).toBe(true)
|
||||
generations.push({ ...sheet, observed })
|
||||
}
|
||||
expect(generations[0].url).not.toBe(generations[1].url)
|
||||
const cleanup = await page.evaluate(() => {
|
||||
window.tool.destroy()
|
||||
return { created: window.createdThumbnailUrls, revoked: window.revokedThumbnailUrls, videoConnected: window.tool.video.isConnected, players: window.Artplayer.instances.length, errors: window.toolErrors }
|
||||
})
|
||||
expect(cleanup.revoked.filter(url => url === '')).toHaveLength(core === 'published' ? 2 : 0)
|
||||
expect([...cleanup.created].sort()).toEqual(cleanup.revoked.filter(url => url !== '').sort())
|
||||
expect(cleanup).toMatchObject({ videoConnected: false, players: 0, errors: [] })
|
||||
await testInfo.attach('thumbnail-core-results', { contentType: 'application/json', body: JSON.stringify({ core, implementation: implementation.name, generations, cleanup, scope: 'Native local file extraction, real hover and screenshot pixels on two generations; historical core defects asserted separately; no physical device claim' }) })
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user