videospeed 控制器可见性契约:分层状态机、渲染优先级与 TLA+ 形式化验证 前端音视频【免费下载链接】videospeedHTML5 video speed controller (for Google Chrome)项目地址https://gitcode.com/gh_mirrors/vi/videospeed点击查看免费下载videospeedHTML5 video speed controller for Google Chrome的控制器可见性Controller Visibility不是一个布尔值或一个粘性 CSS 类而是一套由用户意图、媒体状态、站点自动隐藏、瞬时反馈、不可用媒体、外部宿主 CSS 与控制器生命周期七类独立输入共同作用的分层状态机且每一项都有显式的优先级。本文以仓库文档 docs/controller-visibility.md 为主线结合 src/core/controller-visibility.js 的纯策略实现、specs/ControllerVisibility.tla 的 TLA 模型以及四层可执行验证完整讲解可见性契约的状态定义、渲染优先级公式、用户切换转换、反馈与生命周期语义并给出面向开发者的变更检查清单。读完本文你将掌握一次显示动作如何从渲染态采样出正确意图广播与定向动作为何能各自独立过渡以及如何为一次可见性改动补齐模型、差分测试与 Chrome 矩阵的完整方法论。为什么可见性不能是一个布尔值控制器可见性契约的出发点是一条硬性设计原则可见性是分层状态机它不是一个布尔值也绝不能被实现成单个粘性 CSS 类。原因在于同一个控制器在某一时刻的可见/隐藏由彼此独立的输入共同决定用户通过键盘或弹窗发出的显式覆盖意图AUTO/SHOW/HIDE来自startHidden设置、媒体可见性与音频控制器启用的自动层站点自有的自动隐藏如 YouTube 的.ytp-autohide临时性的视频反馈与持久性的音频反馈无媒体源no-source与外部宿主隐藏host CSS定向的与文档级广播的显示动作定时器到期与控制器销毁release。如果只用一个布尔位或一个类去承载这些语义任何一个输入的变化都会踩踏其它输入用户显式SHOW会被站点自动隐藏悄悄夺走、过期的反馈类又可能让一个已被显式HIDE的控制器重新浮出水面。契约要求这些输入以明确的优先级组合成最终的渲染结果且每个输入只影响自己所属的渲染层。生产策略的唯一实现是 src/core/controller-visibility.js其机器可检查的模型是 specs/ControllerVisibility.tlaDOM 与 CSS 一致性由 tests/integration/controller-visibility-differential.test.js 与 tests/e2e/display-toggle.e2e.js 双重把关。契约范围Scope契约明确覆盖以下内容每个控制器恰好一个显式覆盖AUTO、SHOW或HIDE来自startHidden、媒体可见性与音频控制器启用的自动可见性站点自有自动隐藏如 YouTube 的.ytp-autohide临时视频反馈有界定时器与持久音频反馈无定时器无媒体源隐藏与外部宿主隐藏定向与文档级广播显示动作定时器到期与控制器销毁。同时契约划定了明确的边界显式SHOW/HIDE意图在其控制器整个生命周期内保持有效跨刷新持久化、跨 frame 同步、以及与页面脚本共享所有权都不属于本契约。文档特别强调任何把这些能力加进来的改动都会改变并发模型必须同时重新审视 TLA 状态空间与 DOM 适配器。状态模型九类状态的分层契约把可见性状态抽象为一张对照表每个概念在纯模型、TLA 模型与 DOM/适配器三层各有对应概念纯模型TLADOM/适配器生命周期attachedattached[i]video.vsc、已连接的vsc-controller、StateManager成员关系用户意图overrideoverrideMode[i]无data-vsc-visibility属性或show/hide自动层automaticHiddenautomaticHidden[i]宿主上的vsc-hidden类不可用媒体noSourcenoSource[i]vsc-nosource类站点自动隐藏siteAutohidesiteAutohide[i]按域名作用域的宿主 CSS观察页面自有状态如.ytp-autohide外部宿主隐藏hostHiddenhostHidden[i]vsc-controller上计算出的display/visibility反馈flashflashMode[i]vsc-show类加可选的flashTimer偏好设置startHiddenstartHidden实时设置值供未来的自动显示与反馈事件查阅媒体种类mediaTypeAudioControllers媒体标签名startHidden初始化自动层但不是永久硬隐藏位startHidden只负责初始化自动层它本身不是一个永久性的硬隐藏位。对startHidden的实时修改是非追溯的non-retroactive它不会立即重写一个已存在的控制器它不会取消正在进行的反馈flash它只阻止未来的自动显示AUTOMATIC_SHOW与反馈请求直到被重新关闭。这一点在 src/core/controller-visibility.js 中由allowsFlash与step的AUTOMATIC_SHOW分支落实allowsFlash只在startHidden为 false 时放行反馈请求而SET_START_HIDDEN事件只改startHidden字段本身不触碰automaticHidden与flash见step中SET_START_HIDDEN分支。单元测试tests/unit/core/controller-visibility.test.js中的 treats startHidden changes as non-retroactive but blocks automatic show 与 blocks new flash under startHidden or explicit HIDE without retroactive cancellation 两条用例正是对这一语义的逐点校验。normalizeOverride抵御伪造值纯模型对覆盖值做了防御性归一化normalizeOverride只承认三个声明值auto/show/hide把缺失的或页面伪造的任何其它值一律归为AUTO。注释明确指出这样做的原因避免产生第四个状态因为 CSS 层与形式化模型都不认识它。单元测试 normalizes only the three declared override values 覆盖了undefined与forged两种输入。渲染优先级唯一真相公式对于任一控制器i最终渲染结果由如下递推公式决定这也是 src/core/controller-visibility.js 中isVisible的逐行对应实现hardHidden !attached || hostHidden || noSource || override HIDE forcedShown override SHOW || flash ! NONE visible !hardHidden (forcedShown || (!automaticHidden !siteAutohide))等效的优先级表述从高到低external host hide / no source / FORCE_HIDE FORCE_SHOW / flash automatic hide / site autohide几个必须注意的语义细节SHOW故意压过vsc-hidden与站点自动隐藏但它不能复活一个已销毁的控制器、让不可用媒体变得可用、或击败页面 CSS 对 light-DOM 宿主本身的隐藏。HIDE可以击败一个过期残留的 flash 类——这是hardHidden中override HIDE置于最高层的原因。opacity 被排除在离散可见性谓词之外因为淡入淡出fade会途经 0而采样需要离散状态。因此采样只看宿主与 shadow 控制器上计算后的display与visibility。单元测试通过枚举全部有效状态断言isVisible与独立预期的expectedVisible完全一致详见后文可执行验证层次。差分集成测试则把hostHidden映射为controller.div.style.display none、把siteAutohide映射为容器上的ytp-autohide类在真实 DOM 适配器上验证同一套优先级见 tests/integration/controller-visibility-differential.test.js 的pipelineState与createWorld。CSS 侧的落地shadow 选择器与 light-DOM 宿主规则优先级在 CSS 层由两套机制共同实现shadow 内部规则src/ui/shadow-dom.js 中createShadowDOM内嵌的样式:host(.vsc-hidden) #controller→ 隐藏自动层不扰动任何显式覆盖:host([data-vsc-visibilityshow]) #controller, :host(.vsc-show) #controller→ 强制显示显式 SHOW 与瞬时反馈同权压过startHidden、媒体可见性与站点自动隐藏:host([data-vsc-visibilityhide]) #controller, :host(.vsc-nosource) #controller→ 最终隐藏flash 与用户 SHOW 都不得揭示它们。light-DOM 宿主规则站点自动隐藏等由域名作用域的宿主 CSS 处理基础规则位于 src/styles/inject.cssmanifest 加载、先于任何 JS站点特定覆盖位于 src/styles/controller-css-defaults.js。YouTube 站点自动隐藏的落地方式文档明确指出 YouTube 站点自动隐藏的实现原则用域名作用域的 light-DOM CSS 作用在vsc-controller上而不是把页面状态复制进扩展自有的 DOM更不依赖已被废弃的:host-context()选择器。src/styles/controller-css-defaults.js 中对应的生产规则为:root[style*--vsc-domain: youtube.com] .ytp-autohide vsc-controller:not([data-vsc-visibilityshow]):not(.vsc-show) { visibility: hidden !important; opacity: 0 !important; transition: opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1); }其设计要点该规则用:root[style*--vsc-domain: DOMAIN]语法按域名包裹注入阶段会把匹配域名的选择器剥掉规则无条件生效不匹配的则替换为永不匹配的[data-vsc-never]--vsc-domain变量并不会真正设置在:root上模块头部注释。这样 YouTube 的.ytp-autohide祖先类永远不会让非 YouTube 站点为无关逻辑付出匹配成本。宿主规则通过:not([data-vsc-visibilityshow]):not(.vsc-show)排除显式SHOW与vsc-show反馈之后才应用visibility: hidden而 shadow 内部选择器继续维护自动隐藏、显式HIDE与 no-source 的最终优先级youtube-nocookie.com 有一份完全相同的复制块。文档特别警告改动任何一侧light-DOM 规则或 shadow 规则都必须跑 Chrome 矩阵测试而不是只跑单元测试——jsdom 无法复现宿主与 shadow 的完整级联。用户切换转换先采样渲染态再决定意图显示动作display action的核心规则是在取消反馈之前先采样当前渲染态。转换关系如下当前覆盖动作前渲染态下一个覆盖动作后反馈AUTO可见HIDEnoneAUTO隐藏SHOWnoneSHOW任意HIDEnoneHIDE任意SHOWnone行为语义是第一次按键反对用户当前所见AUTO 站点自动隐藏 flash时控制器实际上可见动作必须选择HIDE而非SHOW——这解释了采样先于清除vsc-show为何对第一次按键至关重要。后续按键在持久的SHOW/HIDE意图间交替这样播放器自动隐藏无法静默夺回控制权AUTO只在控制器被销毁并创建全新控制器时才会重新进入——显式意图一旦离开AUTO在 release 之前不能返回这正是 TLA 属性ManualIntentPersistsUntilRelease的表述。在纯模型中nextOverride是一个纯函数对SHOW返回HIDE对HIDE返回SHOW对AUTO则要求传入renderedVisible布尔值否则抛TypeError返回其反相。单元测试 maps toggle %s with rendered%s to %s 六种组合逐一验证了该映射。广播动作与定向动作各自独立采样键盘与弹窗的显示动作是文档级广播作用于每一个已挂载控制器每个控制器独立采样自己的第一次转换。因此同一次广播可能在一个可见控制器上产生HIDE、在另一个隐藏控制器上产生SHOW后续广播则让这些控制器以相反的相位交替。定向targeted适配器动作只影响它所属的控制器已销毁的控制器不在广播范围之内也不可能被一个过期定时器改写。E2E 测试在双视频 fixturedual-video.html上验证了这一语义预置 video1 为automaticHidden flash渲染可见、video2 为automaticHidden渲染隐藏一次v键广播后 video1 变HIDE、video2 变SHOW第二次广播则各自反向交替见 tests/e2e/display-toggle.e2e.js 的 broadcast independently flips rendered state 与 broadcast independently alternates persistent intent随后用executeAction(display, 0, media, null)验证定向动作只改变目标控制器以及 release 后控制器不再参与广播。适配器侧如何采样src/core/action-handler.js 的toggleControllerVisibility演示了采样时序先normalizeOverride读取宿主data-vsc-visibility当覆盖为AUTO时才调用isControllerVisible采样因为只有从AUTO出发才需要渲染态参数isControllerVisible分别getComputedStyle宿主与 shadow 内层控制器要求二者的display ! none且visibility ! hidden才判定可见。这样站点 CSS 始终是自动隐藏真相的唯一来源而 opacity 因淡入淡出经过零值被刻意排除。自动、反馈与生命周期转换契约对这些转换逐一规定了精确语义自动隐藏只设置automaticHidden不改覆盖、不动反馈自动显示仅当startHidden为 false 时才清除automaticHidden媒体源、站点自动隐藏、外部宿主变化只影响各自所属的渲染层视频反馈被允许时进入TIMED_ARMED定时器推进进入TIMED_DUE到期返回NONE。重复请求会重新武装定时器re-arm音频反馈被允许时进入PERSISTENT没有定时器一直持续到一次显示切换或 releasestartHidden与显式HIDE会阻止新的反馈请求已存在的反馈在之后实时把startHidden改为 true 时仍然存活并正常到期Release 对抽象控制器原子地清除覆盖与反馈、取消生产环境的定时器、移除StateManager成员关系、断开video.vsc、并移除宿主。Release 对该控制器身份是终结性的此后控制同一媒体的行为属于用当前输入重新初始化的全新控制器。在 src/core/controller-visibility.js 中FLASH_REQUEST分支按mediaType区分视频进TIMED_ARMED音频进PERSISTENTTIMER_TICK只在TIMED_ARMED时推进到TIMED_DUEFLASH_EXPIRE只在TIMED_DUE时回到NONE。assertState则从不变式层面拒绝非法组合音频不能携带定时反馈TIMED_ARMED/TIMED_DUE、视频不能携带PERSISTENT、显式HIDE不能与任何反馈共存、已销毁控制器必须是AUTO且无反馈。单元测试 models timed video flash and persistent audio flash 用视频的三段推进与音频对TIMER_TICK/FLASH_EXPIRE的免疫验证了这条媒体相关语义。形式化模型TLA 双控制器specs/ControllerVisibility.tla 使用两个控制器一个视频、一个音频来建模因为键盘/弹窗显示命令是文档级广播模型必须同时检查局部非干扰与独立的广播转换。模型探索的动作空间包括局部切换、广播切换、自动与环境变化、实时startHidden变化、反馈请求、有界定时器推进、到期与 release。StopTimerRefresh是一个辅助环境动作无论它是否发生安全性检查都成立而它的 false 状态标记了一段不再有视频反馈请求重新武装定时器的后缀——这是让最终清除成为一条显式、非空non-vacuous的活性性质的关键对应属性TimedFlashEventuallyClearsAfterRefreshStops。TLC 检查的属性类型与媒体特定的反馈不变式TypeOK、FlashMatchesMediaType显式HIDE与反馈互斥HideHasNoFlash已销毁控制器的惰性DetachedControllerIsInert、VisibleImpliesAttached定向动作的局部性与广播独立性LocalActionsAreLocal、ToggleOneContract、ToggleAllContract渲染感知的第一次切换与后续显式SHOW/HIDE交替StickyToggleIntentContract环境与设置不干扰用户意图EnvironmentPreservesIntent、StartHiddenSettingIsNonRetroactive意图只通过切换或 release 改变且显式意图在 release 之前不能返回AUTOIntentChangesOnlyByToggleOrRelease、ManualIntentPersistsUntilRelease已武装/已到期的视频定时器阶段的弱公平最终推进ArmedFlashEventuallyAdvances、DueFlashEventuallyHandled对应规格中的WF_vars环境停止重新武装定时器后视频反馈最终清除或 releaseTimedFlashEventuallyClearsAfterRefreshStops。文档还澄清了两类属性的边界HardHideDominates、ForceShowDominatesAutomatic、FlashDominatesAutomatic、AutoLayerIsExact这些硬隐藏/强制显示/反馈/自动层优先级属性都是对派生谓词Visible的一致性引理consistency lemmas——它们让渲染定义可审阅但不是独立的转换安全性证明把定义代入后它们会变成同义反复tautology。真正的独立检查是Chrome 矩阵它验证真实样式表确实精化了该谓词。此外有界定时器建模的是次序与最终推进而不是墙钟毫秒数CSS 选择器、计算样式、DOM 连接、JavaScript 定时器所有权与事件派发都属于适配器关注点刻意放在 TLA 之外验证。可执行验证层次四层答案不同的问题契约给出了四个验证层次各自回答不同的问题npm run test:tlc穷尽检查双控制器的时态模型。当前配置达到49,152 个不同状态、生成724,800 个状态并检查三条非空的视频定时器活性分支脚本入口 scripts/tlc.mjs。tests/unit/core/controller-visibility.test.js枚举448 个有效局部状态2 种媒体 × 各自合法的 flash 集合 × 2 的 5 次方布尔组合 × 3 覆盖扣除不合法组合与6,720 个状态/事件对对纯 JavaScript 转换策略做穷尽断言。tests/integration/controller-visibility-differential.test.js用同一事件流同时驱动纯模型与真实的ActionHandler/VideoController适配器一个视频控制器 一个真实audio控制器回放局部与广播动作、视频与音频反馈、环境变化、实时设置、到期与 release每个操作后都断言适配器管线状态与纯模型逐字段相等。tests/e2e/display-toggle.e2e.js在真实 Chrome 中检查文档与 shadow 的完整级联对3 overrides × 2 automaticHidden × 2 siteAutohide × 2 flash × 2 noSource × 2 hostHidden 96种渲染组合逐一断言测试在注入的临时样式表上只关闭 transition 以消除过渡时序干扰生产选择器级联本身仍是测试对象随后验证混合双控制器的局部、广播、flash 采样与 release 行为。文档给出的结论是严格的互补关系TLA 跑绿不能证明 CSS 源码顺序正确浏览器矩阵跑绿也不能证明定时器活性或跨所有动作序列的非干扰。两者都是本契约改动的必要条件对应脚本见 package.json 的test:tlc、test:e2e与前置发布链路prerelease。变更检查清单任何可见性改动都必须满足以下六步缺一不可说明哪一条转换或优先级规则发生了变化更新 src/core/controller-visibility.js 及其有界 JavaScript 测试当抽象状态、动作字母表、安全不变式或活性期望变化时更新 specs/ControllerVisibility.tla当 DOM 类、属性、定时器所有权、派发作用域或生命周期映射变化时更新差分适配器测试当选择器、宿主渲染或级联优先级变化时更新 Chrome 矩阵依次运行npm test、npm run test:tlc、npm run build与node tests/e2e/run-e2e.js display。最后还有两条红线式的实现边界不得改写页面自有的html或body来持久化 VSC 状态data-vsc-visibility只允许出现在扩展自有的vsc-controller宿主上站点自有的祖先状态只允许通过计算样式观察核心可见性逻辑绝不能复制站点的自动隐藏状态机——那是站点自己的领域。结语videospeed 的控制器可见性契约演示了一种把显示/隐藏从临时 CSS 修补提升到工程规范的路径以七类独立输入构建分层状态机用一份显式的优先级公式统一纯模型、TLA 与 DOM 适配器三方的可见定义再通过穷举单元测试、差分回放与 Chrome 渲染矩阵从不同侧面互相补足。对于希望在浏览器扩展中可靠实现播放器控制显隐、抵御站点自动隐藏干扰、或为状态机引入形式化验证的开发者本仓库的这份契约文档连同 specs/ControllerVisibility.tla 与 tests/e2e/display-toggle.e2e.js 是一份可以直接参照的完整范本。赞分享前端音视频【免费下载链接】videospeedHTML5 video speed controller (for Google Chrome)项目地址https://gitcode.com/gh_mirrors/vi/videospeed点击查看免费下载相关推荐10分钟上手gotags提升Go开发效率的必备工具10分钟上手gotags提升Go开发效率的必备工具 在Go语言开发过程中快速定位代码定义和理解项目结构是提升开发效率的关键。 gotags 作为一款与cta开发工具终极指南在Windows 7/Vista系统上安装Python 3.8-3.14的完整解决方案终极指南在Windows 7/Vista系统上安装Python 3.8 3.14的完整解决方案 你是否还在为Windows 7或Vista系统上无法安装Pyt操作系统HyperFrames Keyframes 机制全解从关键帧姿势契约到 seek-safe 渲染验证HyperFrames Keyframes 机制全解从关键帧姿势契约到 seek safe 渲染验证 关键帧是 HyperFrames 中可见姿态的契约音视频视频AI 技能上一篇CubeSandbox 自定义模板镜像接入指南为自有镜像注入 envd 并创建 AI Agent 沙箱模板下一篇Kedro HTTP 服务器实战指南通过 REST API 触发管道运行与项目检查创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考