@streamscloud/embeddable 9.0.0 → 10.0.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/dist/content-player/cmp.content-player.svelte +1 -1
- package/dist/content-player/content-player-config.svelte.d.ts +4 -4
- package/dist/content-player/controls-and-attachments.svelte +1 -1
- package/dist/content-player/header.svelte +1 -1
- package/dist/core/document.event-handlers.d.ts +1 -0
- package/dist/core/document.event-handlers.js +3 -0
- package/dist/media-center/config/internal-media-center-analytics-handler.d.ts +1 -1
- package/dist/media-center/config/internal-media-center-config.js +34 -44
- package/dist/media-center/config/operations.generated.d.ts +0 -104
- package/dist/media-center/config/operations.generated.js +0 -320
- package/dist/media-center/config/operations.graphql +0 -24
- package/dist/media-center/config/types.d.ts +7 -9
- package/dist/media-center/media-center/cmp.media-center.svelte +27 -7
- package/dist/media-center/media-center/cmp.media-center.svelte.d.ts +2 -2
- package/dist/media-center/media-center/discover-panel-handler.svelte.d.ts +2 -2
- package/dist/media-center/media-center/discover-panel.svelte +1 -1
- package/dist/media-center/media-center/discover-panel.svelte.d.ts +2 -1
- package/dist/media-center/media-center/post-player-provider-generator.d.ts +2 -2
- package/dist/media-center/media-center/post-player-provider-generator.js +2 -1
- package/dist/media-center/media-center/streams-in-category-panel-handler.svelte.d.ts +5 -2
- package/dist/media-center/media-center/streams-in-category-panel-handler.svelte.js +5 -0
- package/dist/media-center/media-center/streams-in-category-panel.svelte +2 -2
- package/dist/media-center/media-center/streams-in-category-panel.svelte.d.ts +3 -2
- package/dist/media-center/media-center/streams-player-provider-generator.d.ts +8 -0
- package/dist/media-center/media-center/streams-player-provider-generator.js +36 -0
- package/dist/media-center/media-center/types.d.ts +0 -6
- package/dist/posts/controls/cmp.controls.svelte +1 -1
- package/dist/posts/data-loaders/index.d.ts +1 -0
- package/dist/posts/data-loaders/index.js +1 -0
- package/dist/posts/{posts-player → data-loaders}/mapper.d.ts +1 -1
- package/dist/{short-videos/data-providers → posts/data-loaders}/operations.generated.d.ts +82 -4
- package/dist/{short-videos/data-providers → posts/data-loaders}/operations.generated.js +232 -3
- package/dist/posts/data-loaders/operations.graphql +17 -0
- package/dist/posts/data-loaders/posts-loader.d.ts +19 -0
- package/dist/posts/data-loaders/posts-loader.js +28 -0
- package/dist/posts/posts-player/index.d.ts +27 -6
- package/dist/posts/posts-player/index.js +2 -3
- package/dist/posts/posts-player/posts-player-view.svelte +29 -13
- package/dist/posts/posts-player/types.d.ts +2 -2
- package/dist/short-videos/data-providers/internal-short-video-player-items-provider.d.ts +5 -6
- package/dist/short-videos/data-providers/internal-short-video-player-items-provider.js +12 -32
- package/dist/short-videos/short-videos-player/index.d.ts +2 -3
- package/dist/short-videos/short-videos-player/index.js +1 -1
- package/dist/streams/data-loaders/index.d.ts +2 -0
- package/dist/streams/data-loaders/index.js +2 -0
- package/dist/streams/{stream-player → data-loaders}/mapper.d.ts +1 -1
- package/dist/streams/{stream-player → data-loaders}/operations.generated.d.ts +27 -24
- package/dist/streams/{stream-player → data-loaders}/operations.generated.js +18 -17
- package/dist/streams/{stream-player → data-loaders}/operations.graphql +6 -3
- package/dist/streams/data-loaders/stream-pages-loader.d.ts +10 -0
- package/dist/streams/data-loaders/stream-pages-loader.js +33 -0
- package/dist/streams/data-loaders/streams-loader.d.ts +19 -0
- package/dist/streams/data-loaders/streams-loader.js +28 -0
- package/dist/streams/{stream-player → streams-player}/index.d.ts +21 -22
- package/dist/streams/{stream-player → streams-player}/index.js +9 -7
- package/dist/streams/streams-player/internal-streams-player-data-provider.d.ts +16 -0
- package/dist/streams/streams-player/internal-streams-player-data-provider.js +55 -0
- package/dist/streams/{stream-player → streams-player}/stream-overview.svelte +18 -15
- package/dist/streams/{stream-player → streams-player}/stream-overview.svelte.d.ts +2 -2
- package/dist/streams/streams-player/streams-player-buffer.svelte.d.ts +8 -0
- package/dist/streams/streams-player/streams-player-buffer.svelte.js +15 -0
- package/dist/streams/{stream-player/stream-player-view.svelte → streams-player/streams-player-view.svelte} +69 -55
- package/dist/streams/streams-player/streams-player-view.svelte.d.ts +8 -0
- package/dist/streams/{stream-player → streams-player}/types.d.ts +9 -7
- package/dist/ui/{player-button → player/button}/cmp.player-button.svelte +1 -1
- package/dist/ui/{player-button → player/button}/cmp.player-button.svelte.d.ts +1 -1
- package/dist/ui/{player-button → player/button}/cmp.player-buttons-group.svelte +1 -1
- package/dist/ui/{player-button → player/button}/types.d.ts +1 -1
- package/dist/ui/player/button/types.js +1 -0
- package/dist/ui/player/providers/chunks-player-buffer/index.d.ts +2 -0
- package/dist/ui/player/providers/chunks-player-buffer/index.js +2 -0
- package/dist/ui/player/providers/chunks-player-buffer/player-chunk-item.svelte.d.ts +11 -0
- package/dist/ui/player/providers/chunks-player-buffer/player-chunk-item.svelte.js +11 -0
- package/dist/ui/player/providers/chunks-player-buffer/player-chunk.svelte.d.ts +31 -0
- package/dist/ui/player/providers/chunks-player-buffer/player-chunk.svelte.js +67 -0
- package/dist/ui/player/providers/chunks-player-buffer/player-chunks-manager.svelte.d.ts +23 -0
- package/dist/ui/player/providers/chunks-player-buffer/player-chunks-manager.svelte.js +119 -0
- package/dist/ui/player/providers/default-chunks-player-buffer.svelte.d.ts +20 -0
- package/dist/ui/player/providers/default-chunks-player-buffer.svelte.js +47 -0
- package/dist/ui/player/providers/default-feed-player-buffer.svelte.d.ts +27 -0
- package/dist/ui/player/providers/default-feed-player-buffer.svelte.js +78 -0
- package/dist/ui/player/providers/index.d.ts +3 -0
- package/dist/ui/player/providers/index.js +2 -0
- package/dist/ui/player/providers/types.d.ts +49 -0
- package/dist/ui/{player-slider → player/slider}/cmp.player-slider.svelte +7 -20
- package/dist/ui/{player-slider → player/slider}/cmp.player-slider.svelte.d.ts +4 -4
- package/dist/ui/{player-slider → player/slider}/index.d.ts +0 -2
- package/dist/ui/{player-slider → player/slider}/index.js +0 -1
- package/dist/ui/player/slider/types.d.ts +16 -0
- package/dist/ui/player/slider/types.js +1 -0
- package/package.json +4 -4
- package/dist/posts/posts-player/operations.generated.d.ts +0 -80
- package/dist/posts/posts-player/operations.generated.js +0 -229
- package/dist/posts/posts-player/operations.graphql +0 -7
- package/dist/short-videos/data-providers/operations.graphql +0 -9
- package/dist/streams/stream-player/internal-stream-player-data-provider.d.ts +0 -12
- package/dist/streams/stream-player/internal-stream-player-data-provider.js +0 -48
- package/dist/streams/stream-player/stream-player-buffer.svelte.d.ts +0 -28
- package/dist/streams/stream-player/stream-player-buffer.svelte.js +0 -79
- package/dist/streams/stream-player/stream-player-view.svelte.d.ts +0 -8
- package/dist/ui/player-button/types.js +0 -1
- package/dist/ui/player-slider/player-buffer.svelte.d.ts +0 -32
- package/dist/ui/player-slider/player-buffer.svelte.js +0 -76
- package/dist/ui/player-slider/types.d.ts +0 -26
- /package/dist/posts/{posts-player → data-loaders}/mapper.js +0 -0
- /package/dist/streams/{stream-player → data-loaders}/mapper.js +0 -0
- /package/dist/streams/{stream-player → streams-player}/internal-stream-analytics-handler.d.ts +0 -0
- /package/dist/streams/{stream-player → streams-player}/internal-stream-analytics-handler.js +0 -0
- /package/dist/streams/{stream-player → streams-player}/stream-player-localization.d.ts +0 -0
- /package/dist/streams/{stream-player → streams-player}/stream-player-localization.js +0 -0
- /package/dist/streams/{stream-player → streams-player}/types.js +0 -0
- /package/dist/ui/{player-button → player/button}/cmp.player-buttons-group.svelte.d.ts +0 -0
- /package/dist/ui/{player-button → player/button}/index.d.ts +0 -0
- /package/dist/ui/{player-button → player/button}/index.js +0 -0
- /package/dist/ui/{player-slider → player/providers}/types.js +0 -0
- /package/dist/ui/{player-slider → player/slider}/prevent-slider-scroll.d.ts +0 -0
- /package/dist/ui/{player-slider → player/slider}/prevent-slider-scroll.js +0 -0
- /package/dist/ui/{player-slider → player/slider}/wheel-gestures-adapter.d.ts +0 -0
- /package/dist/ui/{player-slider → player/slider}/wheel-gestures-adapter.js +0 -0
|
@@ -11,14 +11,13 @@ var _a;
|
|
|
11
11
|
import { ContentPlayer, ContentPlayerConfig } from '../../content-player';
|
|
12
12
|
import { ContentPlayerSettings } from '../../content-player/content-player-settings';
|
|
13
13
|
import { preloadImage } from '../../core/image-preloader';
|
|
14
|
-
import { toastrWarning } from '../../core/toastr';
|
|
15
14
|
import { mapToPostModel } from '../layout/models';
|
|
16
15
|
import { StreamPageViewer } from '../stream-page-viewer';
|
|
17
16
|
import { default as Overview } from './stream-overview.svelte';
|
|
18
|
-
import { StreamPlayerBuffer } from './stream-player-buffer.svelte';
|
|
19
17
|
import { StreamPlayerLocalization } from './stream-player-localization';
|
|
18
|
+
import { StreamsPlayerBuffer } from './streams-player-buffer.svelte';
|
|
20
19
|
import { untrack } from 'svelte';
|
|
21
|
-
let {
|
|
20
|
+
let { dataProvider, analyticsHandler, postSocialInteractionsHandler, amplificationParameters, playerSettings, on, mediaCenterData } = $props();
|
|
22
21
|
const localization = $derived(new StreamPlayerLocalization((_a = playerSettings === null || playerSettings === void 0 ? void 0 : playerSettings.locale) !== null && _a !== void 0 ? _a : 'en'));
|
|
23
22
|
let currentStreamModel = $state(null);
|
|
24
23
|
let activePageId = $derived.by(() => { var _a, _b; return (_b = (_a = buffer === null || buffer === void 0 ? void 0 : buffer.current) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : ''; });
|
|
@@ -30,22 +29,13 @@ let activityTimeout = null;
|
|
|
30
29
|
let trackingInterval = null;
|
|
31
30
|
let maxPageIndexViewed = 0;
|
|
32
31
|
$effect(() => {
|
|
33
|
-
void
|
|
32
|
+
void dataProvider;
|
|
34
33
|
untrack(() => {
|
|
35
34
|
buffer = null;
|
|
36
35
|
contentPlayerConfig.playerBuffer = null;
|
|
37
|
-
|
|
36
|
+
initPlayerBuffer();
|
|
38
37
|
});
|
|
39
|
-
return () => {
|
|
40
|
-
stopActivityTracking();
|
|
41
|
-
if (currentStreamModel) {
|
|
42
|
-
analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackStreamEngagementTime(currentStreamModel.id, totalEngagementTimeSeconds);
|
|
43
|
-
if (buffer && buffer.loaded.length > 0) {
|
|
44
|
-
let scrollDepth = Math.round(((maxPageIndexViewed + 1) / buffer.loaded.length) * 100);
|
|
45
|
-
analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackStreamScrollDepth(currentStreamModel.id, scrollDepth);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
};
|
|
38
|
+
return () => { };
|
|
49
39
|
});
|
|
50
40
|
$effect(() => contentPlayerConfig.updateMediaCenterData(mediaCenterData));
|
|
51
41
|
$effect(() => contentPlayerConfig.updateTrackingParams(currentStreamModel
|
|
@@ -54,6 +44,31 @@ $effect(() => contentPlayerConfig.updateTrackingParams(currentStreamModel
|
|
|
54
44
|
campaignId: amplificationParameters === null || amplificationParameters === void 0 ? void 0 : amplificationParameters.campaignId
|
|
55
45
|
}
|
|
56
46
|
: null));
|
|
47
|
+
$effect(() => {
|
|
48
|
+
const stream = buffer === null || buffer === void 0 ? void 0 : buffer.activeChunk.model;
|
|
49
|
+
untrack(() => {
|
|
50
|
+
var _a;
|
|
51
|
+
if (stream) {
|
|
52
|
+
currentStreamModel = stream;
|
|
53
|
+
if (stream.organizationId) {
|
|
54
|
+
analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.setOrganizationId(stream.organizationId);
|
|
55
|
+
}
|
|
56
|
+
(_a = on === null || on === void 0 ? void 0 : on.streamActivated) === null || _a === void 0 ? void 0 : _a.call(on, { title: stream.title, image: stream.cover });
|
|
57
|
+
analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackStreamView(stream.id);
|
|
58
|
+
startActivityTracking();
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
return () => {
|
|
62
|
+
stopActivityTracking();
|
|
63
|
+
if (currentStreamModel) {
|
|
64
|
+
analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackStreamEngagementTime(currentStreamModel.id, totalEngagementTimeSeconds);
|
|
65
|
+
let scrollDepth = Math.round(((maxPageIndexViewed + 1) / currentStreamModel.pagesCount) * 100);
|
|
66
|
+
analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackStreamScrollDepth(currentStreamModel.id, scrollDepth);
|
|
67
|
+
}
|
|
68
|
+
totalEngagementTimeSeconds = 0;
|
|
69
|
+
maxPageIndexViewed = 0;
|
|
70
|
+
};
|
|
71
|
+
});
|
|
57
72
|
const streamTrackingParams = $derived.by(() => {
|
|
58
73
|
return currentStreamModel
|
|
59
74
|
? {
|
|
@@ -62,39 +77,20 @@ const streamTrackingParams = $derived.by(() => {
|
|
|
62
77
|
}
|
|
63
78
|
: false;
|
|
64
79
|
});
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
if (stream.organizationId) {
|
|
74
|
-
analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.setOrganizationId(stream.organizationId);
|
|
75
|
-
}
|
|
76
|
-
(_b = on === null || on === void 0 ? void 0 : on.streamActivated) === null || _b === void 0 ? void 0 : _b.call(on, { title: stream.title, image: stream.cover });
|
|
77
|
-
// start tracking the stream
|
|
78
|
-
currentStreamModel = stream;
|
|
79
|
-
new StreamPlayerBuffer({
|
|
80
|
-
streamId,
|
|
81
|
-
dataProvider: dataProvider,
|
|
82
|
-
on: {
|
|
83
|
-
preloaded: (instance) => __awaiter(void 0, void 0, void 0, function* () {
|
|
84
|
-
if (instance.loaded.length) {
|
|
85
|
-
const coverUrl = instance.loaded[0].cover;
|
|
86
|
-
if (coverUrl) {
|
|
87
|
-
yield preloadImage(coverUrl);
|
|
88
|
-
}
|
|
89
|
-
contentPlayerConfig.setBackgroundImageUrl(coverUrl);
|
|
80
|
+
const initPlayerBuffer = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
81
|
+
new StreamsPlayerBuffer(dataProvider, {
|
|
82
|
+
preloaded: (instance) => __awaiter(void 0, void 0, void 0, function* () {
|
|
83
|
+
if (instance.loaded.length) {
|
|
84
|
+
const coverUrl = instance.loaded[0].cover;
|
|
85
|
+
if (coverUrl) {
|
|
86
|
+
yield preloadImage(coverUrl);
|
|
90
87
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
88
|
+
contentPlayerConfig.setBackgroundImageUrl(coverUrl);
|
|
89
|
+
}
|
|
90
|
+
buffer = instance;
|
|
91
|
+
contentPlayerConfig.playerBuffer = instance;
|
|
92
|
+
})
|
|
95
93
|
});
|
|
96
|
-
analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackStreamView(stream.id);
|
|
97
|
-
startActivityTracking();
|
|
98
94
|
});
|
|
99
95
|
const contentPlayerConfig = new ContentPlayerConfig({
|
|
100
96
|
playerBuffer: null,
|
|
@@ -131,37 +127,55 @@ const contentPlayerConfig = new ContentPlayerConfig({
|
|
|
131
127
|
},
|
|
132
128
|
playerSliderCallbacks: {
|
|
133
129
|
itemActivated: (item) => onPageActivated(item),
|
|
134
|
-
itemDeactivated: (itemId) =>
|
|
130
|
+
itemDeactivated: (itemId) => executeWithStreamId((streamId) => {
|
|
131
|
+
analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.reportPageVideoViews(itemId, streamId);
|
|
132
|
+
})
|
|
135
133
|
}
|
|
136
134
|
});
|
|
137
135
|
const handleChangePage = (index) => {
|
|
138
136
|
if (!buffer) {
|
|
139
137
|
return;
|
|
140
138
|
}
|
|
141
|
-
buffer.
|
|
139
|
+
buffer.setActiveChunkItemIndex(index);
|
|
142
140
|
};
|
|
143
141
|
const onPageActivated = (id) => {
|
|
144
|
-
const
|
|
142
|
+
const activeChunk = buffer === null || buffer === void 0 ? void 0 : buffer.activeChunk;
|
|
143
|
+
if (!activeChunk) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const page = activeChunk.items.find((x) => x.id === id);
|
|
145
147
|
contentPlayerConfig.setBackgroundImageUrl((page === null || page === void 0 ? void 0 : page.cover) || null);
|
|
146
148
|
if (page) {
|
|
147
|
-
analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackStreamPageView(id,
|
|
149
|
+
analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackStreamPageView(id, activeChunk.model.id);
|
|
148
150
|
if (page.type === 'short-video' && page.shortVideo) {
|
|
149
151
|
analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackShortVideoView(page.shortVideo.id);
|
|
150
152
|
}
|
|
151
|
-
const currentIndex =
|
|
152
|
-
if (currentIndex
|
|
153
|
+
const currentIndex = activeChunk.items.findIndex((p) => p.id === id);
|
|
154
|
+
if (currentIndex > maxPageIndexViewed) {
|
|
153
155
|
maxPageIndexViewed = currentIndex;
|
|
154
156
|
}
|
|
155
157
|
}
|
|
156
158
|
};
|
|
157
159
|
const onStreamProductClick = (productId) => {
|
|
158
|
-
|
|
160
|
+
executeWithStreamId((streamId) => {
|
|
161
|
+
analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackStreamProductClicked(productId, streamId);
|
|
162
|
+
});
|
|
159
163
|
};
|
|
160
164
|
const onStreamProductImpression = (productId) => {
|
|
161
|
-
|
|
165
|
+
executeWithStreamId((streamId) => {
|
|
166
|
+
analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackStreamProductImpression(productId, streamId);
|
|
167
|
+
});
|
|
162
168
|
};
|
|
163
169
|
const onProgress = (pageId, videoId, progress) => {
|
|
164
|
-
|
|
170
|
+
executeWithStreamId((streamId) => {
|
|
171
|
+
analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackShortVideoProgress(pageId, videoId, progress, streamId);
|
|
172
|
+
});
|
|
173
|
+
};
|
|
174
|
+
const executeWithStreamId = (action) => {
|
|
175
|
+
if (!currentStreamModel) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
action(currentStreamModel.id);
|
|
165
179
|
};
|
|
166
180
|
//#region Activity Tracking
|
|
167
181
|
const resetInactivityTimer = () => {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { MediaCenterData } from '../../media-center/model/types';
|
|
2
|
+
import type { StreamsPlayerProps } from './types';
|
|
3
|
+
type $$ComponentProps = StreamsPlayerProps & {
|
|
4
|
+
mediaCenterData?: MediaCenterData;
|
|
5
|
+
};
|
|
6
|
+
declare const StreamsPlayerView: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type StreamsPlayerView = ReturnType<typeof StreamsPlayerView>;
|
|
8
|
+
export default StreamsPlayerView;
|
|
@@ -15,13 +15,12 @@ export type StreamPlayerModel = {
|
|
|
15
15
|
};
|
|
16
16
|
pagesCount: number;
|
|
17
17
|
};
|
|
18
|
-
export type
|
|
19
|
-
|
|
20
|
-
dataProvider: IStreamPlayerDataProvider;
|
|
18
|
+
export type StreamsPlayerProps = {
|
|
19
|
+
dataProvider: IStreamsPlayerDataProvider;
|
|
21
20
|
postSocialInteractionsHandler?: IPostSocialInteractionsHandler;
|
|
22
21
|
analyticsHandler?: IStreamAnalyticsHandler;
|
|
23
22
|
amplificationParameters?: StreamAmplificationParameters;
|
|
24
|
-
playerSettings?:
|
|
23
|
+
playerSettings?: StreamsPlayerSettings;
|
|
25
24
|
on?: {
|
|
26
25
|
streamActivated?: (data: {
|
|
27
26
|
title: string;
|
|
@@ -30,14 +29,17 @@ export type StreamPlayerProps = {
|
|
|
30
29
|
playerClosed?: () => void;
|
|
31
30
|
};
|
|
32
31
|
};
|
|
33
|
-
export type
|
|
32
|
+
export type StreamsPlayerSettings = Pick<IContentPlayerSettingsInitializer, 'disableBackground' | 'hideCloseButton' | 'locale' | 'showStreamsCloudWatermark'>;
|
|
34
33
|
export type StreamAmplificationParameters = {
|
|
35
34
|
campaignId: string;
|
|
36
35
|
campaignName: string;
|
|
37
36
|
source: string;
|
|
38
37
|
};
|
|
39
|
-
export interface
|
|
40
|
-
|
|
38
|
+
export interface IStreamsPlayerDataProvider {
|
|
39
|
+
initialData: {
|
|
40
|
+
prefetchedStreams: StreamPlayerModel[];
|
|
41
|
+
};
|
|
42
|
+
loadMoreStreams: () => Promise<StreamPlayerModel[]>;
|
|
41
43
|
getStreamPages: (streamId: string, continuationToken: string | null | undefined) => Promise<{
|
|
42
44
|
items: StreamPageViewerModel[];
|
|
43
45
|
continuationToken: string | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { IconColor } from '../../icon';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { PlayerChunkItem } from './player-chunk-item.svelte';
|
|
2
|
+
import type { WithId } from '../types';
|
|
3
|
+
export declare class PlayerChunk<TItem extends WithId, TChunk extends WithId> {
|
|
4
|
+
readonly model: TChunk;
|
|
5
|
+
readonly items: TItem[];
|
|
6
|
+
readonly chunkItems: PlayerChunkItem<TItem>[];
|
|
7
|
+
readonly chunkIndex: number;
|
|
8
|
+
readonly activeChunkItem: PlayerChunkItem<TItem>;
|
|
9
|
+
readonly isEmpty: boolean;
|
|
10
|
+
isFullyLoaded: boolean;
|
|
11
|
+
private _chunkItems;
|
|
12
|
+
private _activeItemIndex;
|
|
13
|
+
private _isLoading;
|
|
14
|
+
private _itemsLoader;
|
|
15
|
+
constructor(data: {
|
|
16
|
+
chunk: TChunk;
|
|
17
|
+
chunkIndex: number;
|
|
18
|
+
provider: {
|
|
19
|
+
loadChunkItems: (chunkId: string, continuationToken: string | null | undefined) => Promise<{
|
|
20
|
+
items: TItem[];
|
|
21
|
+
continuationToken: string | null;
|
|
22
|
+
}>;
|
|
23
|
+
};
|
|
24
|
+
callbacks?: {
|
|
25
|
+
onChunkFullyLoaded: (chunk: PlayerChunk<TItem, TChunk>) => void;
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
loadMore: () => Promise<TItem[]>;
|
|
29
|
+
setActiveItemIndex: (index: number, warmUp?: boolean) => Promise<void>;
|
|
30
|
+
warmUp: () => Promise<void>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ContinuationToken } from '../../../../core/continuation-token';
|
|
2
|
+
import { CursorDataLoader } from '../../../../core/data-loaders';
|
|
3
|
+
import { PlayerChunkItem } from './player-chunk-item.svelte';
|
|
4
|
+
const CHUNK_ITEMS_BUFFER_SIZE = 5;
|
|
5
|
+
export class PlayerChunk {
|
|
6
|
+
model;
|
|
7
|
+
items = $derived.by(() => this._chunkItems.map((i) => i.model));
|
|
8
|
+
chunkItems = $derived.by(() => this._chunkItems);
|
|
9
|
+
chunkIndex;
|
|
10
|
+
activeChunkItem = $derived.by(() => this._chunkItems[this._activeItemIndex] ?? null);
|
|
11
|
+
isEmpty = $derived.by(() => this.isFullyLoaded && this._chunkItems.length === 0);
|
|
12
|
+
isFullyLoaded = $state(false);
|
|
13
|
+
_chunkItems = $state.raw([]);
|
|
14
|
+
_activeItemIndex = $state(0);
|
|
15
|
+
_isLoading = $state(false);
|
|
16
|
+
_itemsLoader;
|
|
17
|
+
constructor(data) {
|
|
18
|
+
const { chunk, provider, chunkIndex, callbacks } = data;
|
|
19
|
+
this.model = chunk;
|
|
20
|
+
this.chunkIndex = chunkIndex;
|
|
21
|
+
this._itemsLoader = new CursorDataLoader({
|
|
22
|
+
loadPage: async (continuationToken) => {
|
|
23
|
+
if (this.isFullyLoaded) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
const result = await provider.loadChunkItems(this.model.id, continuationToken.toNextChunkString());
|
|
27
|
+
const newItems = result.items;
|
|
28
|
+
this._chunkItems = [
|
|
29
|
+
...this._chunkItems,
|
|
30
|
+
...newItems.map((item, index) => new PlayerChunkItem({
|
|
31
|
+
model: item,
|
|
32
|
+
indexWithinChunk: this._chunkItems.length + index,
|
|
33
|
+
chunkId: this.model.id
|
|
34
|
+
}))
|
|
35
|
+
];
|
|
36
|
+
const continuationTokenResult = ContinuationToken.fromPayload(result.continuationToken);
|
|
37
|
+
if (!continuationTokenResult.canLoadMore) {
|
|
38
|
+
this.isFullyLoaded = true;
|
|
39
|
+
callbacks?.onChunkFullyLoaded(this);
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
items: newItems,
|
|
43
|
+
continuationToken: continuationTokenResult
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
loadMore = () => this._itemsLoader.loadMore();
|
|
49
|
+
setActiveItemIndex = async (index, warmUp = true) => {
|
|
50
|
+
this._activeItemIndex = index;
|
|
51
|
+
if (warmUp) {
|
|
52
|
+
await this.warmUp();
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
warmUp = async () => {
|
|
56
|
+
if (this._chunkItems.length >= this._activeItemIndex + CHUNK_ITEMS_BUFFER_SIZE || this._isLoading) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
this._isLoading = true;
|
|
60
|
+
try {
|
|
61
|
+
await this.loadMore();
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
this._isLoading = false;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { PlayerChunk } from './player-chunk.svelte';
|
|
2
|
+
import type { IChunksPlayerDataProvider, WithId } from '../types';
|
|
3
|
+
export declare class PlayerChunksManager<TItem extends WithId, TChunk extends WithId> {
|
|
4
|
+
private provider;
|
|
5
|
+
private callabacks;
|
|
6
|
+
readonly activeChunk: PlayerChunk<TItem, TChunk>;
|
|
7
|
+
readonly loadedChunks: PlayerChunk<TItem, TChunk>[];
|
|
8
|
+
readonly flattenedChunkItems: TItem[];
|
|
9
|
+
readonly flattenedActiveChunkItemIndex: number;
|
|
10
|
+
private _activeChunkIndex;
|
|
11
|
+
private _loadedChunks;
|
|
12
|
+
private _isLoading;
|
|
13
|
+
constructor(provider: IChunksPlayerDataProvider<TItem, TChunk>, callabacks: {
|
|
14
|
+
onInitializationFinished: () => void;
|
|
15
|
+
onEndReached: () => void;
|
|
16
|
+
});
|
|
17
|
+
initialize: () => Promise<void>;
|
|
18
|
+
setActiveChunkIndex: (index: number) => Promise<void>;
|
|
19
|
+
activateItemAtFlattenedIndex: (index: number) => Promise<void>;
|
|
20
|
+
warmUp: () => Promise<void>;
|
|
21
|
+
reset: () => void;
|
|
22
|
+
private populateChunkAtIndex;
|
|
23
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { PlayerChunk } from './player-chunk.svelte';
|
|
2
|
+
const CHUNKS_BUFFER_SIZE = 5;
|
|
3
|
+
const FIXED_START_INDEX = 0;
|
|
4
|
+
export class PlayerChunksManager {
|
|
5
|
+
provider;
|
|
6
|
+
callabacks;
|
|
7
|
+
activeChunk = $derived.by(() => this._loadedChunks[this._activeChunkIndex] ?? null);
|
|
8
|
+
loadedChunks = $derived.by(() => this._loadedChunks);
|
|
9
|
+
flattenedChunkItems = $derived.by(() => this._loadedChunks.reduce((acc, chunk) => {
|
|
10
|
+
acc.push(...chunk.items);
|
|
11
|
+
return acc;
|
|
12
|
+
}, []));
|
|
13
|
+
flattenedActiveChunkItemIndex = $derived.by(() => {
|
|
14
|
+
if (!this.activeChunk || !this.activeChunk.activeChunkItem) {
|
|
15
|
+
return -1;
|
|
16
|
+
}
|
|
17
|
+
let itemsBeforeActiveChunk = 0;
|
|
18
|
+
for (let i = 0; i < this.activeChunk.chunkIndex; i++) {
|
|
19
|
+
itemsBeforeActiveChunk += this._loadedChunks[i].items.length;
|
|
20
|
+
}
|
|
21
|
+
return itemsBeforeActiveChunk + this.activeChunk.activeChunkItem.indexWithinChunk;
|
|
22
|
+
});
|
|
23
|
+
_activeChunkIndex = $state(-1);
|
|
24
|
+
_loadedChunks = $state.raw([]);
|
|
25
|
+
_isLoading = $state(false);
|
|
26
|
+
constructor(provider, callabacks) {
|
|
27
|
+
this.provider = provider;
|
|
28
|
+
this.callabacks = callabacks;
|
|
29
|
+
}
|
|
30
|
+
initialize = async () => {
|
|
31
|
+
const { onInitializationFinished, onEndReached } = this.callabacks;
|
|
32
|
+
const handleInitialized = async () => {
|
|
33
|
+
const startIndex = Math.min(FIXED_START_INDEX, this._loadedChunks.length - 1);
|
|
34
|
+
const populateChunkResult = await this.populateChunkAtIndex(startIndex, (currentIndex) => currentIndex + 1);
|
|
35
|
+
if (!populateChunkResult) {
|
|
36
|
+
onEndReached();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
this.setActiveChunkIndex(populateChunkResult.closestReadyChunkIndex);
|
|
40
|
+
if (populateChunkResult.closestReadyChunkIndex === FIXED_START_INDEX &&
|
|
41
|
+
this.provider.initialData.startItemIndex &&
|
|
42
|
+
this.provider.initialData.startItemIndex > 0) {
|
|
43
|
+
this.activeChunk.setActiveItemIndex(this.provider.initialData.startItemIndex);
|
|
44
|
+
}
|
|
45
|
+
onInitializationFinished();
|
|
46
|
+
};
|
|
47
|
+
this._loadedChunks = this.provider.initialData.prefetchedChunks.map((chunk, chunkIndex) => new PlayerChunk({ chunk, chunkIndex, provider: { loadChunkItems: this.provider.loadChunkItems } }));
|
|
48
|
+
const considerInitialized = this._loadedChunks.length !== 0;
|
|
49
|
+
if (considerInitialized) {
|
|
50
|
+
handleInitialized();
|
|
51
|
+
}
|
|
52
|
+
await this.warmUp();
|
|
53
|
+
if (!considerInitialized) {
|
|
54
|
+
handleInitialized();
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
setActiveChunkIndex = async (index) => {
|
|
58
|
+
this._activeChunkIndex = index;
|
|
59
|
+
this._loadedChunks.forEach((c) => c.setActiveItemIndex(0, false));
|
|
60
|
+
await this.populateChunkAtIndex(this._activeChunkIndex + 1, (currentIndex) => currentIndex + 1);
|
|
61
|
+
};
|
|
62
|
+
activateItemAtFlattenedIndex = async (index) => {
|
|
63
|
+
const activeChunkId = this.activeChunk?.model.id;
|
|
64
|
+
const flattenedItems = this.loadedChunks.flatMap((x) => x.chunkItems);
|
|
65
|
+
const nextItem = flattenedItems[index];
|
|
66
|
+
if (!nextItem) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (nextItem.chunkId !== activeChunkId) {
|
|
70
|
+
this.setActiveChunkIndex(this.loadedChunks.findIndex((c) => c.model.id === nextItem.chunkId));
|
|
71
|
+
this.activeChunk.warmUp();
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
this.activeChunk.setActiveItemIndex(nextItem.indexWithinChunk);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
warmUp = async () => {
|
|
78
|
+
// Early return if manager is sufficient or already loading
|
|
79
|
+
if (this._loadedChunks.length >= this._activeChunkIndex + CHUNKS_BUFFER_SIZE || this._isLoading) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
this._isLoading = true;
|
|
83
|
+
try {
|
|
84
|
+
const result = await this.provider.loadMoreChunks();
|
|
85
|
+
this._loadedChunks = [
|
|
86
|
+
...this._loadedChunks,
|
|
87
|
+
...result.map((chunk, index) => new PlayerChunk({
|
|
88
|
+
chunk,
|
|
89
|
+
chunkIndex: this._loadedChunks.length + index,
|
|
90
|
+
provider: { loadChunkItems: this.provider.loadChunkItems }
|
|
91
|
+
}))
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
this._isLoading = false;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
reset = () => {
|
|
99
|
+
this._activeChunkIndex = -1;
|
|
100
|
+
this._loadedChunks = [];
|
|
101
|
+
this._isLoading = false;
|
|
102
|
+
this.warmUp();
|
|
103
|
+
};
|
|
104
|
+
populateChunkAtIndex = async (index, nextIndexFn) => {
|
|
105
|
+
const chunkAtIndex = this._loadedChunks[index];
|
|
106
|
+
if (!chunkAtIndex) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
await chunkAtIndex.warmUp();
|
|
110
|
+
if (chunkAtIndex.items.length === 0) {
|
|
111
|
+
const nextIndex = nextIndexFn(index);
|
|
112
|
+
if (nextIndex > index) {
|
|
113
|
+
await this.warmUp();
|
|
114
|
+
}
|
|
115
|
+
return await this.populateChunkAtIndex(nextIndexFn(index), nextIndexFn);
|
|
116
|
+
}
|
|
117
|
+
return { closestReadyChunkIndex: index };
|
|
118
|
+
};
|
|
119
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IChunksPlayerBuffer, IChunksPlayerDataProvider, WithId } from './types';
|
|
2
|
+
export declare class DefaultChunksPlayerBuffer<TItem extends WithId, TChunk extends WithId> implements IChunksPlayerBuffer<TItem> {
|
|
3
|
+
readonly kind = "chunks";
|
|
4
|
+
readonly loaded: TItem[];
|
|
5
|
+
readonly currentIndex: number;
|
|
6
|
+
readonly current: TItem | null;
|
|
7
|
+
readonly canLoadNext: boolean;
|
|
8
|
+
readonly canLoadPrevious: boolean;
|
|
9
|
+
readonly navigationDisabled: boolean;
|
|
10
|
+
readonly animationDuration = 500;
|
|
11
|
+
private _playerChunksManager;
|
|
12
|
+
constructor(provider: IChunksPlayerDataProvider<TItem, TChunk>, on?: {
|
|
13
|
+
preloaded?: (self: DefaultChunksPlayerBuffer<TItem, TChunk>) => void;
|
|
14
|
+
});
|
|
15
|
+
get activeChunk(): import("./chunks-player-buffer").PlayerChunk<TItem, TChunk>;
|
|
16
|
+
setActiveChunkItemIndex: (index: number) => void;
|
|
17
|
+
loadNext: () => Promise<void>;
|
|
18
|
+
loadPrevious: () => Promise<void>;
|
|
19
|
+
reset: () => void;
|
|
20
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Utils } from '../../../core/utils';
|
|
2
|
+
import { PlayerChunksManager } from './chunks-player-buffer';
|
|
3
|
+
export class DefaultChunksPlayerBuffer {
|
|
4
|
+
kind = 'chunks';
|
|
5
|
+
loaded = $derived.by(() => this._playerChunksManager.flattenedChunkItems);
|
|
6
|
+
currentIndex = $derived.by(() => this._playerChunksManager.flattenedActiveChunkItemIndex);
|
|
7
|
+
current = $derived(this.currentIndex >= 0 ? this.loaded[this.currentIndex] : null);
|
|
8
|
+
canLoadNext = $derived(this.currentIndex < this.loaded.length - 1);
|
|
9
|
+
canLoadPrevious = $derived(this.currentIndex > 0);
|
|
10
|
+
navigationDisabled = $derived(!this.canLoadNext && !this.canLoadPrevious);
|
|
11
|
+
animationDuration = 500;
|
|
12
|
+
_playerChunksManager;
|
|
13
|
+
constructor(provider, on) {
|
|
14
|
+
// Throttle navigation methods
|
|
15
|
+
this.loadNext = Utils.throttle(this.loadNext, this.animationDuration);
|
|
16
|
+
this.loadPrevious = Utils.throttle(this.loadPrevious, this.animationDuration);
|
|
17
|
+
this._playerChunksManager = new PlayerChunksManager(provider, {
|
|
18
|
+
onInitializationFinished: () => on?.preloaded?.(this),
|
|
19
|
+
onEndReached: () => console.warn('end reached')
|
|
20
|
+
});
|
|
21
|
+
this._playerChunksManager.initialize();
|
|
22
|
+
}
|
|
23
|
+
get activeChunk() {
|
|
24
|
+
return this._playerChunksManager.activeChunk;
|
|
25
|
+
}
|
|
26
|
+
setActiveChunkItemIndex = (index) => {
|
|
27
|
+
if (!this.activeChunk) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
this.activeChunk.setActiveItemIndex(index);
|
|
31
|
+
};
|
|
32
|
+
loadNext = async () => {
|
|
33
|
+
if (!this.canLoadNext) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
this._playerChunksManager.activateItemAtFlattenedIndex(this.currentIndex + 1);
|
|
37
|
+
};
|
|
38
|
+
loadPrevious = async () => {
|
|
39
|
+
if (!this.canLoadPrevious) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
this._playerChunksManager.activateItemAtFlattenedIndex(this.currentIndex - 1);
|
|
43
|
+
};
|
|
44
|
+
reset = () => {
|
|
45
|
+
this._playerChunksManager.reset();
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { IFeedPlayerBuffer, IFeedPlayerDataProvider, WithId } from './types';
|
|
2
|
+
export declare class DefaultFeedPlayerBuffer<T extends WithId> implements IFeedPlayerBuffer<T> {
|
|
3
|
+
readonly kind = "feed";
|
|
4
|
+
readonly loaded: (T & {
|
|
5
|
+
mediaIndex?: number;
|
|
6
|
+
})[];
|
|
7
|
+
readonly currentIndex: number;
|
|
8
|
+
readonly current: (T & {
|
|
9
|
+
mediaIndex?: number;
|
|
10
|
+
}) | null;
|
|
11
|
+
readonly canLoadNext: boolean;
|
|
12
|
+
readonly canLoadPrevious: boolean;
|
|
13
|
+
readonly navigationDisabled: boolean;
|
|
14
|
+
readonly animationDuration = 500;
|
|
15
|
+
private _currentIndex;
|
|
16
|
+
private _loaded;
|
|
17
|
+
private _loadMoreFn;
|
|
18
|
+
private _isLoading;
|
|
19
|
+
constructor(provider: IFeedPlayerDataProvider<T>, on?: {
|
|
20
|
+
preloaded?: (self: DefaultFeedPlayerBuffer<T>) => void;
|
|
21
|
+
});
|
|
22
|
+
loadNext: () => Promise<void>;
|
|
23
|
+
loadPrevious: () => Promise<void>;
|
|
24
|
+
reset: () => void;
|
|
25
|
+
private initializeBuffer;
|
|
26
|
+
private warmUpBuffer;
|
|
27
|
+
}
|