@xhub-short/core 1.0.0-beta.24 → 1.0.0-beta.26
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/dist/index.d.ts +29 -2
- package/dist/index.js +107 -20
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -2023,6 +2023,7 @@ interface PlaylistCollectionState {
|
|
|
2023
2023
|
declare class PlaylistManager {
|
|
2024
2024
|
private readonly dataSource?;
|
|
2025
2025
|
private readonly governor?;
|
|
2026
|
+
private readonly storage?;
|
|
2026
2027
|
/** Zustand vanilla store */
|
|
2027
2028
|
readonly store: StoreApi<PlaylistState>;
|
|
2028
2029
|
/** Resolved configuration */
|
|
@@ -2034,10 +2035,17 @@ declare class PlaylistManager {
|
|
|
2034
2035
|
private fullMetadataItems;
|
|
2035
2036
|
/** Unsubscribe from governor events */
|
|
2036
2037
|
private governorUnsubscribe?;
|
|
2037
|
-
constructor(dataSource?: IPlaylistDataSource | undefined, config?: PlaylistConfig, governor?: ResourceGovernor | undefined);
|
|
2038
|
+
constructor(dataSource?: IPlaylistDataSource | undefined, config?: PlaylistConfig, governor?: ResourceGovernor | undefined, storage?: ISessionStorage | undefined);
|
|
2038
2039
|
/**
|
|
2039
2040
|
* Load a playlist by ID
|
|
2040
2041
|
*/
|
|
2042
|
+
/**
|
|
2043
|
+
* Generates a cache key for a specific playlist
|
|
2044
|
+
*/
|
|
2045
|
+
private getCacheKey;
|
|
2046
|
+
/**
|
|
2047
|
+
* Load playlist data, using cache for an immediate render before network finishes.
|
|
2048
|
+
*/
|
|
2041
2049
|
loadPlaylist(id: string): Promise<void>;
|
|
2042
2050
|
/**
|
|
2043
2051
|
* Set playlist data directly
|
|
@@ -2059,6 +2067,14 @@ declare class PlaylistManager {
|
|
|
2059
2067
|
* Reset state
|
|
2060
2068
|
*/
|
|
2061
2069
|
reset(): void;
|
|
2070
|
+
/**
|
|
2071
|
+
* Get the full (un-minified) list of items in the current playlist.
|
|
2072
|
+
*
|
|
2073
|
+
* Unlike `store.items` (which applies the sliding window and may contain
|
|
2074
|
+
* minified items), this always returns the complete metadata for every item.
|
|
2075
|
+
* Used by PlaylistFeedAdapter to ensure FeedManager receives playable data.
|
|
2076
|
+
*/
|
|
2077
|
+
getFullItems(): ContentItem[];
|
|
2062
2078
|
/**
|
|
2063
2079
|
* Destroy the manager
|
|
2064
2080
|
*/
|
|
@@ -2085,9 +2101,20 @@ declare class PlaylistManager {
|
|
|
2085
2101
|
*/
|
|
2086
2102
|
declare class PlaylistCollectionManager {
|
|
2087
2103
|
private readonly dataSource?;
|
|
2104
|
+
private readonly storage?;
|
|
2088
2105
|
/** Zustand vanilla store */
|
|
2089
2106
|
readonly store: StoreApi<PlaylistCollectionState>;
|
|
2090
|
-
|
|
2107
|
+
/** Cache key for playlist collection */
|
|
2108
|
+
private static readonly CACHE_KEY;
|
|
2109
|
+
constructor(dataSource?: IPlaylistDataSource | undefined, storage?: ISessionStorage | undefined);
|
|
2110
|
+
/**
|
|
2111
|
+
* Hydrate collection from cache
|
|
2112
|
+
*/
|
|
2113
|
+
hydrateFromCache(): Promise<void>;
|
|
2114
|
+
/**
|
|
2115
|
+
* Update cache with current state
|
|
2116
|
+
*/
|
|
2117
|
+
private updateCache;
|
|
2091
2118
|
/**
|
|
2092
2119
|
* Load more playlists (pagination)
|
|
2093
2120
|
*/
|
package/dist/index.js
CHANGED
|
@@ -2042,11 +2042,21 @@ function calculateWindowIndices(focusedIndex, totalItems, maxAllocations = 3) {
|
|
|
2042
2042
|
const indices = [];
|
|
2043
2043
|
const clampedFocus = Math.max(0, Math.min(focusedIndex, totalItems - 1));
|
|
2044
2044
|
indices.push(clampedFocus);
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2045
|
+
let offset = 1;
|
|
2046
|
+
while (indices.length < maxAllocations) {
|
|
2047
|
+
let added = false;
|
|
2048
|
+
if (clampedFocus - offset >= 0 && indices.length < maxAllocations) {
|
|
2049
|
+
indices.push(clampedFocus - offset);
|
|
2050
|
+
added = true;
|
|
2051
|
+
}
|
|
2052
|
+
if (clampedFocus + offset < totalItems && indices.length < maxAllocations) {
|
|
2053
|
+
indices.push(clampedFocus + offset);
|
|
2054
|
+
added = true;
|
|
2055
|
+
}
|
|
2056
|
+
if (!added) {
|
|
2057
|
+
break;
|
|
2058
|
+
}
|
|
2059
|
+
offset++;
|
|
2050
2060
|
}
|
|
2051
2061
|
return indices.sort((a, b) => a - b);
|
|
2052
2062
|
}
|
|
@@ -2101,18 +2111,18 @@ function mapNetworkType(type) {
|
|
|
2101
2111
|
}
|
|
2102
2112
|
var DEFAULT_SCROLL_THRASHING_CONFIG = {
|
|
2103
2113
|
windowMs: 1e3,
|
|
2104
|
-
maxChangesInWindow:
|
|
2105
|
-
cooldownMs:
|
|
2114
|
+
maxChangesInWindow: 3,
|
|
2115
|
+
cooldownMs: 500
|
|
2106
2116
|
};
|
|
2107
2117
|
var DEFAULT_PREFETCH_CONFIG = {
|
|
2108
2118
|
wifi: {
|
|
2109
|
-
posterCount:
|
|
2110
|
-
videoSegmentCount:
|
|
2119
|
+
posterCount: 5,
|
|
2120
|
+
videoSegmentCount: 2,
|
|
2111
2121
|
prefetchVideo: true
|
|
2112
2122
|
},
|
|
2113
2123
|
cellular: {
|
|
2114
|
-
posterCount:
|
|
2115
|
-
videoSegmentCount:
|
|
2124
|
+
posterCount: 3,
|
|
2125
|
+
videoSegmentCount: 1,
|
|
2116
2126
|
prefetchVideo: true
|
|
2117
2127
|
},
|
|
2118
2128
|
offline: {
|
|
@@ -2567,7 +2577,7 @@ var ResourceGovernor = class {
|
|
|
2567
2577
|
newPreloadingIndices.add(index);
|
|
2568
2578
|
}
|
|
2569
2579
|
this.store.setState({ preloadingIndices: newPreloadingIndices });
|
|
2570
|
-
const maxParallel =
|
|
2580
|
+
const maxParallel = 2;
|
|
2571
2581
|
const executeInBatches = async () => {
|
|
2572
2582
|
for (let i = 0; i < indicesToPreload.length; i += maxParallel) {
|
|
2573
2583
|
const batch = indicesToPreload.slice(i, i + maxParallel);
|
|
@@ -3678,9 +3688,10 @@ var createInitialState6 = () => ({
|
|
|
3678
3688
|
error: null
|
|
3679
3689
|
});
|
|
3680
3690
|
var PlaylistManager = class {
|
|
3681
|
-
constructor(dataSource, config = {}, governor) {
|
|
3691
|
+
constructor(dataSource, config = {}, governor, storage) {
|
|
3682
3692
|
this.dataSource = dataSource;
|
|
3683
3693
|
this.governor = governor;
|
|
3694
|
+
this.storage = storage;
|
|
3684
3695
|
/**
|
|
3685
3696
|
* Internal cache of full metadata items.
|
|
3686
3697
|
* Items in store.items may be minified to save memory.
|
|
@@ -3704,20 +3715,49 @@ var PlaylistManager = class {
|
|
|
3704
3715
|
/**
|
|
3705
3716
|
* Load a playlist by ID
|
|
3706
3717
|
*/
|
|
3718
|
+
/**
|
|
3719
|
+
* Generates a cache key for a specific playlist
|
|
3720
|
+
*/
|
|
3721
|
+
getCacheKey(id) {
|
|
3722
|
+
return `sv-playlist-data-${id}`;
|
|
3723
|
+
}
|
|
3724
|
+
/**
|
|
3725
|
+
* Load playlist data, using cache for an immediate render before network finishes.
|
|
3726
|
+
*/
|
|
3707
3727
|
async loadPlaylist(id) {
|
|
3708
3728
|
if (!this.dataSource) {
|
|
3709
3729
|
this.store.setState({ error: new Error("No playlist data source provided") });
|
|
3710
3730
|
return;
|
|
3711
3731
|
}
|
|
3732
|
+
const cacheKey = this.getCacheKey(id);
|
|
3733
|
+
try {
|
|
3734
|
+
if (this.storage) {
|
|
3735
|
+
const cachedPlaylist = await this.storage.get(cacheKey);
|
|
3736
|
+
if (cachedPlaylist) {
|
|
3737
|
+
this.setPlaylist(cachedPlaylist);
|
|
3738
|
+
}
|
|
3739
|
+
}
|
|
3740
|
+
} catch {
|
|
3741
|
+
}
|
|
3712
3742
|
this.store.setState({ loading: true, error: null });
|
|
3713
3743
|
try {
|
|
3714
3744
|
const playlist = await this.dataSource.fetchPlaylist(id);
|
|
3715
3745
|
this.setPlaylist(playlist);
|
|
3746
|
+
if (this.storage) {
|
|
3747
|
+
const itemsToCache = playlist.items.slice(0, Math.max(this.config.metadataWindowSize, 5));
|
|
3748
|
+
const cachePayload = { ...playlist, items: itemsToCache };
|
|
3749
|
+
this.storage.set(cacheKey, cachePayload).catch(() => {
|
|
3750
|
+
});
|
|
3751
|
+
}
|
|
3716
3752
|
} catch (error) {
|
|
3717
|
-
this.store.
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3753
|
+
if (!this.store.getState().playlist) {
|
|
3754
|
+
this.store.setState({
|
|
3755
|
+
loading: false,
|
|
3756
|
+
error: error instanceof Error ? error : new Error("Failed to load playlist")
|
|
3757
|
+
});
|
|
3758
|
+
} else {
|
|
3759
|
+
this.store.setState({ loading: false });
|
|
3760
|
+
}
|
|
3721
3761
|
}
|
|
3722
3762
|
}
|
|
3723
3763
|
/**
|
|
@@ -3725,10 +3765,15 @@ var PlaylistManager = class {
|
|
|
3725
3765
|
*/
|
|
3726
3766
|
setPlaylist(playlist) {
|
|
3727
3767
|
this.fullMetadataItems = [...playlist.items];
|
|
3728
|
-
this.
|
|
3768
|
+
const { metadataWindowSize } = this.config;
|
|
3769
|
+
const end = Math.min(this.fullMetadataItems.length, metadataWindowSize);
|
|
3770
|
+
const windowedItems = this.fullMetadataItems.map(
|
|
3771
|
+
(item, index) => index < end ? item : this.minifyItem(item)
|
|
3772
|
+
);
|
|
3729
3773
|
this.store.setState({
|
|
3730
3774
|
playlist,
|
|
3731
3775
|
currentIndex: 0,
|
|
3776
|
+
items: windowedItems,
|
|
3732
3777
|
loading: false,
|
|
3733
3778
|
error: null
|
|
3734
3779
|
});
|
|
@@ -3767,6 +3812,16 @@ var PlaylistManager = class {
|
|
|
3767
3812
|
this.fullMetadataItems = [];
|
|
3768
3813
|
this.store.setState(createInitialState6());
|
|
3769
3814
|
}
|
|
3815
|
+
/**
|
|
3816
|
+
* Get the full (un-minified) list of items in the current playlist.
|
|
3817
|
+
*
|
|
3818
|
+
* Unlike `store.items` (which applies the sliding window and may contain
|
|
3819
|
+
* minified items), this always returns the complete metadata for every item.
|
|
3820
|
+
* Used by PlaylistFeedAdapter to ensure FeedManager receives playable data.
|
|
3821
|
+
*/
|
|
3822
|
+
getFullItems() {
|
|
3823
|
+
return [...this.fullMetadataItems];
|
|
3824
|
+
}
|
|
3770
3825
|
/**
|
|
3771
3826
|
* Destroy the manager
|
|
3772
3827
|
*/
|
|
@@ -3829,11 +3884,38 @@ var createInitialState7 = () => ({
|
|
|
3829
3884
|
hasMore: true,
|
|
3830
3885
|
error: null
|
|
3831
3886
|
});
|
|
3832
|
-
var
|
|
3833
|
-
constructor(dataSource) {
|
|
3887
|
+
var _PlaylistCollectionManager = class _PlaylistCollectionManager {
|
|
3888
|
+
constructor(dataSource, storage) {
|
|
3834
3889
|
this.dataSource = dataSource;
|
|
3890
|
+
this.storage = storage;
|
|
3835
3891
|
this.store = createStore(createInitialState7);
|
|
3836
3892
|
}
|
|
3893
|
+
/**
|
|
3894
|
+
* Hydrate collection from cache
|
|
3895
|
+
*/
|
|
3896
|
+
async hydrateFromCache() {
|
|
3897
|
+
if (!this.storage) return;
|
|
3898
|
+
try {
|
|
3899
|
+
const cached = await this.storage.get(_PlaylistCollectionManager.CACHE_KEY);
|
|
3900
|
+
if (Array.isArray(cached?.playlists)) {
|
|
3901
|
+
this.store.setState({
|
|
3902
|
+
playlists: cached.playlists,
|
|
3903
|
+
cursor: cached.cursor,
|
|
3904
|
+
hasMore: cached.hasMore
|
|
3905
|
+
});
|
|
3906
|
+
}
|
|
3907
|
+
} catch {
|
|
3908
|
+
}
|
|
3909
|
+
}
|
|
3910
|
+
/**
|
|
3911
|
+
* Update cache with current state
|
|
3912
|
+
*/
|
|
3913
|
+
updateCache() {
|
|
3914
|
+
if (!this.storage) return;
|
|
3915
|
+
const { playlists, cursor, hasMore } = this.store.getState();
|
|
3916
|
+
this.storage.set(_PlaylistCollectionManager.CACHE_KEY, { playlists, cursor, hasMore }).catch(() => {
|
|
3917
|
+
});
|
|
3918
|
+
}
|
|
3837
3919
|
/**
|
|
3838
3920
|
* Load more playlists (pagination)
|
|
3839
3921
|
*/
|
|
@@ -3849,6 +3931,7 @@ var PlaylistCollectionManager = class {
|
|
|
3849
3931
|
hasMore: response.hasMore,
|
|
3850
3932
|
loading: false
|
|
3851
3933
|
}));
|
|
3934
|
+
this.updateCache();
|
|
3852
3935
|
} catch (error) {
|
|
3853
3936
|
this.store.setState({
|
|
3854
3937
|
loading: false,
|
|
@@ -3871,6 +3954,7 @@ var PlaylistCollectionManager = class {
|
|
|
3871
3954
|
loading: false,
|
|
3872
3955
|
error: null
|
|
3873
3956
|
});
|
|
3957
|
+
this.updateCache();
|
|
3874
3958
|
} catch (error) {
|
|
3875
3959
|
this.store.setState({
|
|
3876
3960
|
loading: false,
|
|
@@ -3885,5 +3969,8 @@ var PlaylistCollectionManager = class {
|
|
|
3885
3969
|
this.store.setState(createInitialState7());
|
|
3886
3970
|
}
|
|
3887
3971
|
};
|
|
3972
|
+
/** Cache key for playlist collection */
|
|
3973
|
+
_PlaylistCollectionManager.CACHE_KEY = "sv-playlist-collection";
|
|
3974
|
+
var PlaylistCollectionManager = _PlaylistCollectionManager;
|
|
3888
3975
|
|
|
3889
3976
|
export { CommentManager, DEFAULT_COMMENT_MANAGER_CONFIG, DEFAULT_FEED_CONFIG, DEFAULT_LIFECYCLE_CONFIG, DEFAULT_OPTIMISTIC_CONFIG, DEFAULT_PLAYER_CONFIG, DEFAULT_PREFETCH_CACHE_CONFIG, DEFAULT_PREFETCH_CONFIG, DEFAULT_RESOURCE_CONFIG, FeedManager, LifecycleManager, OptimisticManager, PlayerEngine, PlayerStatus, PlaylistCollectionManager, PlaylistManager, ResourceGovernor, calculatePrefetchIndices, calculateWindowIndices, canPause, canPlay, canSeek, computeAllocationChanges, createInitialCommentState, createInitialVideoCommentState, isActiveState, isValidTransition, mapNetworkType };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xhub-short/core",
|
|
3
3
|
"sideEffects": false,
|
|
4
|
-
"version": "1.0.0-beta.
|
|
4
|
+
"version": "1.0.0-beta.26",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -21,14 +21,14 @@
|
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"zustand": "^5.0.0",
|
|
24
|
-
"@xhub-short/contracts": "1.0.0-beta.
|
|
24
|
+
"@xhub-short/contracts": "1.0.0-beta.26"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"tsup": "^8.3.0",
|
|
28
28
|
"typescript": "^5.7.0",
|
|
29
29
|
"vitest": "^2.1.0",
|
|
30
|
-
"@xhub-short/tsconfig": "0.1
|
|
31
|
-
"@xhub-short/vitest-config": "0.1.0-beta.
|
|
30
|
+
"@xhub-short/tsconfig": "0.0.1-beta.2",
|
|
31
|
+
"@xhub-short/vitest-config": "0.1.0-beta.13"
|
|
32
32
|
},
|
|
33
33
|
"scripts": {
|
|
34
34
|
"build": "tsup",
|