5.6 KiB
Ads implementation and maintenance
Ads is a single preroll attached by artplayerPluginAds(option)(art). The factory and
returned { name, skip, pause, play } are synchronous. Package public declarations are
still scheduled for PKG-ADS-04; do not infer that their current source/type fields are
implemented runtime aliases. Runtime input remains html/video/url plus timing, mute and i18n.
Module boundaries
| File | Responsibility |
|---|---|
| src/index.ts | Public factory, checked legacy constructor capabilities, import-time style injection |
| src/options.ts | Per-attachment defaults and the existing shallow validator schema |
| src/types.ts | Internal options, result and narrow core/DOM dependencies; public types remain separate for now |
| src/countdown.ts | One owned timeout, whole-second counting, pause/resume and terminal cancellation; no core or DOM dependency |
| src/view.ts | Existing HTML/CSS hooks, labels, ad element, mute and fullscreen icon rendering |
| src/resources.ts | Instance-owned core/DOM subscriptions, guarded callbacks and disposal that continues after cleanup failures |
| src/session.ts | Ready/first-play lifecycle, ad readiness, playback requests, completion, destruction and cross-module ownership |
The entry calls options/session. Session composes view/countdown/resources. View receives only a parent, icons, options, three DOM utilities and callbacks, rather than the whole player. Style remains in src/style.less. There are no runtime imports from the ArtPlayer core package; all imports of its declarations are erased. Old cores do not need new lifecycle helpers.
State and ordering
waiting -> active -> ended, with any state able to become destroyed. Ready arms the two
existing first-play signals; only one can initialize. Repeated ready/play/metadata cannot
create another view or timer. The normalized option belongs to this attachment even when a
caller reuses the factory. Emitted options retain their identity and remain live: for example,
changing totalDuration in an ad-click listener affects subsequent ticks.
For video, the element is created without a source. Error and loadedmetadata listeners are installed before assigning src. Metadata starts the timer and requests ad playback. HTML starts immediately. The ad video loops independently from the totalDuration countdown. Public pause/play still control only the countdown; they do not pause/resume the ad video. Native document visibility and the newer core visibility bridge both control that same timer; idempotent resume prevents duplicate timer chains. Initially hidden documents pause counting.
Skip first closes the timer and active subscriptions. For an initialized ad it requests main content playback, pauses the ad, hides the overlay and synchronously emits artplayerPluginAds:skip with the normalized option. This keeps the historical successful ordering. Reentrant destruction prevents subsequent dispatch. Repeated completion is inert. Before initialization, play/pause are inert; skip cancels the pending preroll and emits once without starting main playback or creating DOM. These early-call semantics repair historical exceptions and are covered separately from normal old behavior.
Internally requested play Promises are observed. An ad play rejection warns with the original error and completes the ad like a media load failure. Rejected main-content restoration also warns, while completion remains visible and synchronous. Direct consumer calls to art.play are not wrapped or changed. If an ad play settles after its owner ended/died, its own video is paused again; stale rejections cannot restart content.
Resource ownership
The session owns one countdown, active core/native listeners, a separate destroy subscription, and the overlay. Finishing releases active listeners and pauses video, but keeps the hidden overlay and source/error state available until destroy. Destroy cancels the timer, disposes all owned subscriptions, pauses/releases the ad src via load, and removes the overlay even when the core keeps its HTML. Only an owned template.$ads value is removed. Foreign DOM listeners and caller-owned replacement template references are not removed.
Native DOM listeners are locally owned; the plugin does not mutate the core event registry or depend on new resource APIs. Cleanup guards stale callbacks and handles partial view construction/registration failure. A failure while cleaning one subscription does not stop the remaining cleanup. Root ownership is recorded as soon as it is appended.
Keep all artplayer-plugin-ads class names and the template.$ads hook. The full screen button uses the core fullscreen property; its icons reflect both the initial value and the core fullscreen event. Actual device/native fullscreen acceptance remains part of PKG-ADS-05.
Verification and remaining work
Use pinned Yarn/Node. yarn test:ads covers source/frozen releases and candidate lifecycle
regressions; yarn test:browser test/browser/ads.spec.js covers real local media and old/new
cores. yarn typecheck checks the strict package configuration. yarn build artplayer-plugin-ads
generates main/legacy/ESM through the repository build. Do not hand-edit dist or copied docs assets.
Tests distinguish actual media decoding from injected errors/controlled clocks. Baseline and open release gates live in Ads validation. Public declaration reconciliation, old CommonJS default compatibility, isolated package consumption and demo validation remain PKG-ADS-04/06. Real hidden-page/device behavior and complete media-resource acceptance remain PKG-ADS-05. No claim of compatibility with every historical 4.x core is made.