ogplayer 1.2.1 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Control glyphs — the EXACT vector paths from the Android SDK's
3
- * `og_ic_*.xml` drawables (24×24 viewport, stroked, round caps/joins), so
2
+ * Control glyphs — the SDK's vector paths (24×24 viewport, stroked, round
3
+ * caps/joins), so
4
4
  * the three platforms render identical iconography. `filled` paths use fill
5
5
  * instead of stroke (play/pause/volume body).
6
6
  */
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Keyboard shortcuts for `<og-player>` — the map from `KeyboardEvent.key` to
3
+ * a player action, kept DOM-free so the resolution is unit-testable.
4
+ * Desktop keyboards only; TV remotes are a separate concern and are not
5
+ * wired through here.
6
+ *
7
+ * The default map is the one viewers already know from the big video sites:
8
+ * Space/K play-pause, ←/→ and J/L seek by the player's seek increment,
9
+ * ↑/↓ volume, M mute, F fullscreen, C subtitles, 0–9 jump to 0–90 % (VOD),
10
+ * Home/End start/end (live edge on live), Esc leaves fullscreen.
11
+ */
12
+ export type OGKeyAction = "playPause" | "seekBackward" | "seekForward" | "volumeUp" | "volumeDown" | "toggleMute" | "toggleFullscreen" | "exitFullscreen" | "toggleSubtitles" | "seekToStart" | "seekToEnd" | "seekToPercent";
13
+ /** Per-key overrides merged over {@link DEFAULT_KEYMAP}: `null` removes a
14
+ * key, an action adds or remaps one. Keys are `KeyboardEvent.key` values;
15
+ * single characters are matched case-insensitively. */
16
+ export type OGKeymap = Partial<Record<string, OGKeyAction | null>>;
17
+ export declare const DEFAULT_KEYMAP: Readonly<Record<string, OGKeyAction>>;
18
+ /** Single characters compare case-insensitively ("M" and "m" are one key);
19
+ * named keys ("ArrowLeft", "Home") are used as they come. */
20
+ export declare function normalizeKey(key: string): string;
21
+ /** The effective map: defaults, then the host's overrides on top. Never
22
+ * mutates {@link DEFAULT_KEYMAP}. */
23
+ export declare function mergeKeymap(overrides?: OGKeymap): Record<string, OGKeyAction>;
24
+ export interface KeyLike {
25
+ key: string;
26
+ ctrlKey?: boolean;
27
+ metaKey?: boolean;
28
+ altKey?: boolean;
29
+ }
30
+ export interface ResolvedKey {
31
+ action: OGKeyAction;
32
+ /** 0–9 for `seekToPercent` (the digit key that was pressed). */
33
+ digit?: number;
34
+ }
35
+ /**
36
+ * Which action, if any, a key press means under `keymap`. Returns `null` for
37
+ * keys that are not ours — including every modifier chord (Ctrl/Cmd/Alt),
38
+ * which stays with the browser and the page. `seekToPercent` only resolves
39
+ * from a digit key, because the digit is the target.
40
+ */
41
+ export declare function resolveKeyAction(e: KeyLike, keymap: Record<string, OGKeyAction>): ResolvedKey | null;
@@ -1,15 +1,16 @@
1
1
  import type { OGPlayer } from "../core/player.js";
2
2
  import type { OGPlayerError } from "../core/types.js";
3
3
  import { type OGControlColors, type OGControlDimens } from "./tokens.js";
4
+ import { type OGKeymap } from "./keymap.js";
4
5
  /** A host-supplied icon button rendered left of the (future) cast position —
5
- * icon-only, max 8, part of the chrome (mirrors Android/iOS `CustomAction`). */
6
+ * icon-only, max 8, part of the chrome (. */
6
7
  export interface CustomAction {
7
8
  /** Inline SVG markup (24×24 recommended); rendered with the chrome tint. */
8
9
  svg: string;
9
10
  accessibilityLabel?: string;
10
11
  onClick: () => void;
11
12
  }
12
- /** Per-control visibility + behavior — Android's `OGUiConfig` counterpart. */
13
+ /** Per-control visibility + behavior. */
13
14
  export interface OGUIConfig {
14
15
  showProgressBar: boolean;
15
16
  showTimeLabels: boolean;
@@ -101,16 +102,28 @@ export interface OGUIConfig {
101
102
  /** Extra inline CSS for the card (same contract as `titleStyle`), e.g.
102
103
  * "background:#F6C445E6;color:#131313;font-family:Georgia,serif". */
103
104
  upNextStyle?: string;
105
+ /** Keyboard shortcuts while the player has focus (default true): Space/K
106
+ * play-pause, ←/→ and J/L seek by the seek increment, ↑/↓ volume, M mute,
107
+ * F fullscreen, C subtitles on/off, 0–9 jump to 0–90 % (VOD), Home/End
108
+ * start/end (live edge on live), Esc leaves fullscreen. Seek keys obey
109
+ * the live rules and stay inert during ads. `false` = the element handles
110
+ * no keys at all (not even Space) — the host owns the keyboard. */
111
+ keyboardShortcuts: boolean;
112
+ /** Per-key overrides merged over the default map: `{ m: null }` removes
113
+ * mute, `{ p: "playPause" }` adds a key, `{ ArrowUp: "seekForward" }`
114
+ * remaps one. Keys are KeyboardEvent.key values; letters are
115
+ * case-insensitive. Unmapped keys pass through to the page. */
116
+ keymap?: OGKeymap;
104
117
  }
105
118
  export declare const defaultUIConfig: OGUIConfig;
106
119
  /** Every control flag off — headless chrome in one call (mobile parity:
107
- * `hideAllControls()`). Title/ratings stay, exactly like Android/iOS. */
120
+ * `hideAllControls()`). Title/ratings stay,. */
108
121
  export declare function hidingAllControls(overrides?: Partial<OGUIConfig>): Partial<OGUIConfig>;
109
122
  /**
110
123
  * `<og-player>` — the OGPlayer UI as a framework-agnostic custom element
111
124
  * (works in plain HTML, React, Vue, Angular alike). Attach an `OGPlayer`
112
125
  * engine via the `player` property; overlays (watermarks, logos) go into the
113
- * nine named slots (`slot="top-end"` …), mirroring the Android/iOS
126
+ * nine named slots (`slot="top-end"` …),
114
127
  * `OverlaySlot` system including the clearance choreography.
115
128
  */
116
129
  export declare class OGPlayerElement extends HTMLElement {
@@ -119,6 +132,8 @@ export declare class OGPlayerElement extends HTMLElement {
119
132
  private root;
120
133
  private controlsVisible;
121
134
  private hideTimer;
135
+ /** Whether the current ad's provider draws its own layer over the video (IMA). */
136
+ private currentAdRendersUi;
122
137
  /** Where the last deliberate tap-to-hide happened; gates hover-raise. */
123
138
  private hidePoint;
124
139
  /** Pointer type of the most recent pointerdown on the stage; "" until one lands. */
@@ -143,6 +158,8 @@ export declare class OGPlayerElement extends HTMLElement {
143
158
  constructor();
144
159
  get player(): OGPlayer | null;
145
160
  set player(p: OGPlayer | null);
161
+ /** Subtitle track the C key switched off, restored on the next press. */
162
+ private lastTextTrackId;
146
163
  get config(): OGUIConfig;
147
164
  set config(c: Partial<OGUIConfig>);
148
165
  connectedCallback(): void;
@@ -171,7 +188,7 @@ export declare class OGPlayerElement extends HTMLElement {
171
188
  private maybeShowOnceOverlays;
172
189
  private ratingNode;
173
190
  /** While the rating row is shown, the top-end button row drops below it
174
- * and top-row overlays clear both — the Android/iOS choreography. */
191
+ * and top-row overlays clear both. */
175
192
  private setRatingRow;
176
193
  private applyOverlayInsets;
177
194
  private showControls;
@@ -188,8 +205,9 @@ export declare class OGPlayerElement extends HTMLElement {
188
205
  private paintAdCues;
189
206
  private syncPeriodic;
190
207
  /** Break-mode UI: the SDK yields the chrome to the ad layer and draws its
191
- * own yellow bar + AD chip + centered transport (mobile parity — IMA
192
- * renders its own skip/clickthrough on top of its layer). */
208
+ * own yellow bar + play/pause + AD chip (mobile parity — IMA renders its own
209
+ * skip/clickthrough on top of its layer). Nothing sits over a playing ad:
210
+ * the bar button is the transport for the whole break. */
193
211
  private syncAdUi;
194
212
  private syncWatermark;
195
213
  /** Same markup as the template's `.watermark` — used when the node was removed from the open shadow root. */
@@ -202,6 +220,11 @@ export declare class OGPlayerElement extends HTMLElement {
202
220
  * a "starts in fullscreen" flow calls this from its start button. */
203
221
  enterFullscreen(): Promise<void>;
204
222
  exitFullscreen(): void;
223
+ /** One keyboard shortcut → one player action. Seek keys follow the live
224
+ * rules (nothing on edge-locked LIVE, window-bound on LIVE_DVR, End = the
225
+ * live edge) and stay inert during ads; volume, mute and fullscreen work
226
+ * everywhere. Actions that change what the viewer sees raise the chrome. */
227
+ private runKeyAction;
205
228
  private toggleFullscreen;
206
229
  private detach;
207
230
  }
@@ -2,8 +2,7 @@ import { type OGVerticalFeedConfig, type OGVerticalFeedItem } from "../core/vert
2
2
  import type { OGPlayerError } from "../core/types.js";
3
3
  /**
4
4
  * `<og-vertical-feed>` — a swipeable, full-screen vertical video feed built
5
- * on the OGPlayer engine; the web counterpart of the Android/iOS
6
- * `OGVerticalFeedView`, with the same names and semantics. A separate
5
+ * on the OGPlayer engine. A separate
7
6
  * surface from `<og-player>` on purpose: portrait-only, no fullscreen or
8
7
  * rotation API, its own minimal chrome.
9
8
  *
@@ -1,7 +1,5 @@
1
1
  /**
2
- * Design tokens — Android's `OGControlColors` / `OGControlDimens`,
3
- * token-for-token (dp → px at CSS-pixel scale, which is the same unit
4
- * philosophy the Android/iOS SDKs use).
2
+ * Design tokens — colours and dimensions in CSS pixels.
5
3
  */
6
4
  export interface OGControlColors {
7
5
  foreground: string;
@@ -47,5 +45,5 @@ export interface OGControlDimens {
47
45
  adCueMarkerSize: number;
48
46
  }
49
47
  export declare const embeddedDimens: OGControlDimens;
50
- /** Fullscreen step-up (Android `forFullscreen()`). */
48
+ /** Fullscreen step-up. */
51
49
  export declare const fullscreenDimens: OGControlDimens;
@@ -8,8 +8,7 @@
8
8
  * throw on the missing node and take every other overlay down with it, and
9
9
  * (2) while the player is unlicensed the mark is re-created on the next sync,
10
10
  * so a removal lasts only until the next player event — the same standing as
11
- * Android/iOS, where the mark is a composable / SwiftUI view with no
12
- * addressable instance to remove. Tampering with the mark is a terms-of-use
11
+ * native views, where the mark has no addressable instance to remove. Tampering with the mark is a terms-of-use
13
12
  * matter either way (terms §3); this keeps the SDK's own behaviour consistent.
14
13
  */
15
14
  export interface WatermarkHost {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ogplayer",
3
- "version": "1.2.1",
3
+ "version": "1.3.1",
4
4
  "description": "OGPlayer video player for the browser — an <og-player> web component with HLS, DRM (Widevine, PlayReady, FairPlay), Google IMA ads, playlists and themeable controls.",
5
5
  "type": "module",
6
6
  "main": "./dist/ogplayer.js",