@rixl/media-core 1.0.2 → 1.1.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.
- package/README.md +74 -84
- package/dist/chunks/B-QvSqjj.js +1 -0
- package/dist/chunks/B2DDE32u.js +1 -0
- package/dist/chunks/DMkwQjgA.js +1 -0
- package/dist/index.d.ts +1906 -82
- package/dist/index.js +6 -73
- package/package.json +13 -6
- package/dist/api/analytics.d.ts +0 -16
- package/dist/api/analytics.js +0 -227
- package/dist/api/feed.js +0 -52
- package/dist/api/heatmap.d.ts +0 -6
- package/dist/api/heatmap.js +0 -28
- package/dist/api/hot-segments.d.ts +0 -7
- package/dist/api/hot-segments.js +0 -20
- package/dist/api/image.js +0 -11
- package/dist/api/rixl-client.d.ts +0 -3
- package/dist/api/rixl-client.js +0 -14
- package/dist/api/upload.d.ts +0 -76
- package/dist/api/upload.js +0 -150
- package/dist/api/video.js +0 -11
- package/dist/lib/analytics-builders.d.ts +0 -59
- package/dist/lib/analytics-builders.js +0 -88
- package/dist/lib/analytics-initialize.d.ts +0 -1
- package/dist/lib/analytics-initialize.js +0 -59
- package/dist/lib/analytics-utils.d.ts +0 -43
- package/dist/lib/analytics-utils.js +0 -85
- package/dist/lib/analytics-wire.js +0 -153
- package/dist/lib/buffer-progress.d.ts +0 -20
- package/dist/lib/buffer-progress.js +0 -37
- package/dist/lib/caption-styles.d.ts +0 -20
- package/dist/lib/caption-styles.js +0 -56
- package/dist/lib/caption-utils.d.ts +0 -80
- package/dist/lib/caption-utils.js +0 -111
- package/dist/lib/chapter-utils.d.ts +0 -102
- package/dist/lib/chapter-utils.js +0 -147
- package/dist/lib/click-disambiguation.d.ts +0 -44
- package/dist/lib/click-disambiguation.js +0 -80
- package/dist/lib/click-outside.d.ts +0 -68
- package/dist/lib/click-outside.js +0 -64
- package/dist/lib/colors.d.ts +0 -6
- package/dist/lib/colors.js +0 -16
- package/dist/lib/content-analytics.d.ts +0 -27
- package/dist/lib/content-analytics.js +0 -38
- package/dist/lib/environment-effects.d.ts +0 -89
- package/dist/lib/environment-effects.js +0 -139
- package/dist/lib/feed-autoscroll.d.ts +0 -10
- package/dist/lib/feed-autoscroll.js +0 -13
- package/dist/lib/feed-container-height.d.ts +0 -7
- package/dist/lib/feed-container-height.js +0 -11
- package/dist/lib/feed-description-overflow.d.ts +0 -1
- package/dist/lib/feed-description-overflow.js +0 -9
- package/dist/lib/feed-dwell.d.ts +0 -2
- package/dist/lib/feed-dwell.js +0 -8
- package/dist/lib/feed-loop.d.ts +0 -10
- package/dist/lib/feed-loop.js +0 -21
- package/dist/lib/feed-scroll.d.ts +0 -11
- package/dist/lib/feed-scroll.js +0 -19
- package/dist/lib/feed-transforms.d.ts +0 -5
- package/dist/lib/feed-transforms.js +0 -30
- package/dist/lib/filter-undefined.js +0 -11
- package/dist/lib/fullscreen-utils.d.ts +0 -1
- package/dist/lib/fullscreen-utils.js +0 -7
- package/dist/lib/hls-buffer-flush.js +0 -46
- package/dist/lib/hls-error-recovery.d.ts +0 -35
- package/dist/lib/hls-error-recovery.js +0 -75
- package/dist/lib/hls-event-handlers.js +0 -61
- package/dist/lib/hls-loader.js +0 -23
- package/dist/lib/hls-setup.d.ts +0 -72
- package/dist/lib/hls-setup.js +0 -144
- package/dist/lib/hls-utils.d.ts +0 -31
- package/dist/lib/hls-utils.js +0 -34
- package/dist/lib/image-render.d.ts +0 -29
- package/dist/lib/image-render.js +0 -63
- package/dist/lib/keyboard-config.d.ts +0 -66
- package/dist/lib/keyboard-config.js +0 -127
- package/dist/lib/keyboard-utils.d.ts +0 -4
- package/dist/lib/keyboard-utils.js +0 -11
- package/dist/lib/lifecycle-effects.d.ts +0 -67
- package/dist/lib/lifecycle-effects.js +0 -78
- package/dist/lib/loading-debounce.d.ts +0 -26
- package/dist/lib/loading-debounce.js +0 -38
- package/dist/lib/numbers.d.ts +0 -6
- package/dist/lib/numbers.js +0 -36
- package/dist/lib/pip-utils.d.ts +0 -16
- package/dist/lib/pip-utils.js +0 -32
- package/dist/lib/playback-handlers.d.ts +0 -33
- package/dist/lib/playback-handlers.js +0 -51
- package/dist/lib/playback-slider.d.ts +0 -23
- package/dist/lib/playback-slider.js +0 -24
- package/dist/lib/player-labels.d.ts +0 -23
- package/dist/lib/player-labels.js +0 -132
- package/dist/lib/player-menu-labels.d.ts +0 -80
- package/dist/lib/player-menu-labels.js +0 -829
- package/dist/lib/player-ui-actions.d.ts +0 -10
- package/dist/lib/player-ui-actions.js +0 -58
- package/dist/lib/progress-fraction.d.ts +0 -11
- package/dist/lib/progress-fraction.js +0 -20
- package/dist/lib/progress-persist.d.ts +0 -28
- package/dist/lib/progress-persist.js +0 -54
- package/dist/lib/segment-analytics.d.ts +0 -20
- package/dist/lib/segment-analytics.js +0 -29
- package/dist/lib/subtitle-logic.d.ts +0 -31
- package/dist/lib/subtitle-logic.js +0 -75
- package/dist/lib/subtitle-utils.d.ts +0 -16
- package/dist/lib/subtitle-utils.js +0 -37
- package/dist/lib/time.d.ts +0 -1
- package/dist/lib/time.js +0 -17
- package/dist/lib/track-persistence.d.ts +0 -4
- package/dist/lib/track-persistence.js +0 -35
- package/dist/lib/video-preload-config.d.ts +0 -34
- package/dist/lib/video-preload-config.js +0 -41
- package/dist/lib/video-spinner.d.ts +0 -25
- package/dist/lib/video-spinner.js +0 -35
- package/dist/lib/video-stats.d.ts +0 -28
- package/dist/lib/video-stats.js +0 -44
- package/dist/lib/volume-utils.d.ts +0 -59
- package/dist/lib/volume-utils.js +0 -55
- package/dist/progressbar.d.ts +0 -10
- package/dist/progressbar.js +0 -125
- package/dist/store/analytics-context-store.d.ts +0 -4
- package/dist/store/analytics-context-store.js +0 -13
- package/dist/store/analytics-device-store.d.ts +0 -8
- package/dist/store/analytics-device-store.js +0 -44
- package/dist/store/analytics-session-store.d.ts +0 -8
- package/dist/store/analytics-session-store.js +0 -40
- package/dist/store/analytics-store.d.ts +0 -30
- package/dist/store/analytics-store.js +0 -88
- package/dist/store/controls-store.d.ts +0 -16
- package/dist/store/controls-store.js +0 -53
- package/dist/store/feed-cache-store.d.ts +0 -24
- package/dist/store/feed-cache-store.js +0 -165
- package/dist/store/feed-interaction-store.d.ts +0 -17
- package/dist/store/feed-interaction-store.js +0 -32
- package/dist/store/feed-store.d.ts +0 -16
- package/dist/store/feed-store.js +0 -38
- package/dist/store/generic-store.js +0 -24
- package/dist/store/image-store.d.ts +0 -2
- package/dist/store/image-store.js +0 -8
- package/dist/store/player-container-element-store.d.ts +0 -10
- package/dist/store/player-container-element-store.js +0 -38
- package/dist/store/player-global-actions.js +0 -53
- package/dist/store/player-media-element-store.d.ts +0 -10
- package/dist/store/player-media-element-store.js +0 -38
- package/dist/store/player-store-actions.js +0 -197
- package/dist/store/player-store.d.ts +0 -94
- package/dist/store/player-store.js +0 -127
- package/dist/store/player-track-actions.js +0 -44
- package/dist/store/postStore.d.ts +0 -20
- package/dist/store/postStore.js +0 -112
- package/dist/store/settings/constants.d.ts +0 -15
- package/dist/store/settings/constants.js +0 -47
- package/dist/store/settings/defaults.d.ts +0 -2
- package/dist/store/settings/defaults.js +0 -24
- package/dist/store/settings/storage.d.ts +0 -3
- package/dist/store/settings/storage.js +0 -28
- package/dist/store/settings/store.d.ts +0 -32
- package/dist/store/settings/store.js +0 -59
- package/dist/store/settings/types.d.ts +0 -27
- package/dist/store/settings/validation.d.ts +0 -7
- package/dist/store/settings/validation.js +0 -55
- package/dist/store/settings-menu-store.d.ts +0 -19
- package/dist/store/settings-menu-store.js +0 -30
- package/dist/store/video-store.d.ts +0 -2
- package/dist/store/video-store.js +0 -8
- package/dist/types/analytics.d.ts +0 -113
- package/dist/types/feed.d.ts +0 -21
- package/dist/types/file.d.ts +0 -12
- package/dist/types/heatmap.d.ts +0 -5
- package/dist/types/hot-segments.d.ts +0 -9
- package/dist/types/image.d.ts +0 -9
- package/dist/types/uuid.d.ts +0 -1
- package/dist/types/video.d.ts +0 -22
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import { filterUndefined } from "./filter-undefined.js";
|
|
2
|
-
|
|
3
|
-
// src/lib/analytics-wire.ts
|
|
4
|
-
function msToProtoDuration(ms) {
|
|
5
|
-
const seconds = ms / 1e3;
|
|
6
|
-
return `${Number(seconds.toFixed(3))}s`;
|
|
7
|
-
}
|
|
8
|
-
function toWireMediaType(type) {
|
|
9
|
-
return type === "video" ? "MEDIA_TYPE_VIDEO" : "MEDIA_TYPE_IMAGE";
|
|
10
|
-
}
|
|
11
|
-
function toWireSegment(segment) {
|
|
12
|
-
return {
|
|
13
|
-
start_ms: msToProtoDuration(segment.start_ms),
|
|
14
|
-
end_ms: msToProtoDuration(segment.end_ms),
|
|
15
|
-
speed: segment.speed
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
function toWireContentView(event, { context, deviceId }) {
|
|
19
|
-
const wire = {
|
|
20
|
-
content_id: event.content_id,
|
|
21
|
-
content_type: toWireMediaType(event.content_type),
|
|
22
|
-
view_type: event.view_type,
|
|
23
|
-
watch_duration_ms: msToProtoDuration(event.watch_duration_ms),
|
|
24
|
-
page: event.page,
|
|
25
|
-
device_id: event.device_id ?? deviceId,
|
|
26
|
-
...filterUndefined({
|
|
27
|
-
feed_id: event.feed_id,
|
|
28
|
-
post_id: event.post_id,
|
|
29
|
-
video_position_ms: event.video_position_ms !== void 0 ? msToProtoDuration(event.video_position_ms) : void 0,
|
|
30
|
-
video_total_duration_ms: event.video_total_duration_ms !== void 0 ? msToProtoDuration(event.video_total_duration_ms) : void 0,
|
|
31
|
-
segments: event.segments !== void 0 && event.segments.length > 0 ? event.segments.map(toWireSegment) : void 0
|
|
32
|
-
})
|
|
33
|
-
};
|
|
34
|
-
const country = event.country ?? context.country;
|
|
35
|
-
if (country !== void 0) wire.country = country;
|
|
36
|
-
return wire;
|
|
37
|
-
}
|
|
38
|
-
function toWireEngagement(event, { context, sessionId }) {
|
|
39
|
-
const wire = {
|
|
40
|
-
engagement_type: event.engagement_type,
|
|
41
|
-
session_id: event.session_id ?? sessionId,
|
|
42
|
-
...filterUndefined({
|
|
43
|
-
resource_type: event.resource_type,
|
|
44
|
-
resource_id: event.resource_id,
|
|
45
|
-
page: event.page,
|
|
46
|
-
comment_text: event.comment_text,
|
|
47
|
-
share_platform: event.share_platform
|
|
48
|
-
})
|
|
49
|
-
};
|
|
50
|
-
const country = event.country ?? context.country;
|
|
51
|
-
if (country !== void 0) wire.country = country;
|
|
52
|
-
const deviceType = event.device_type ?? context.device;
|
|
53
|
-
if (deviceType !== void 0) wire.device_type = deviceType;
|
|
54
|
-
return wire;
|
|
55
|
-
}
|
|
56
|
-
function toWireInteraction(event, { context, sessionId }) {
|
|
57
|
-
const wire = {
|
|
58
|
-
interaction_type: event.interaction_type,
|
|
59
|
-
session_id: event.session_id ?? sessionId,
|
|
60
|
-
...filterUndefined({
|
|
61
|
-
element_type: event.element_type,
|
|
62
|
-
element_id: event.element_id,
|
|
63
|
-
page: event.page,
|
|
64
|
-
page_url: event.page_url,
|
|
65
|
-
scroll_depth: event.scroll_depth,
|
|
66
|
-
search_query: event.search_query,
|
|
67
|
-
click_x: event.click_x,
|
|
68
|
-
click_y: event.click_y,
|
|
69
|
-
resource_id: event.resource_id,
|
|
70
|
-
resource_type: event.resource_type,
|
|
71
|
-
feed_id: event.feed_id,
|
|
72
|
-
post_id: event.post_id,
|
|
73
|
-
content_id: event.content_id,
|
|
74
|
-
device_type: event.device_type,
|
|
75
|
-
browser: event.browser
|
|
76
|
-
})
|
|
77
|
-
};
|
|
78
|
-
const deviceType = wire.device_type ?? context.device;
|
|
79
|
-
if (deviceType !== void 0) wire.device_type = deviceType;
|
|
80
|
-
const browser = wire.browser ?? context.browser;
|
|
81
|
-
if (browser !== void 0) wire.browser = browser;
|
|
82
|
-
return wire;
|
|
83
|
-
}
|
|
84
|
-
function toWireError(event, { context, sessionId }) {
|
|
85
|
-
const wire = {
|
|
86
|
-
error_type: event.error_type,
|
|
87
|
-
session_id: event.session_id ?? sessionId,
|
|
88
|
-
...filterUndefined({
|
|
89
|
-
error_code: event.error_code,
|
|
90
|
-
error_message: event.error_message,
|
|
91
|
-
stack_trace: event.stack_trace,
|
|
92
|
-
resource_type: event.resource_type,
|
|
93
|
-
resource_id: event.resource_id,
|
|
94
|
-
endpoint: event.endpoint,
|
|
95
|
-
device_type: event.device_type,
|
|
96
|
-
browser: event.browser,
|
|
97
|
-
os: event.os
|
|
98
|
-
})
|
|
99
|
-
};
|
|
100
|
-
const deviceType = wire.device_type ?? context.device;
|
|
101
|
-
if (deviceType !== void 0) wire.device_type = deviceType;
|
|
102
|
-
const browser = wire.browser ?? context.browser;
|
|
103
|
-
if (browser !== void 0) wire.browser = browser;
|
|
104
|
-
const os = wire.os ?? context.os;
|
|
105
|
-
if (os !== void 0) wire.os = os;
|
|
106
|
-
return wire;
|
|
107
|
-
}
|
|
108
|
-
function toWireSessionStart(event) {
|
|
109
|
-
return { ...filterUndefined({
|
|
110
|
-
utm_source: event.utm_source,
|
|
111
|
-
utm_campaign: event.utm_campaign,
|
|
112
|
-
browser: event.browser,
|
|
113
|
-
language: event.language,
|
|
114
|
-
screen_resolution: event.screen_resolution,
|
|
115
|
-
platform: event.platform,
|
|
116
|
-
tg_platform: event.tg_platform,
|
|
117
|
-
tg_version: event.tg_version,
|
|
118
|
-
timezone: event.timezone,
|
|
119
|
-
timezone_offset: event.timezone_offset,
|
|
120
|
-
color_depth: event.color_depth,
|
|
121
|
-
touch_support: event.touch_support,
|
|
122
|
-
country: event.country,
|
|
123
|
-
user_id: event.user_id
|
|
124
|
-
}) };
|
|
125
|
-
}
|
|
126
|
-
function applyTimestamp(wire, timestamp) {
|
|
127
|
-
if (timestamp !== void 0) wire.timestamp = (/* @__PURE__ */ new Date(timestamp * 1e3)).toISOString();
|
|
128
|
-
}
|
|
129
|
-
function toWireEvent(event, options) {
|
|
130
|
-
let wire;
|
|
131
|
-
switch (event._type) {
|
|
132
|
-
case "content_views":
|
|
133
|
-
wire = { content_view: toWireContentView(event, options) };
|
|
134
|
-
break;
|
|
135
|
-
case "engagement":
|
|
136
|
-
wire = { engagement: toWireEngagement(event, options) };
|
|
137
|
-
break;
|
|
138
|
-
case "interaction":
|
|
139
|
-
wire = { interaction: toWireInteraction(event, options) };
|
|
140
|
-
break;
|
|
141
|
-
case "error":
|
|
142
|
-
wire = { error: toWireError(event, options) };
|
|
143
|
-
break;
|
|
144
|
-
case "session_start":
|
|
145
|
-
wire = { session_start: toWireSessionStart(event) };
|
|
146
|
-
break;
|
|
147
|
-
default: throw new Error(`Unsupported analytics event type: ${event._type}`);
|
|
148
|
-
}
|
|
149
|
-
applyTimestamp(wire, event.timestamp);
|
|
150
|
-
return wire;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export { msToProtoDuration, toWireEvent, toWireSegment };
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure buffer-progress computations extracted from useBufferProgress.
|
|
3
|
-
* Operate on plain TimeRanges + numbers, not HTMLVideoElement, so they
|
|
4
|
-
* are framework-agnostic and trivially testable.
|
|
5
|
-
*/
|
|
6
|
-
export interface BufferRange {
|
|
7
|
-
start: number;
|
|
8
|
-
end: number;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Convert a TimeRanges into normalized 0-100 percentage ranges.
|
|
12
|
-
* Returns [] when duration is zero/invalid or timeRanges is missing.
|
|
13
|
-
*/
|
|
14
|
-
export declare const computeBufferRanges: (timeRanges: TimeRanges | null | undefined, duration: number) => BufferRange[];
|
|
15
|
-
/**
|
|
16
|
-
* How much buffer (as a 0-100 percentage) is loaded ahead of the
|
|
17
|
-
* current playback position. Considers only ranges that cover the
|
|
18
|
-
* current position; takes the maximum contiguous lookahead.
|
|
19
|
-
*/
|
|
20
|
-
export declare const computeBufferedAhead: (ranges: BufferRange[], currentTime: number, duration: number) => number;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
// src/lib/buffer-progress.ts
|
|
2
|
-
/**
|
|
3
|
-
* Convert a TimeRanges into normalized 0-100 percentage ranges.
|
|
4
|
-
* Returns [] when duration is zero/invalid or timeRanges is missing.
|
|
5
|
-
*/
|
|
6
|
-
const computeBufferRanges = (timeRanges, duration) => {
|
|
7
|
-
if (!timeRanges || !duration || !Number.isFinite(duration) || duration <= 0) return [];
|
|
8
|
-
const ranges = [];
|
|
9
|
-
try {
|
|
10
|
-
for (let i = 0; i < timeRanges.length; i++) {
|
|
11
|
-
const end = timeRanges.end(i) / duration * 100;
|
|
12
|
-
ranges.push({
|
|
13
|
-
start: 0,
|
|
14
|
-
end: Math.min(100, end)
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
} catch {
|
|
18
|
-
return [];
|
|
19
|
-
}
|
|
20
|
-
return ranges;
|
|
21
|
-
};
|
|
22
|
-
/**
|
|
23
|
-
* How much buffer (as a 0-100 percentage) is loaded ahead of the
|
|
24
|
-
* current playback position. Considers only ranges that cover the
|
|
25
|
-
* current position; takes the maximum contiguous lookahead.
|
|
26
|
-
*/
|
|
27
|
-
const computeBufferedAhead = (ranges, currentTime, duration) => {
|
|
28
|
-
if (!ranges.length || !duration || !Number.isFinite(duration) || duration <= 0) return 0;
|
|
29
|
-
const currentPercent = currentTime / duration * 100;
|
|
30
|
-
let bufferAhead = 0;
|
|
31
|
-
ranges.forEach((range) => {
|
|
32
|
-
if (range.end > currentPercent && range.start <= currentPercent + .1) bufferAhead = Math.max(bufferAhead, range.end - currentPercent);
|
|
33
|
-
});
|
|
34
|
-
return bufferAhead;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export { computeBufferRanges, computeBufferedAhead };
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Position } from "./caption-utils.js";
|
|
2
|
-
import { CSSProperties } from "./image-render.js";
|
|
3
|
-
import { SettingsState } from "../store/settings/types.js";
|
|
4
|
-
export interface SmartCaptionPositionParams {
|
|
5
|
-
position: Position;
|
|
6
|
-
isDragging: boolean;
|
|
7
|
-
controlsVisible: boolean;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Caption window placement: percent-based within the safe zone, snapping to
|
|
11
|
-
* the bottom (above the controls bar when visible) once dragged past the
|
|
12
|
-
* snap threshold. Single source for the React hook and the Lit overlay.
|
|
13
|
-
*/
|
|
14
|
-
export declare function getSmartCaptionPosition({ position, isDragging, controlsVisible }: SmartCaptionPositionParams): CSSProperties;
|
|
15
|
-
export type CaptionWindowSettings = Pick<SettingsState, "captionWindowColor" | "captionWindowOpacity">;
|
|
16
|
-
/** Caption window box: width from the safe viewport, settings-driven background, drag cursor. */
|
|
17
|
-
export declare function getCaptionWindowStyle(settings: CaptionWindowSettings, safeViewportWidth: number, isDragging: boolean): CSSProperties;
|
|
18
|
-
export type CaptionTextSettings = Pick<SettingsState, "captionFontFamily" | "captionFontColor" | "captionFontOpacity" | "captionBGColor" | "captionBGOpacity" | "captionCharacterEdgeStyle">;
|
|
19
|
-
/** Caption text styling from the user's caption settings (font, colors, edge-style shadow). */
|
|
20
|
-
export declare function getCaptionTextStyle(settings: CaptionTextSettings, fontSize: number): CSSProperties;
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { BOTTOM_OFFSET_CONTROLS_HIDDEN, BOTTOM_OFFSET_CONTROLS_VISIBLE, CAPTION_WIDTH_RATIO, getTextShadowValue, shouldPinToBottom } from "./caption-utils.js";
|
|
2
|
-
import { hexToRGBAString } from "./colors.js";
|
|
3
|
-
import { FONT_FAMILIES } from "../store/settings/constants.js";
|
|
4
|
-
|
|
5
|
-
// src/lib/caption-styles.ts
|
|
6
|
-
/**
|
|
7
|
-
* Caption window placement: percent-based within the safe zone, snapping to
|
|
8
|
-
* the bottom (above the controls bar when visible) once dragged past the
|
|
9
|
-
* snap threshold. Single source for the React hook and the Lit overlay.
|
|
10
|
-
*/
|
|
11
|
-
function getSmartCaptionPosition({ position, isDragging, controlsVisible }) {
|
|
12
|
-
const transition = isDragging ? "none" : "all 300ms ease";
|
|
13
|
-
if (shouldPinToBottom(position.y, isDragging)) {
|
|
14
|
-
const bottomOffset = controlsVisible ? 80 : 24;
|
|
15
|
-
return {
|
|
16
|
-
left: `${position.x}%`,
|
|
17
|
-
top: `calc(100% - ${bottomOffset}px)`,
|
|
18
|
-
bottom: "auto",
|
|
19
|
-
transform: "translateY(-100%)",
|
|
20
|
-
transition
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
return {
|
|
24
|
-
left: `${position.x}%`,
|
|
25
|
-
top: `${position.y}%`,
|
|
26
|
-
bottom: "auto",
|
|
27
|
-
transform: "translateY(0)",
|
|
28
|
-
transition
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
/** Caption window box: width from the safe viewport, settings-driven background, drag cursor. */
|
|
32
|
-
function getCaptionWindowStyle(settings, safeViewportWidth, isDragging) {
|
|
33
|
-
const width = (safeViewportWidth || 300) * CAPTION_WIDTH_RATIO;
|
|
34
|
-
const backgroundColor = settings.captionWindowOpacity > 0 ? hexToRGBAString(settings.captionWindowColor, settings.captionWindowOpacity) : "transparent";
|
|
35
|
-
return {
|
|
36
|
-
width: `${width}px`,
|
|
37
|
-
backgroundColor,
|
|
38
|
-
cursor: isDragging ? "grabbing" : "grab",
|
|
39
|
-
touchAction: "none"
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
/** Caption text styling from the user's caption settings (font, colors, edge-style shadow). */
|
|
43
|
-
function getCaptionTextStyle(settings, fontSize) {
|
|
44
|
-
const fontFamily = FONT_FAMILIES[settings.captionFontFamily] || FONT_FAMILIES.proportional_sans;
|
|
45
|
-
return {
|
|
46
|
-
fontSize: `${fontSize}px`,
|
|
47
|
-
fontFamily,
|
|
48
|
-
color: hexToRGBAString(settings.captionFontColor, settings.captionFontOpacity),
|
|
49
|
-
backgroundColor: settings.captionBGOpacity > 0 ? hexToRGBAString(settings.captionBGColor, settings.captionBGOpacity) : "transparent",
|
|
50
|
-
textShadow: getTextShadowValue(settings.captionCharacterEdgeStyle, fontSize),
|
|
51
|
-
userSelect: "none",
|
|
52
|
-
touchAction: "none"
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export { getCaptionTextStyle, getCaptionWindowStyle, getSmartCaptionPosition };
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
export type Viewport = {
|
|
2
|
-
width: number;
|
|
3
|
-
height: number;
|
|
4
|
-
};
|
|
5
|
-
export interface Position {
|
|
6
|
-
x: number;
|
|
7
|
-
y: number;
|
|
8
|
-
}
|
|
9
|
-
export declare const DEFAULT_FONT_SIZE = 16;
|
|
10
|
-
export declare const MIN_FONT_SIZE = 12;
|
|
11
|
-
export declare const MAX_FONT_SIZE = 120;
|
|
12
|
-
export declare const FONT_SIZE_RATIO = .03;
|
|
13
|
-
export declare const FONT_SIZE_VIEWPORT_RATIO = .07;
|
|
14
|
-
export declare const DEFAULT_CAPTION_FONT_SIZE = 100;
|
|
15
|
-
export declare const SAFE_ZONE_MARGIN = 8;
|
|
16
|
-
export declare const CAPTION_WIDTH_RATIO = .6;
|
|
17
|
-
/**
|
|
18
|
-
* Smart caption positioning constants
|
|
19
|
-
*/
|
|
20
|
-
export declare const BOTTOM_SNAP_THRESHOLD = 85;
|
|
21
|
-
export declare const BOTTOM_OFFSET_CONTROLS_VISIBLE = 80;
|
|
22
|
-
export declare const BOTTOM_OFFSET_CONTROLS_HIDDEN = 24;
|
|
23
|
-
/**
|
|
24
|
-
* Calculates the font size based on the viewport width and user preference.
|
|
25
|
-
* Uses a logarithmic scale
|
|
26
|
-
* 100% -> 1.0x
|
|
27
|
-
* 200% -> 1.5x
|
|
28
|
-
* 400% -> 2.0x
|
|
29
|
-
*/
|
|
30
|
-
export declare const calculateFontSize: (viewport: Viewport, captionFontSize: number) => number;
|
|
31
|
-
/**
|
|
32
|
-
* Constrains a percentage-based position to be within safe bounds (0-100).
|
|
33
|
-
* Assumes the input position is already in percentages.
|
|
34
|
-
*/
|
|
35
|
-
export declare const constrainPercentagePosition: (position: Position, elementWidthRatio?: number) => Position;
|
|
36
|
-
/**
|
|
37
|
-
* Converts pixel coordinates to percentage coordinates relative to the viewport.
|
|
38
|
-
*/
|
|
39
|
-
export declare const pixelsToPercentage: (x: number, y: number, viewport: Viewport) => Position;
|
|
40
|
-
/**
|
|
41
|
-
* Calculate pointer offsets for caption dragging
|
|
42
|
-
*/
|
|
43
|
-
export interface PointerOffsets {
|
|
44
|
-
clickXRelative: number;
|
|
45
|
-
clickYRelative: number;
|
|
46
|
-
currentVisualX: number;
|
|
47
|
-
currentVisualY: number;
|
|
48
|
-
}
|
|
49
|
-
export interface GetPointerOffsetsOptions {
|
|
50
|
-
containerRect: DOMRect;
|
|
51
|
-
elementRect: DOMRect;
|
|
52
|
-
clientX: number;
|
|
53
|
-
clientY: number;
|
|
54
|
-
}
|
|
55
|
-
export declare function getPointerOffsets(options: GetPointerOffsetsOptions): PointerOffsets;
|
|
56
|
-
/**
|
|
57
|
-
* Calculate new drag position from delta
|
|
58
|
-
*/
|
|
59
|
-
export interface CalculateDragPositionOptions {
|
|
60
|
-
startPositionPixels: Position;
|
|
61
|
-
startX: number;
|
|
62
|
-
startY: number;
|
|
63
|
-
currentXRelative: number;
|
|
64
|
-
currentYRelative: number;
|
|
65
|
-
viewport: Viewport;
|
|
66
|
-
}
|
|
67
|
-
export declare function calculateDragPosition(options: CalculateDragPositionOptions): Position;
|
|
68
|
-
/**
|
|
69
|
-
* Calculate safe zone viewport dimensions
|
|
70
|
-
*/
|
|
71
|
-
export declare function calculateSafeViewport(viewport: Viewport): Viewport;
|
|
72
|
-
/**
|
|
73
|
-
* Determine if caption should be pinned to bottom
|
|
74
|
-
*/
|
|
75
|
-
export declare function shouldPinToBottom(positionY: number, isDragging: boolean): boolean;
|
|
76
|
-
/**
|
|
77
|
-
* CSS text-shadow value for a caption character edge style.
|
|
78
|
-
* Shadow size scales with font size so edges stay proportional.
|
|
79
|
-
*/
|
|
80
|
-
export declare function getTextShadowValue(edgeStyle: string, fontSize: number): string;
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { clamp } from "./numbers.js";
|
|
2
|
-
|
|
3
|
-
// src/lib/caption-utils.ts
|
|
4
|
-
const DEFAULT_FONT_SIZE = 16;
|
|
5
|
-
const MIN_FONT_SIZE = 12;
|
|
6
|
-
const MAX_FONT_SIZE = 120;
|
|
7
|
-
const FONT_SIZE_RATIO = .03;
|
|
8
|
-
const FONT_SIZE_VIEWPORT_RATIO = .07;
|
|
9
|
-
const DEFAULT_CAPTION_FONT_SIZE = 100;
|
|
10
|
-
const SAFE_ZONE_MARGIN = 8;
|
|
11
|
-
const CAPTION_WIDTH_RATIO = .6;
|
|
12
|
-
/**
|
|
13
|
-
* Smart caption positioning constants
|
|
14
|
-
*/
|
|
15
|
-
const BOTTOM_SNAP_THRESHOLD = 85;
|
|
16
|
-
const BOTTOM_OFFSET_CONTROLS_VISIBLE = 80;
|
|
17
|
-
const BOTTOM_OFFSET_CONTROLS_HIDDEN = 24;
|
|
18
|
-
/**
|
|
19
|
-
* Calculates the font size based on the viewport width and user preference.
|
|
20
|
-
* Uses a logarithmic scale
|
|
21
|
-
* 100% -> 1.0x
|
|
22
|
-
* 200% -> 1.5x
|
|
23
|
-
* 400% -> 2.0x
|
|
24
|
-
*/
|
|
25
|
-
const calculateFontSize = (viewport, captionFontSize) => {
|
|
26
|
-
if (!viewport.width) return 16;
|
|
27
|
-
const baseSize = viewport.width * FONT_SIZE_RATIO;
|
|
28
|
-
const ratio = Math.max(.1, captionFontSize / 100);
|
|
29
|
-
const scaledSize = baseSize * (1 + .5 * Math.log2(ratio));
|
|
30
|
-
const maxSize = Math.min(120, viewport.width * FONT_SIZE_VIEWPORT_RATIO);
|
|
31
|
-
return clamp(scaledSize, 12, maxSize);
|
|
32
|
-
};
|
|
33
|
-
/**
|
|
34
|
-
* Constrains a percentage-based position to be within safe bounds (0-100).
|
|
35
|
-
* Assumes the input position is already in percentages.
|
|
36
|
-
*/
|
|
37
|
-
const constrainPercentagePosition = (position, elementWidthRatio = .6) => {
|
|
38
|
-
const widthPercentage = elementWidthRatio * 100;
|
|
39
|
-
const maxX = Math.max(0, 100 - widthPercentage);
|
|
40
|
-
return {
|
|
41
|
-
x: clamp(position.x, 0, maxX),
|
|
42
|
-
y: clamp(position.y, 0, 100)
|
|
43
|
-
};
|
|
44
|
-
};
|
|
45
|
-
/**
|
|
46
|
-
* Converts pixel coordinates to percentage coordinates relative to the viewport.
|
|
47
|
-
*/
|
|
48
|
-
const pixelsToPercentage = (x, y, viewport) => {
|
|
49
|
-
if (!viewport.width || !viewport.height) return {
|
|
50
|
-
x: 0,
|
|
51
|
-
y: 0
|
|
52
|
-
};
|
|
53
|
-
return {
|
|
54
|
-
x: x / viewport.width * 100,
|
|
55
|
-
y: y / viewport.height * 100
|
|
56
|
-
};
|
|
57
|
-
};
|
|
58
|
-
function getPointerOffsets(options) {
|
|
59
|
-
const { containerRect, elementRect, clientX, clientY } = options;
|
|
60
|
-
return {
|
|
61
|
-
clickXRelative: clientX - containerRect.left,
|
|
62
|
-
clickYRelative: clientY - containerRect.top,
|
|
63
|
-
currentVisualX: elementRect.left - containerRect.left,
|
|
64
|
-
currentVisualY: elementRect.top - containerRect.top
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
function calculateDragPosition(options) {
|
|
68
|
-
const { startPositionPixels, startX, startY, currentXRelative, currentYRelative, viewport } = options;
|
|
69
|
-
const deltaX = currentXRelative - startX;
|
|
70
|
-
const deltaY = currentYRelative - startY;
|
|
71
|
-
const newPixelX = startPositionPixels.x + deltaX;
|
|
72
|
-
const newPixelY = startPositionPixels.y + deltaY;
|
|
73
|
-
const raw = pixelsToPercentage(newPixelX, newPixelY, viewport);
|
|
74
|
-
return constrainPercentagePosition(raw, CAPTION_WIDTH_RATIO);
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Calculate safe zone viewport dimensions
|
|
78
|
-
*/
|
|
79
|
-
function calculateSafeViewport(viewport) {
|
|
80
|
-
return {
|
|
81
|
-
width: viewport.width - 16,
|
|
82
|
-
height: viewport.height - 16
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Determine if caption should be pinned to bottom
|
|
87
|
-
*/
|
|
88
|
-
function shouldPinToBottom(positionY, isDragging) {
|
|
89
|
-
return !isDragging && positionY > 85;
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* CSS text-shadow value for a caption character edge style.
|
|
93
|
-
* Shadow size scales with font size so edges stay proportional.
|
|
94
|
-
*/
|
|
95
|
-
function getTextShadowValue(edgeStyle, fontSize) {
|
|
96
|
-
const shadowSize = Math.max(1, fontSize * .06);
|
|
97
|
-
switch (edgeStyle) {
|
|
98
|
-
case "drop-shadow": return `${shadowSize}px ${shadowSize}px ${shadowSize}px rgba(0, 0, 0, 0.75)`;
|
|
99
|
-
case "raised": return `${shadowSize}px ${shadowSize}px 0 rgba(0, 0, 0, 0.5), -${shadowSize * .5}px -${shadowSize * .5}px 0 rgba(255, 255, 255, 0.25)`;
|
|
100
|
-
case "depressed": return `-${shadowSize}px -${shadowSize}px 0 rgba(0, 0, 0, 0.5), ${shadowSize * .5}px ${shadowSize * .5}px 0 rgba(255, 255, 255, 0.25)`;
|
|
101
|
-
case "outline": return `
|
|
102
|
-
-${shadowSize}px -${shadowSize}px 0 #000,
|
|
103
|
-
${shadowSize}px -${shadowSize}px 0 #000,
|
|
104
|
-
-${shadowSize}px ${shadowSize}px 0 #000,
|
|
105
|
-
${shadowSize}px ${shadowSize}px 0 #000
|
|
106
|
-
`;
|
|
107
|
-
default: return "none";
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export { BOTTOM_OFFSET_CONTROLS_HIDDEN, BOTTOM_OFFSET_CONTROLS_VISIBLE, BOTTOM_SNAP_THRESHOLD, CAPTION_WIDTH_RATIO, DEFAULT_CAPTION_FONT_SIZE, DEFAULT_FONT_SIZE, FONT_SIZE_RATIO, FONT_SIZE_VIEWPORT_RATIO, MAX_FONT_SIZE, MIN_FONT_SIZE, SAFE_ZONE_MARGIN, calculateDragPosition, calculateFontSize, calculateSafeViewport, constrainPercentagePosition, getPointerOffsets, getTextShadowValue, pixelsToPercentage, shouldPinToBottom };
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { Chapter } from "../types/video.js";
|
|
2
|
-
import { BufferRange } from "./buffer-progress.js";
|
|
3
|
-
/**
|
|
4
|
-
* Chapter with calculated end time and duration
|
|
5
|
-
*/
|
|
6
|
-
export interface ChapterWithEnd extends Chapter {
|
|
7
|
-
endTime: number;
|
|
8
|
-
durationSec: number;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Check if a single chapter is within the video duration
|
|
12
|
-
* @param chapter - The chapter to validate
|
|
13
|
-
* @param videoDuration - The total video duration in seconds
|
|
14
|
-
* @param tolerance - Tolerance in seconds for rounding errors (default: 1)
|
|
15
|
-
* @returns Whether the chapter is within valid bounds
|
|
16
|
-
*/
|
|
17
|
-
export declare function isChapterWithinDuration(chapter: Chapter, videoDuration: number, tolerance?: number): boolean;
|
|
18
|
-
/**
|
|
19
|
-
* Validate chapters for use with chaptered progress bar
|
|
20
|
-
* Returns false if:
|
|
21
|
-
* - chapters is undefined or empty
|
|
22
|
-
* - less than 2 chapters (need multiple for chaptered bar)
|
|
23
|
-
* - any chapter exceeds video duration
|
|
24
|
-
*
|
|
25
|
-
* @param chapters - Array of chapters to validate
|
|
26
|
-
* @param videoDuration - The total video duration in seconds
|
|
27
|
-
* @param tolerance - Tolerance in seconds for rounding errors (default: 1)
|
|
28
|
-
* @returns Whether chapters are valid for chaptered progress bar
|
|
29
|
-
*/
|
|
30
|
-
export declare function validateChapters(chapters: Chapter[] | undefined, videoDuration: number, tolerance?: number): boolean;
|
|
31
|
-
/**
|
|
32
|
-
* Calculate chapter end times based on next chapter start or video duration
|
|
33
|
-
*/
|
|
34
|
-
export declare function calculateChaptersWithEnd(chapters: Chapter[], duration: number): ChapterWithEnd[];
|
|
35
|
-
/**
|
|
36
|
-
* Slice heatmap data for a specific chapter based on its time range
|
|
37
|
-
*/
|
|
38
|
-
interface HeatmapSliceParams {
|
|
39
|
-
heatmapData: number[];
|
|
40
|
-
chapterStartTime: number;
|
|
41
|
-
chapterEndTime: number;
|
|
42
|
-
videoDuration: number;
|
|
43
|
-
}
|
|
44
|
-
export declare function sliceHeatmapData({ heatmapData, chapterStartTime, chapterEndTime, videoDuration }: HeatmapSliceParams): number[];
|
|
45
|
-
/**
|
|
46
|
-
* Calculate all heatmap slices for chapters
|
|
47
|
-
*/
|
|
48
|
-
export declare function calculateHeatmapSlices(heatmapData: number[] | null, chapters: ChapterWithEnd[], duration: number): number[][];
|
|
49
|
-
/**
|
|
50
|
-
* Calculate global max value from heatmap data for consistent normalization
|
|
51
|
-
*/
|
|
52
|
-
export declare function calculateGlobalMax(heatmapData: number[] | null): number;
|
|
53
|
-
/**
|
|
54
|
-
* Calculate progress percentage within a chapter segment
|
|
55
|
-
* @returns 0-100 percentage
|
|
56
|
-
*/
|
|
57
|
-
export declare function calculateSegmentProgress(currentPosition: number, chapterStart: number, chapterEnd: number): number;
|
|
58
|
-
/**
|
|
59
|
-
* Calculate buffer ranges within a chapter segment
|
|
60
|
-
* Converts global buffer ranges to segment-local 0-100 scale
|
|
61
|
-
*/
|
|
62
|
-
type SegmentBufferParams = {
|
|
63
|
-
globalBufferRanges: BufferRange[];
|
|
64
|
-
chapterStart: number;
|
|
65
|
-
chapterEnd: number;
|
|
66
|
-
videoDuration: number;
|
|
67
|
-
};
|
|
68
|
-
export declare function calculateSegmentBufferRanges({ globalBufferRanges, chapterStart, chapterEnd, videoDuration }: SegmentBufferParams): BufferRange[];
|
|
69
|
-
/**
|
|
70
|
-
* Calculate flex grow ratio for a chapter based on its duration
|
|
71
|
-
*/
|
|
72
|
-
export declare function calculateFlexGrow(chapterDuration: number, videoDuration: number): number;
|
|
73
|
-
/**
|
|
74
|
-
* Determine current playback position
|
|
75
|
-
* Uses progress during drag for real-time feedback, currentTime otherwise
|
|
76
|
-
*/
|
|
77
|
-
interface CurrentPositionParams {
|
|
78
|
-
isDragging: boolean;
|
|
79
|
-
progress: number;
|
|
80
|
-
duration: number;
|
|
81
|
-
currentTime: number;
|
|
82
|
-
}
|
|
83
|
-
export declare function getCurrentPosition({ isDragging, progress, duration, currentTime }: CurrentPositionParams): number;
|
|
84
|
-
/**
|
|
85
|
-
* Find which segment is hovered based on mouse X position
|
|
86
|
-
* @param segments - Array of segment DOM elements
|
|
87
|
-
* @param mouseX - Mouse X coordinate (clientX)
|
|
88
|
-
* @returns Index of hovered segment, or null if none
|
|
89
|
-
*/
|
|
90
|
-
export declare function findHoveredSegmentIndex(segments: Array<HTMLDivElement | null>, mouseX: number): number | null;
|
|
91
|
-
/**
|
|
92
|
-
* Start time of the first chapter after the current position, or null when
|
|
93
|
-
* already in the last chapter. Mirrors React useChapterNavigation.
|
|
94
|
-
*/
|
|
95
|
-
export declare function getNextChapterStart(chapters: Chapter[] | undefined, currentTime: number): number | null;
|
|
96
|
-
/**
|
|
97
|
-
* Target for "previous chapter": restart the current chapter when more than
|
|
98
|
-
* 3s in (or when it is the first), otherwise jump to the previous chapter.
|
|
99
|
-
* Mirrors React useChapterNavigation.
|
|
100
|
-
*/
|
|
101
|
-
export declare function getPrevChapterTarget(chapters: Chapter[] | undefined, currentTime: number): number | null;
|
|
102
|
-
export {};
|