@streamscloud/embeddable 13.0.1 → 13.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.
Files changed (64) hide show
  1. package/dist/core/utils/utils.d.ts +1 -0
  2. package/dist/core/utils/utils.js +4 -0
  3. package/dist/external-api/data-providers/internal-media-center-data-provider.svelte.d.ts +2 -0
  4. package/dist/external-api/data-providers/internal-media-center-data-provider.svelte.js +4 -3
  5. package/dist/media-center/config/types.d.ts +2 -1
  6. package/dist/media-center/media-center/cmp.media-center-proxy.svelte +8 -3
  7. package/dist/media-center/media-center/discover/community-features.svelte +3 -3
  8. package/dist/media-center/media-center/discover/data-loading.js +1 -1
  9. package/dist/media-center/media-center/discover/discover-view-handler.svelte.d.ts +10 -3
  10. package/dist/media-center/media-center/discover/discover-view-handler.svelte.js +11 -11
  11. package/dist/media-center/media-center/discover/discover-view.svelte +17 -17
  12. package/dist/media-center/media-center/footer/media-center-footer.svelte +1 -1
  13. package/dist/media-center/media-center/header/media-center-header.svelte +11 -7
  14. package/dist/media-center/media-center/media-center-context.svelte.d.ts +14 -10
  15. package/dist/media-center/media-center/media-center-context.svelte.js +101 -43
  16. package/dist/media-center/media-center/media-center-settings.svelte.d.ts +3 -1
  17. package/dist/media-center/media-center/media-center-settings.svelte.js +8 -14
  18. package/dist/media-center/media-center/media-center-view.svelte +22 -25
  19. package/dist/media-center/media-center/moments/moments-feed-handler.svelte.d.ts +13 -4
  20. package/dist/media-center/media-center/moments/moments-feed-handler.svelte.js +30 -6
  21. package/dist/media-center/media-center/moments/moments-state.svelte.d.ts +4 -1
  22. package/dist/media-center/media-center/moments/moments-state.svelte.js +10 -2
  23. package/dist/media-center/media-center/{feed → posts-feed}/feed-providers-generator.d.ts +4 -8
  24. package/dist/media-center/media-center/posts-feed/feed-providers-generator.js +61 -0
  25. package/dist/media-center/media-center/posts-feed/index.d.ts +1 -0
  26. package/dist/media-center/media-center/posts-feed/index.js +1 -0
  27. package/dist/media-center/media-center/posts-feed/posts-feed-handler.svelte.d.ts +42 -0
  28. package/dist/media-center/media-center/posts-feed/posts-feed-handler.svelte.js +106 -0
  29. package/dist/media-center/media-center/posts-feed/types.d.ts +8 -0
  30. package/dist/media-center/media-center/streams-feed/feed-providers-generator.d.ts +12 -0
  31. package/dist/media-center/media-center/streams-feed/feed-providers-generator.js +56 -0
  32. package/dist/media-center/media-center/streams-feed/index.d.ts +1 -0
  33. package/dist/media-center/media-center/streams-feed/index.js +1 -0
  34. package/dist/media-center/media-center/streams-feed/streams-feed-handler.svelte.d.ts +45 -0
  35. package/dist/media-center/media-center/streams-feed/streams-feed-handler.svelte.js +111 -0
  36. package/dist/media-center/media-center/streams-feed/types.d.ts +9 -0
  37. package/dist/media-center/media-center/types.d.ts +3 -1
  38. package/dist/media-center/navigation/index.d.ts +1 -1
  39. package/dist/media-center/navigation/{media-center-state.d.ts → media-center-state.types.d.ts} +4 -3
  40. package/dist/media-center/navigation/media-center-state.types.js +1 -0
  41. package/dist/media-center/navigation/mock-navigation-handler.svelte.d.ts +3 -2
  42. package/dist/media-center/navigation/mock-navigation-handler.svelte.js +5 -2
  43. package/dist/media-center/navigation/types.d.ts +1 -2
  44. package/dist/media-page/cmp.media-page.svelte +1 -1
  45. package/dist/media-page/index.d.ts +4 -1
  46. package/dist/streams/streams-player/streams-player-view.svelte +4 -4
  47. package/dist/streams/streams-player/types.d.ts +5 -0
  48. package/dist/ui/player/providers/chunks-player-buffer/player-chunks-manager.svelte.d.ts +1 -0
  49. package/dist/ui/player/providers/chunks-player-buffer/player-chunks-manager.svelte.js +10 -0
  50. package/dist/ui/player/providers/default-chunks-player-buffer.svelte.d.ts +1 -0
  51. package/dist/ui/player/providers/default-chunks-player-buffer.svelte.js +3 -0
  52. package/dist/ui/player/providers/default-feed-player-buffer.svelte.d.ts +1 -0
  53. package/dist/ui/player/providers/default-feed-player-buffer.svelte.js +8 -0
  54. package/dist/ui/player/providers/types.d.ts +1 -0
  55. package/dist/ui/player/slider/cmp.player-slider.svelte +1 -1
  56. package/package.json +9 -7
  57. package/dist/media-center/media-center/feed/feed-handler.svelte.d.ts +0 -52
  58. package/dist/media-center/media-center/feed/feed-handler.svelte.js +0 -92
  59. package/dist/media-center/media-center/feed/feed-providers-generator.js +0 -83
  60. package/dist/media-center/media-center/feed/index.d.ts +0 -1
  61. package/dist/media-center/media-center/feed/index.js +0 -1
  62. package/dist/media-center/media-center/feed/types.d.ts +0 -12
  63. /package/dist/media-center/media-center/{feed → posts-feed}/types.js +0 -0
  64. /package/dist/media-center/{navigation/media-center-state.js → media-center/streams-feed/types.js} +0 -0
@@ -3,21 +3,15 @@ export class MediaCenterSettings {
3
3
  showStreamsCloudWatermark = $state(true);
4
4
  disableBackground = $state(false);
5
5
  theme = $state('dark');
6
+ state = $state.raw(null);
6
7
  constructor(init) {
7
- this.patch(init);
8
+ this.update(init);
8
9
  }
9
- patch = (data) => {
10
- if (data?.locale !== undefined) {
11
- this.locale = data.locale;
12
- }
13
- if (data?.showStreamsCloudWatermark !== undefined) {
14
- this.showStreamsCloudWatermark = data.showStreamsCloudWatermark;
15
- }
16
- if (data?.disableBackground !== undefined) {
17
- this.disableBackground = data.disableBackground;
18
- }
19
- if (data?.theme !== undefined) {
20
- this.theme = data.theme;
21
- }
10
+ update = (data) => {
11
+ this.locale = data?.locale ?? 'en';
12
+ this.showStreamsCloudWatermark = data?.showStreamsCloudWatermark ?? true;
13
+ this.disableBackground = data?.disableBackground ?? false;
14
+ this.theme = data?.theme ?? 'dark';
15
+ this.state = data?.state ?? null;
22
16
  };
23
17
  }
@@ -22,24 +22,21 @@ let { context, dynamicActions } = $props();
22
22
  let headerHeight = $state(0);
23
23
  let isMobileView = $state(false);
24
24
  const selectCategory = (categoryId) => __awaiter(void 0, void 0, void 0, function* () {
25
+ if (!context.mediaCenterMode) {
26
+ return;
27
+ }
25
28
  switch (context.mediaCenterMode) {
26
- case 'feed':
27
- if (!context.feedPlayerProps) {
29
+ case 'posts-feed':
30
+ if (!context.postsFeedHandler.feedPlayerProps) {
28
31
  return;
29
32
  }
30
- switch (context.feedPlayerProps.type) {
31
- case 'posts':
32
- if (context.categoriesHandler.selectedCategoryId === categoryId) {
33
- return;
34
- }
35
- context.playPostsFeed({ filter: { categoryId } });
36
- break;
37
- case 'streams':
38
- context.tryActivateStreamsInCategory(categoryId);
39
- return;
40
- default:
41
- Utils.assertUnreachable(context.feedPlayerProps);
33
+ if (context.categoriesHandler.selectedCategoryId === categoryId) {
34
+ return;
42
35
  }
36
+ context.playPostsFeed({ filter: { categoryId } });
37
+ break;
38
+ case 'streams-feed':
39
+ context.tryActivateStreamsInCategory(categoryId);
43
40
  break;
44
41
  case 'discover':
45
42
  context.activateDiscover({ categoryId });
@@ -52,13 +49,13 @@ const selectCategory = (categoryId) => __awaiter(void 0, void 0, void 0, functio
52
49
  }
53
50
  });
54
51
  const activateSelectedShortVideoPlayer = (shortVideo) => {
55
- context.playPostsFeed({ filter: { prefetchedItems: [shortVideo] } });
52
+ context.playPostsFeed({ init: { prefetchedItems: [shortVideo] } });
56
53
  };
57
54
  const activateSelectedStreamPlayer = (stream) => {
58
- context.playStreamsFeed({ filter: { prefetchedStreams: [stream] } });
55
+ context.playStreamsFeed({ init: { prefetchedStreams: [stream] } });
59
56
  };
60
57
  const activateSelectedStreamOfCategoryPlayer = (id, prefetchedStreams, categoryId) => {
61
- context.playStreamsFeed({ filter: { categoryId, prefetchedStreams, initialStreamId: id } });
58
+ context.playStreamsFeed({ filter: { categoryId }, init: { prefetchedStreams, initialStreamId: id } });
62
59
  };
63
60
  const onHeaderHeightChanged = (height) => {
64
61
  headerHeight = height;
@@ -139,13 +136,13 @@ const swipeToOpen = (node) => {
139
136
  {/if}
140
137
 
141
138
  <div class="media-center__content-container" use:swipeToOpen>
142
- {#if context.mediaCenterMode === 'feed' && context.feedPlayerProps}
139
+ {#if context.mediaCenterMode === 'posts-feed' && context.postsFeedHandler.feedPlayerProps}
140
+ <div class="media-center__content" class:media-center__content--faded={context.overlayIsActive} transition:fade={{ duration: 300 }}>
141
+ <PostsPlayerView {...context.postsFeedHandler.feedPlayerProps} />
142
+ </div>
143
+ {:else if context.mediaCenterMode === 'streams-feed' && context.streamsFeedHandler.feedPlayerProps}
143
144
  <div class="media-center__content" class:media-center__content--faded={context.overlayIsActive} transition:fade={{ duration: 300 }}>
144
- {#if context.feedPlayerProps.type === 'posts'}
145
- <PostsPlayerView {...context.feedPlayerProps.props} />
146
- {:else if context.feedPlayerProps.type === 'streams'}
147
- <StreamsPlayerView {...context.feedPlayerProps.props} />
148
- {/if}
145
+ <StreamsPlayerView {...context.streamsFeedHandler.feedPlayerProps} />
149
146
  </div>
150
147
  {:else if context.mediaCenterMode === 'discover'}
151
148
  <div class="media-center__content" transition:fade={{ duration: 300 }}>
@@ -156,9 +153,9 @@ const swipeToOpen = (node) => {
156
153
  streamSelected: (stream) => activateSelectedStreamPlayer(stream)
157
154
  }} />
158
155
  </div>
159
- {:else if context.mediaCenterMode === 'moments' && context.momentsPlayerProps}
156
+ {:else if context.mediaCenterMode === 'moments' && context.momentsFeedHandler.momentsPlayerProps}
160
157
  <div class="media-center__content" class:media-center__content--faded={context.overlayIsActive} transition:fade={{ duration: 300 }}>
161
- <PostsPlayerView {...context.momentsPlayerProps} />
158
+ <PostsPlayerView {...context.momentsFeedHandler.momentsPlayerProps} />
162
159
  </div>
163
160
  {/if}
164
161
  </div>
@@ -1,4 +1,5 @@
1
- import type { IMediaCenterDataProvider } from '../..';
1
+ import type { IMediaCenterDataProvider } from '../../config/types';
2
+ import type { MediaCenterState } from '../../navigation';
2
3
  import type { PostsPlayerProps } from '../../../posts/posts-player/types';
3
4
  import type { ICloseOrchestrator } from '../../../ui/player/close-orchestrator';
4
5
  import { MomentsState } from './moments-state.svelte';
@@ -10,17 +11,25 @@ export declare class MomentsFeedHandler {
10
11
  private _dataProvider;
11
12
  private _mediaCenterSettingsHandler;
12
13
  private _closeOrchestrator;
13
- private _onPlayerReachedEnd;
14
+ private _callbacks;
14
15
  constructor(data: {
15
16
  dataProvider: IMediaCenterDataProvider;
16
17
  mediaCenterSettingsHandler: MediaCenterSettingsHandler;
17
18
  closeOrchestrator: ICloseOrchestrator;
18
- onPlayerReachedEnd: () => void;
19
+ on: Callbacks;
19
20
  });
20
21
  get active(): boolean;
21
22
  get momentsPlayerProps(): PostsPlayerProps | null;
22
23
  get hasUnwatchedMoments(): boolean;
23
24
  get hasMoments(): boolean;
24
25
  deactivate: () => void;
25
- activateMoments: () => Promise<void>;
26
+ activate: (data?: {
27
+ initialMomentId?: string | null;
28
+ }) => Promise<void>;
29
+ private tryRestoreState;
26
30
  }
31
+ type Callbacks = {
32
+ playerReachedEnd: () => void;
33
+ navigationStateChanged: (state: MediaCenterState) => void;
34
+ };
35
+ export {};
@@ -8,14 +8,14 @@ export class MomentsFeedHandler {
8
8
  _dataProvider;
9
9
  _mediaCenterSettingsHandler;
10
10
  _closeOrchestrator;
11
- _onPlayerReachedEnd;
11
+ _callbacks;
12
12
  constructor(data) {
13
- const { dataProvider, mediaCenterSettingsHandler, closeOrchestrator, onPlayerReachedEnd } = data;
13
+ const { dataProvider, mediaCenterSettingsHandler, closeOrchestrator, on } = data;
14
14
  this.momentsState = new MomentsState(dataProvider);
15
15
  this._mediaCenterSettingsHandler = mediaCenterSettingsHandler;
16
16
  this._dataProvider = dataProvider;
17
17
  this._closeOrchestrator = closeOrchestrator;
18
- this._onPlayerReachedEnd = onPlayerReachedEnd;
18
+ this._callbacks = on;
19
19
  }
20
20
  get active() {
21
21
  return this._active;
@@ -31,19 +31,43 @@ export class MomentsFeedHandler {
31
31
  }
32
32
  deactivate = () => {
33
33
  this._active = false;
34
+ this._momentsPlayerProps = null;
34
35
  };
35
- activateMoments = async () => {
36
+ activate = async (data) => {
37
+ if (data?.initialMomentId && this.tryRestoreState(data.initialMomentId)) {
38
+ // Already active with the requested buffer
39
+ return;
40
+ }
36
41
  this._momentsPlayerProps = {
37
- dataProvider: { type: 'buffer', buffer: initBufferFromProvider(this.momentsState.generatePlayerDataProvider(this._onPlayerReachedEnd)) },
42
+ dataProvider: {
43
+ type: 'buffer',
44
+ buffer: initBufferFromProvider(this.momentsState.generatePlayerDataProvider({
45
+ initialId: data?.initialMomentId,
46
+ onEndReached: this._callbacks.playerReachedEnd
47
+ }))
48
+ },
38
49
  socialInteractionsHandler: this._dataProvider.handlers?.socialInteractionsHandler,
39
50
  analyticsHandler: this._dataProvider.handlers?.analyticsHandler,
40
51
  playerSettings: this._mediaCenterSettingsHandler.playerSettings,
41
52
  closeOrchestrator: this._closeOrchestrator,
42
53
  on: {
43
- postActivated: (id) => this.momentsState.markMomentAsSeen(id),
54
+ postActivated: (id) => {
55
+ this.momentsState.markMomentAsSeen(id);
56
+ this._callbacks.navigationStateChanged({ mode: 'moments', momentId: id });
57
+ },
44
58
  backgroundImageLoaded: this._mediaCenterSettingsHandler.backgroundImageLoadedHandler
45
59
  }
46
60
  };
47
61
  this._active = true;
48
62
  };
63
+ tryRestoreState = (initialMomentId) => {
64
+ if (!this._active || !this._momentsPlayerProps) {
65
+ return false;
66
+ }
67
+ const buffer = this._momentsPlayerProps.dataProvider.type === 'buffer' ? this._momentsPlayerProps.dataProvider.buffer : null;
68
+ if (!buffer) {
69
+ return false;
70
+ }
71
+ return buffer.tryActivateItemById(initialMomentId);
72
+ };
49
73
  }
@@ -16,5 +16,8 @@ export declare class MomentsState {
16
16
  isSeen: boolean;
17
17
  }[];
18
18
  markMomentAsSeen: (momentId: string) => void;
19
- generatePlayerDataProvider: (onEndReached: () => void) => IChunksPlayerDataProvider<PostPlayerModel>;
19
+ generatePlayerDataProvider: (data: {
20
+ initialId: string | null | undefined;
21
+ onEndReached: () => void;
22
+ }) => IChunksPlayerDataProvider<PostPlayerModel>;
20
23
  }
@@ -17,7 +17,8 @@ export class MomentsState {
17
17
  this.momentsSeenLocally = [...this.momentsSeenLocally, momentId];
18
18
  }
19
19
  };
20
- generatePlayerDataProvider = (onEndReached) => {
20
+ generatePlayerDataProvider = (data) => {
21
+ const { initialId, onEndReached } = data;
21
22
  const collectionCapacity = 5;
22
23
  const sortedMoments = [...this.allMoments].sort((a, b) => {
23
24
  const aUnwatched = !a.isSeen && !this.momentsSeenLocally.includes(a.id);
@@ -27,6 +28,13 @@ export class MomentsState {
27
28
  }
28
29
  return aUnwatched ? -1 : 1;
29
30
  });
31
+ if (initialId) {
32
+ const initialIndex = sortedMoments.findIndex((m) => m.id === initialId);
33
+ if (initialIndex >= 0) {
34
+ const [initialMoment] = sortedMoments.splice(initialIndex, 1);
35
+ sortedMoments.unshift(initialMoment);
36
+ }
37
+ }
30
38
  const ids = sortedMoments.map((m) => m.id);
31
39
  const idOrder = new Map();
32
40
  ids.forEach((id, idx) => idOrder.set(id, idx));
@@ -62,7 +70,7 @@ export class MomentsState {
62
70
  const moments = await this.dataProvider.postsPlayer.getPostsCursor({
63
71
  filter: {
64
72
  types: [PostType.Moment],
65
- includeIds: momentsInChunk
73
+ ids: momentsInChunk
66
74
  },
67
75
  limit: collectionCapacity
68
76
  });
@@ -1,17 +1,13 @@
1
1
  import type { IMediaCenterDataProvider } from '../../config/types';
2
2
  import type { PostPlayerModel } from '../../../posts/posts-player/types';
3
- import type { IStreamsPlayerDataProvider } from '../../../streams/streams-player/types';
4
3
  import type { IFeedPlayerDataProvider } from '../../../ui/player/providers';
5
- import type { PostsDataProviderFilter, StreamsDataProviderFilter } from './types';
4
+ import type { PostsFeedFilter, PostsFeedProviderInit } from './types';
6
5
  export declare class FeedProvidersGenerator {
7
6
  private dataProvider;
8
7
  constructor(dataProvider: IMediaCenterDataProvider);
9
8
  makePostPlayerItemsProvider: (data: {
10
- filter?: PostsDataProviderFilter;
9
+ filter: PostsFeedFilter | undefined;
10
+ init: PostsFeedProviderInit | undefined;
11
11
  onEndReached: () => void;
12
- }) => IFeedPlayerDataProvider<PostPlayerModel>;
13
- makeStreamsPlayerDataProvider: (data: {
14
- filter?: StreamsDataProviderFilter;
15
- onEndReached: () => void;
16
- }) => IStreamsPlayerDataProvider;
12
+ }) => Promise<IFeedPlayerDataProvider<PostPlayerModel>>;
17
13
  }
@@ -0,0 +1,61 @@
1
+ import { ContinuationToken } from '../../../core/continuation-token';
2
+ import { CursorDataLoader } from '../../../core/data-loaders';
3
+ import { PostType } from '../../../core/enums';
4
+ const SUPPORTED_POST_TYPES = [PostType.Article, PostType.Media, PostType.ShortVideo, PostType.Video];
5
+ export class FeedProvidersGenerator {
6
+ dataProvider;
7
+ constructor(dataProvider) {
8
+ this.dataProvider = dataProvider;
9
+ }
10
+ makePostPlayerItemsProvider = async (data) => {
11
+ const { filter, init, onEndReached } = data;
12
+ const { categoryId } = filter || {};
13
+ const { prefetchedItems: initialPrefetchedItems = [], initialPostId } = init || {};
14
+ const loader = new CursorDataLoader({
15
+ loadPage: async (continuationToken) => {
16
+ const result = await this.dataProvider.postsPlayer.getPostsCursor({
17
+ filter: {
18
+ types: SUPPORTED_POST_TYPES,
19
+ categoryId: categoryId || undefined,
20
+ excludeIds: initialPrefetchedItems.length ? initialPrefetchedItems.map((i) => i.id) : undefined
21
+ },
22
+ continuationToken: continuationToken.toNextChunkString(),
23
+ limit: 20
24
+ });
25
+ const items = result.items;
26
+ return {
27
+ items: items,
28
+ continuationToken: ContinuationToken.fromPayload(result.continuationToken)
29
+ };
30
+ }
31
+ });
32
+ if (initialPostId && !initialPrefetchedItems.find((p) => p.id === initialPostId)) {
33
+ const fetchedPost = await this.dataProvider.postsPlayer.getPostsCursor({
34
+ filter: {
35
+ types: SUPPORTED_POST_TYPES,
36
+ ids: [initialPostId]
37
+ },
38
+ limit: 1
39
+ });
40
+ if (fetchedPost.items.length) {
41
+ initialPrefetchedItems.push(fetchedPost.items[0]);
42
+ }
43
+ }
44
+ let prefetchedItems = initialPrefetchedItems;
45
+ if (initialPostId) {
46
+ const targetPost = prefetchedItems.find((p) => p.id === initialPostId);
47
+ if (targetPost) {
48
+ prefetchedItems = [targetPost, ...prefetchedItems.filter((p) => p.id !== initialPostId)];
49
+ }
50
+ }
51
+ return {
52
+ kind: 'feed',
53
+ initialData: {
54
+ prefetchedItems,
55
+ startIndex: prefetchedItems.length ? 0 : -1
56
+ },
57
+ loadMore: loader.loadMore,
58
+ onEndReached
59
+ };
60
+ };
61
+ }
@@ -0,0 +1 @@
1
+ export { PostsFeedHandler } from './posts-feed-handler.svelte';
@@ -0,0 +1 @@
1
+ export { PostsFeedHandler } from './posts-feed-handler.svelte';
@@ -0,0 +1,42 @@
1
+ import type { IMediaCenterDataProvider } from '../../config/types';
2
+ import type { MediaCenterState } from '../../navigation';
3
+ import type { PostPlayerModel, PostsPlayerProps } from '../../../posts/posts-player/types';
4
+ import type { ICloseOrchestrator } from '../../../ui/player/close-orchestrator';
5
+ import type { IPlayerDataProvider } from '../../../ui/player/providers';
6
+ import { MediaCenterSettingsHandler } from '../handlers';
7
+ import type { PostsFeedFilter, PostsFeedProviderInit } from './types';
8
+ export declare class PostsFeedHandler {
9
+ private _state;
10
+ private _providersGenerator;
11
+ private _feedPlayerData;
12
+ private _dataProvider;
13
+ private _mediaCenterSettingsHandler;
14
+ private _closeOrchestrator;
15
+ private _callbacks;
16
+ constructor(data: {
17
+ dataProvider: IMediaCenterDataProvider;
18
+ mediaCenterSettingsHandler: MediaCenterSettingsHandler;
19
+ closeOrchestrator: ICloseOrchestrator;
20
+ on: Callbacks;
21
+ });
22
+ get activated(): boolean;
23
+ get active(): boolean;
24
+ get loading(): boolean;
25
+ get feedPlayerProps(): PostsPlayerProps | null;
26
+ deactivate: () => void;
27
+ activateWithExistingProvider: (data: {
28
+ dataProvider: IPlayerDataProvider<PostPlayerModel>;
29
+ onPostActivated?: (id: string) => void;
30
+ }) => Promise<void>;
31
+ activate: (options: Partial<{
32
+ filter: PostsFeedFilter;
33
+ init: PostsFeedProviderInit;
34
+ }>) => Promise<void>;
35
+ private tryRestoreState;
36
+ private makePostsPlayerProps;
37
+ }
38
+ type Callbacks = {
39
+ playerReachedEnd: () => void;
40
+ navigationStateChanged: (state: MediaCenterState) => void;
41
+ };
42
+ export {};
@@ -0,0 +1,106 @@
1
+ import { Utils } from '../../../core/utils';
2
+ import { initBufferFromProvider } from '../../../ui/player/providers/service';
3
+ import { MediaCenterSettingsHandler } from '../handlers';
4
+ import { FeedProvidersGenerator } from './feed-providers-generator';
5
+ export class PostsFeedHandler {
6
+ _state = $state('inactive');
7
+ _providersGenerator;
8
+ _feedPlayerData = $state.raw(null);
9
+ _dataProvider;
10
+ _mediaCenterSettingsHandler;
11
+ _closeOrchestrator;
12
+ _callbacks;
13
+ constructor(data) {
14
+ const { dataProvider, mediaCenterSettingsHandler, closeOrchestrator, on } = data;
15
+ this._providersGenerator = new FeedProvidersGenerator(dataProvider);
16
+ this._mediaCenterSettingsHandler = mediaCenterSettingsHandler;
17
+ this._dataProvider = dataProvider;
18
+ this._closeOrchestrator = closeOrchestrator;
19
+ this._callbacks = on;
20
+ }
21
+ get activated() {
22
+ return this._state !== 'inactive';
23
+ }
24
+ get active() {
25
+ return this._state === 'ready';
26
+ }
27
+ get loading() {
28
+ return this._state === 'loading';
29
+ }
30
+ get feedPlayerProps() {
31
+ return this._feedPlayerData?.props || null;
32
+ }
33
+ deactivate = () => {
34
+ this._state = 'inactive';
35
+ this._feedPlayerData = null;
36
+ };
37
+ activateWithExistingProvider = async (data) => {
38
+ const { dataProvider, onPostActivated } = data;
39
+ const on = {
40
+ postActivated: (id) => {
41
+ onPostActivated?.(id);
42
+ this._callbacks.navigationStateChanged({ mode: 'posts-feed', postId: id, categoryId: null });
43
+ }
44
+ };
45
+ try {
46
+ this._state = 'loading';
47
+ if (!dataProvider.onEndReached) {
48
+ dataProvider.onEndReached = this._callbacks.playerReachedEnd;
49
+ }
50
+ this._feedPlayerData = {
51
+ props: this.makePostsPlayerProps({ dataProvider, on }),
52
+ filter: {}
53
+ };
54
+ }
55
+ finally {
56
+ this._state = 'ready';
57
+ }
58
+ };
59
+ activate = async (options) => {
60
+ const { filter, init } = options;
61
+ if (init?.initialPostId && this.tryRestoreState(init.initialPostId, filter)) {
62
+ // Already active with the requested buffer
63
+ return;
64
+ }
65
+ const on = {
66
+ postActivated: (id) => {
67
+ this._callbacks.navigationStateChanged({ mode: 'posts-feed', postId: id, categoryId: filter?.categoryId ?? null });
68
+ }
69
+ };
70
+ try {
71
+ this._state = 'loading';
72
+ const dataProvider = await this._providersGenerator.makePostPlayerItemsProvider({ filter, init, onEndReached: this._callbacks.playerReachedEnd });
73
+ this._feedPlayerData = {
74
+ props: this.makePostsPlayerProps({ dataProvider, on }),
75
+ filter: filter || {}
76
+ };
77
+ }
78
+ finally {
79
+ this._state = 'ready';
80
+ }
81
+ };
82
+ tryRestoreState = (initialPostId, filter) => {
83
+ if (this._state !== 'ready' || !this._feedPlayerData || !Utils.areEqual(this._feedPlayerData.filter, filter)) {
84
+ return false;
85
+ }
86
+ const buffer = this._feedPlayerData.props.dataProvider.type === 'buffer' ? this._feedPlayerData.props.dataProvider.buffer : null;
87
+ if (!buffer) {
88
+ return false;
89
+ }
90
+ return buffer.tryActivateItemById(initialPostId);
91
+ };
92
+ makePostsPlayerProps = (data) => {
93
+ const { dataProvider, on } = data;
94
+ return {
95
+ dataProvider: { type: 'buffer', buffer: initBufferFromProvider(dataProvider) },
96
+ socialInteractionsHandler: this._dataProvider.handlers?.socialInteractionsHandler,
97
+ analyticsHandler: this._dataProvider.handlers?.analyticsHandler,
98
+ playerSettings: this._mediaCenterSettingsHandler.playerSettings,
99
+ closeOrchestrator: this._closeOrchestrator,
100
+ on: {
101
+ postActivated: on.postActivated,
102
+ backgroundImageLoaded: this._mediaCenterSettingsHandler.backgroundImageLoadedHandler
103
+ }
104
+ };
105
+ };
106
+ }
@@ -0,0 +1,8 @@
1
+ import type { PostPlayerModel } from '../../../posts/posts-player/types';
2
+ export type PostsFeedFilter = {
3
+ categoryId?: string | null;
4
+ };
5
+ export type PostsFeedProviderInit = {
6
+ prefetchedItems?: PostPlayerModel[];
7
+ initialPostId?: string | null;
8
+ };
@@ -0,0 +1,12 @@
1
+ import type { IMediaCenterDataProvider } from '../../config/types';
2
+ import type { IStreamsPlayerDataProvider } from '../../../streams/streams-player/types';
3
+ import type { StreamsFeedFilter, StreamsFeedProviderInit } from './types';
4
+ export declare class FeedProvidersGenerator {
5
+ private dataProvider;
6
+ constructor(dataProvider: IMediaCenterDataProvider);
7
+ makeStreamsPlayerDataProvider: (data: {
8
+ filter: StreamsFeedFilter | undefined;
9
+ init: StreamsFeedProviderInit | undefined;
10
+ onEndReached: () => void;
11
+ }) => Promise<IStreamsPlayerDataProvider>;
12
+ }
@@ -0,0 +1,56 @@
1
+ import { ContinuationToken } from '../../../core/continuation-token';
2
+ import { CursorDataLoader } from '../../../core/data-loaders';
3
+ export class FeedProvidersGenerator {
4
+ dataProvider;
5
+ constructor(dataProvider) {
6
+ this.dataProvider = dataProvider;
7
+ }
8
+ makeStreamsPlayerDataProvider = async (data) => {
9
+ const { filter, init, onEndReached } = data;
10
+ const { categoryId } = filter || {};
11
+ const { prefetchedStreams: initialPrefetchedStreams = [], initialStreamId } = init || {};
12
+ const loader = new CursorDataLoader({
13
+ loadPage: async (continuationToken) => {
14
+ const result = await this.dataProvider.streamPlayer.getStreamsCursor({
15
+ filter: {
16
+ categoryId: categoryId || undefined,
17
+ excludeIds: initialPrefetchedStreams.length ? initialPrefetchedStreams.map((i) => i.id) : undefined
18
+ },
19
+ continuationToken: continuationToken.toNextChunkString(),
20
+ limit: 20
21
+ });
22
+ const items = result.items;
23
+ return {
24
+ items: items,
25
+ continuationToken: ContinuationToken.fromPayload(result.continuationToken)
26
+ };
27
+ }
28
+ });
29
+ if (initialStreamId && !initialPrefetchedStreams.find((p) => p.id === initialStreamId)) {
30
+ const fetchedStreams = await this.dataProvider.streamPlayer.getStreamsCursor({
31
+ filter: {
32
+ ids: [initialStreamId]
33
+ },
34
+ limit: 1
35
+ });
36
+ if (fetchedStreams.items.length) {
37
+ initialPrefetchedStreams.push(fetchedStreams.items[0]);
38
+ }
39
+ }
40
+ let prefetchedStreams = initialPrefetchedStreams;
41
+ if (initialStreamId) {
42
+ const targetStream = prefetchedStreams.find((stream) => stream.id === initialStreamId);
43
+ if (targetStream) {
44
+ prefetchedStreams = [targetStream, ...prefetchedStreams.filter((stream) => stream.id !== initialStreamId)];
45
+ }
46
+ }
47
+ return {
48
+ initialData: {
49
+ prefetchedStreams
50
+ },
51
+ loadMoreStreams: loader.loadMore,
52
+ getStreamPages: this.dataProvider.streamPlayer.getStreamPages,
53
+ onEndReached
54
+ };
55
+ };
56
+ }
@@ -0,0 +1 @@
1
+ export { StreamsFeedHandler } from './streams-feed-handler.svelte';
@@ -0,0 +1 @@
1
+ export { StreamsFeedHandler } from './streams-feed-handler.svelte';
@@ -0,0 +1,45 @@
1
+ import type { IMediaCenterDataProvider } from '../../config/types';
2
+ import type { MediaCenterState } from '../../navigation';
3
+ import type { StreamsPlayerProps, IStreamsPlayerDataProvider } from '../../../streams/streams-player/types';
4
+ import type { ICloseOrchestrator } from '../../../ui/player/close-orchestrator';
5
+ import { MediaCenterSettingsHandler } from '../handlers';
6
+ import type { StreamsFeedFilter, StreamsFeedProviderInit } from './types';
7
+ export declare class StreamsFeedHandler {
8
+ private _state;
9
+ private _providersGenerator;
10
+ private _feedPlayerData;
11
+ private _dataProvider;
12
+ private _mediaCenterSettingsHandler;
13
+ private _closeOrchestrator;
14
+ private _callbacks;
15
+ constructor(data: {
16
+ dataProvider: IMediaCenterDataProvider;
17
+ mediaCenterSettingsHandler: MediaCenterSettingsHandler;
18
+ closeOrchestrator: ICloseOrchestrator;
19
+ on: Callbacks;
20
+ });
21
+ get activated(): boolean;
22
+ get active(): boolean;
23
+ get loading(): boolean;
24
+ get feedPlayerProps(): StreamsPlayerProps | null;
25
+ deactivate: () => void;
26
+ activateWithExistingProvider: (data: {
27
+ dataProvider: IStreamsPlayerDataProvider;
28
+ onStreamActivated?: (data: {
29
+ id: string;
30
+ title: string;
31
+ image: string | null;
32
+ }) => void;
33
+ }) => Promise<void>;
34
+ activate: (options: Partial<{
35
+ filter: StreamsFeedFilter;
36
+ init: StreamsFeedProviderInit;
37
+ }>) => Promise<void>;
38
+ private tryRestoreState;
39
+ private makeStreamsPlayerProps;
40
+ }
41
+ type Callbacks = {
42
+ playerReachedEnd: () => void;
43
+ navigationStateChanged: (state: MediaCenterState) => void;
44
+ };
45
+ export {};