@rixl/media-core 1.0.1 → 1.1.0
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/BZFoe94X.js +1 -0
- package/dist/chunks/DMkwQjgA.js +1 -0
- package/dist/index.d.ts +2005 -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 -123
- 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
package/dist/lib/video-stats.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
// src/lib/video-stats.ts
|
|
2
|
-
function getDroppedFrames(video) {
|
|
3
|
-
if (!("getVideoPlaybackQuality" in video)) return 0;
|
|
4
|
-
return video.getVideoPlaybackQuality().droppedVideoFrames;
|
|
5
|
-
}
|
|
6
|
-
function getBufferHealth(video) {
|
|
7
|
-
if (video.buffered.length === 0) return 0;
|
|
8
|
-
const currentTime = video.currentTime;
|
|
9
|
-
for (let i = 0; i < video.buffered.length; i++) if (video.buffered.start(i) <= currentTime && video.buffered.end(i) >= currentTime) return Math.max(0, video.buffered.end(i) - currentTime);
|
|
10
|
-
return 0;
|
|
11
|
-
}
|
|
12
|
-
function getOptimalRes(input) {
|
|
13
|
-
const levelIndex = input.hlsAutoLevelEnabled ? input.hlsAutoLevelCapping : input.hlsCurrentLevel;
|
|
14
|
-
if (levelIndex < 0 || levelIndex >= input.hlsLevels.length) return null;
|
|
15
|
-
const level = input.hlsLevels[levelIndex];
|
|
16
|
-
return level ? {
|
|
17
|
-
width: level.width,
|
|
18
|
-
height: level.height
|
|
19
|
-
} : null;
|
|
20
|
-
}
|
|
21
|
-
function collectVideoStats(input) {
|
|
22
|
-
const { video } = input;
|
|
23
|
-
if (!video) return {
|
|
24
|
-
droppedFrames: 0,
|
|
25
|
-
volume: 0,
|
|
26
|
-
networkSpeed: 0,
|
|
27
|
-
bufferHealth: 0,
|
|
28
|
-
currentRes: null,
|
|
29
|
-
optimalRes: null
|
|
30
|
-
};
|
|
31
|
-
return {
|
|
32
|
-
droppedFrames: getDroppedFrames(video),
|
|
33
|
-
volume: Math.round(video.volume * 100),
|
|
34
|
-
networkSpeed: input.hlsBandwidthEstimate ?? 0,
|
|
35
|
-
bufferHealth: getBufferHealth(video),
|
|
36
|
-
currentRes: video.videoWidth > 0 ? {
|
|
37
|
-
width: video.videoWidth,
|
|
38
|
-
height: video.videoHeight
|
|
39
|
-
} : null,
|
|
40
|
-
optimalRes: getOptimalRes(input)
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export { collectVideoStats, getBufferHealth, getDroppedFrames };
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Volume and mute utility functions
|
|
3
|
-
* Pure functions for volume calculations and mute state logic
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Calculate the volume to set, ensuring it's never 0 when unmuting
|
|
7
|
-
* @param currentVolume - The current volume from settings (0-1)
|
|
8
|
-
* @param defaultVolume - The default volume to use if current is 0 (default: 1.0)
|
|
9
|
-
* @returns The volume to set (0-1)
|
|
10
|
-
*/
|
|
11
|
-
export declare function calculateVolumeToSet(currentVolume: number, defaultVolume?: number): number;
|
|
12
|
-
/**
|
|
13
|
-
* Determine if video should be muted based on player state and interaction state
|
|
14
|
-
* @param playerMuted - Whether the current player is muted
|
|
15
|
-
* @param isFeed - Whether this is a feed video
|
|
16
|
-
* @param feedInteracted - Whether user has interacted with the feed
|
|
17
|
-
* @param playerInteracted - Whether user has interacted with the player
|
|
18
|
-
* @returns Whether the video should be muted
|
|
19
|
-
*/
|
|
20
|
-
interface MuteCheckParams {
|
|
21
|
-
playerMuted: boolean;
|
|
22
|
-
playerInteracted: boolean;
|
|
23
|
-
}
|
|
24
|
-
export declare function shouldBeMuted({ playerMuted, playerInteracted }: MuteCheckParams): boolean;
|
|
25
|
-
/**
|
|
26
|
-
* Get the volume to restore when unmuting, with a minimum threshold
|
|
27
|
-
* @param currentVolume - The current volume (0-1)
|
|
28
|
-
* @param previousVolume - The previously saved volume before muting (0-1)
|
|
29
|
-
* @param minVolume - The minimum volume to restore to (default: 0.1)
|
|
30
|
-
* @returns The volume to restore (0-1)
|
|
31
|
-
*/
|
|
32
|
-
export declare function getRestoredVolume(currentVolume: number, previousVolume: number, minVolume?: number): number;
|
|
33
|
-
/**
|
|
34
|
-
* Clamp volume to valid range (0-1)
|
|
35
|
-
* @param volume - The volume to clamp
|
|
36
|
-
* @returns Volume clamped to 0-1 range
|
|
37
|
-
*/
|
|
38
|
-
export declare function clampVolume(volume: number): number;
|
|
39
|
-
/**
|
|
40
|
-
* Check if volume is effectively muted (0 or very close to 0)
|
|
41
|
-
* @param volume - The volume to check
|
|
42
|
-
* @param threshold - The threshold below which volume is considered muted (default: 0.01)
|
|
43
|
-
* @returns Whether volume is effectively muted
|
|
44
|
-
*/
|
|
45
|
-
export declare function isEffectivelyMuted(volume: number, threshold?: number): boolean;
|
|
46
|
-
interface MousePointerLike {
|
|
47
|
-
clientX: number;
|
|
48
|
-
}
|
|
49
|
-
interface TouchPointerLike {
|
|
50
|
-
touches: ArrayLike<MousePointerLike>;
|
|
51
|
-
}
|
|
52
|
-
/** clientX of a mouse or touch event (first touch) — shared by the volume sliders. */
|
|
53
|
-
export declare function getPointerClientX(event: MousePointerLike | TouchPointerLike): number;
|
|
54
|
-
/** Map a pointer position over a slider rect to a clamped 0-1 volume. */
|
|
55
|
-
export declare function getVolumeFromPointer(rect: {
|
|
56
|
-
left: number;
|
|
57
|
-
width: number;
|
|
58
|
-
}, clientX: number): number;
|
|
59
|
-
export {};
|
package/dist/lib/volume-utils.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
// src/lib/volume-utils.ts
|
|
2
|
-
/**
|
|
3
|
-
* Volume and mute utility functions
|
|
4
|
-
* Pure functions for volume calculations and mute state logic
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* Calculate the volume to set, ensuring it's never 0 when unmuting
|
|
8
|
-
* @param currentVolume - The current volume from settings (0-1)
|
|
9
|
-
* @param defaultVolume - The default volume to use if current is 0 (default: 1.0)
|
|
10
|
-
* @returns The volume to set (0-1)
|
|
11
|
-
*/
|
|
12
|
-
function calculateVolumeToSet(currentVolume, defaultVolume = 1) {
|
|
13
|
-
return currentVolume > 0 ? currentVolume : defaultVolume;
|
|
14
|
-
}
|
|
15
|
-
function shouldBeMuted({ playerMuted, playerInteracted }) {
|
|
16
|
-
return playerMuted || !playerInteracted;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Get the volume to restore when unmuting, with a minimum threshold
|
|
20
|
-
* @param currentVolume - The current volume (0-1)
|
|
21
|
-
* @param previousVolume - The previously saved volume before muting (0-1)
|
|
22
|
-
* @param minVolume - The minimum volume to restore to (default: 0.1)
|
|
23
|
-
* @returns The volume to restore (0-1)
|
|
24
|
-
*/
|
|
25
|
-
function getRestoredVolume(currentVolume, previousVolume, minVolume = .1) {
|
|
26
|
-
if (currentVolume === 0) return Math.max(minVolume, previousVolume);
|
|
27
|
-
return currentVolume;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Clamp volume to valid range (0-1)
|
|
31
|
-
* @param volume - The volume to clamp
|
|
32
|
-
* @returns Volume clamped to 0-1 range
|
|
33
|
-
*/
|
|
34
|
-
function clampVolume(volume) {
|
|
35
|
-
return Math.max(0, Math.min(1, volume));
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Check if volume is effectively muted (0 or very close to 0)
|
|
39
|
-
* @param volume - The volume to check
|
|
40
|
-
* @param threshold - The threshold below which volume is considered muted (default: 0.01)
|
|
41
|
-
* @returns Whether volume is effectively muted
|
|
42
|
-
*/
|
|
43
|
-
function isEffectivelyMuted(volume, threshold = .01) {
|
|
44
|
-
return volume < threshold;
|
|
45
|
-
}
|
|
46
|
-
/** clientX of a mouse or touch event (first touch) — shared by the volume sliders. */
|
|
47
|
-
function getPointerClientX(event) {
|
|
48
|
-
return "touches" in event ? event.touches[0].clientX : event.clientX;
|
|
49
|
-
}
|
|
50
|
-
/** Map a pointer position over a slider rect to a clamped 0-1 volume. */
|
|
51
|
-
function getVolumeFromPointer(rect, clientX) {
|
|
52
|
-
return clampVolume((clientX - rect.left) / rect.width);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export { calculateVolumeToSet, clampVolume, getPointerClientX, getRestoredVolume, getVolumeFromPointer, isEffectivelyMuted, shouldBeMuted };
|
package/dist/progressbar.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export interface ProgressBarProps {
|
|
2
|
-
video: HTMLVideoElement;
|
|
3
|
-
onDraggingChange?: (isDragging: boolean) => void;
|
|
4
|
-
onProgressChange?: (progress: number) => void;
|
|
5
|
-
}
|
|
6
|
-
export interface ProgressBarControls {
|
|
7
|
-
handleDragStart: (event: MouseEvent | TouchEvent) => void;
|
|
8
|
-
destroy: () => void;
|
|
9
|
-
}
|
|
10
|
-
export declare const initProgressBar: ({ video, onDraggingChange, onProgressChange }: ProgressBarProps) => ProgressBarControls;
|
package/dist/progressbar.js
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
// src/progressbar.ts
|
|
2
|
-
const SWIPE_DISTANCE_THRESHOLD = 15;
|
|
3
|
-
const SWIPE_TIME_THRESHOLD = 200;
|
|
4
|
-
const manageListeners = (action, events, handler) => events.forEach((e) => window[`${action}EventListener`](e, handler));
|
|
5
|
-
const clamp01 = (value) => Math.min(Math.max(value, 0), 1);
|
|
6
|
-
const getClientX = (event) => {
|
|
7
|
-
if ("touches" in event) return event.touches[0]?.clientX ?? event.changedTouches?.[0]?.clientX ?? 0;
|
|
8
|
-
return event.clientX;
|
|
9
|
-
};
|
|
10
|
-
const createProgressBarState = (video) => ({
|
|
11
|
-
isDragging: false,
|
|
12
|
-
progress: video.currentTime / (video.duration || 1),
|
|
13
|
-
initialRect: null,
|
|
14
|
-
initialClientX: null,
|
|
15
|
-
initialProgress: 0,
|
|
16
|
-
startTime: 0,
|
|
17
|
-
hasMoved: false
|
|
18
|
-
});
|
|
19
|
-
const setProgress = (state, value, onProgressChange) => {
|
|
20
|
-
state.progress = Number(value.toFixed(6));
|
|
21
|
-
onProgressChange?.(state.progress);
|
|
22
|
-
};
|
|
23
|
-
const setDragging = (state, value, onDraggingChange) => {
|
|
24
|
-
state.isDragging = value;
|
|
25
|
-
onDraggingChange?.(value);
|
|
26
|
-
};
|
|
27
|
-
const shouldStartDragging = (state, clientX) => {
|
|
28
|
-
if (state.initialClientX === null) return false;
|
|
29
|
-
const distanceMoved = Math.abs(clientX - state.initialClientX);
|
|
30
|
-
const timeElapsed = Date.now() - state.startTime;
|
|
31
|
-
return distanceMoved >= SWIPE_DISTANCE_THRESHOLD || timeElapsed >= SWIPE_TIME_THRESHOLD;
|
|
32
|
-
};
|
|
33
|
-
const startDragging = (state, clientX, onDraggingChange) => {
|
|
34
|
-
state.hasMoved = true;
|
|
35
|
-
setDragging(state, true, onDraggingChange);
|
|
36
|
-
state.initialClientX = clientX;
|
|
37
|
-
state.initialProgress = state.progress;
|
|
38
|
-
};
|
|
39
|
-
const getDragProgress = (state, clientX) => {
|
|
40
|
-
if (!state.initialRect) return null;
|
|
41
|
-
const offset = (clientX - (state.initialClientX ?? state.initialRect.left)) / state.initialRect.width;
|
|
42
|
-
const baseProgress = state.initialClientX ? state.initialProgress : 0;
|
|
43
|
-
return clamp01(offset + baseProgress);
|
|
44
|
-
};
|
|
45
|
-
const getClickProgress = (state) => {
|
|
46
|
-
if (!state.initialRect || state.initialClientX === null) return null;
|
|
47
|
-
return clamp01((state.initialClientX - state.initialRect.left) / state.initialRect.width);
|
|
48
|
-
};
|
|
49
|
-
const resetDragState = (state, onDraggingChange) => {
|
|
50
|
-
setDragging(state, false, onDraggingChange);
|
|
51
|
-
state.hasMoved = false;
|
|
52
|
-
state.initialRect = null;
|
|
53
|
-
state.initialClientX = null;
|
|
54
|
-
};
|
|
55
|
-
const createTimeUpdateHandler = (state, video, onProgressChange) => () => {
|
|
56
|
-
if (state.isDragging) return;
|
|
57
|
-
setProgress(state, video.currentTime / (video.duration || 1), onProgressChange);
|
|
58
|
-
};
|
|
59
|
-
const createMoveHandler = (state, onDraggingChange, onProgressChange) => (event) => {
|
|
60
|
-
const clientX = getClientX(event);
|
|
61
|
-
if (!state.isDragging) {
|
|
62
|
-
if (!shouldStartDragging(state, clientX)) return;
|
|
63
|
-
startDragging(state, clientX, onDraggingChange);
|
|
64
|
-
}
|
|
65
|
-
const newProgress = getDragProgress(state, clientX);
|
|
66
|
-
if (newProgress === null) return;
|
|
67
|
-
setProgress(state, newProgress, onProgressChange);
|
|
68
|
-
};
|
|
69
|
-
const createEndHandler = ({ state, video, onDraggingChange, onProgressChange, removeListeners }) => () => {
|
|
70
|
-
const clickProgress = !state.hasMoved ? getClickProgress(state) : null;
|
|
71
|
-
if (clickProgress !== null) {
|
|
72
|
-
setProgress(state, clickProgress, onProgressChange);
|
|
73
|
-
video.currentTime = clickProgress * video.duration;
|
|
74
|
-
} else if (state.isDragging && video.duration) video.currentTime = state.progress * video.duration;
|
|
75
|
-
resetDragState(state, onDraggingChange);
|
|
76
|
-
removeListeners();
|
|
77
|
-
};
|
|
78
|
-
const createDragStartHandler = (state, handleMove, handleEnd) => (event) => {
|
|
79
|
-
state.initialRect = event.currentTarget.getBoundingClientRect();
|
|
80
|
-
state.startTime = Date.now();
|
|
81
|
-
state.hasMoved = false;
|
|
82
|
-
state.initialClientX = getClientX(event);
|
|
83
|
-
manageListeners("add", ["mousemove", "touchmove"], handleMove);
|
|
84
|
-
manageListeners("add", [
|
|
85
|
-
"mouseup",
|
|
86
|
-
"touchend",
|
|
87
|
-
"blur"
|
|
88
|
-
], handleEnd);
|
|
89
|
-
};
|
|
90
|
-
const initProgressBar = ({ video, onDraggingChange, onProgressChange }) => {
|
|
91
|
-
const state = createProgressBarState(video);
|
|
92
|
-
onDraggingChange?.(false);
|
|
93
|
-
onProgressChange?.(state.progress);
|
|
94
|
-
const handleTimeUpdate = createTimeUpdateHandler(state, video, onProgressChange);
|
|
95
|
-
const handleMove = createMoveHandler(state, onDraggingChange, onProgressChange);
|
|
96
|
-
let handleEnd;
|
|
97
|
-
const removeListeners = () => {
|
|
98
|
-
manageListeners("remove", ["mousemove", "touchmove"], handleMove);
|
|
99
|
-
manageListeners("remove", [
|
|
100
|
-
"mouseup",
|
|
101
|
-
"touchend",
|
|
102
|
-
"blur"
|
|
103
|
-
], handleEnd);
|
|
104
|
-
};
|
|
105
|
-
handleEnd = createEndHandler({
|
|
106
|
-
state,
|
|
107
|
-
video,
|
|
108
|
-
onDraggingChange,
|
|
109
|
-
onProgressChange,
|
|
110
|
-
removeListeners
|
|
111
|
-
});
|
|
112
|
-
const handleDragStart = createDragStartHandler(state, handleMove, handleEnd);
|
|
113
|
-
video.addEventListener("timeupdate", handleTimeUpdate);
|
|
114
|
-
return {
|
|
115
|
-
handleDragStart,
|
|
116
|
-
destroy: () => {
|
|
117
|
-
handleEnd();
|
|
118
|
-
video.removeEventListener("timeupdate", handleTimeUpdate);
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
export { initProgressBar };
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { atom } from "nanostores";
|
|
2
|
-
|
|
3
|
-
// src/store/analytics-context-store.ts
|
|
4
|
-
const initialContext = {};
|
|
5
|
-
const analyticsContextStore = atom(initialContext);
|
|
6
|
-
function setAnalyticsContext(context) {
|
|
7
|
-
analyticsContextStore.set({
|
|
8
|
-
...analyticsContextStore.get(),
|
|
9
|
-
...context
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export { analyticsContextStore, setAnalyticsContext };
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { WritableAtom } from "nanostores";
|
|
2
|
-
interface DeviceState {
|
|
3
|
-
deviceId: string | undefined;
|
|
4
|
-
}
|
|
5
|
-
export declare const analyticsDeviceStore: WritableAtom<DeviceState>;
|
|
6
|
-
export declare function getOrCreateDeviceId(): string;
|
|
7
|
-
export declare function setDeviceId(deviceId: string): void;
|
|
8
|
-
export {};
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { atom } from "nanostores";
|
|
2
|
-
|
|
3
|
-
// src/store/analytics-device-store.ts
|
|
4
|
-
const STORAGE_KEY = "rixl_analytics_device_id";
|
|
5
|
-
const initialState = { deviceId: void 0 };
|
|
6
|
-
const analyticsDeviceStore = atom(initialState);
|
|
7
|
-
function generateDeviceId() {
|
|
8
|
-
const cryptoApi = globalThis.crypto;
|
|
9
|
-
if (cryptoApi?.randomUUID) return cryptoApi.randomUUID();
|
|
10
|
-
return `${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;
|
|
11
|
-
}
|
|
12
|
-
function getStoredDeviceId() {
|
|
13
|
-
if (typeof localStorage === "undefined" || !localStorage) return;
|
|
14
|
-
try {
|
|
15
|
-
return localStorage.getItem(STORAGE_KEY) ?? void 0;
|
|
16
|
-
} catch {
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
function setStoredDeviceId(deviceId) {
|
|
21
|
-
if (typeof localStorage === "undefined" || !localStorage) return;
|
|
22
|
-
try {
|
|
23
|
-
localStorage.setItem(STORAGE_KEY, deviceId);
|
|
24
|
-
} catch {}
|
|
25
|
-
}
|
|
26
|
-
function getOrCreateDeviceId() {
|
|
27
|
-
const state = analyticsDeviceStore.get();
|
|
28
|
-
if (state.deviceId) return state.deviceId;
|
|
29
|
-
const stored = getStoredDeviceId();
|
|
30
|
-
if (stored) {
|
|
31
|
-
analyticsDeviceStore.set({ deviceId: stored });
|
|
32
|
-
return stored;
|
|
33
|
-
}
|
|
34
|
-
const generated = generateDeviceId();
|
|
35
|
-
setStoredDeviceId(generated);
|
|
36
|
-
analyticsDeviceStore.set({ deviceId: generated });
|
|
37
|
-
return generated;
|
|
38
|
-
}
|
|
39
|
-
function setDeviceId(deviceId) {
|
|
40
|
-
setStoredDeviceId(deviceId);
|
|
41
|
-
analyticsDeviceStore.set({ deviceId });
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export { analyticsDeviceStore, getOrCreateDeviceId, setDeviceId };
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { WritableAtom } from "nanostores";
|
|
2
|
-
interface SessionState {
|
|
3
|
-
sessionId: string | undefined;
|
|
4
|
-
started: boolean;
|
|
5
|
-
}
|
|
6
|
-
export declare const analyticsSessionStore: WritableAtom<SessionState>;
|
|
7
|
-
export declare function getOrCreateSessionId(): string;
|
|
8
|
-
export {};
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { atom } from "nanostores";
|
|
2
|
-
|
|
3
|
-
// src/store/analytics-session-store.ts
|
|
4
|
-
const initialState = {
|
|
5
|
-
sessionId: void 0,
|
|
6
|
-
started: false
|
|
7
|
-
};
|
|
8
|
-
const analyticsSessionStore = atom(initialState);
|
|
9
|
-
function generateSessionId() {
|
|
10
|
-
const cryptoApi = globalThis.crypto;
|
|
11
|
-
if (cryptoApi?.randomUUID) return cryptoApi.randomUUID();
|
|
12
|
-
return `s-${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;
|
|
13
|
-
}
|
|
14
|
-
function getOrCreateSessionId() {
|
|
15
|
-
const state = analyticsSessionStore.get();
|
|
16
|
-
if (state.sessionId) return state.sessionId;
|
|
17
|
-
const sessionId = generateSessionId();
|
|
18
|
-
analyticsSessionStore.set({
|
|
19
|
-
...state,
|
|
20
|
-
sessionId
|
|
21
|
-
});
|
|
22
|
-
return sessionId;
|
|
23
|
-
}
|
|
24
|
-
function hasSessionStarted() {
|
|
25
|
-
return analyticsSessionStore.get().started;
|
|
26
|
-
}
|
|
27
|
-
function markSessionStarted() {
|
|
28
|
-
analyticsSessionStore.set({
|
|
29
|
-
...analyticsSessionStore.get(),
|
|
30
|
-
started: true
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
function resetSession() {
|
|
34
|
-
analyticsSessionStore.set({
|
|
35
|
-
sessionId: void 0,
|
|
36
|
-
started: false
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export { analyticsSessionStore, getOrCreateSessionId, hasSessionStarted, markSessionStarted, resetSession };
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { Segment } from "../types/analytics.js";
|
|
2
|
-
import { WritableAtom } from "nanostores";
|
|
3
|
-
interface CurrentSegment {
|
|
4
|
-
start_ms: number;
|
|
5
|
-
speed: number;
|
|
6
|
-
}
|
|
7
|
-
interface AnalyticsState {
|
|
8
|
-
segments: Map<string, Segment[]>;
|
|
9
|
-
currentSegment: Map<string, CurrentSegment | null>;
|
|
10
|
-
}
|
|
11
|
-
export declare const analyticsStore: WritableAtom<AnalyticsState>;
|
|
12
|
-
export declare const analyticsStoreActions: {
|
|
13
|
-
/**
|
|
14
|
-
* Start tracking a new segment
|
|
15
|
-
*/
|
|
16
|
-
startSegment(playerId: string, positionMs: number, speed: number): void;
|
|
17
|
-
/**
|
|
18
|
-
* End the current segment being tracked
|
|
19
|
-
*/
|
|
20
|
-
endSegment(playerId: string, positionMs: number): void;
|
|
21
|
-
/**
|
|
22
|
-
* Get segments including the current in-progress segment
|
|
23
|
-
*/
|
|
24
|
-
getSegmentsWithCurrent(playerId: string, currentPositionMs: number): Segment[];
|
|
25
|
-
/**
|
|
26
|
-
* Clear all segments for a player
|
|
27
|
-
*/
|
|
28
|
-
clearSegments(playerId: string): void;
|
|
29
|
-
};
|
|
30
|
-
export {};
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { atom } from "nanostores";
|
|
2
|
-
|
|
3
|
-
// src/store/analytics-store.ts
|
|
4
|
-
const analyticsStore = atom({
|
|
5
|
-
segments: /* @__PURE__ */ new Map(),
|
|
6
|
-
currentSegment: /* @__PURE__ */ new Map()
|
|
7
|
-
});
|
|
8
|
-
const analyticsStoreActions = {
|
|
9
|
-
/**
|
|
10
|
-
* Start tracking a new segment
|
|
11
|
-
*/
|
|
12
|
-
startSegment(playerId, positionMs, speed) {
|
|
13
|
-
if (analyticsStore.get().currentSegment.get(playerId)) this.endSegment(playerId, positionMs);
|
|
14
|
-
const updatedState = analyticsStore.get();
|
|
15
|
-
const newCurrentSegment = new Map(updatedState.currentSegment);
|
|
16
|
-
newCurrentSegment.set(playerId, {
|
|
17
|
-
start_ms: positionMs,
|
|
18
|
-
speed
|
|
19
|
-
});
|
|
20
|
-
analyticsStore.set({
|
|
21
|
-
...updatedState,
|
|
22
|
-
currentSegment: newCurrentSegment
|
|
23
|
-
});
|
|
24
|
-
},
|
|
25
|
-
/**
|
|
26
|
-
* End the current segment being tracked
|
|
27
|
-
*/
|
|
28
|
-
endSegment(playerId, positionMs) {
|
|
29
|
-
const state = analyticsStore.get();
|
|
30
|
-
const currentSegment = state.currentSegment.get(playerId);
|
|
31
|
-
if (!currentSegment) return;
|
|
32
|
-
if (positionMs - currentSegment.start_ms > 100) {
|
|
33
|
-
const segment = {
|
|
34
|
-
start_ms: Math.round(currentSegment.start_ms),
|
|
35
|
-
end_ms: Math.round(positionMs),
|
|
36
|
-
speed: currentSegment.speed
|
|
37
|
-
};
|
|
38
|
-
const newSegments = new Map(state.segments);
|
|
39
|
-
const playerSegments = newSegments.get(playerId) || [];
|
|
40
|
-
newSegments.set(playerId, [...playerSegments, segment]);
|
|
41
|
-
const newCurrentSegment = new Map(state.currentSegment);
|
|
42
|
-
newCurrentSegment.set(playerId, null);
|
|
43
|
-
analyticsStore.set({
|
|
44
|
-
...state,
|
|
45
|
-
segments: newSegments,
|
|
46
|
-
currentSegment: newCurrentSegment
|
|
47
|
-
});
|
|
48
|
-
} else {
|
|
49
|
-
const newCurrentSegment = new Map(state.currentSegment);
|
|
50
|
-
newCurrentSegment.set(playerId, null);
|
|
51
|
-
analyticsStore.set({
|
|
52
|
-
...state,
|
|
53
|
-
currentSegment: newCurrentSegment
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
/**
|
|
58
|
-
* Get segments including the current in-progress segment
|
|
59
|
-
*/
|
|
60
|
-
getSegmentsWithCurrent(playerId, currentPositionMs) {
|
|
61
|
-
const state = analyticsStore.get();
|
|
62
|
-
const segments = [...state.segments.get(playerId) || []];
|
|
63
|
-
const currentSegment = state.currentSegment.get(playerId);
|
|
64
|
-
if (currentSegment && currentPositionMs - currentSegment.start_ms > 100) segments.push({
|
|
65
|
-
start_ms: Math.round(currentSegment.start_ms),
|
|
66
|
-
end_ms: Math.round(currentPositionMs),
|
|
67
|
-
speed: currentSegment.speed
|
|
68
|
-
});
|
|
69
|
-
return segments;
|
|
70
|
-
},
|
|
71
|
-
/**
|
|
72
|
-
* Clear all segments for a player
|
|
73
|
-
*/
|
|
74
|
-
clearSegments(playerId) {
|
|
75
|
-
const state = analyticsStore.get();
|
|
76
|
-
const newSegments = new Map(state.segments);
|
|
77
|
-
newSegments.delete(playerId);
|
|
78
|
-
const newCurrentSegment = new Map(state.currentSegment);
|
|
79
|
-
newCurrentSegment.delete(playerId);
|
|
80
|
-
analyticsStore.set({
|
|
81
|
-
...state,
|
|
82
|
-
segments: newSegments,
|
|
83
|
-
currentSegment: newCurrentSegment
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
export { analyticsStore, analyticsStoreActions };
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { UUID } from "../types/uuid.js";
|
|
2
|
-
import { MapStore } from "nanostores";
|
|
3
|
-
export interface ControlsState {
|
|
4
|
-
visible: boolean;
|
|
5
|
-
hideTimeout: ReturnType<typeof setTimeout> | null;
|
|
6
|
-
}
|
|
7
|
-
interface ControlsStore {
|
|
8
|
-
state: Map<UUID, MapStore<ControlsState>>;
|
|
9
|
-
get: (id: UUID) => MapStore<ControlsState>;
|
|
10
|
-
deleteControls: (id: UUID) => void;
|
|
11
|
-
setVisible: (id: UUID, visible: boolean) => void;
|
|
12
|
-
showControls: (id: UUID, autoHideMs?: number) => void;
|
|
13
|
-
hideControls: (id: UUID) => void;
|
|
14
|
-
}
|
|
15
|
-
export declare const controlsStore: ControlsStore;
|
|
16
|
-
export {};
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { map } from "nanostores";
|
|
2
|
-
|
|
3
|
-
// src/store/controls-store.ts
|
|
4
|
-
const initialControls = {
|
|
5
|
-
visible: false,
|
|
6
|
-
hideTimeout: null
|
|
7
|
-
};
|
|
8
|
-
const controlsStore = {
|
|
9
|
-
state: /* @__PURE__ */ new Map(),
|
|
10
|
-
get: (id) => {
|
|
11
|
-
let controls = controlsStore.state.get(id);
|
|
12
|
-
if (!controls) {
|
|
13
|
-
controls = map({ ...initialControls });
|
|
14
|
-
controlsStore.state.set(id, controls);
|
|
15
|
-
}
|
|
16
|
-
return controls;
|
|
17
|
-
},
|
|
18
|
-
deleteControls: (id) => {
|
|
19
|
-
const controls = controlsStore.state.get(id);
|
|
20
|
-
if (controls) {
|
|
21
|
-
const state = controls.get();
|
|
22
|
-
if (state.hideTimeout) clearTimeout(state.hideTimeout);
|
|
23
|
-
}
|
|
24
|
-
controlsStore.state.delete(id);
|
|
25
|
-
},
|
|
26
|
-
setVisible: (id, visible) => {
|
|
27
|
-
const controls = controlsStore.get(id);
|
|
28
|
-
const currentState = controls.get();
|
|
29
|
-
if (currentState.hideTimeout) clearTimeout(currentState.hideTimeout);
|
|
30
|
-
controls.setKey("visible", visible);
|
|
31
|
-
controls.setKey("hideTimeout", null);
|
|
32
|
-
},
|
|
33
|
-
showControls: (id, autoHideMs) => {
|
|
34
|
-
const controls = controlsStore.get(id);
|
|
35
|
-
const currentState = controls.get();
|
|
36
|
-
if (currentState.hideTimeout) clearTimeout(currentState.hideTimeout);
|
|
37
|
-
let hideTimeout = null;
|
|
38
|
-
if (autoHideMs !== void 0 && autoHideMs > 0) hideTimeout = setTimeout(() => {
|
|
39
|
-
controlsStore.setVisible(id, false);
|
|
40
|
-
}, autoHideMs);
|
|
41
|
-
controls.setKey("visible", true);
|
|
42
|
-
controls.setKey("hideTimeout", hideTimeout);
|
|
43
|
-
},
|
|
44
|
-
hideControls: (id) => {
|
|
45
|
-
const controls = controlsStore.get(id);
|
|
46
|
-
const currentState = controls.get();
|
|
47
|
-
if (currentState.hideTimeout) clearTimeout(currentState.hideTimeout);
|
|
48
|
-
controls.setKey("visible", false);
|
|
49
|
-
controls.setKey("hideTimeout", null);
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
export { controlsStore };
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { FeedPost } from "../types/feed.js";
|
|
2
|
-
import { WritableAtom } from "nanostores";
|
|
3
|
-
interface FeedCacheState {
|
|
4
|
-
cachedPosts: FeedPost[];
|
|
5
|
-
isLoadingFromCache: boolean;
|
|
6
|
-
}
|
|
7
|
-
export declare const feedCacheAtom: WritableAtom<FeedCacheState>;
|
|
8
|
-
interface FeedCacheStore {
|
|
9
|
-
currentFeedId: string | undefined;
|
|
10
|
-
loadCache: (feedId?: string) => FeedPost[];
|
|
11
|
-
/**
|
|
12
|
-
* Append posts to the cache. Pass the feed the posts came from and the batch
|
|
13
|
-
* is refused if the cache has since moved to another feed.
|
|
14
|
-
*/
|
|
15
|
-
saveNewPosts: (newPosts: FeedPost[], feedId?: string) => void;
|
|
16
|
-
removePost: (postId: string) => void;
|
|
17
|
-
clearCache: () => void;
|
|
18
|
-
getCacheStats: () => {
|
|
19
|
-
size: number;
|
|
20
|
-
timestamp: number | null;
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
export declare const feedCacheStore: FeedCacheStore;
|
|
24
|
-
export {};
|