@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
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import { atom } from "nanostores";
|
|
2
|
-
|
|
3
|
-
// src/store/feed-cache-store.ts
|
|
4
|
-
const CACHE_KEY = "rixl_feed_cache";
|
|
5
|
-
const CACHE_VERSION = 6;
|
|
6
|
-
const MAX_CACHED_POSTS = 50;
|
|
7
|
-
const feedCacheAtom = atom({
|
|
8
|
-
cachedPosts: [],
|
|
9
|
-
isLoadingFromCache: false
|
|
10
|
-
});
|
|
11
|
-
/**
|
|
12
|
-
* Check that a value is a non-null object (narrows from unknown)
|
|
13
|
-
*/
|
|
14
|
-
function isObject(value) {
|
|
15
|
-
return typeof value === "object" && value !== null;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Check that all common string fields are present on a post-like object
|
|
19
|
-
*/
|
|
20
|
-
function hasRequiredStringFields(post) {
|
|
21
|
-
return typeof post.id === "string" && typeof post.creatorId === "string" && typeof post.feedId === "string" && typeof post.description === "string" && typeof post.createdAt === "string";
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Validate a single post to ensure it has all required fields
|
|
25
|
-
*/
|
|
26
|
-
function isValidPost(post) {
|
|
27
|
-
if (!isObject(post)) return false;
|
|
28
|
-
if (!hasRequiredStringFields(post)) return false;
|
|
29
|
-
const isVideo = post.type === "video";
|
|
30
|
-
const isImage = post.type === "image";
|
|
31
|
-
if (!isVideo && !isImage) return false;
|
|
32
|
-
return isVideo ? post.video !== void 0 : post.image !== void 0;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Load cached posts from localStorage.
|
|
36
|
-
* If feedId is provided and doesn't match the cached feedId, cache is cleared.
|
|
37
|
-
*/
|
|
38
|
-
function loadFromLocalStorage(feedId) {
|
|
39
|
-
try {
|
|
40
|
-
const cached = localStorage.getItem(CACHE_KEY);
|
|
41
|
-
if (!cached) return [];
|
|
42
|
-
const data = JSON.parse(cached);
|
|
43
|
-
if (data.version !== CACHE_VERSION) {
|
|
44
|
-
localStorage.removeItem(CACHE_KEY);
|
|
45
|
-
return [];
|
|
46
|
-
}
|
|
47
|
-
if (feedId && data.feedId && data.feedId !== feedId) {
|
|
48
|
-
localStorage.removeItem(CACHE_KEY);
|
|
49
|
-
return [];
|
|
50
|
-
}
|
|
51
|
-
const validPosts = data.posts.filter((post) => {
|
|
52
|
-
if (!isValidPost(post)) {
|
|
53
|
-
console.warn("[FeedCache] Invalid post found in cache:", post);
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
return true;
|
|
57
|
-
});
|
|
58
|
-
if (validPosts.length !== data.posts.length) saveToLocalStorage(validPosts, feedId);
|
|
59
|
-
return validPosts;
|
|
60
|
-
} catch {
|
|
61
|
-
localStorage.removeItem(CACHE_KEY);
|
|
62
|
-
return [];
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Save posts to localStorage
|
|
67
|
-
*/
|
|
68
|
-
function saveToLocalStorage(posts, feedId) {
|
|
69
|
-
try {
|
|
70
|
-
const postsToCache = posts.slice(0, MAX_CACHED_POSTS);
|
|
71
|
-
const data = {
|
|
72
|
-
version: CACHE_VERSION,
|
|
73
|
-
feedId,
|
|
74
|
-
posts: postsToCache,
|
|
75
|
-
timestamp: Date.now()
|
|
76
|
-
};
|
|
77
|
-
localStorage.setItem(CACHE_KEY, JSON.stringify(data));
|
|
78
|
-
} catch (error) {
|
|
79
|
-
if (error instanceof DOMException && error.name === "QuotaExceededError") localStorage.removeItem(CACHE_KEY);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
const feedCacheStore = {
|
|
83
|
-
/** The current feed ID associated with the cache */
|
|
84
|
-
currentFeedId: void 0,
|
|
85
|
-
/**
|
|
86
|
-
* Load cached posts from localStorage on app init.
|
|
87
|
-
* Clears cache if feedId changed since last session.
|
|
88
|
-
*/
|
|
89
|
-
loadCache(feedId) {
|
|
90
|
-
this.currentFeedId = feedId;
|
|
91
|
-
feedCacheAtom.set({
|
|
92
|
-
...feedCacheAtom.get(),
|
|
93
|
-
isLoadingFromCache: true
|
|
94
|
-
});
|
|
95
|
-
const cachedPosts = loadFromLocalStorage(feedId);
|
|
96
|
-
feedCacheAtom.set({
|
|
97
|
-
cachedPosts,
|
|
98
|
-
isLoadingFromCache: false
|
|
99
|
-
});
|
|
100
|
-
return cachedPosts;
|
|
101
|
-
},
|
|
102
|
-
/**
|
|
103
|
-
* Save new posts to cache (append to existing)
|
|
104
|
-
*/
|
|
105
|
-
saveNewPosts(newPosts, feedId) {
|
|
106
|
-
if (feedId !== void 0 && feedId !== this.currentFeedId) return;
|
|
107
|
-
const currentState = feedCacheAtom.get();
|
|
108
|
-
const existingIds = new Set(currentState.cachedPosts.map((p) => p.id));
|
|
109
|
-
const uniqueNewPosts = newPosts.filter((post) => !existingIds.has(post.id));
|
|
110
|
-
if (uniqueNewPosts.length === 0) return;
|
|
111
|
-
const updatedPosts = [...currentState.cachedPosts, ...uniqueNewPosts];
|
|
112
|
-
feedCacheAtom.set({
|
|
113
|
-
...currentState,
|
|
114
|
-
cachedPosts: updatedPosts
|
|
115
|
-
});
|
|
116
|
-
saveToLocalStorage(updatedPosts, this.currentFeedId);
|
|
117
|
-
},
|
|
118
|
-
/**
|
|
119
|
-
* Remove a viewed post from cache
|
|
120
|
-
*/
|
|
121
|
-
removePost(postId) {
|
|
122
|
-
const currentState = feedCacheAtom.get();
|
|
123
|
-
const filteredPosts = currentState.cachedPosts.filter((post) => post.id !== postId);
|
|
124
|
-
if (filteredPosts.length === currentState.cachedPosts.length) return;
|
|
125
|
-
feedCacheAtom.set({
|
|
126
|
-
...currentState,
|
|
127
|
-
cachedPosts: filteredPosts
|
|
128
|
-
});
|
|
129
|
-
saveToLocalStorage(filteredPosts, this.currentFeedId);
|
|
130
|
-
},
|
|
131
|
-
/**
|
|
132
|
-
* Clear all cached posts
|
|
133
|
-
*/
|
|
134
|
-
clearCache() {
|
|
135
|
-
localStorage.removeItem(CACHE_KEY);
|
|
136
|
-
feedCacheAtom.set({
|
|
137
|
-
cachedPosts: [],
|
|
138
|
-
isLoadingFromCache: false
|
|
139
|
-
});
|
|
140
|
-
},
|
|
141
|
-
/**
|
|
142
|
-
* Get cache statistics
|
|
143
|
-
*/
|
|
144
|
-
getCacheStats() {
|
|
145
|
-
try {
|
|
146
|
-
const cached = localStorage.getItem(CACHE_KEY);
|
|
147
|
-
if (!cached) return {
|
|
148
|
-
size: 0,
|
|
149
|
-
timestamp: null
|
|
150
|
-
};
|
|
151
|
-
const data = JSON.parse(cached);
|
|
152
|
-
return {
|
|
153
|
-
size: data.posts.length,
|
|
154
|
-
timestamp: data.timestamp
|
|
155
|
-
};
|
|
156
|
-
} catch {
|
|
157
|
-
return {
|
|
158
|
-
size: 0,
|
|
159
|
-
timestamp: null
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
export { feedCacheAtom, feedCacheStore };
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { WritableAtom } from "nanostores";
|
|
2
|
-
export declare const FEED_COMPONENTS_COUNT = 5;
|
|
3
|
-
export declare const FEED_TRANSITION_THRESHOLD: number;
|
|
4
|
-
interface FeedInteractionStore {
|
|
5
|
-
hasInteracted: WritableAtom<boolean>;
|
|
6
|
-
whenInteracted: WritableAtom<Date>;
|
|
7
|
-
hasInitialized: WritableAtom<boolean>;
|
|
8
|
-
videosInitialized: WritableAtom<number>;
|
|
9
|
-
components: WritableAtom<number[]>;
|
|
10
|
-
originalPositions: WritableAtom<number[]>;
|
|
11
|
-
transforms: WritableAtom<number[]>;
|
|
12
|
-
setTransforms: (transforms: number[]) => void;
|
|
13
|
-
}
|
|
14
|
-
export declare const feedStore: FeedInteractionStore;
|
|
15
|
-
export declare const setHasInteracted: () => boolean;
|
|
16
|
-
export declare const initializeVideo: () => void;
|
|
17
|
-
export {};
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { atom } from "nanostores";
|
|
2
|
-
|
|
3
|
-
// src/store/feed-interaction-store.ts
|
|
4
|
-
const FEED_COMPONENTS_COUNT = 5;
|
|
5
|
-
const FEED_TRANSITION_THRESHOLD = Math.floor(5 / 2);
|
|
6
|
-
const feedStore = {
|
|
7
|
-
hasInteracted: atom(false),
|
|
8
|
-
whenInteracted: atom(/* @__PURE__ */ new Date(0)),
|
|
9
|
-
hasInitialized: atom(false),
|
|
10
|
-
videosInitialized: atom(5),
|
|
11
|
-
components: atom(Array.from({ length: 5 })),
|
|
12
|
-
originalPositions: atom(Array.from({ length: 5 }).map((_, i) => i)),
|
|
13
|
-
transforms: atom(Array.from({ length: 5 }).map((_, i) => i)),
|
|
14
|
-
setTransforms: (transforms) => {
|
|
15
|
-
const current = feedStore.transforms.get();
|
|
16
|
-
if (current.length === transforms.length && current.every((v, i) => v === transforms[i])) return;
|
|
17
|
-
feedStore.transforms.set(transforms);
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
const setHasInteracted = () => {
|
|
21
|
-
if (feedStore.hasInitialized.get()) {
|
|
22
|
-
feedStore.hasInteracted.set(true);
|
|
23
|
-
feedStore.whenInteracted.set(/* @__PURE__ */ new Date());
|
|
24
|
-
}
|
|
25
|
-
return feedStore.hasInteracted.get();
|
|
26
|
-
};
|
|
27
|
-
const initializeVideo = () => {
|
|
28
|
-
feedStore.videosInitialized.set(feedStore.videosInitialized.get() + 1);
|
|
29
|
-
if (feedStore.videosInitialized.get() >= 5) feedStore.hasInitialized.set(true);
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export { FEED_COMPONENTS_COUNT, FEED_TRANSITION_THRESHOLD, feedStore, initializeVideo, setHasInteracted };
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { FeedPost, FeedPostsResponse } from "../types/feed.js";
|
|
2
|
-
/**
|
|
3
|
-
* Get a feed post by ID, using cache if available
|
|
4
|
-
* @param feedId ID of the feed
|
|
5
|
-
* @param postId ID of the post to fetch
|
|
6
|
-
* @returns Promise with the feed post
|
|
7
|
-
*/
|
|
8
|
-
export declare const getFeedPost: (feedId: string, postId: string) => Promise<FeedPost>;
|
|
9
|
-
/**
|
|
10
|
-
* Get posts from a specific feed, with pagination
|
|
11
|
-
* @param feedId ID of the feed
|
|
12
|
-
* @param offset Pagination offset
|
|
13
|
-
* @param limit Maximum number of items to return
|
|
14
|
-
* @returns Promise with feed posts response
|
|
15
|
-
*/
|
|
16
|
-
export declare const getFeedPosts: (feedId: string, offset?: number, limit?: number) => Promise<FeedPostsResponse>;
|
package/dist/store/feed-store.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { fetchFeedPost, fetchFeedPosts } from "../api/feed.js";
|
|
2
|
-
import { createStore } from "./generic-store.js";
|
|
3
|
-
|
|
4
|
-
// src/store/feed-store.ts
|
|
5
|
-
const store = createStore();
|
|
6
|
-
const feedListCache = /* @__PURE__ */ new Map();
|
|
7
|
-
/**
|
|
8
|
-
* Get a feed post by ID, using cache if available
|
|
9
|
-
* @param feedId ID of the feed
|
|
10
|
-
* @param postId ID of the post to fetch
|
|
11
|
-
* @returns Promise with the feed post
|
|
12
|
-
*/
|
|
13
|
-
const getFeedPost = async (feedId, postId) => {
|
|
14
|
-
const cacheKey = `${feedId}:${postId}`;
|
|
15
|
-
return store.get(cacheKey, () => fetchFeedPost(feedId, postId));
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* Get posts from a specific feed, with pagination
|
|
19
|
-
* @param feedId ID of the feed
|
|
20
|
-
* @param offset Pagination offset
|
|
21
|
-
* @param limit Maximum number of items to return
|
|
22
|
-
* @returns Promise with feed posts response
|
|
23
|
-
*/
|
|
24
|
-
const getFeedPosts = async (feedId, offset = 0, limit = 10) => {
|
|
25
|
-
if (offset > 0) return fetchFeedPosts(feedId, offset, limit);
|
|
26
|
-
const cacheKey = `feed:${feedId}`;
|
|
27
|
-
const cachedPosts = feedListCache.get(cacheKey);
|
|
28
|
-
if (cachedPosts) return cachedPosts;
|
|
29
|
-
const posts = await fetchFeedPosts(feedId, offset, limit);
|
|
30
|
-
feedListCache.set(cacheKey, posts);
|
|
31
|
-
posts.posts.forEach((post) => {
|
|
32
|
-
const postKey = `${feedId}:${post.id}`;
|
|
33
|
-
store.get(postKey, () => Promise.resolve(post));
|
|
34
|
-
});
|
|
35
|
-
return posts;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export { getFeedPost, getFeedPosts };
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
// src/store/generic-store.ts
|
|
2
|
-
const createStore = () => {
|
|
3
|
-
const store = /* @__PURE__ */ new Map();
|
|
4
|
-
const pendingRequests = /* @__PURE__ */ new Map();
|
|
5
|
-
const get = async (id, fetcher) => {
|
|
6
|
-
const item = store.get(id);
|
|
7
|
-
if (item) return item;
|
|
8
|
-
const pendingRequest = pendingRequests.get(id);
|
|
9
|
-
if (pendingRequest) return pendingRequest;
|
|
10
|
-
const request = fetcher(id).then((apiItem) => {
|
|
11
|
-
store.set(id, apiItem);
|
|
12
|
-
pendingRequests.delete(id);
|
|
13
|
-
return apiItem;
|
|
14
|
-
}).catch((error) => {
|
|
15
|
-
pendingRequests.delete(id);
|
|
16
|
-
throw error;
|
|
17
|
-
});
|
|
18
|
-
pendingRequests.set(id, request);
|
|
19
|
-
return request;
|
|
20
|
-
};
|
|
21
|
-
return { get };
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export { createStore };
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { UUID } from "../types/uuid.js";
|
|
2
|
-
interface PlayerContainerElementStore {
|
|
3
|
-
register: (playerId: UUID, element: HTMLDivElement) => void;
|
|
4
|
-
unregister: (playerId: UUID) => void;
|
|
5
|
-
get: (playerId: UUID) => HTMLDivElement | null;
|
|
6
|
-
subscribe: (playerId: UUID, listener: () => void) => () => void;
|
|
7
|
-
clear: () => void;
|
|
8
|
-
}
|
|
9
|
-
export declare const playerContainerElementStore: PlayerContainerElementStore;
|
|
10
|
-
export {};
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// src/store/player-container-element-store.ts
|
|
2
|
-
const state = /* @__PURE__ */ new Map();
|
|
3
|
-
const listeners = /* @__PURE__ */ new Map();
|
|
4
|
-
function notify(playerId) {
|
|
5
|
-
listeners.get(playerId)?.forEach((listener) => listener());
|
|
6
|
-
}
|
|
7
|
-
const playerContainerElementStore = {
|
|
8
|
-
register: (playerId, element) => {
|
|
9
|
-
state.set(playerId, element);
|
|
10
|
-
notify(playerId);
|
|
11
|
-
},
|
|
12
|
-
unregister: (playerId) => {
|
|
13
|
-
state.delete(playerId);
|
|
14
|
-
notify(playerId);
|
|
15
|
-
},
|
|
16
|
-
get: (playerId) => state.get(playerId) ?? null,
|
|
17
|
-
subscribe: (playerId, listener) => {
|
|
18
|
-
let playerListeners = listeners.get(playerId);
|
|
19
|
-
if (!playerListeners) {
|
|
20
|
-
playerListeners = /* @__PURE__ */ new Set();
|
|
21
|
-
listeners.set(playerId, playerListeners);
|
|
22
|
-
}
|
|
23
|
-
playerListeners.add(listener);
|
|
24
|
-
return () => {
|
|
25
|
-
const currentListeners = listeners.get(playerId);
|
|
26
|
-
if (!currentListeners) return;
|
|
27
|
-
currentListeners.delete(listener);
|
|
28
|
-
if (currentListeners.size === 0) listeners.delete(playerId);
|
|
29
|
-
};
|
|
30
|
-
},
|
|
31
|
-
clear: () => {
|
|
32
|
-
const playerIds = /* @__PURE__ */ new Set([...state.keys(), ...listeners.keys()]);
|
|
33
|
-
state.clear();
|
|
34
|
-
playerIds.forEach((playerId) => notify(playerId));
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export { playerContainerElementStore };
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { settingsStore } from "./settings/store.js";
|
|
2
|
-
|
|
3
|
-
// src/store/player-global-actions.ts
|
|
4
|
-
function findTrackIndexByLanguage(tracks, language) {
|
|
5
|
-
return tracks.findIndex((track) => track.language === language);
|
|
6
|
-
}
|
|
7
|
-
const playerGlobalActions = {
|
|
8
|
-
setGlobalMuted(muted) {
|
|
9
|
-
this.state.forEach((_atom, playerId) => {
|
|
10
|
-
if (!muted) this.setHasInteracted(playerId);
|
|
11
|
-
this.setMuted(playerId, muted);
|
|
12
|
-
});
|
|
13
|
-
settingsStore.setMuted(muted);
|
|
14
|
-
},
|
|
15
|
-
setGlobalVolume(volume) {
|
|
16
|
-
this.state.forEach((_atom, playerId) => this.setVolume(playerId, volume));
|
|
17
|
-
settingsStore.setVolume(volume);
|
|
18
|
-
},
|
|
19
|
-
setGlobalPlaybackRate(rate) {
|
|
20
|
-
this.state.forEach((_atom, playerId) => this.setPlaybackRate(playerId, rate));
|
|
21
|
-
settingsStore.setPlaybackSpeed(rate);
|
|
22
|
-
},
|
|
23
|
-
setGlobalPreferredQuality(quality) {
|
|
24
|
-
settingsStore.setPreferredQuality(quality);
|
|
25
|
-
},
|
|
26
|
-
setGlobalPreferredAudioLanguage(language) {
|
|
27
|
-
settingsStore.setPreferredAudioLanguage(language);
|
|
28
|
-
if (!language) return;
|
|
29
|
-
this.state.forEach((_atom, playerId) => {
|
|
30
|
-
const { availableAudioTracks } = this.get(playerId).get();
|
|
31
|
-
const index = findTrackIndexByLanguage(availableAudioTracks, language);
|
|
32
|
-
if (index >= 0) this.setAudioTrack(playerId, index);
|
|
33
|
-
});
|
|
34
|
-
},
|
|
35
|
-
setGlobalPreferredSubtitleLanguage(language) {
|
|
36
|
-
settingsStore.setPreferredSubtitleLanguage(language);
|
|
37
|
-
if (language === void 0) return;
|
|
38
|
-
if (language === "") {
|
|
39
|
-
this.state.forEach((_atom, playerId) => this.setSubtitleTrack(playerId, -1));
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
this.state.forEach((_atom, playerId) => {
|
|
43
|
-
const { availableSubtitleTracks } = this.get(playerId).get();
|
|
44
|
-
const index = findTrackIndexByLanguage(availableSubtitleTracks, language);
|
|
45
|
-
if (index >= 0) this.setSubtitleTrack(playerId, index);
|
|
46
|
-
});
|
|
47
|
-
},
|
|
48
|
-
pauseAllPlayers() {
|
|
49
|
-
this.state.forEach((_atom, playerId) => this.setPaused(playerId, true));
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
export { playerGlobalActions };
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { UUID } from "../types/uuid.js";
|
|
2
|
-
interface PlayerMediaElementStore {
|
|
3
|
-
register: (playerId: UUID, element: HTMLVideoElement) => void;
|
|
4
|
-
unregister: (playerId: UUID) => void;
|
|
5
|
-
get: (playerId: UUID) => HTMLVideoElement | null;
|
|
6
|
-
subscribe: (playerId: UUID, listener: () => void) => () => void;
|
|
7
|
-
clear: () => void;
|
|
8
|
-
}
|
|
9
|
-
export declare const playerMediaElementStore: PlayerMediaElementStore;
|
|
10
|
-
export {};
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// src/store/player-media-element-store.ts
|
|
2
|
-
const state = /* @__PURE__ */ new Map();
|
|
3
|
-
const listeners = /* @__PURE__ */ new Map();
|
|
4
|
-
function notify(playerId) {
|
|
5
|
-
listeners.get(playerId)?.forEach((listener) => listener());
|
|
6
|
-
}
|
|
7
|
-
const playerMediaElementStore = {
|
|
8
|
-
register: (playerId, element) => {
|
|
9
|
-
state.set(playerId, element);
|
|
10
|
-
notify(playerId);
|
|
11
|
-
},
|
|
12
|
-
unregister: (playerId) => {
|
|
13
|
-
state.delete(playerId);
|
|
14
|
-
notify(playerId);
|
|
15
|
-
},
|
|
16
|
-
get: (playerId) => state.get(playerId) ?? null,
|
|
17
|
-
subscribe: (playerId, listener) => {
|
|
18
|
-
let playerListeners = listeners.get(playerId);
|
|
19
|
-
if (!playerListeners) {
|
|
20
|
-
playerListeners = /* @__PURE__ */ new Set();
|
|
21
|
-
listeners.set(playerId, playerListeners);
|
|
22
|
-
}
|
|
23
|
-
playerListeners.add(listener);
|
|
24
|
-
return () => {
|
|
25
|
-
const currentListeners = listeners.get(playerId);
|
|
26
|
-
if (!currentListeners) return;
|
|
27
|
-
currentListeners.delete(listener);
|
|
28
|
-
if (currentListeners.size === 0) listeners.delete(playerId);
|
|
29
|
-
};
|
|
30
|
-
},
|
|
31
|
-
clear: () => {
|
|
32
|
-
const playerIds = /* @__PURE__ */ new Set([...state.keys(), ...listeners.keys()]);
|
|
33
|
-
state.clear();
|
|
34
|
-
playerIds.forEach((playerId) => notify(playerId));
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export { playerMediaElementStore };
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import { clamp } from "../lib/numbers.js";
|
|
2
|
-
import { clampVolume, getRestoredVolume } from "../lib/volume-utils.js";
|
|
3
|
-
import { playerMediaElementStore } from "./player-media-element-store.js";
|
|
4
|
-
|
|
5
|
-
// src/store/player-store-actions.ts
|
|
6
|
-
const PROGRESS_EVENTS = [
|
|
7
|
-
"loadedmetadata",
|
|
8
|
-
"durationchange",
|
|
9
|
-
"timeupdate",
|
|
10
|
-
"progress",
|
|
11
|
-
"seeking",
|
|
12
|
-
"seeked",
|
|
13
|
-
"emptied"
|
|
14
|
-
];
|
|
15
|
-
const progressSnapshotCache = /* @__PURE__ */ new Map();
|
|
16
|
-
function toSafeDuration(video) {
|
|
17
|
-
const duration = video?.duration ?? 0;
|
|
18
|
-
return Number.isFinite(duration) && duration > 0 ? duration : 0;
|
|
19
|
-
}
|
|
20
|
-
function toSafeCurrentTime(video, duration) {
|
|
21
|
-
if (!video || duration <= 0) return 0;
|
|
22
|
-
const currentTime = video.currentTime;
|
|
23
|
-
if (!Number.isFinite(currentTime)) return 0;
|
|
24
|
-
return clamp(currentTime, 0, duration);
|
|
25
|
-
}
|
|
26
|
-
function toSafeBuffered(video, duration) {
|
|
27
|
-
if (!video || duration <= 0 || video.buffered.length === 0) return 0;
|
|
28
|
-
try {
|
|
29
|
-
const bufferedEnd = video.buffered.end(video.buffered.length - 1);
|
|
30
|
-
if (!Number.isFinite(bufferedEnd)) return 0;
|
|
31
|
-
return clamp(bufferedEnd / duration, 0, 1);
|
|
32
|
-
} catch {
|
|
33
|
-
return 0;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
function subscribeToProgressVideo(video, onStoreChange) {
|
|
37
|
-
if (!video) return () => {};
|
|
38
|
-
let active = true;
|
|
39
|
-
let queued = false;
|
|
40
|
-
const handleStoreChange = () => {
|
|
41
|
-
if (queued) return;
|
|
42
|
-
queued = true;
|
|
43
|
-
queueMicrotask(() => {
|
|
44
|
-
queued = false;
|
|
45
|
-
if (!active) return;
|
|
46
|
-
onStoreChange();
|
|
47
|
-
});
|
|
48
|
-
};
|
|
49
|
-
PROGRESS_EVENTS.forEach((eventName) => {
|
|
50
|
-
video.addEventListener(eventName, handleStoreChange);
|
|
51
|
-
});
|
|
52
|
-
return () => {
|
|
53
|
-
active = false;
|
|
54
|
-
PROGRESS_EVENTS.forEach((eventName) => {
|
|
55
|
-
video.removeEventListener(eventName, handleStoreChange);
|
|
56
|
-
});
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Apply the store's volume/muted to the registered media element — same
|
|
61
|
-
* pattern as playMedia/pauseMedia, so frameworks never re-apply by hand.
|
|
62
|
-
*/
|
|
63
|
-
function applyVolumeStateToElement(id, state) {
|
|
64
|
-
const video = playerMediaElementStore.get(id);
|
|
65
|
-
if (!video) return;
|
|
66
|
-
video.volume = state.volume;
|
|
67
|
-
video.muted = state.muted;
|
|
68
|
-
}
|
|
69
|
-
const playerStateActions = {
|
|
70
|
-
getEffectiveMediaMuted: (player) => player.muted || player.volume === 0 || !player.hasInteracted,
|
|
71
|
-
muteMedia(id) {
|
|
72
|
-
const player = this.get(id).get();
|
|
73
|
-
this.setHasInteracted(id);
|
|
74
|
-
if (player.volume > 0) this.setPreviousVolume(id, player.volume);
|
|
75
|
-
this.setVolume(id, 0);
|
|
76
|
-
this.setMuted(id, true);
|
|
77
|
-
applyVolumeStateToElement(id, this.get(id).get());
|
|
78
|
-
},
|
|
79
|
-
unmuteMedia(id) {
|
|
80
|
-
const player = this.get(id).get();
|
|
81
|
-
const restoredVolume = getRestoredVolume(player.volume, player.previousVolume);
|
|
82
|
-
this.setHasInteracted(id);
|
|
83
|
-
if (player.volume === 0) this.setVolume(id, restoredVolume);
|
|
84
|
-
this.setMuted(id, false);
|
|
85
|
-
applyVolumeStateToElement(id, this.get(id).get());
|
|
86
|
-
},
|
|
87
|
-
toggleMediaMute(id) {
|
|
88
|
-
const player = this.get(id).get();
|
|
89
|
-
if (this.getEffectiveMediaMuted(player)) {
|
|
90
|
-
this.unmuteMedia(id);
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
this.muteMedia(id);
|
|
94
|
-
},
|
|
95
|
-
setMediaVolume(id, volume) {
|
|
96
|
-
const player = this.get(id).get();
|
|
97
|
-
const nextVolume = clampVolume(volume);
|
|
98
|
-
this.setHasInteracted(id);
|
|
99
|
-
if (nextVolume === 0 && player.volume > 0) this.setPreviousVolume(id, player.volume);
|
|
100
|
-
this.setVolume(id, nextVolume);
|
|
101
|
-
this.setMuted(id, nextVolume === 0);
|
|
102
|
-
applyVolumeStateToElement(id, this.get(id).get());
|
|
103
|
-
},
|
|
104
|
-
async playMedia(id) {
|
|
105
|
-
const video = playerMediaElementStore.get(id);
|
|
106
|
-
if (!video) return;
|
|
107
|
-
this.setHasInteracted(id);
|
|
108
|
-
this.setEnded(id, false);
|
|
109
|
-
this.setPaused(id, false);
|
|
110
|
-
try {
|
|
111
|
-
await video.play();
|
|
112
|
-
} catch {
|
|
113
|
-
this.setPaused(id, true);
|
|
114
|
-
}
|
|
115
|
-
},
|
|
116
|
-
pauseMedia(id) {
|
|
117
|
-
const video = playerMediaElementStore.get(id);
|
|
118
|
-
if (!video) return;
|
|
119
|
-
video.pause();
|
|
120
|
-
this.setPaused(id, true);
|
|
121
|
-
},
|
|
122
|
-
async toggleMediaPlayback(id) {
|
|
123
|
-
if (this.get(id).get().paused) {
|
|
124
|
-
await this.playMedia(id);
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
this.pauseMedia(id);
|
|
128
|
-
},
|
|
129
|
-
pauseOtherMedia(except) {
|
|
130
|
-
this.state.forEach((_player, playerId) => {
|
|
131
|
-
if (playerId === except) return;
|
|
132
|
-
const video = playerMediaElementStore.get(playerId);
|
|
133
|
-
if (video) video.pause();
|
|
134
|
-
this.setPaused(playerId, true);
|
|
135
|
-
});
|
|
136
|
-
},
|
|
137
|
-
setMediaPlaybackRate(id, playbackRate) {
|
|
138
|
-
const video = playerMediaElementStore.get(id);
|
|
139
|
-
this.setPlaybackRate(id, playbackRate);
|
|
140
|
-
if (video) video.playbackRate = this.get(id).get().playbackRate;
|
|
141
|
-
},
|
|
142
|
-
readProgressSnapshot(id) {
|
|
143
|
-
const video = playerMediaElementStore.get(id);
|
|
144
|
-
const duration = toSafeDuration(video);
|
|
145
|
-
const currentTime = toSafeCurrentTime(video, duration);
|
|
146
|
-
const nextSnapshot = {
|
|
147
|
-
currentTime,
|
|
148
|
-
duration,
|
|
149
|
-
progress: duration > 0 ? clamp(currentTime / duration, 0, 1) : 0,
|
|
150
|
-
buffered: toSafeBuffered(video, duration)
|
|
151
|
-
};
|
|
152
|
-
const cachedSnapshot = progressSnapshotCache.get(id);
|
|
153
|
-
if (cachedSnapshot && cachedSnapshot.currentTime === nextSnapshot.currentTime && cachedSnapshot.duration === nextSnapshot.duration && cachedSnapshot.progress === nextSnapshot.progress && cachedSnapshot.buffered === nextSnapshot.buffered) return cachedSnapshot;
|
|
154
|
-
progressSnapshotCache.set(id, nextSnapshot);
|
|
155
|
-
return nextSnapshot;
|
|
156
|
-
},
|
|
157
|
-
subscribeToProgress(id, onStoreChange) {
|
|
158
|
-
let currentVideo = playerMediaElementStore.get(id);
|
|
159
|
-
let unsubscribeVideo = subscribeToProgressVideo(currentVideo, onStoreChange);
|
|
160
|
-
const unsubscribeRegistry = playerMediaElementStore.subscribe(id, () => {
|
|
161
|
-
const nextVideo = playerMediaElementStore.get(id);
|
|
162
|
-
if (nextVideo === currentVideo) return;
|
|
163
|
-
unsubscribeVideo();
|
|
164
|
-
currentVideo = nextVideo;
|
|
165
|
-
unsubscribeVideo = subscribeToProgressVideo(currentVideo, onStoreChange);
|
|
166
|
-
onStoreChange();
|
|
167
|
-
});
|
|
168
|
-
return () => {
|
|
169
|
-
unsubscribeRegistry();
|
|
170
|
-
unsubscribeVideo();
|
|
171
|
-
};
|
|
172
|
-
},
|
|
173
|
-
seekProgressTo(id, seconds) {
|
|
174
|
-
const video = playerMediaElementStore.get(id);
|
|
175
|
-
if (!video) return;
|
|
176
|
-
const duration = toSafeDuration(video);
|
|
177
|
-
if (duration <= 0) {
|
|
178
|
-
video.currentTime = 0;
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
video.currentTime = clamp(Number.isFinite(seconds) ? seconds : 0, 0, duration);
|
|
182
|
-
},
|
|
183
|
-
seekProgressBy(id, deltaSeconds) {
|
|
184
|
-
const video = playerMediaElementStore.get(id);
|
|
185
|
-
if (!video) return;
|
|
186
|
-
const duration = toSafeDuration(video);
|
|
187
|
-
if (duration <= 0) {
|
|
188
|
-
video.currentTime = 0;
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
const delta = Number.isFinite(deltaSeconds) ? deltaSeconds : 0;
|
|
192
|
-
const currentTime = toSafeCurrentTime(video, duration);
|
|
193
|
-
video.currentTime = clamp(currentTime + delta, 0, duration);
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
export { playerStateActions };
|