@streamscloud/embeddable 14.0.1 → 14.0.2
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/posts/post-viewer/cmp.post-viewer.svelte.d.ts +1 -1
- package/dist/posts/posts-player/posts-player-view.svelte +7 -7
- package/dist/streams/streams-player/streams-player-view.svelte +15 -13
- package/dist/ui/player/index.d.ts +1 -0
- package/dist/ui/player/index.js +1 -0
- package/dist/ui/player/{content-player/cmp.content-player.svelte → player/cmp.player.svelte} +16 -16
- package/dist/ui/player/{content-player/cmp.content-player.svelte.d.ts → player/cmp.player.svelte.d.ts} +2 -2
- package/dist/ui/player/{content-player → player}/controls-and-attachments.svelte +1 -1
- package/dist/ui/player/{content-player → player}/controls-and-attachments.svelte.d.ts +2 -2
- package/dist/ui/player/player/index.d.ts +3 -0
- package/dist/ui/player/player/index.js +3 -0
- package/dist/ui/player/{content-player → player}/overview-panel.svelte.d.ts +4 -4
- package/dist/ui/player/player/player-config.svelte.d.ts +21 -0
- package/dist/ui/player/player/player-config.svelte.js +19 -0
- package/dist/ui/player/{content-player/content-player-settings.svelte.d.ts → player/player-settings.svelte.d.ts} +1 -1
- package/dist/ui/player/{content-player/content-player-settings.svelte.js → player/player-settings.svelte.js} +1 -1
- package/dist/ui/player/{content-player → player}/ui-manager.svelte.d.ts +1 -1
- package/dist/ui/player/{content-player → player}/ui-manager.svelte.js +1 -1
- package/dist/ui/player/providers/chunks-player-buffer/player-chunk.svelte.d.ts +3 -5
- package/dist/ui/player/providers/chunks-player-buffer/player-chunk.svelte.js +39 -39
- package/dist/ui/player/providers/chunks-player-buffer/player-chunks-manager.svelte.d.ts +4 -4
- package/dist/ui/player/providers/chunks-player-buffer/player-chunks-manager.svelte.js +80 -63
- package/dist/ui/player/providers/default-chunks-player-buffer.svelte.js +5 -1
- package/package.json +1 -1
- package/dist/ui/player/content-player/content-player-config.svelte.d.ts +0 -29
- package/dist/ui/player/content-player/content-player-config.svelte.js +0 -27
- package/dist/ui/player/content-player/index.d.ts +0 -3
- package/dist/ui/player/content-player/index.js +0 -3
- /package/dist/ui/player/{content-player → player}/overview-panel.svelte +0 -0
|
@@ -4,7 +4,7 @@ import { PostModel } from '../model';
|
|
|
4
4
|
import { type PlayerButtonDef } from '../../ui/player/button';
|
|
5
5
|
type Props = {
|
|
6
6
|
model: PostModel;
|
|
7
|
-
trackingParams: TrackingParams | null
|
|
7
|
+
trackingParams: TrackingParams | null;
|
|
8
8
|
enableAttachments?: boolean;
|
|
9
9
|
enableControls?: boolean;
|
|
10
10
|
controlsColors: {
|
|
@@ -14,7 +14,7 @@ import { PostActionsGenerator } from '../controls';
|
|
|
14
14
|
import { getPostCoverImage, PostModel } from '../model';
|
|
15
15
|
import { PostViewer } from '../post-viewer';
|
|
16
16
|
import { IconColor } from '../../ui/icon';
|
|
17
|
-
import {
|
|
17
|
+
import { Player, PlayerConfig, PlayerSettings } from '../../ui/player';
|
|
18
18
|
import {} from '../../ui/player/providers';
|
|
19
19
|
import { initBufferFromProvider } from '../../ui/player/providers/service';
|
|
20
20
|
import IconDelete from '@fluentui/svg-icons/icons/delete_32_regular.svg?raw';
|
|
@@ -55,9 +55,9 @@ const getLoadedItemById = (id) => {
|
|
|
55
55
|
}
|
|
56
56
|
return buffer.loaded.find((item) => item.id === id) || null;
|
|
57
57
|
};
|
|
58
|
-
const contentPlayerConfig = new
|
|
58
|
+
const contentPlayerConfig = new PlayerConfig({
|
|
59
59
|
playerBuffer: null,
|
|
60
|
-
settings: new
|
|
60
|
+
settings: new PlayerSettings(playerSettings),
|
|
61
61
|
closeOrchestrator,
|
|
62
62
|
playerSliderCallbacks: {
|
|
63
63
|
itemActivated: (id) => {
|
|
@@ -161,7 +161,7 @@ const currentItemActions = $derived.by(() => {
|
|
|
161
161
|
salePrice: contentPlayerConfig.playerColors.salePrice,
|
|
162
162
|
buttonBackground: contentPlayerConfig.playerColors.cardButton
|
|
163
163
|
}}
|
|
164
|
-
trackingParams={
|
|
164
|
+
trackingParams={false}
|
|
165
165
|
locale={contentPlayerConfig.settings.locale}
|
|
166
166
|
on={{
|
|
167
167
|
productClick: (id) => onProductClick(id, postModel.id),
|
|
@@ -170,7 +170,7 @@ const currentItemActions = $derived.by(() => {
|
|
|
170
170
|
adImpression: (id) => onAdImpression(id)
|
|
171
171
|
}} />
|
|
172
172
|
{/snippet}
|
|
173
|
-
<
|
|
173
|
+
<Player
|
|
174
174
|
config={contentPlayerConfig}
|
|
175
175
|
itemActions={currentItemActions}
|
|
176
176
|
attachmentsView={buffer?.current && itemAsPostModel(buffer.current).attachments ? attachmentsView : undefined}>
|
|
@@ -181,7 +181,7 @@ const currentItemActions = $derived.by(() => {
|
|
|
181
181
|
model={postModel}
|
|
182
182
|
controlsColors={{ active: contentPlayerConfig.playerColors.button, inactive: contentPlayerConfig.playerColors.buttonInactive }}
|
|
183
183
|
controlActions={handler.actions}
|
|
184
|
-
trackingParams={
|
|
184
|
+
trackingParams={false}
|
|
185
185
|
enableAttachments={contentPlayerConfig.uiManager.showAttachmentsOverlay}
|
|
186
186
|
enableControls={contentPlayerConfig.uiManager.showControlsOverlay}
|
|
187
187
|
autoplay="on-appearance"
|
|
@@ -193,4 +193,4 @@ const currentItemActions = $derived.by(() => {
|
|
|
193
193
|
adImpression: (adId) => onAdImpression(adId)
|
|
194
194
|
}} />
|
|
195
195
|
{/snippet}
|
|
196
|
-
</
|
|
196
|
+
</Player>
|
|
@@ -16,7 +16,7 @@ import { StreamActionsGenerator } from '../controls';
|
|
|
16
16
|
import { mapToPostModel } from '../layout/models';
|
|
17
17
|
import { StreamPageViewer } from '../stream-page-viewer';
|
|
18
18
|
import { IconColor } from '../../ui/icon';
|
|
19
|
-
import {
|
|
19
|
+
import { Player, PlayerConfig, PlayerSettings } from '../../ui/player';
|
|
20
20
|
import { default as Overview } from './stream-overview.svelte';
|
|
21
21
|
import { StreamPlayerLocalization } from './stream-player-localization';
|
|
22
22
|
import { StreamsPlayerBuffer } from './streams-player-buffer.svelte';
|
|
@@ -35,6 +35,14 @@ let isActive = true;
|
|
|
35
35
|
let activityTimeout = null;
|
|
36
36
|
let trackingInterval = null;
|
|
37
37
|
let maxPageIndexViewed = 0;
|
|
38
|
+
const trackingParams = $derived.by(() => {
|
|
39
|
+
return currentStreamModel
|
|
40
|
+
? {
|
|
41
|
+
streamId: currentStreamModel.id,
|
|
42
|
+
campaignId: amplificationParameters === null || amplificationParameters === void 0 ? void 0 : amplificationParameters.campaignId
|
|
43
|
+
}
|
|
44
|
+
: false;
|
|
45
|
+
});
|
|
38
46
|
$effect(() => {
|
|
39
47
|
void dataProvider;
|
|
40
48
|
untrack(() => {
|
|
@@ -45,12 +53,6 @@ $effect(() => {
|
|
|
45
53
|
});
|
|
46
54
|
return () => { };
|
|
47
55
|
});
|
|
48
|
-
$effect(() => contentPlayerConfig.updateTrackingParams(currentStreamModel
|
|
49
|
-
? {
|
|
50
|
-
streamId: currentStreamModel.id,
|
|
51
|
-
campaignId: amplificationParameters === null || amplificationParameters === void 0 ? void 0 : amplificationParameters.campaignId
|
|
52
|
-
}
|
|
53
|
-
: null));
|
|
54
56
|
$effect(() => {
|
|
55
57
|
var _a;
|
|
56
58
|
const stream = (_a = buffer === null || buffer === void 0 ? void 0 : buffer.activeChunk) === null || _a === void 0 ? void 0 : _a.model;
|
|
@@ -103,9 +105,9 @@ const initPlayerBuffer = (dataProvider) => __awaiter(void 0, void 0, void 0, fun
|
|
|
103
105
|
buffer = newBuffer;
|
|
104
106
|
contentPlayerConfig.playerBuffer = newBuffer;
|
|
105
107
|
});
|
|
106
|
-
const contentPlayerConfig = new
|
|
108
|
+
const contentPlayerConfig = new PlayerConfig({
|
|
107
109
|
playerBuffer: null,
|
|
108
|
-
settings: new
|
|
110
|
+
settings: new PlayerSettings(playerSettings),
|
|
109
111
|
closeOrchestrator,
|
|
110
112
|
playerSliderCallbacks: {
|
|
111
113
|
itemActivated: (item) => onPageActivated(item),
|
|
@@ -288,7 +290,7 @@ const stopActivityTracking = () => {
|
|
|
288
290
|
salePrice: contentPlayerConfig.playerColors.salePrice,
|
|
289
291
|
buttonBackground: contentPlayerConfig.playerColors.cardButton
|
|
290
292
|
}}
|
|
291
|
-
trackingParams={
|
|
293
|
+
trackingParams={trackingParams}
|
|
292
294
|
locale={contentPlayerConfig.settings.locale}
|
|
293
295
|
on={{
|
|
294
296
|
productClick: (id) => onShortVideoProductClick(id, postModel.id),
|
|
@@ -298,7 +300,7 @@ const stopActivityTracking = () => {
|
|
|
298
300
|
}} />
|
|
299
301
|
{/if}
|
|
300
302
|
{/snippet}
|
|
301
|
-
<
|
|
303
|
+
<Player
|
|
302
304
|
config={contentPlayerConfig}
|
|
303
305
|
itemActions={currentItemActions}
|
|
304
306
|
attachmentsView={buffer?.current && itemAsPostModel(buffer.current)?.attachments ? attachmentsView : undefined}>
|
|
@@ -336,7 +338,7 @@ const stopActivityTracking = () => {
|
|
|
336
338
|
<PostViewer
|
|
337
339
|
model={postModel}
|
|
338
340
|
controlsColors={{ active: contentPlayerConfig.playerColors.button, inactive: contentPlayerConfig.playerColors.buttonInactive }}
|
|
339
|
-
trackingParams={
|
|
341
|
+
trackingParams={trackingParams}
|
|
340
342
|
enableAttachments={contentPlayerConfig.uiManager.showAttachmentsOverlay}
|
|
341
343
|
enableControls={contentPlayerConfig.uiManager.showControlsOverlay}
|
|
342
344
|
controlActions={handler?.actions ?? []}
|
|
@@ -362,4 +364,4 @@ const stopActivityTracking = () => {
|
|
|
362
364
|
}} />
|
|
363
365
|
{/if}
|
|
364
366
|
{/snippet}
|
|
365
|
-
</
|
|
367
|
+
</Player>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Player, PlayerConfig, PlayerSettings } from './player';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Player, PlayerConfig, PlayerSettings } from './player';
|
package/dist/ui/player/{content-player/cmp.content-player.svelte → player/cmp.player.svelte}
RENAMED
|
@@ -13,7 +13,7 @@ let overviewPosition = $state({
|
|
|
13
13
|
right: 0
|
|
14
14
|
});
|
|
15
15
|
const uiManager = config.uiManager;
|
|
16
|
-
const
|
|
16
|
+
const handlePlayerMounted = (node) => {
|
|
17
17
|
const markAsTouched = () => {
|
|
18
18
|
everTouched = true;
|
|
19
19
|
removeListeners();
|
|
@@ -74,9 +74,9 @@ const handleSliderMounted = (node) => {
|
|
|
74
74
|
break;
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
|
-
node.style.setProperty('--
|
|
78
|
-
node.style.setProperty('--
|
|
79
|
-
node.style.setProperty('--
|
|
77
|
+
node.style.setProperty('--_player--content--width', width);
|
|
78
|
+
node.style.setProperty('--_player--content--height', height);
|
|
79
|
+
node.style.setProperty('--_player--content--margin', margin);
|
|
80
80
|
uiManager.contentViewWidth = contentWidthNumber;
|
|
81
81
|
const verticalIndent = uiManager.isMobileView ? 0 : 13;
|
|
82
82
|
overviewPosition = {
|
|
@@ -101,19 +101,19 @@ const handleSliderMounted = (node) => {
|
|
|
101
101
|
}
|
|
102
102
|
}} />
|
|
103
103
|
|
|
104
|
-
<div class="
|
|
104
|
+
<div class="player" use:handlePlayerMounted>
|
|
105
105
|
{#if config.settings.showStreamsCloudWatermark}
|
|
106
|
-
<div class="
|
|
106
|
+
<div class="player__watermark">
|
|
107
107
|
<a href="https://streamscloud.com/" tabindex="-1" aria-label="none">
|
|
108
108
|
<img src="https://embedabble-assets.streamscloud-cdn.com/watermark.svg" alt="StreamsCloud" />
|
|
109
109
|
</a>
|
|
110
110
|
</div>
|
|
111
111
|
{/if}
|
|
112
112
|
{#if config.playerBuffer}
|
|
113
|
-
<div class="
|
|
113
|
+
<div class="player__slider" use:handleSliderMounted>
|
|
114
114
|
<PlayerSlider buffer={config.playerBuffer} on={config.playerSliderCallbacks}>
|
|
115
115
|
{#snippet children({ item })}
|
|
116
|
-
<div class="
|
|
116
|
+
<div class="player__content">
|
|
117
117
|
{@render itemView({ item })}
|
|
118
118
|
{#if uiManager.isMobileView && config.playerBuffer && config.playerBuffer.loaded.length > 1 && !everTouched}
|
|
119
119
|
<SwipeIndicator locale={config.settings.locale} />
|
|
@@ -145,7 +145,7 @@ const handleSliderMounted = (node) => {
|
|
|
145
145
|
opacity: 1;
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
-
.
|
|
148
|
+
.player {
|
|
149
149
|
display: flex;
|
|
150
150
|
flex: 1;
|
|
151
151
|
min-height: 0;
|
|
@@ -154,11 +154,11 @@ const handleSliderMounted = (node) => {
|
|
|
154
154
|
/* Set 'container-type: inline-size;' to reference container*/
|
|
155
155
|
}
|
|
156
156
|
@container (width < 576px) {
|
|
157
|
-
.
|
|
157
|
+
.player {
|
|
158
158
|
padding: 0;
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
|
-
.
|
|
161
|
+
.player__slider {
|
|
162
162
|
width: 100%;
|
|
163
163
|
min-width: 100%;
|
|
164
164
|
max-width: 100%;
|
|
@@ -166,15 +166,15 @@ const handleSliderMounted = (node) => {
|
|
|
166
166
|
min-height: 100%;
|
|
167
167
|
max-height: 100%;
|
|
168
168
|
}
|
|
169
|
-
.
|
|
169
|
+
.player__watermark {
|
|
170
170
|
position: absolute;
|
|
171
171
|
bottom: 5rem;
|
|
172
172
|
left: 4.375rem;
|
|
173
173
|
}
|
|
174
|
-
.
|
|
175
|
-
width: var(--
|
|
176
|
-
height: var(--
|
|
177
|
-
margin: var(--
|
|
174
|
+
.player__content {
|
|
175
|
+
width: var(--_player--content--width, 100%);
|
|
176
|
+
height: var(--_player--content--height, 100%);
|
|
177
|
+
margin: var(--_player--content--margin, 0);
|
|
178
178
|
position: relative;
|
|
179
179
|
display: flex;
|
|
180
180
|
justify-content: center;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { PlayerButtonDef } from '../button';
|
|
2
|
-
import type {
|
|
2
|
+
import type { PlayerConfig } from './player-config.svelte';
|
|
3
3
|
import { type Snippet } from 'svelte';
|
|
4
4
|
declare class __sveltets_Render<T extends {
|
|
5
5
|
id: string;
|
|
6
6
|
}> {
|
|
7
7
|
props(): {
|
|
8
|
-
config:
|
|
8
|
+
config: PlayerConfig<T>;
|
|
9
9
|
itemActions: PlayerButtonDef[];
|
|
10
10
|
itemView: Snippet<[{
|
|
11
11
|
item: T;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">import { slideHorizontally } from '../../../core/transitions';
|
|
2
2
|
import { PlayerButton, ResponsivePlayerButtonsGroup } from '../button';
|
|
3
|
-
import {
|
|
3
|
+
import { PlayerConfig } from './player-config.svelte.js';
|
|
4
4
|
import IconCalendarWeekNumbers from '@fluentui/svg-icons/icons/calendar_week_numbers_24_regular.svg?raw';
|
|
5
5
|
import IconChevronDown from '@fluentui/svg-icons/icons/chevron_down_28_regular.svg?raw';
|
|
6
6
|
import IconChevronUp from '@fluentui/svg-icons/icons/chevron_up_28_regular.svg?raw';
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { type PlayerButtonDef } from '../button';
|
|
2
|
-
import {
|
|
2
|
+
import { PlayerConfig } from './player-config.svelte.js';
|
|
3
3
|
import type { Snippet } from 'svelte';
|
|
4
4
|
declare class __sveltets_Render<T extends {
|
|
5
5
|
id: string;
|
|
6
6
|
}> {
|
|
7
7
|
props(): {
|
|
8
|
-
config:
|
|
8
|
+
config: PlayerConfig<T>;
|
|
9
9
|
hasOverview: boolean;
|
|
10
10
|
itemActions: PlayerButtonDef[];
|
|
11
11
|
attachmentsView?: Snippet<[{
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
1
|
+
import type { PlayerConfig } from './player-config.svelte.js';
|
|
2
|
+
import type { PlayerUIManager } from './ui-manager.svelte';
|
|
3
3
|
import type { Snippet } from 'svelte';
|
|
4
4
|
declare class __sveltets_Render<T extends {
|
|
5
5
|
id: string;
|
|
6
6
|
}> {
|
|
7
7
|
props(): {
|
|
8
|
-
config:
|
|
9
|
-
uiManager:
|
|
8
|
+
config: PlayerConfig<T>;
|
|
9
|
+
uiManager: PlayerUIManager;
|
|
10
10
|
position: {
|
|
11
11
|
top: number;
|
|
12
12
|
bottom: number;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ICloseOrchestrator } from '../close-orchestrator';
|
|
2
|
+
import type { IPlayerBuffer } from '../providers';
|
|
3
|
+
import type { PlayerSliderCallbacks } from '../slider/types';
|
|
4
|
+
import { PlayerSettings } from './player-settings.svelte';
|
|
5
|
+
import { PlayerUIManager } from './ui-manager.svelte';
|
|
6
|
+
export declare class PlayerConfig<T extends {
|
|
7
|
+
id: string;
|
|
8
|
+
}> {
|
|
9
|
+
playerBuffer: IPlayerBuffer<T> | null;
|
|
10
|
+
readonly settings: PlayerSettings;
|
|
11
|
+
readonly playerSliderCallbacks: PlayerSliderCallbacks | undefined;
|
|
12
|
+
readonly closeOrchestrator: ICloseOrchestrator;
|
|
13
|
+
readonly uiManager: PlayerUIManager;
|
|
14
|
+
constructor(init: {
|
|
15
|
+
playerBuffer: IPlayerBuffer<T> | null;
|
|
16
|
+
settings?: PlayerSettings;
|
|
17
|
+
playerSliderCallbacks?: PlayerSliderCallbacks;
|
|
18
|
+
closeOrchestrator: ICloseOrchestrator;
|
|
19
|
+
});
|
|
20
|
+
get playerColors(): import("../colors").PlayerColors;
|
|
21
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { PlayerSettings } from './player-settings.svelte';
|
|
2
|
+
import { PlayerUIManager } from './ui-manager.svelte';
|
|
3
|
+
export class PlayerConfig {
|
|
4
|
+
playerBuffer = $state.raw(null);
|
|
5
|
+
settings;
|
|
6
|
+
playerSliderCallbacks;
|
|
7
|
+
closeOrchestrator;
|
|
8
|
+
uiManager = new PlayerUIManager();
|
|
9
|
+
constructor(init) {
|
|
10
|
+
const { playerBuffer, settings, playerSliderCallbacks, closeOrchestrator } = init;
|
|
11
|
+
this.playerBuffer = playerBuffer;
|
|
12
|
+
this.settings = settings || new PlayerSettings();
|
|
13
|
+
this.playerSliderCallbacks = playerSliderCallbacks;
|
|
14
|
+
this.closeOrchestrator = closeOrchestrator;
|
|
15
|
+
}
|
|
16
|
+
get playerColors() {
|
|
17
|
+
return this.settings.playerColors;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Locale } from '../../../core/locale';
|
|
2
2
|
import { type ThemeValue } from '../../../core/theme';
|
|
3
3
|
import { PlayerColors } from '../colors';
|
|
4
|
-
export declare class
|
|
4
|
+
export declare class PlayerSettings {
|
|
5
5
|
locale: Locale;
|
|
6
6
|
showStreamsCloudWatermark: boolean;
|
|
7
7
|
allPlayerColors: Record<ThemeValue, PlayerColors>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const ATTACHMENTS_MAX_WIDTH = 176;
|
|
2
2
|
const OVERLAY_MAX_WIDTH = 150;
|
|
3
3
|
const SAFE_AREA_SIZE = 70;
|
|
4
|
-
export class
|
|
4
|
+
export class PlayerUIManager {
|
|
5
5
|
overviewCollapsed = $state(true);
|
|
6
6
|
overviewCanBeShown = $derived.by(() => this.overviewMaxWidth <= this.sidePanelsMaxWidth);
|
|
7
7
|
overviewMaxWidth = OVERLAY_MAX_WIDTH;
|
|
@@ -5,11 +5,9 @@ export declare class PlayerChunk<TItem extends WithId, TChunk extends WithId> {
|
|
|
5
5
|
readonly items: TItem[];
|
|
6
6
|
readonly chunkItems: PlayerChunkItem<TItem>[];
|
|
7
7
|
readonly activeChunkItem: PlayerChunkItem<TItem>;
|
|
8
|
-
readonly isEmpty: boolean;
|
|
9
|
-
isFullyLoaded: boolean;
|
|
10
8
|
private _chunkItems;
|
|
11
9
|
private _activeItemIndex;
|
|
12
|
-
private
|
|
10
|
+
private _fetchDeferred;
|
|
13
11
|
private _itemsLoader;
|
|
14
12
|
constructor(data: {
|
|
15
13
|
chunk: TChunk;
|
|
@@ -24,9 +22,9 @@ export declare class PlayerChunk<TItem extends WithId, TChunk extends WithId> {
|
|
|
24
22
|
};
|
|
25
23
|
});
|
|
26
24
|
get isLoading(): boolean;
|
|
25
|
+
get canLoadMore(): boolean;
|
|
27
26
|
get activeItemIndex(): number;
|
|
28
27
|
loadMore: () => Promise<TItem[]>;
|
|
29
|
-
setActiveItemIndex: (index: number
|
|
28
|
+
setActiveItemIndex: (index: number) => Promise<void>;
|
|
30
29
|
mutateChunkItems: (items: PlayerChunkItem<TItem>[]) => void;
|
|
31
|
-
warmUp: () => Promise<void>;
|
|
32
30
|
}
|
|
@@ -1,73 +1,73 @@
|
|
|
1
1
|
import { ContinuationToken } from '../../../../core/continuation-token';
|
|
2
2
|
import { CursorDataLoader } from '../../../../core/data-loaders';
|
|
3
|
+
import { Deferred } from '../../../../core/deferred';
|
|
3
4
|
import { PlayerChunkItem } from './player-chunk-item.svelte';
|
|
4
|
-
const CHUNK_ITEMS_BUFFER_SIZE = 5;
|
|
5
5
|
export class PlayerChunk {
|
|
6
6
|
model;
|
|
7
7
|
items = $derived.by(() => this._chunkItems.map((i) => i.model));
|
|
8
8
|
chunkItems = $derived.by(() => this._chunkItems);
|
|
9
9
|
activeChunkItem = $derived.by(() => this._chunkItems[this._activeItemIndex] ?? null);
|
|
10
|
-
isEmpty = $derived.by(() => this.isFullyLoaded && this._chunkItems.length === 0);
|
|
11
|
-
isFullyLoaded = $state(false);
|
|
12
10
|
_chunkItems = $state.raw([]);
|
|
13
11
|
_activeItemIndex = $state(0);
|
|
14
|
-
|
|
12
|
+
_fetchDeferred = $state.raw(null);
|
|
15
13
|
_itemsLoader;
|
|
16
14
|
constructor(data) {
|
|
17
15
|
const { chunk, provider, callbacks } = data;
|
|
18
16
|
this.model = chunk;
|
|
19
17
|
this._itemsLoader = new CursorDataLoader({
|
|
20
18
|
loadPage: async (continuationToken) => {
|
|
21
|
-
if (this.
|
|
19
|
+
if (this._fetchDeferred) {
|
|
20
|
+
return await this._fetchDeferred.promise;
|
|
21
|
+
}
|
|
22
|
+
if (!this.canLoadMore) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
this._fetchDeferred = new Deferred();
|
|
27
|
+
const itemsResult = await provider.loadChunkItems(this.model.id, continuationToken.toNextChunkString());
|
|
28
|
+
const newItems = itemsResult.items;
|
|
29
|
+
this._chunkItems = [
|
|
30
|
+
...this._chunkItems,
|
|
31
|
+
...newItems.map((item) => new PlayerChunkItem({
|
|
32
|
+
model: item,
|
|
33
|
+
chunkId: this.model.id
|
|
34
|
+
}))
|
|
35
|
+
];
|
|
36
|
+
const continuationTokenResult = ContinuationToken.fromPayload(itemsResult.continuationToken);
|
|
37
|
+
if (!continuationTokenResult.canLoadMore) {
|
|
38
|
+
callbacks?.onChunkFullyLoaded(this);
|
|
39
|
+
}
|
|
40
|
+
const result = {
|
|
41
|
+
items: newItems,
|
|
42
|
+
continuationToken: continuationTokenResult
|
|
43
|
+
};
|
|
44
|
+
this._fetchDeferred.resolve(result);
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
this._fetchDeferred?.resolve(null);
|
|
22
49
|
return null;
|
|
23
50
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
this._chunkItems = [
|
|
27
|
-
...this._chunkItems,
|
|
28
|
-
...newItems.map((item) => new PlayerChunkItem({
|
|
29
|
-
model: item,
|
|
30
|
-
chunkId: this.model.id
|
|
31
|
-
}))
|
|
32
|
-
];
|
|
33
|
-
const continuationTokenResult = ContinuationToken.fromPayload(result.continuationToken);
|
|
34
|
-
if (!continuationTokenResult.canLoadMore) {
|
|
35
|
-
this.isFullyLoaded = true;
|
|
36
|
-
callbacks?.onChunkFullyLoaded(this);
|
|
51
|
+
finally {
|
|
52
|
+
this._fetchDeferred = null;
|
|
37
53
|
}
|
|
38
|
-
return {
|
|
39
|
-
items: newItems,
|
|
40
|
-
continuationToken: continuationTokenResult
|
|
41
|
-
};
|
|
42
54
|
}
|
|
43
55
|
});
|
|
44
56
|
}
|
|
45
57
|
get isLoading() {
|
|
46
|
-
return this.
|
|
58
|
+
return !!this._fetchDeferred;
|
|
59
|
+
}
|
|
60
|
+
get canLoadMore() {
|
|
61
|
+
return this._itemsLoader.continuationToken.canLoadMore;
|
|
47
62
|
}
|
|
48
63
|
get activeItemIndex() {
|
|
49
64
|
return this._activeItemIndex;
|
|
50
65
|
}
|
|
51
66
|
loadMore = () => this._itemsLoader.loadMore();
|
|
52
|
-
setActiveItemIndex = async (index
|
|
67
|
+
setActiveItemIndex = async (index) => {
|
|
53
68
|
this._activeItemIndex = index;
|
|
54
|
-
if (warmUp) {
|
|
55
|
-
await this.warmUp();
|
|
56
|
-
}
|
|
57
69
|
};
|
|
58
70
|
mutateChunkItems = (items) => {
|
|
59
71
|
this._chunkItems = items;
|
|
60
72
|
};
|
|
61
|
-
warmUp = async () => {
|
|
62
|
-
if (this._chunkItems.length >= this._activeItemIndex + CHUNK_ITEMS_BUFFER_SIZE || this._isLoading) {
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
this._isLoading = true;
|
|
66
|
-
try {
|
|
67
|
-
await this.loadMore();
|
|
68
|
-
}
|
|
69
|
-
finally {
|
|
70
|
-
this._isLoading = false;
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
73
|
}
|
|
@@ -4,7 +4,7 @@ export declare class PlayerChunksManager<TItem extends WithId, TChunk extends Wi
|
|
|
4
4
|
private provider;
|
|
5
5
|
private _activeChunkIndex;
|
|
6
6
|
private _loadedChunks;
|
|
7
|
-
private
|
|
7
|
+
private _warmUpDeferred;
|
|
8
8
|
constructor(provider: IChunksPlayerDataProvider<TItem, TChunk>);
|
|
9
9
|
get activeChunk(): PlayerChunk<TItem, TChunk>;
|
|
10
10
|
get loadedChunks(): PlayerChunk<TItem, TChunk>[];
|
|
@@ -15,9 +15,9 @@ export declare class PlayerChunksManager<TItem extends WithId, TChunk extends Wi
|
|
|
15
15
|
removeItemById: (id: string) => boolean;
|
|
16
16
|
removeChunkById: (id: string) => boolean | undefined;
|
|
17
17
|
initialize: () => Promise<void>;
|
|
18
|
-
setActiveChunkIndex: (index: number) => Promise<void>;
|
|
18
|
+
setActiveChunkIndex: (index: number, chunkItemIndex: number) => Promise<void>;
|
|
19
19
|
activateItemAtFlattenedIndex: (index: number) => Promise<void>;
|
|
20
20
|
warmUp: () => Promise<void>;
|
|
21
|
-
reset: () => void
|
|
22
|
-
private
|
|
21
|
+
reset: () => Promise<void>;
|
|
22
|
+
private warmUpSequentially;
|
|
23
23
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { Deferred } from '../../../../core/deferred';
|
|
2
2
|
import { PlayerChunk } from './player-chunk.svelte';
|
|
3
|
-
const
|
|
4
|
-
|
|
3
|
+
const ITEMS_BUFFER_SIZE = 10;
|
|
4
|
+
// Configuration: if true, always start from first item when switching chunks
|
|
5
|
+
// if false, activate the exact item at its position in the new chunk
|
|
6
|
+
const START_FROM_FIRST_ITEM_ON_CHUNK_SWITCH = true;
|
|
5
7
|
export class PlayerChunksManager {
|
|
6
8
|
provider;
|
|
7
9
|
_activeChunkIndex = $state(-1);
|
|
8
10
|
_loadedChunks = $state.raw([]);
|
|
9
|
-
|
|
11
|
+
_warmUpDeferred = $state.raw(null);
|
|
10
12
|
constructor(provider) {
|
|
11
13
|
this.provider = provider;
|
|
12
14
|
}
|
|
@@ -17,7 +19,7 @@ export class PlayerChunksManager {
|
|
|
17
19
|
return this._loadedChunks;
|
|
18
20
|
}
|
|
19
21
|
get isLoading() {
|
|
20
|
-
return this.
|
|
22
|
+
return this._warmUpDeferred !== null || this._loadedChunks.some((c) => c.isLoading);
|
|
21
23
|
}
|
|
22
24
|
get flattenedChunkItems() {
|
|
23
25
|
return this._loadedChunks.reduce((acc, chunk) => {
|
|
@@ -42,8 +44,7 @@ export class PlayerChunksManager {
|
|
|
42
44
|
return false;
|
|
43
45
|
}
|
|
44
46
|
const itemIndex = chunkWithItem.items.findIndex((item) => item.id === id);
|
|
45
|
-
this.setActiveChunkIndex(chunkWithItemIndex);
|
|
46
|
-
this.activeChunk.setActiveItemIndex(itemIndex);
|
|
47
|
+
this.setActiveChunkIndex(chunkWithItemIndex, itemIndex);
|
|
47
48
|
return true;
|
|
48
49
|
};
|
|
49
50
|
removeItemById = (id) => {
|
|
@@ -106,37 +107,27 @@ export class PlayerChunksManager {
|
|
|
106
107
|
else if (this._activeChunkIndex > chunkIndex) {
|
|
107
108
|
newActiveChunkIndex--;
|
|
108
109
|
}
|
|
109
|
-
this.setActiveChunkIndex(newActiveChunkIndex);
|
|
110
|
+
this.setActiveChunkIndex(newActiveChunkIndex, 0);
|
|
110
111
|
return true;
|
|
111
112
|
};
|
|
112
113
|
initialize = async () => {
|
|
113
|
-
const handleInitialized = async () => {
|
|
114
|
-
const startIndex = Math.min(FIXED_START_INDEX, this._loadedChunks.length - 1);
|
|
115
|
-
const populateChunkResult = await this.populateChunkAtIndex(startIndex, (currentIndex) => currentIndex + 1);
|
|
116
|
-
if (!populateChunkResult) {
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
this.setActiveChunkIndex(populateChunkResult.closestReadyChunkIndex);
|
|
120
|
-
if (populateChunkResult.closestReadyChunkIndex === FIXED_START_INDEX &&
|
|
121
|
-
this.provider.initialData.startItemIndex &&
|
|
122
|
-
this.provider.initialData.startItemIndex > 0) {
|
|
123
|
-
this.activeChunk.setActiveItemIndex(this.provider.initialData.startItemIndex);
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
114
|
this._loadedChunks = this.provider.initialData.prefetchedChunks.map((chunk) => new PlayerChunk({ chunk, provider: { loadChunkItems: this.provider.loadChunkItems } }));
|
|
127
|
-
const considerInitialized = this._loadedChunks.length !== 0;
|
|
128
|
-
if (considerInitialized) {
|
|
129
|
-
handleInitialized();
|
|
130
|
-
}
|
|
131
115
|
await this.warmUp();
|
|
132
|
-
if (
|
|
133
|
-
|
|
116
|
+
if (this._loadedChunks.length === 0 || this.flattenedChunkItems.length === 0) {
|
|
117
|
+
this.provider.onEndReached?.();
|
|
118
|
+
return;
|
|
134
119
|
}
|
|
120
|
+
const firstFilledChunkIndex = this._loadedChunks.findIndex((c) => c.items.length > 0);
|
|
121
|
+
const initialStartItemIndex = firstFilledChunkIndex === 0 && this.provider.initialData.startItemIndex && this.provider.initialData.startItemIndex > 0
|
|
122
|
+
? this.provider.initialData.startItemIndex
|
|
123
|
+
: 0;
|
|
124
|
+
this.setActiveChunkIndex(firstFilledChunkIndex, initialStartItemIndex);
|
|
125
|
+
// Start background warm-up after initialization
|
|
126
|
+
this.warmUp();
|
|
135
127
|
};
|
|
136
|
-
setActiveChunkIndex = async (index) => {
|
|
128
|
+
setActiveChunkIndex = async (index, chunkItemIndex) => {
|
|
137
129
|
this._activeChunkIndex = index;
|
|
138
|
-
this.
|
|
139
|
-
await this.populateChunkAtIndex(this._activeChunkIndex + 1, (currentIndex) => currentIndex + 1);
|
|
130
|
+
this.activeChunk.setActiveItemIndex(chunkItemIndex);
|
|
140
131
|
// Don't wait for warm up to be finished, it runs in the background
|
|
141
132
|
this.warmUp();
|
|
142
133
|
};
|
|
@@ -148,56 +139,82 @@ export class PlayerChunksManager {
|
|
|
148
139
|
return;
|
|
149
140
|
}
|
|
150
141
|
if (nextItem.chunkId !== activeChunkId) {
|
|
151
|
-
this.
|
|
152
|
-
|
|
142
|
+
const nextChunkIndex = this.loadedChunks.findIndex((c) => c.model.id === nextItem.chunkId);
|
|
143
|
+
if (nextChunkIndex === -1) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const itemIndexInChunk = START_FROM_FIRST_ITEM_ON_CHUNK_SWITCH ? 0 : this.loadedChunks[nextChunkIndex].chunkItems.indexOf(nextItem);
|
|
147
|
+
this.setActiveChunkIndex(nextChunkIndex, itemIndexInChunk);
|
|
153
148
|
}
|
|
154
149
|
else {
|
|
155
150
|
this.activeChunk.setActiveItemIndex(this.activeChunk.chunkItems.indexOf(nextItem));
|
|
156
151
|
}
|
|
157
152
|
};
|
|
158
153
|
warmUp = async () => {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
return this._fetchDeferred.promise;
|
|
162
|
-
}
|
|
163
|
-
if (this._loadedChunks.length >= this._activeChunkIndex + CHUNKS_BUFFER_SIZE) {
|
|
164
|
-
return;
|
|
154
|
+
if (this._warmUpDeferred) {
|
|
155
|
+
return this._warmUpDeferred.promise;
|
|
165
156
|
}
|
|
166
|
-
this.
|
|
157
|
+
this._warmUpDeferred = new Deferred();
|
|
167
158
|
try {
|
|
168
|
-
|
|
169
|
-
this._loadedChunks = [
|
|
170
|
-
...this._loadedChunks,
|
|
171
|
-
...result.map((chunk) => new PlayerChunk({
|
|
172
|
-
chunk,
|
|
173
|
-
provider: { loadChunkItems: this.provider.loadChunkItems }
|
|
174
|
-
}))
|
|
175
|
-
];
|
|
159
|
+
await this.warmUpSequentially();
|
|
176
160
|
}
|
|
177
161
|
finally {
|
|
178
|
-
this.
|
|
179
|
-
this.
|
|
162
|
+
this._warmUpDeferred.resolve();
|
|
163
|
+
this._warmUpDeferred = null;
|
|
180
164
|
}
|
|
181
165
|
};
|
|
182
|
-
reset = () => {
|
|
166
|
+
reset = async () => {
|
|
183
167
|
this._activeChunkIndex = -1;
|
|
184
168
|
this._loadedChunks = [];
|
|
185
|
-
this.
|
|
186
|
-
this.warmUp();
|
|
169
|
+
this._warmUpDeferred = null;
|
|
170
|
+
await this.warmUp();
|
|
187
171
|
};
|
|
188
|
-
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
172
|
+
warmUpSequentially = async () => {
|
|
173
|
+
const startChunkIndex = Math.max(0, this._activeChunkIndex);
|
|
174
|
+
// Calculate how many items we need ahead of current position
|
|
175
|
+
const getItemsAhead = () => {
|
|
176
|
+
const currentFlatIndex = this.flattenedActiveChunkItemIndex;
|
|
177
|
+
const totalItems = this.flattenedChunkItems.length;
|
|
178
|
+
return totalItems - currentFlatIndex - 1; // -1 because current item doesn't count
|
|
179
|
+
};
|
|
180
|
+
while (getItemsAhead() < ITEMS_BUFFER_SIZE) {
|
|
181
|
+
// Find first non-fully-loaded chunk starting from active
|
|
182
|
+
let targetChunkIndex = -1;
|
|
183
|
+
for (let i = startChunkIndex; i < this._loadedChunks.length; i++) {
|
|
184
|
+
if (this._loadedChunks[i].canLoadMore) {
|
|
185
|
+
targetChunkIndex = i;
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// If all chunks are fully loaded, load more chunks
|
|
190
|
+
if (targetChunkIndex === -1) {
|
|
191
|
+
const result = await this.provider.loadMoreChunks();
|
|
192
|
+
if (result.length === 0) {
|
|
193
|
+
// No more chunks available
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
this._loadedChunks = [
|
|
197
|
+
...this._loadedChunks,
|
|
198
|
+
...result.map((chunk) => new PlayerChunk({
|
|
199
|
+
chunk,
|
|
200
|
+
provider: { loadChunkItems: this.provider.loadChunkItems }
|
|
201
|
+
}))
|
|
202
|
+
];
|
|
203
|
+
continue; // Re-check for chunks to fill
|
|
204
|
+
}
|
|
205
|
+
// Load one page from target chunk
|
|
206
|
+
const chunk = this._loadedChunks[targetChunkIndex];
|
|
207
|
+
const itemsBefore = chunk.items.length;
|
|
208
|
+
await chunk.loadMore();
|
|
209
|
+
const itemsAfter = chunk.items.length;
|
|
210
|
+
// If chunk became fully loaded but added no items, continue to next chunk
|
|
211
|
+
if (itemsAfter === itemsBefore && !chunk.canLoadMore) {
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
// If no progress made and chunk is not fully loaded, something went wrong
|
|
215
|
+
if (itemsAfter === itemsBefore && chunk.canLoadMore) {
|
|
216
|
+
break; // Avoid infinite loop
|
|
198
217
|
}
|
|
199
|
-
return await this.populateChunkAtIndex(nextIndexFn(index), nextIndexFn);
|
|
200
218
|
}
|
|
201
|
-
return { closestReadyChunkIndex: index };
|
|
202
219
|
};
|
|
203
220
|
}
|
|
@@ -9,7 +9,11 @@ export class DefaultChunksPlayerBuffer {
|
|
|
9
9
|
if (this.loaded.length && this.currentIndex < this.loaded.length - 1) {
|
|
10
10
|
return true;
|
|
11
11
|
}
|
|
12
|
-
|
|
12
|
+
// Check if manager is still loading
|
|
13
|
+
if (this._playerChunksManager.isLoading) {
|
|
14
|
+
return false; // Don't trigger onEndReached while loading
|
|
15
|
+
}
|
|
16
|
+
return !!this._onEndReachedFn;
|
|
13
17
|
});
|
|
14
18
|
canLoadPrevious = $derived(this.currentIndex > 0);
|
|
15
19
|
navigationDisabled = $derived(!this.canLoadNext && !this.canLoadPrevious);
|
package/package.json
CHANGED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { ICloseOrchestrator } from '../close-orchestrator';
|
|
2
|
-
import type { IPlayerBuffer } from '../providers';
|
|
3
|
-
import type { PlayerSliderCallbacks } from '../slider/types';
|
|
4
|
-
import { ContentPlayerSettings } from './content-player-settings.svelte';
|
|
5
|
-
import { ContentPlayerUIManager } from './ui-manager.svelte';
|
|
6
|
-
export declare class ContentPlayerConfig<T extends {
|
|
7
|
-
id: string;
|
|
8
|
-
}> {
|
|
9
|
-
playerBuffer: IPlayerBuffer<T> | null;
|
|
10
|
-
readonly settings: ContentPlayerSettings;
|
|
11
|
-
readonly playerSliderCallbacks: PlayerSliderCallbacks | undefined;
|
|
12
|
-
readonly closeOrchestrator: ICloseOrchestrator;
|
|
13
|
-
readonly uiManager: ContentPlayerUIManager;
|
|
14
|
-
private _trackingParams;
|
|
15
|
-
constructor(init: {
|
|
16
|
-
playerBuffer: IPlayerBuffer<T> | null;
|
|
17
|
-
settings?: ContentPlayerSettings;
|
|
18
|
-
playerSliderCallbacks?: PlayerSliderCallbacks;
|
|
19
|
-
trackingParams?: ContentPlayerTrackingParams | null;
|
|
20
|
-
closeOrchestrator: ICloseOrchestrator;
|
|
21
|
-
});
|
|
22
|
-
get playerColors(): import("../colors").PlayerColors;
|
|
23
|
-
get trackingParams(): ContentPlayerConfig<T>['_trackingParams'];
|
|
24
|
-
updateTrackingParams: (data: ContentPlayerTrackingParams | null) => void;
|
|
25
|
-
}
|
|
26
|
-
export type ContentPlayerTrackingParams = {
|
|
27
|
-
streamId?: string;
|
|
28
|
-
campaignId?: string;
|
|
29
|
-
} | false;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { ContentPlayerSettings } from './content-player-settings.svelte';
|
|
2
|
-
import { ContentPlayerUIManager } from './ui-manager.svelte';
|
|
3
|
-
export class ContentPlayerConfig {
|
|
4
|
-
playerBuffer = $state.raw(null);
|
|
5
|
-
settings;
|
|
6
|
-
playerSliderCallbacks;
|
|
7
|
-
closeOrchestrator;
|
|
8
|
-
uiManager = new ContentPlayerUIManager();
|
|
9
|
-
_trackingParams = $state.raw(null);
|
|
10
|
-
constructor(init) {
|
|
11
|
-
const { playerBuffer, trackingParams, settings, playerSliderCallbacks, closeOrchestrator } = init;
|
|
12
|
-
this.playerBuffer = playerBuffer;
|
|
13
|
-
this._trackingParams = trackingParams ?? null;
|
|
14
|
-
this.settings = settings || new ContentPlayerSettings();
|
|
15
|
-
this.playerSliderCallbacks = playerSliderCallbacks;
|
|
16
|
-
this.closeOrchestrator = closeOrchestrator;
|
|
17
|
-
}
|
|
18
|
-
get playerColors() {
|
|
19
|
-
return this.settings.playerColors;
|
|
20
|
-
}
|
|
21
|
-
get trackingParams() {
|
|
22
|
-
return this._trackingParams;
|
|
23
|
-
}
|
|
24
|
-
updateTrackingParams = (data) => {
|
|
25
|
-
this._trackingParams = data ?? null;
|
|
26
|
-
};
|
|
27
|
-
}
|
|
File without changes
|