@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,10 +0,0 @@
|
|
|
1
|
-
import { UUID } from "../types/uuid.js";
|
|
2
|
-
interface PlayerUiActionTargets {
|
|
3
|
-
container?: HTMLDivElement | null;
|
|
4
|
-
video?: HTMLVideoElement | null;
|
|
5
|
-
}
|
|
6
|
-
export declare function showPlayerControls(playerId: UUID): void;
|
|
7
|
-
export declare function hidePlayerControls(playerId: UUID): void;
|
|
8
|
-
export declare function togglePlayerFullscreen(playerId: UUID, overrides?: PlayerUiActionTargets): Promise<void>;
|
|
9
|
-
export declare function togglePlayerPictureInPicture(playerId: UUID, overrides?: PlayerUiActionTargets): Promise<void>;
|
|
10
|
-
export {};
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { isDocumentFullscreen } from "./fullscreen-utils.js";
|
|
2
|
-
import { togglePictureInPicture } from "./pip-utils.js";
|
|
3
|
-
import { controlsStore } from "../store/controls-store.js";
|
|
4
|
-
import { playerContainerElementStore } from "../store/player-container-element-store.js";
|
|
5
|
-
import { playerMediaElementStore } from "../store/player-media-element-store.js";
|
|
6
|
-
import { playerStateStore } from "../store/player-store.js";
|
|
7
|
-
|
|
8
|
-
// src/lib/player-ui-actions.ts
|
|
9
|
-
function getPlayerUiTargets(playerId, overrides) {
|
|
10
|
-
return {
|
|
11
|
-
container: overrides?.container ?? playerContainerElementStore.get(playerId),
|
|
12
|
-
video: overrides?.video ?? playerMediaElementStore.get(playerId)
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
function shouldExitFullscreen(playerId) {
|
|
16
|
-
return playerStateStore.get(playerId).get().isFullscreen || isDocumentFullscreen();
|
|
17
|
-
}
|
|
18
|
-
async function exitPlayerFullscreen(playerId, video) {
|
|
19
|
-
try {
|
|
20
|
-
if (isDocumentFullscreen() && document.exitFullscreen) await document.exitFullscreen();
|
|
21
|
-
else if (video && typeof video.webkitExitFullscreen === "function") video.webkitExitFullscreen();
|
|
22
|
-
else return;
|
|
23
|
-
playerStateStore.setFullscreen(playerId, false);
|
|
24
|
-
} catch {}
|
|
25
|
-
}
|
|
26
|
-
async function enterPlayerFullscreen(playerId, container, video) {
|
|
27
|
-
try {
|
|
28
|
-
if (container?.requestFullscreen) await container.requestFullscreen();
|
|
29
|
-
else if (video?.requestFullscreen) await video.requestFullscreen();
|
|
30
|
-
else if (video && typeof video.webkitEnterFullscreen === "function") video.webkitEnterFullscreen();
|
|
31
|
-
else return;
|
|
32
|
-
playerStateStore.setFullscreen(playerId, true);
|
|
33
|
-
} catch {}
|
|
34
|
-
}
|
|
35
|
-
function showPlayerControls(playerId) {
|
|
36
|
-
controlsStore.setVisible(playerId, true);
|
|
37
|
-
}
|
|
38
|
-
function hidePlayerControls(playerId) {
|
|
39
|
-
controlsStore.hideControls(playerId);
|
|
40
|
-
}
|
|
41
|
-
async function togglePlayerFullscreen(playerId, overrides) {
|
|
42
|
-
const { container, video } = getPlayerUiTargets(playerId, overrides);
|
|
43
|
-
if (!container && !video) return;
|
|
44
|
-
if (shouldExitFullscreen(playerId)) {
|
|
45
|
-
await exitPlayerFullscreen(playerId, video);
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
await enterPlayerFullscreen(playerId, container, video);
|
|
49
|
-
}
|
|
50
|
-
async function togglePlayerPictureInPicture(playerId, overrides) {
|
|
51
|
-
const { video } = getPlayerUiTargets(playerId, overrides);
|
|
52
|
-
if (!video) return;
|
|
53
|
-
const nextPictureInPictureState = !playerStateStore.get(playerId).get().isPictureInPicture;
|
|
54
|
-
await togglePictureInPicture(video);
|
|
55
|
-
playerStateStore.setPictureInPicture(playerId, nextPictureInPictureState);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export { hidePlayerControls, showPlayerControls, togglePlayerFullscreen, togglePlayerPictureInPicture };
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure progress-fraction helper extracted from useProgressBar.
|
|
3
|
-
*
|
|
4
|
-
* Returns a value in [0, 1] representing how far through `duration`
|
|
5
|
-
* `currentTime` is. Defensive against the common edge cases where
|
|
6
|
-
* duration is zero, NaN, or Infinity (e.g. before metadata loads),
|
|
7
|
-
* and against non-finite currentTime values. The previous inline
|
|
8
|
-
* `video.currentTime / video.duration` formula produced NaN in
|
|
9
|
-
* those cases, which leaked into React state.
|
|
10
|
-
*/
|
|
11
|
-
export declare function computeProgressFraction(currentTime: number, duration: number): number;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
// src/lib/progress-fraction.ts
|
|
2
|
-
/**
|
|
3
|
-
* Pure progress-fraction helper extracted from useProgressBar.
|
|
4
|
-
*
|
|
5
|
-
* Returns a value in [0, 1] representing how far through `duration`
|
|
6
|
-
* `currentTime` is. Defensive against the common edge cases where
|
|
7
|
-
* duration is zero, NaN, or Infinity (e.g. before metadata loads),
|
|
8
|
-
* and against non-finite currentTime values. The previous inline
|
|
9
|
-
* `video.currentTime / video.duration` formula produced NaN in
|
|
10
|
-
* those cases, which leaked into React state.
|
|
11
|
-
*/
|
|
12
|
-
function computeProgressFraction(currentTime, duration) {
|
|
13
|
-
if (!Number.isFinite(duration) || duration <= 0) return 0;
|
|
14
|
-
if (!Number.isFinite(currentTime)) return 0;
|
|
15
|
-
if (currentTime <= 0) return 0;
|
|
16
|
-
if (currentTime >= duration) return 1;
|
|
17
|
-
return currentTime / duration;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export { computeProgressFraction };
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Minimum position in seconds to resume from (skip if too close to start)
|
|
3
|
-
*/
|
|
4
|
-
export declare const RESUME_MIN_POSITION_SECONDS = 5;
|
|
5
|
-
/**
|
|
6
|
-
* Minimum remaining duration in seconds to resume (skip if too close to end)
|
|
7
|
-
*/
|
|
8
|
-
export declare const RESUME_MIN_REMAINING_SECONDS = 5;
|
|
9
|
-
/**
|
|
10
|
-
* Interval in milliseconds between progress persistence operations
|
|
11
|
-
*/
|
|
12
|
-
export declare const PERSIST_INTERVAL_MS = 2e3;
|
|
13
|
-
export declare const getPersistedProgress: (videoId: string) => number;
|
|
14
|
-
export declare const persistProgress: (videoId: string, positionMs: number) => void;
|
|
15
|
-
/**
|
|
16
|
-
* Determine if a saved progress position should be used to resume playback
|
|
17
|
-
* @param savedPositionSeconds - The saved position in seconds
|
|
18
|
-
* @param durationSeconds - The total video duration in seconds
|
|
19
|
-
* @returns true if position is valid for resuming (not too close to start or end)
|
|
20
|
-
*/
|
|
21
|
-
export declare function shouldResumeFromPosition(savedPositionSeconds: number, durationSeconds: number): boolean;
|
|
22
|
-
/**
|
|
23
|
-
* Determine if enough time has elapsed to persist progress again
|
|
24
|
-
* @param lastPersistTime - Timestamp of last persist operation (from performance.now())
|
|
25
|
-
* @param currentTime - Current timestamp (from performance.now())
|
|
26
|
-
* @returns true if interval has elapsed
|
|
27
|
-
*/
|
|
28
|
-
export declare function shouldPersistProgress(lastPersistTime: number, currentTime: number): boolean;
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
// src/lib/progress-persist.ts
|
|
2
|
-
const KEY = "videosdk_progress_map";
|
|
3
|
-
/**
|
|
4
|
-
* Minimum position in seconds to resume from (skip if too close to start)
|
|
5
|
-
*/
|
|
6
|
-
const RESUME_MIN_POSITION_SECONDS = 5;
|
|
7
|
-
/**
|
|
8
|
-
* Minimum remaining duration in seconds to resume (skip if too close to end)
|
|
9
|
-
*/
|
|
10
|
-
const RESUME_MIN_REMAINING_SECONDS = 5;
|
|
11
|
-
/**
|
|
12
|
-
* Interval in milliseconds between progress persistence operations
|
|
13
|
-
*/
|
|
14
|
-
const PERSIST_INTERVAL_MS = 2e3;
|
|
15
|
-
const getPersistedProgress = (videoId) => {
|
|
16
|
-
if (typeof window === "undefined") return 0;
|
|
17
|
-
try {
|
|
18
|
-
const raw = window.localStorage.getItem(KEY);
|
|
19
|
-
if (!raw) return 0;
|
|
20
|
-
const map = JSON.parse(raw);
|
|
21
|
-
return Math.max(0, Math.floor(map[videoId] ?? 0));
|
|
22
|
-
} catch {
|
|
23
|
-
return 0;
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
const persistProgress = (videoId, positionMs) => {
|
|
27
|
-
if (typeof window === "undefined") return;
|
|
28
|
-
try {
|
|
29
|
-
const raw = window.localStorage.getItem(KEY);
|
|
30
|
-
const map = raw ? JSON.parse(raw) : {};
|
|
31
|
-
map[videoId] = Math.max(0, Math.floor(positionMs));
|
|
32
|
-
window.localStorage.setItem(KEY, JSON.stringify(map));
|
|
33
|
-
} catch {}
|
|
34
|
-
};
|
|
35
|
-
/**
|
|
36
|
-
* Determine if a saved progress position should be used to resume playback
|
|
37
|
-
* @param savedPositionSeconds - The saved position in seconds
|
|
38
|
-
* @param durationSeconds - The total video duration in seconds
|
|
39
|
-
* @returns true if position is valid for resuming (not too close to start or end)
|
|
40
|
-
*/
|
|
41
|
-
function shouldResumeFromPosition(savedPositionSeconds, durationSeconds) {
|
|
42
|
-
return savedPositionSeconds > 5 && savedPositionSeconds < durationSeconds - 5;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Determine if enough time has elapsed to persist progress again
|
|
46
|
-
* @param lastPersistTime - Timestamp of last persist operation (from performance.now())
|
|
47
|
-
* @param currentTime - Current timestamp (from performance.now())
|
|
48
|
-
* @returns true if interval has elapsed
|
|
49
|
-
*/
|
|
50
|
-
function shouldPersistProgress(lastPersistTime, currentTime) {
|
|
51
|
-
return currentTime - lastPersistTime > PERSIST_INTERVAL_MS;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export { PERSIST_INTERVAL_MS, RESUME_MIN_POSITION_SECONDS, RESUME_MIN_REMAINING_SECONDS, getPersistedProgress, persistProgress, shouldPersistProgress, shouldResumeFromPosition };
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { UUID } from "../types/uuid.js";
|
|
2
|
-
export interface SegmentAnalyticsParams {
|
|
3
|
-
playerId: UUID;
|
|
4
|
-
currentTimeMs: number;
|
|
5
|
-
playbackRate: number;
|
|
6
|
-
isPaused: boolean;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Start tracking a new analytics segment
|
|
10
|
-
*/
|
|
11
|
-
export declare function startSegment(params: SegmentAnalyticsParams): void;
|
|
12
|
-
/**
|
|
13
|
-
* End the current analytics segment
|
|
14
|
-
*/
|
|
15
|
-
export declare function endSegment(params: Pick<SegmentAnalyticsParams, "playerId" | "currentTimeMs">): void;
|
|
16
|
-
/**
|
|
17
|
-
* Restart segment if video is currently playing
|
|
18
|
-
* This is useful when playback rate changes or other segment-breaking events occur
|
|
19
|
-
*/
|
|
20
|
-
export declare function restartSegmentIfPlaying(params: SegmentAnalyticsParams): void;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { analyticsStoreActions } from "../store/analytics-store.js";
|
|
2
|
-
|
|
3
|
-
// src/lib/segment-analytics.ts
|
|
4
|
-
/**
|
|
5
|
-
* Start tracking a new analytics segment
|
|
6
|
-
*/
|
|
7
|
-
function startSegment(params) {
|
|
8
|
-
const { playerId, currentTimeMs, playbackRate } = params;
|
|
9
|
-
analyticsStoreActions.startSegment(playerId, currentTimeMs, playbackRate);
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* End the current analytics segment
|
|
13
|
-
*/
|
|
14
|
-
function endSegment(params) {
|
|
15
|
-
const { playerId, currentTimeMs } = params;
|
|
16
|
-
analyticsStoreActions.endSegment(playerId, currentTimeMs);
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Restart segment if video is currently playing
|
|
20
|
-
* This is useful when playback rate changes or other segment-breaking events occur
|
|
21
|
-
*/
|
|
22
|
-
function restartSegmentIfPlaying(params) {
|
|
23
|
-
const { playerId, currentTimeMs, playbackRate, isPaused } = params;
|
|
24
|
-
if (isPaused) return;
|
|
25
|
-
analyticsStoreActions.endSegment(playerId, currentTimeMs);
|
|
26
|
-
analyticsStoreActions.startSegment(playerId, currentTimeMs, playbackRate);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export { endSegment, restartSegmentIfPlaying, startSegment };
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
export interface SubtitleTrack {
|
|
2
|
-
index: number;
|
|
3
|
-
label: string;
|
|
4
|
-
language: string;
|
|
5
|
-
kind: string;
|
|
6
|
-
track: TextTrack;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Calculates the efficient end time for a cue to prevent flickering and ensure readability.
|
|
10
|
-
*/
|
|
11
|
-
export declare const calculateSmoothedEndTime: (cue: TextTrackCue | VTTCue, nextCue?: TextTrackCue | VTTCue) => number;
|
|
12
|
-
/**
|
|
13
|
-
* Helper to find the next cue in a TextTrackCueList by reference.
|
|
14
|
-
*/
|
|
15
|
-
export declare const findNextCue: (activeCue: TextTrackCue, allCues: TextTrackCueList | null) => TextTrackCue | undefined;
|
|
16
|
-
export declare function stripHtmlTags(input: string): string;
|
|
17
|
-
/**
|
|
18
|
-
* Extracts and cleans text from a cue object.
|
|
19
|
-
* Handles VTTCue vs TextTrackCue differences.
|
|
20
|
-
*/
|
|
21
|
-
export declare const getCleanCueText: (cue: TextTrackCue | VTTCue) => string;
|
|
22
|
-
/**
|
|
23
|
-
* Applies smoothing logic to a list of cues (typically activeCues).
|
|
24
|
-
* Modifies the cues in-place and caches them to avoid re-processing.
|
|
25
|
-
*/
|
|
26
|
-
export declare const processCues: (cues: TextTrackCueList | TextTrackCue[], allCues: TextTrackCueList | null) => void;
|
|
27
|
-
/**
|
|
28
|
-
* Parses the video element's text tracks and extracts relevant subtitle/caption tracks.
|
|
29
|
-
* Also normalizes track state.
|
|
30
|
-
*/
|
|
31
|
-
export declare const extractSubtitleTracks: (tracks: TextTrackList) => SubtitleTrack[];
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { clamp } from "./numbers.js";
|
|
2
|
-
|
|
3
|
-
// src/lib/subtitle-logic.ts
|
|
4
|
-
const SMOOTHING_GAP_THRESHOLD = .5;
|
|
5
|
-
const MIN_SUBTITLE_DURATION = 1;
|
|
6
|
-
const OVERLAP_BUFFER = .1;
|
|
7
|
-
/**
|
|
8
|
-
* Calculates the efficient end time for a cue to prevent flickering and ensure readability.
|
|
9
|
-
*/
|
|
10
|
-
const calculateSmoothedEndTime = (cue, nextCue) => {
|
|
11
|
-
let effectiveEndTime = cue.endTime;
|
|
12
|
-
if (nextCue) {
|
|
13
|
-
if (nextCue.startTime - cue.endTime <= SMOOTHING_GAP_THRESHOLD) return nextCue.startTime + OVERLAP_BUFFER;
|
|
14
|
-
const minEndTime = cue.startTime + MIN_SUBTITLE_DURATION;
|
|
15
|
-
return clamp(minEndTime, effectiveEndTime, nextCue.startTime);
|
|
16
|
-
}
|
|
17
|
-
return Math.max(effectiveEndTime, cue.startTime + MIN_SUBTITLE_DURATION);
|
|
18
|
-
};
|
|
19
|
-
/**
|
|
20
|
-
* Helper to find the next cue in a TextTrackCueList by reference.
|
|
21
|
-
*/
|
|
22
|
-
const findNextCue = (activeCue, allCues) => {
|
|
23
|
-
if (!allCues || allCues.length === 0) return void 0;
|
|
24
|
-
for (let index = 0; index < allCues.length - 1; index++) if (allCues[index] === activeCue) return allCues[index + 1];
|
|
25
|
-
};
|
|
26
|
-
function stripHtmlTags(input) {
|
|
27
|
-
return input.replace(/<[^>]*>/g, "");
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Extracts and cleans text from a cue object.
|
|
31
|
-
* Handles VTTCue vs TextTrackCue differences.
|
|
32
|
-
*/
|
|
33
|
-
const getCleanCueText = (cue) => {
|
|
34
|
-
return stripHtmlTags(cue instanceof VTTCue ? cue.text : cue.text ?? "");
|
|
35
|
-
};
|
|
36
|
-
const processedCues = /* @__PURE__ */ new WeakSet();
|
|
37
|
-
/**
|
|
38
|
-
* Applies smoothing logic to a list of cues (typically activeCues).
|
|
39
|
-
* Modifies the cues in-place and caches them to avoid re-processing.
|
|
40
|
-
*/
|
|
41
|
-
const processCues = (cues, allCues) => {
|
|
42
|
-
for (let i = 0; i < cues.length; i++) {
|
|
43
|
-
const cue = cues[i];
|
|
44
|
-
if (!processedCues.has(cue)) {
|
|
45
|
-
const nextCue = findNextCue(cue, allCues);
|
|
46
|
-
const newEndTime = calculateSmoothedEndTime(cue, nextCue);
|
|
47
|
-
if (Math.abs(cue.endTime - newEndTime) > .01) cue.endTime = newEndTime;
|
|
48
|
-
processedCues.add(cue);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
/**
|
|
53
|
-
* Parses the video element's text tracks and extracts relevant subtitle/caption tracks.
|
|
54
|
-
* Also normalizes track state.
|
|
55
|
-
*/
|
|
56
|
-
const extractSubtitleTracks = (tracks) => {
|
|
57
|
-
const subtitleTracks = [];
|
|
58
|
-
for (let i = 0; i < tracks.length; i++) {
|
|
59
|
-
const track = tracks[i];
|
|
60
|
-
if (track.kind === "subtitles" || track.kind === "captions") {
|
|
61
|
-
if (!track.label && !track.language && !track.id) continue;
|
|
62
|
-
subtitleTracks.push({
|
|
63
|
-
index: i,
|
|
64
|
-
label: track.label || `${track.kind} ${i + 1}`,
|
|
65
|
-
language: track.language || "unknown",
|
|
66
|
-
kind: track.kind,
|
|
67
|
-
track
|
|
68
|
-
});
|
|
69
|
-
track.mode = "disabled";
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return subtitleTracks;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
export { calculateSmoothedEndTime, extractSubtitleTracks, findNextCue, getCleanCueText, processCues, stripHtmlTags };
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { UUID } from "../types/uuid.js";
|
|
2
|
-
/**
|
|
3
|
-
* Structural shape of a video element ref. Compatible with React.RefObject
|
|
4
|
-
* but does not depend on React, keeping this module framework-agnostic.
|
|
5
|
-
*/
|
|
6
|
-
interface VideoElementRef {
|
|
7
|
-
current: HTMLVideoElement | null;
|
|
8
|
-
}
|
|
9
|
-
export declare const handleLoadedMetadata: (videoElement: HTMLVideoElement, playerId: UUID) => void;
|
|
10
|
-
export declare const clearSubtitles: (playerId: UUID) => void;
|
|
11
|
-
/**
|
|
12
|
-
* Handles the 'cuechange' event to update subtitles.
|
|
13
|
-
* Uses event-driven logic + lookahead smoothing to prevent flickering.
|
|
14
|
-
*/
|
|
15
|
-
export declare const handleCueChange: (playerId: UUID, videoRef: VideoElementRef) => void;
|
|
16
|
-
export {};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { playerStateStore } from "../store/player-store.js";
|
|
2
|
-
import { extractSubtitleTracks, getCleanCueText, processCues } from "./subtitle-logic.js";
|
|
3
|
-
|
|
4
|
-
// src/lib/subtitle-utils.ts
|
|
5
|
-
const handleLoadedMetadata = (videoElement, playerId) => {
|
|
6
|
-
const subtitleTracks = extractSubtitleTracks(videoElement.textTracks);
|
|
7
|
-
playerStateStore.setAvailableSubtitleTracks(playerId, subtitleTracks);
|
|
8
|
-
};
|
|
9
|
-
const clearSubtitles = (playerId) => {
|
|
10
|
-
playerStateStore.setCurrentSubtitleText(playerId, "");
|
|
11
|
-
};
|
|
12
|
-
/**
|
|
13
|
-
* Handles the 'cuechange' event to update subtitles.
|
|
14
|
-
* Uses event-driven logic + lookahead smoothing to prevent flickering.
|
|
15
|
-
*/
|
|
16
|
-
const handleCueChange = (playerId, videoRef) => {
|
|
17
|
-
if (!videoRef.current) return;
|
|
18
|
-
const player = playerStateStore.get(playerId).get();
|
|
19
|
-
const index = player.subtitleTrack;
|
|
20
|
-
if (index < 0 || index >= player.availableSubtitleTracks.length) {
|
|
21
|
-
if (player.currentSubtitleText !== "") clearSubtitles(playerId);
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
const trackObj = player.availableSubtitleTracks[index].track;
|
|
25
|
-
if (trackObj.mode !== "showing") return;
|
|
26
|
-
const activeCues = trackObj.activeCues;
|
|
27
|
-
if (!activeCues || activeCues.length === 0) {
|
|
28
|
-
if (player.currentSubtitleText !== "") playerStateStore.setCurrentSubtitleText(playerId, "");
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
processCues(activeCues, trackObj.cues);
|
|
32
|
-
const activeCue = activeCues[activeCues.length - 1];
|
|
33
|
-
const newText = getCleanCueText(activeCue);
|
|
34
|
-
if (newText !== player.currentSubtitleText) playerStateStore.setCurrentSubtitleText(playerId, newText);
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export { clearSubtitles, handleCueChange, handleLoadedMetadata };
|
package/dist/lib/time.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const formatTime: (seconds: number) => string;
|
package/dist/lib/time.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
// src/lib/time.ts
|
|
2
|
-
function leadingZero(num) {
|
|
3
|
-
let numStr = num.toString();
|
|
4
|
-
if (num < 10) numStr = "0" + numStr;
|
|
5
|
-
return numStr;
|
|
6
|
-
}
|
|
7
|
-
const formatTime = (seconds) => {
|
|
8
|
-
if (isNaN(seconds) || seconds < 0) return "00:00";
|
|
9
|
-
const hours = Math.floor(seconds / 3600);
|
|
10
|
-
const minutes = Math.floor(seconds % 3600 / 60);
|
|
11
|
-
const remainingSeconds = Math.floor(seconds % 60);
|
|
12
|
-
const output = `${leadingZero(minutes)}:${leadingZero(remainingSeconds)}`;
|
|
13
|
-
if (hours > 0) return `${leadingZero(hours)}:${output}`;
|
|
14
|
-
return output;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export { formatTime };
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
// src/lib/track-persistence.ts
|
|
2
|
-
const SUBTITLE_TRACK_KEY = "video-player-subtitle-track";
|
|
3
|
-
const AUDIO_TRACK_KEY = "audioTrack";
|
|
4
|
-
const getPersistedSubtitleTrack = () => {
|
|
5
|
-
try {
|
|
6
|
-
const stored = localStorage.getItem(SUBTITLE_TRACK_KEY);
|
|
7
|
-
return stored !== null ? parseInt(stored, 10) : -1;
|
|
8
|
-
} catch {
|
|
9
|
-
return -1;
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
const persistSubtitleTrack = (trackIndex) => {
|
|
13
|
-
try {
|
|
14
|
-
localStorage.setItem(SUBTITLE_TRACK_KEY, trackIndex.toString());
|
|
15
|
-
} catch {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
const getPersistedAudioTrack = () => {
|
|
20
|
-
try {
|
|
21
|
-
const stored = localStorage.getItem(AUDIO_TRACK_KEY);
|
|
22
|
-
return stored ? parseInt(stored, 10) : 0;
|
|
23
|
-
} catch {
|
|
24
|
-
return 0;
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
const persistAudioTrack = (trackIndex) => {
|
|
28
|
-
try {
|
|
29
|
-
localStorage.setItem(AUDIO_TRACK_KEY, trackIndex.toString());
|
|
30
|
-
} catch {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export { getPersistedAudioTrack, getPersistedSubtitleTrack, persistAudioTrack, persistSubtitleTrack };
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PRELOAD_RANGE determines how many videos around the current one should be loaded
|
|
3
|
-
*
|
|
4
|
-
* Example with BEFORE: 1, AFTER: 2, current index is 5:
|
|
5
|
-
*
|
|
6
|
-
* Legend:
|
|
7
|
-
* PRELOADING (buffering in background)
|
|
8
|
-
* PLAYING (currently visible)
|
|
9
|
-
* IDLE (exists but not loaded)
|
|
10
|
-
* UNLOADED (too far, save memory)
|
|
11
|
-
*/
|
|
12
|
-
export declare const PRELOAD_RANGE: {
|
|
13
|
-
BEFORE: number;
|
|
14
|
-
AFTER: number;
|
|
15
|
-
};
|
|
16
|
-
/**
|
|
17
|
-
* UNLOAD_DISTANCE determines when to unload videos to free memory
|
|
18
|
-
* If a video is more than this distance from current, unload it
|
|
19
|
-
*/
|
|
20
|
-
export declare const UNLOAD_DISTANCE = 5;
|
|
21
|
-
/**
|
|
22
|
-
* Video loading states
|
|
23
|
-
*/
|
|
24
|
-
export declare const VideoLoadState: {
|
|
25
|
-
readonly UNLOADED: "unloaded";
|
|
26
|
-
readonly IDLE: "idle";
|
|
27
|
-
readonly PRELOADING: "preloading";
|
|
28
|
-
readonly PLAYING: "playing";
|
|
29
|
-
};
|
|
30
|
-
export type VideoLoadState = (typeof VideoLoadState)[keyof typeof VideoLoadState];
|
|
31
|
-
/**
|
|
32
|
-
* Calculate what state a video should be in based on its distance from current
|
|
33
|
-
*/
|
|
34
|
-
export declare function getVideoLoadState(videoIndex: number, currentIndex: number, isCurrent: boolean): VideoLoadState;
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
// src/lib/video-preload-config.ts
|
|
2
|
-
/**
|
|
3
|
-
* PRELOAD_RANGE determines how many videos around the current one should be loaded
|
|
4
|
-
*
|
|
5
|
-
* Example with BEFORE: 1, AFTER: 2, current index is 5:
|
|
6
|
-
*
|
|
7
|
-
* Legend:
|
|
8
|
-
* PRELOADING (buffering in background)
|
|
9
|
-
* PLAYING (currently visible)
|
|
10
|
-
* IDLE (exists but not loaded)
|
|
11
|
-
* UNLOADED (too far, save memory)
|
|
12
|
-
*/
|
|
13
|
-
const PRELOAD_RANGE = {
|
|
14
|
-
BEFORE: 0,
|
|
15
|
-
AFTER: 1
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* UNLOAD_DISTANCE determines when to unload videos to free memory
|
|
19
|
-
* If a video is more than this distance from current, unload it
|
|
20
|
-
*/
|
|
21
|
-
const UNLOAD_DISTANCE = 5;
|
|
22
|
-
/**
|
|
23
|
-
* Video loading states
|
|
24
|
-
*/
|
|
25
|
-
const VideoLoadState = {
|
|
26
|
-
UNLOADED: "unloaded",
|
|
27
|
-
IDLE: "idle",
|
|
28
|
-
PRELOADING: "preloading",
|
|
29
|
-
PLAYING: "playing"
|
|
30
|
-
};
|
|
31
|
-
/**
|
|
32
|
-
* Calculate what state a video should be in based on its distance from current
|
|
33
|
-
*/
|
|
34
|
-
function getVideoLoadState(videoIndex, currentIndex, isCurrent) {
|
|
35
|
-
if (isCurrent) return VideoLoadState.PLAYING;
|
|
36
|
-
const distance = videoIndex - currentIndex;
|
|
37
|
-
if (Math.abs(distance) > 5) return VideoLoadState.UNLOADED;
|
|
38
|
-
return distance < 0 && distance >= -PRELOAD_RANGE.BEFORE || distance > 0 && distance <= PRELOAD_RANGE.AFTER ? VideoLoadState.PRELOADING : VideoLoadState.IDLE;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export { PRELOAD_RANGE, UNLOAD_DISTANCE, VideoLoadState, getVideoLoadState };
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Live "is the player buffering right now?" predicate.
|
|
3
|
-
*
|
|
4
|
-
* Different from `video-preload-config.ts` despite the similar name:
|
|
5
|
-
* - `video-preload-config.ts` decides the `<video preload>` attribute for
|
|
6
|
-
* a slot in the feed virtualization (one-time decision per slot).
|
|
7
|
-
* - `shouldShowSpinner` is called continuously during playback to decide
|
|
8
|
-
* whether the buffering spinner should currently be visible.
|
|
9
|
-
*
|
|
10
|
-
* Inputs come from a live `<HTMLVideoElement>`. The function is otherwise
|
|
11
|
-
* pure and framework-agnostic.
|
|
12
|
-
*/
|
|
13
|
-
/**
|
|
14
|
-
* Decide whether the buffering spinner should be visible for the given
|
|
15
|
-
* video element.
|
|
16
|
-
*
|
|
17
|
-
* Logic, in order:
|
|
18
|
-
* 1. No video → never show.
|
|
19
|
-
* 2. Playing past the start → if the current time falls inside any buffered
|
|
20
|
-
* range, the player has the bytes it needs; never show.
|
|
21
|
-
* 3. Otherwise fall back to `readyState`/`seeking`: show when the browser
|
|
22
|
-
* reports `HAVE_CURRENT_DATA` (2) or is actively seeking with
|
|
23
|
-
* `readyState < 3` (HAVE_FUTURE_DATA).
|
|
24
|
-
*/
|
|
25
|
-
export declare function shouldShowSpinner(video: HTMLVideoElement | null): boolean;
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
// src/lib/video-spinner.ts
|
|
2
|
-
/**
|
|
3
|
-
* Live "is the player buffering right now?" predicate.
|
|
4
|
-
*
|
|
5
|
-
* Different from `video-preload-config.ts` despite the similar name:
|
|
6
|
-
* - `video-preload-config.ts` decides the `<video preload>` attribute for
|
|
7
|
-
* a slot in the feed virtualization (one-time decision per slot).
|
|
8
|
-
* - `shouldShowSpinner` is called continuously during playback to decide
|
|
9
|
-
* whether the buffering spinner should currently be visible.
|
|
10
|
-
*
|
|
11
|
-
* Inputs come from a live `<HTMLVideoElement>`. The function is otherwise
|
|
12
|
-
* pure and framework-agnostic.
|
|
13
|
-
*/
|
|
14
|
-
/**
|
|
15
|
-
* Decide whether the buffering spinner should be visible for the given
|
|
16
|
-
* video element.
|
|
17
|
-
*
|
|
18
|
-
* Logic, in order:
|
|
19
|
-
* 1. No video → never show.
|
|
20
|
-
* 2. Playing past the start → if the current time falls inside any buffered
|
|
21
|
-
* range, the player has the bytes it needs; never show.
|
|
22
|
-
* 3. Otherwise fall back to `readyState`/`seeking`: show when the browser
|
|
23
|
-
* reports `HAVE_CURRENT_DATA` (2) or is actively seeking with
|
|
24
|
-
* `readyState < 3` (HAVE_FUTURE_DATA).
|
|
25
|
-
*/
|
|
26
|
-
function shouldShowSpinner(video) {
|
|
27
|
-
if (!video) return false;
|
|
28
|
-
if (!video.paused && video.currentTime > 0) {
|
|
29
|
-
const buffered = video.buffered;
|
|
30
|
-
for (let i = 0; i < buffered.length; i++) if (video.currentTime >= buffered.start(i) && video.currentTime < buffered.end(i)) return false;
|
|
31
|
-
}
|
|
32
|
-
return video.readyState < 3 && (video.seeking || video.readyState === 2);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export { shouldShowSpinner };
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
export interface VideoStats {
|
|
2
|
-
droppedFrames: number;
|
|
3
|
-
volume: number;
|
|
4
|
-
networkSpeed: number;
|
|
5
|
-
bufferHealth: number;
|
|
6
|
-
currentRes: {
|
|
7
|
-
width: number;
|
|
8
|
-
height: number;
|
|
9
|
-
} | null;
|
|
10
|
-
optimalRes: {
|
|
11
|
-
width: number;
|
|
12
|
-
height: number;
|
|
13
|
-
} | null;
|
|
14
|
-
}
|
|
15
|
-
export interface CollectStatsInput {
|
|
16
|
-
video: HTMLVideoElement | null;
|
|
17
|
-
hlsBandwidthEstimate: number | null;
|
|
18
|
-
hlsLevels: ReadonlyArray<{
|
|
19
|
-
width: number;
|
|
20
|
-
height: number;
|
|
21
|
-
}>;
|
|
22
|
-
hlsCurrentLevel: number;
|
|
23
|
-
hlsAutoLevelEnabled: boolean;
|
|
24
|
-
hlsAutoLevelCapping: number;
|
|
25
|
-
}
|
|
26
|
-
export declare function getDroppedFrames(video: HTMLVideoElement): number;
|
|
27
|
-
export declare function getBufferHealth(video: HTMLVideoElement): number;
|
|
28
|
-
export declare function collectVideoStats(input: CollectStatsInput): VideoStats;
|