mirror of
https://github.com/jellyfin/jellyfin-vue.git
synced 2024-10-07 11:33:40 +00:00
refactor: merge state into the class instances
* Uniformize the comments used across them * Ensure all the stores are cleared up on user logout
This commit is contained in:
parent
428296f846
commit
7f18016987
@ -12,7 +12,7 @@ import { usei18n, useSnackbar, useRemote, useVuetify } from '@/composables';
|
||||
import { mergeExcludingUnknown } from '@/utils/data-manipulation';
|
||||
|
||||
/**
|
||||
* == INTERFACES ==
|
||||
* == INTERFACES AND TYPES ==
|
||||
* Casted typings for the CustomPrefs property of DisplayPreferencesDto
|
||||
*/
|
||||
export type LocaleStateValues =
|
||||
@ -43,51 +43,52 @@ const BROWSER_LANGUAGE = computed<string>(() => {
|
||||
return cleanString[0];
|
||||
});
|
||||
const browserPrefersDark = usePreferredDark();
|
||||
|
||||
/**
|
||||
* == STATE VARIABLES ==
|
||||
*/
|
||||
const defaultState: ClientSettingsState = {
|
||||
darkMode: 'auto',
|
||||
locale: 'auto'
|
||||
};
|
||||
|
||||
const storeKey = 'clientSettings';
|
||||
|
||||
const state: RemovableRef<ClientSettingsState> = useStorage(
|
||||
storeKey,
|
||||
cloneDeep(defaultState),
|
||||
localStorage,
|
||||
{
|
||||
mergeDefaults: (storageValue, defaults) =>
|
||||
mergeExcludingUnknown(storageValue, defaults)
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* == CLASS CONSTRUCTOR ==
|
||||
*/
|
||||
class ClientSettingsStore {
|
||||
/**
|
||||
* == STATE ==
|
||||
*/
|
||||
private _defaultState: ClientSettingsState = {
|
||||
darkMode: 'auto',
|
||||
locale: 'auto'
|
||||
};
|
||||
|
||||
private _state: RemovableRef<ClientSettingsState> = useStorage(
|
||||
storeKey,
|
||||
cloneDeep(this._defaultState),
|
||||
localStorage,
|
||||
{
|
||||
mergeDefaults: (storageValue, defaults) =>
|
||||
mergeExcludingUnknown(storageValue, defaults)
|
||||
}
|
||||
);
|
||||
/**
|
||||
* == GETTERS AND SETTERS ==
|
||||
*/
|
||||
public set locale(newVal: LocaleStateValues) {
|
||||
if (newVal === 'auto') {
|
||||
const i18n = usei18n();
|
||||
|
||||
state.value.locale = i18n.fallbackLocale.value as LocaleStateValues;
|
||||
this._state.value.locale = i18n.fallbackLocale.value as LocaleStateValues;
|
||||
} else {
|
||||
state.value.locale = newVal;
|
||||
this._state.value.locale = newVal;
|
||||
}
|
||||
}
|
||||
|
||||
public get locale(): LocaleStateValues {
|
||||
return state.value.locale;
|
||||
return this._state.value.locale;
|
||||
}
|
||||
|
||||
public set darkMode(newVal: 'auto' | boolean) {
|
||||
state.value.darkMode = newVal;
|
||||
this._state.value.darkMode = newVal;
|
||||
}
|
||||
|
||||
public get darkMode(): 'auto' | boolean {
|
||||
return state.value.darkMode;
|
||||
return this._state.value.darkMode;
|
||||
}
|
||||
|
||||
private _updateLocale = (): void => {
|
||||
@ -115,6 +116,10 @@ class ClientSettingsStore {
|
||||
});
|
||||
};
|
||||
|
||||
private _clear = (): void => {
|
||||
Object.assign(this._state.value, this._defaultState);
|
||||
};
|
||||
|
||||
public constructor() {
|
||||
const remote = useRemote();
|
||||
/**
|
||||
@ -124,9 +129,9 @@ class ClientSettingsStore {
|
||||
/**
|
||||
* Sync data with server
|
||||
*/
|
||||
const syncDataWatcher = watchPausable(state, async () => {
|
||||
const syncDataWatcher = watchPausable(this._state, async () => {
|
||||
if (remote.auth.currentUser) {
|
||||
await preferencesSync(storeKey, state.value);
|
||||
await preferencesSync(storeKey, this._state.value);
|
||||
}
|
||||
});
|
||||
|
||||
@ -140,12 +145,12 @@ class ClientSettingsStore {
|
||||
try {
|
||||
const data = await fetchSettingsFromServer<ClientSettingsState>(
|
||||
storeKey,
|
||||
state.value
|
||||
this._state.value
|
||||
);
|
||||
|
||||
if (data) {
|
||||
syncDataWatcher.pause();
|
||||
Object.assign(state.value, data);
|
||||
Object.assign(this._state.value, data);
|
||||
await nextTick();
|
||||
syncDataWatcher.resume();
|
||||
}
|
||||
@ -177,6 +182,15 @@ class ClientSettingsStore {
|
||||
this._updateTheme,
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
() => remote.auth.currentUser,
|
||||
() => {
|
||||
if (!remote.auth.currentUser) {
|
||||
this._clear();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,38 +5,37 @@ import { getItemsApi } from '@jellyfin/sdk/lib/utils/api/items-api';
|
||||
import { useRemote } from '@/composables';
|
||||
|
||||
/**
|
||||
* == INTERFACES ==
|
||||
* == INTERFACES AND TYPES ==
|
||||
*/
|
||||
interface ItemsState {
|
||||
byId: Record<string, BaseItemDto>;
|
||||
collectionById: Record<string, string[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
* == STATE VARIABLES ==
|
||||
*/
|
||||
const defaultState: ItemsState = {
|
||||
byId: {},
|
||||
collectionById: {}
|
||||
};
|
||||
|
||||
const state = reactive<ItemsState>(cloneDeep(defaultState));
|
||||
|
||||
/**
|
||||
* == CLASS CONSTRUCTOR ==
|
||||
*/
|
||||
class ItemsStore {
|
||||
/**
|
||||
* == GETTERS ==
|
||||
* == STATE ==
|
||||
*/
|
||||
private _defaultState: ItemsState = {
|
||||
byId: {},
|
||||
collectionById: {}
|
||||
};
|
||||
|
||||
private _state = reactive<ItemsState>(cloneDeep(this._defaultState));
|
||||
/**
|
||||
* == GETTERS AND SETTERS ==
|
||||
*/
|
||||
public getItemById = (id: string | undefined): BaseItemDto | undefined =>
|
||||
id ? state.byId[id] : undefined;
|
||||
id ? this._state.byId[id] : undefined;
|
||||
|
||||
public getItemsById = (ids: string[]): BaseItemDto[] => {
|
||||
const res: BaseItemDto[] = [];
|
||||
|
||||
for (const index of ids) {
|
||||
const item = state.byId[index];
|
||||
const item = this._state.byId[index];
|
||||
|
||||
if (!item) {
|
||||
throw new Error(`Item ${index} doesn't exist in the store`);
|
||||
@ -56,11 +55,11 @@ class ItemsStore {
|
||||
}
|
||||
|
||||
const res: BaseItemDto[] = [];
|
||||
const ids = state.collectionById[id];
|
||||
const ids = this._state.collectionById[id];
|
||||
|
||||
if (ids?.length) {
|
||||
for (const _id of ids) {
|
||||
res.push(state.byId[_id]);
|
||||
res.push(this._state.byId[_id]);
|
||||
}
|
||||
|
||||
return res;
|
||||
@ -84,7 +83,7 @@ class ItemsStore {
|
||||
return item;
|
||||
}
|
||||
|
||||
state.byId[item.Id] = item;
|
||||
this._state.byId[item.Id] = item;
|
||||
|
||||
const fetched = this.getItemById(item.Id);
|
||||
|
||||
@ -106,7 +105,7 @@ class ItemsStore {
|
||||
}
|
||||
|
||||
for (const id of payload) {
|
||||
delete state.byId[id];
|
||||
delete this._state.byId[id];
|
||||
}
|
||||
};
|
||||
|
||||
@ -137,7 +136,7 @@ class ItemsStore {
|
||||
}
|
||||
}
|
||||
|
||||
state.collectionById[parent.Id] = childIds;
|
||||
this._state.collectionById[parent.Id] = childIds;
|
||||
|
||||
return this.getChildrenOfParent(parent.Id) ?? [];
|
||||
};
|
||||
@ -205,6 +204,10 @@ class ItemsStore {
|
||||
}
|
||||
};
|
||||
|
||||
private _clear = (): void => {
|
||||
Object.assign(this._state, this._defaultState);
|
||||
};
|
||||
|
||||
public constructor() {
|
||||
const remote = useRemote();
|
||||
|
||||
@ -224,7 +227,7 @@ class ItemsStore {
|
||||
) {
|
||||
// Update items when metadata changes
|
||||
const itemsToUpdate = Data.ItemsUpdated.filter((itemId: string) => {
|
||||
return Object.keys(state.byId).includes(itemId);
|
||||
return Object.keys(this._state.byId).includes(itemId);
|
||||
});
|
||||
|
||||
this.updateStoreItems(itemsToUpdate);
|
||||
@ -237,7 +240,7 @@ class ItemsStore {
|
||||
(updatedData: any) => {
|
||||
const itemId = updatedData.ItemId ?? '';
|
||||
|
||||
return Object.keys(state.byId).includes(itemId);
|
||||
return Object.keys(this._state.byId).includes(itemId);
|
||||
}
|
||||
).map((updatedData: any) => {
|
||||
return updatedData.ItemId;
|
||||
@ -248,6 +251,15 @@ class ItemsStore {
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => remote.auth.currentUser,
|
||||
() => {
|
||||
if (!remote.auth.currentUser) {
|
||||
this._clear();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ import { msToTicks } from '@/utils/time';
|
||||
import playbackProfile from '@/utils/playback-profiles';
|
||||
|
||||
/**
|
||||
* == INTERFACES ==
|
||||
* == INTERFACES AND TYPES ==
|
||||
*/
|
||||
|
||||
export enum PlaybackStatus {
|
||||
@ -93,37 +93,12 @@ interface PlaybackManagerState {
|
||||
}
|
||||
|
||||
/**
|
||||
* == STATE VARIABLES
|
||||
* == UTILITY VARIABLES ==
|
||||
*/
|
||||
/**
|
||||
* Amount of time to wait between playback reports
|
||||
*/
|
||||
const progressReportInterval = 3500;
|
||||
const defaultState: PlaybackManagerState = {
|
||||
status: PlaybackStatus.Stopped,
|
||||
currentSourceUrl: undefined,
|
||||
isRemotePlayer: false,
|
||||
lastItemIndex: undefined,
|
||||
currentItemIndex: undefined,
|
||||
currentMediaSource: undefined,
|
||||
currentVideoStreamIndex: undefined,
|
||||
currentAudioStreamIndex: undefined,
|
||||
currentSubtitleStreamIndex: undefined,
|
||||
currentItemChapters: undefined,
|
||||
remotePlaybackTime: 0,
|
||||
lastProgressUpdate: 0,
|
||||
remoteCurrentVolume: 100,
|
||||
isRemoteMuted: false,
|
||||
isShuffling: false,
|
||||
repeatMode: RepeatMode.RepeatNone,
|
||||
queue: [],
|
||||
originalQueue: [],
|
||||
playSessionId: undefined,
|
||||
playbackInitiator: undefined,
|
||||
playbackInitMode: InitMode.Unknown
|
||||
};
|
||||
|
||||
const state = reactive<PlaybackManagerState>(cloneDeep(defaultState));
|
||||
const reactiveDate = useNow();
|
||||
export const mediaElementRef = ref<HTMLMediaElement>();
|
||||
export const mediaControls = useMediaControls(mediaElementRef);
|
||||
@ -135,12 +110,45 @@ const remote = useRemote();
|
||||
*/
|
||||
const mediaMetadata = new MediaMetadata();
|
||||
|
||||
/**
|
||||
* == CLASS CONSTRUCTOR ==
|
||||
*/
|
||||
class PlaybackManagerStore {
|
||||
/**
|
||||
* == GETTERS ==
|
||||
* == STATE ==
|
||||
*/
|
||||
private _defaultState: PlaybackManagerState = {
|
||||
status: PlaybackStatus.Stopped,
|
||||
currentSourceUrl: undefined,
|
||||
isRemotePlayer: false,
|
||||
lastItemIndex: undefined,
|
||||
currentItemIndex: undefined,
|
||||
currentMediaSource: undefined,
|
||||
currentVideoStreamIndex: undefined,
|
||||
currentAudioStreamIndex: undefined,
|
||||
currentSubtitleStreamIndex: undefined,
|
||||
currentItemChapters: undefined,
|
||||
remotePlaybackTime: 0,
|
||||
lastProgressUpdate: 0,
|
||||
remoteCurrentVolume: 100,
|
||||
isRemoteMuted: false,
|
||||
isShuffling: false,
|
||||
repeatMode: RepeatMode.RepeatNone,
|
||||
queue: [],
|
||||
originalQueue: [],
|
||||
playSessionId: undefined,
|
||||
playbackInitiator: undefined,
|
||||
playbackInitMode: InitMode.Unknown
|
||||
};
|
||||
|
||||
private _state = reactive<PlaybackManagerState>(
|
||||
cloneDeep(this._defaultState)
|
||||
);
|
||||
/**
|
||||
* == GETTERS AND SETTERS ==
|
||||
*/
|
||||
public get status(): PlaybackStatus {
|
||||
return state.status;
|
||||
return this._state.status;
|
||||
}
|
||||
/**
|
||||
* Get if playback is buffering
|
||||
@ -158,19 +166,19 @@ class PlaybackManagerStore {
|
||||
* Get if the repeat status is not set to none
|
||||
*/
|
||||
public get isRepeating(): boolean {
|
||||
return state.repeatMode !== RepeatMode.RepeatNone;
|
||||
return this._state.repeatMode !== RepeatMode.RepeatNone;
|
||||
}
|
||||
/**
|
||||
* Get if the queue is being repeated
|
||||
*/
|
||||
public get isRepeatingAll(): boolean {
|
||||
return state.repeatMode === RepeatMode.RepeatAll;
|
||||
return this._state.repeatMode === RepeatMode.RepeatAll;
|
||||
}
|
||||
/**
|
||||
* Get if an item is being repeated
|
||||
*/
|
||||
public get isRepeatingOnce(): boolean {
|
||||
return state.repeatMode === RepeatMode.RepeatOne;
|
||||
return this._state.repeatMode === RepeatMode.RepeatOne;
|
||||
}
|
||||
/**
|
||||
* Get if an item is paused at this moment
|
||||
@ -182,7 +190,7 @@ class PlaybackManagerStore {
|
||||
* Get if the current playback session is remote or local
|
||||
*/
|
||||
public get isRemotePlayer(): boolean {
|
||||
return state.isRemotePlayer;
|
||||
return this._state.isRemotePlayer;
|
||||
}
|
||||
/**
|
||||
* Get reactive BaseItemDto's objects of the queue
|
||||
@ -190,7 +198,7 @@ class PlaybackManagerStore {
|
||||
public get queue(): BaseItemDto[] {
|
||||
const items = itemsStore();
|
||||
|
||||
return items.getItemsById(state.queue);
|
||||
return items.getItemsById(this._state.queue);
|
||||
}
|
||||
/**
|
||||
* Get a reactive BaseItemDto object of the currently playing item
|
||||
@ -198,12 +206,12 @@ class PlaybackManagerStore {
|
||||
public get currentItem(): BaseItemDto | undefined {
|
||||
const items = itemsStore();
|
||||
|
||||
if (!isNil(state.currentItemIndex)) {
|
||||
return items.getItemById(state.queue[state.currentItemIndex]);
|
||||
if (!isNil(this._state.currentItemIndex)) {
|
||||
return items.getItemById(this._state.queue[this._state.currentItemIndex]);
|
||||
}
|
||||
}
|
||||
public get currentSourceUrl(): string | undefined {
|
||||
return state.currentSourceUrl;
|
||||
return this._state.currentSourceUrl;
|
||||
}
|
||||
/**
|
||||
* Get a reactive BaseItemDto object of the previous item in queue
|
||||
@ -211,8 +219,8 @@ class PlaybackManagerStore {
|
||||
public get previousItem(): BaseItemDto | undefined {
|
||||
const items = itemsStore();
|
||||
|
||||
if (!isNil(state.lastItemIndex)) {
|
||||
return items.getItemById(state.queue[state.lastItemIndex]);
|
||||
if (!isNil(this._state.lastItemIndex)) {
|
||||
return items.getItemById(this._state.queue[this._state.lastItemIndex]);
|
||||
}
|
||||
}
|
||||
/**
|
||||
@ -222,12 +230,14 @@ class PlaybackManagerStore {
|
||||
const items = itemsStore();
|
||||
|
||||
if (
|
||||
!isNil(state.currentItemIndex) &&
|
||||
state.currentItemIndex + 1 < state.queue.length
|
||||
!isNil(this._state.currentItemIndex) &&
|
||||
this._state.currentItemIndex + 1 < this._state.queue.length
|
||||
) {
|
||||
return items.getItemById(state.queue[state.currentItemIndex + 1]);
|
||||
} else if (state.repeatMode === RepeatMode.RepeatAll) {
|
||||
return items.getItemById(state.queue[0]);
|
||||
return items.getItemById(
|
||||
this._state.queue[this._state.currentItemIndex + 1]
|
||||
);
|
||||
} else if (this._state.repeatMode === RepeatMode.RepeatAll) {
|
||||
return items.getItemById(this._state.queue[0]);
|
||||
}
|
||||
}
|
||||
/**
|
||||
@ -236,8 +246,9 @@ class PlaybackManagerStore {
|
||||
public get currentlyPlayingType(): BaseItemKind | undefined {
|
||||
const items = itemsStore();
|
||||
|
||||
if (!isNil(state.currentItemIndex)) {
|
||||
return items.getItemById(state.queue[state.currentItemIndex])?.Type;
|
||||
if (!isNil(this._state.currentItemIndex)) {
|
||||
return items.getItemById(this._state.queue[this._state.currentItemIndex])
|
||||
?.Type;
|
||||
}
|
||||
}
|
||||
/**
|
||||
@ -246,16 +257,17 @@ class PlaybackManagerStore {
|
||||
public get currentlyPlayingMediaType(): string | null | undefined {
|
||||
const items = itemsStore();
|
||||
|
||||
if (!isNil(state.currentItemIndex)) {
|
||||
return items.getItemById(state.queue[state.currentItemIndex])?.MediaType;
|
||||
if (!isNil(this._state.currentItemIndex)) {
|
||||
return items.getItemById(this._state.queue[this._state.currentItemIndex])
|
||||
?.MediaType;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get current's item audio tracks
|
||||
*/
|
||||
public get currentItemAudioTracks(): MediaStream[] | undefined {
|
||||
if (!isNil(state.currentMediaSource?.MediaStreams)) {
|
||||
return state.currentMediaSource?.MediaStreams.filter((stream) => {
|
||||
if (!isNil(this._state.currentMediaSource?.MediaStreams)) {
|
||||
return this._state.currentMediaSource?.MediaStreams.filter((stream) => {
|
||||
return stream.Type === 'Audio';
|
||||
});
|
||||
}
|
||||
@ -264,19 +276,21 @@ class PlaybackManagerStore {
|
||||
* Get current's item subtitle tracks
|
||||
*/
|
||||
public get currentItemSubtitleTracks(): MediaStream[] | undefined {
|
||||
if (!isNil(state.currentMediaSource?.MediaStreams)) {
|
||||
return state.currentMediaSource?.MediaStreams.filter((stream) => {
|
||||
if (!isNil(this._state.currentMediaSource?.MediaStreams)) {
|
||||
return this._state.currentMediaSource?.MediaStreams.filter((stream) => {
|
||||
return stream.Type === 'Subtitle';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public get currentItemParsedSubtitleTracks(): PlaybackTrack[] | undefined {
|
||||
if (!isNil(state.currentMediaSource)) {
|
||||
return state.currentMediaSource.MediaStreams?.map((stream, index) => ({
|
||||
srcIndex: index,
|
||||
...stream
|
||||
}))
|
||||
if (!isNil(this._state.currentMediaSource)) {
|
||||
return this._state.currentMediaSource.MediaStreams?.map(
|
||||
(stream, index) => ({
|
||||
srcIndex: index,
|
||||
...stream
|
||||
})
|
||||
)
|
||||
.filter(
|
||||
(sub) =>
|
||||
sub.Type === MediaStreamType.Subtitle &&
|
||||
@ -326,121 +340,121 @@ class PlaybackManagerStore {
|
||||
|
||||
public get currentVideoTrack(): MediaStream | undefined {
|
||||
if (
|
||||
!isNil(state.currentMediaSource?.MediaStreams) &&
|
||||
!isNil(state.currentVideoStreamIndex)
|
||||
!isNil(this._state.currentMediaSource?.MediaStreams) &&
|
||||
!isNil(this._state.currentVideoStreamIndex)
|
||||
) {
|
||||
return state.currentMediaSource?.MediaStreams.find(
|
||||
return this._state.currentMediaSource?.MediaStreams.find(
|
||||
(stream) =>
|
||||
stream.Type === 'Video' &&
|
||||
stream.Index === state.currentVideoStreamIndex
|
||||
stream.Index === this._state.currentVideoStreamIndex
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public get currentAudioTrack(): MediaStream | undefined {
|
||||
if (
|
||||
!isNil(state.currentMediaSource?.MediaStreams) &&
|
||||
!isNil(state.currentAudioStreamIndex)
|
||||
!isNil(this._state.currentMediaSource?.MediaStreams) &&
|
||||
!isNil(this._state.currentAudioStreamIndex)
|
||||
) {
|
||||
return state.currentMediaSource?.MediaStreams.find(
|
||||
return this._state.currentMediaSource?.MediaStreams.find(
|
||||
(stream) =>
|
||||
stream.Type === 'Audio' &&
|
||||
stream.Index === state.currentAudioStreamIndex
|
||||
stream.Index === this._state.currentAudioStreamIndex
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public get currentSubtitleTrack(): MediaStream | undefined {
|
||||
if (
|
||||
!isNil(state.currentMediaSource?.MediaStreams) &&
|
||||
!isNil(state.currentSubtitleStreamIndex)
|
||||
!isNil(this._state.currentMediaSource?.MediaStreams) &&
|
||||
!isNil(this._state.currentSubtitleStreamIndex)
|
||||
) {
|
||||
return state.currentMediaSource?.MediaStreams.find(
|
||||
return this._state.currentMediaSource?.MediaStreams.find(
|
||||
(stream) =>
|
||||
stream.Type === 'Subtitle' &&
|
||||
stream.Index === state.currentSubtitleStreamIndex
|
||||
stream.Index === this._state.currentSubtitleStreamIndex
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public get currentSubtitleStreamIndex(): number | undefined {
|
||||
return state.currentSubtitleStreamIndex;
|
||||
return this._state.currentSubtitleStreamIndex;
|
||||
}
|
||||
public set currentSubtitleStreamIndex(newIndex: number | undefined) {
|
||||
state.currentSubtitleStreamIndex = newIndex;
|
||||
this._state.currentSubtitleStreamIndex = newIndex;
|
||||
}
|
||||
|
||||
public get currentAudioStreamIndex(): number | undefined {
|
||||
return state.currentAudioStreamIndex;
|
||||
return this._state.currentAudioStreamIndex;
|
||||
}
|
||||
public set currentAudioStreamIndex(newIndex: number | undefined) {
|
||||
state.currentAudioStreamIndex = newIndex;
|
||||
this._state.currentAudioStreamIndex = newIndex;
|
||||
}
|
||||
|
||||
public get initiator(): BaseItemDto | undefined {
|
||||
return state.playbackInitiator;
|
||||
return this._state.playbackInitiator;
|
||||
}
|
||||
|
||||
public get playbackInitMode(): InitMode {
|
||||
return state.playbackInitMode;
|
||||
return this._state.playbackInitMode;
|
||||
}
|
||||
|
||||
public get queueIds(): string[] {
|
||||
return state.queue;
|
||||
return this._state.queue;
|
||||
}
|
||||
|
||||
public get isShuffling(): boolean {
|
||||
return state.isShuffling;
|
||||
return this._state.isShuffling;
|
||||
}
|
||||
|
||||
public get repeatMode(): RepeatMode {
|
||||
return state.repeatMode;
|
||||
return this._state.repeatMode;
|
||||
}
|
||||
|
||||
public get currentTime(): number {
|
||||
return !this.isRemotePlayer
|
||||
? mediaControls.currentTime.value
|
||||
: state.remotePlaybackTime;
|
||||
: this._state.remotePlaybackTime;
|
||||
}
|
||||
public set currentTime(newValue: number) {
|
||||
if (this.isRemotePlayer) {
|
||||
state.remotePlaybackTime = newValue;
|
||||
this._state.remotePlaybackTime = newValue;
|
||||
} else {
|
||||
mediaControls.currentTime.value = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
public get currentItemIndex(): number | undefined {
|
||||
return state.currentItemIndex;
|
||||
return this._state.currentItemIndex;
|
||||
}
|
||||
public set currentItemIndex(index: number | undefined) {
|
||||
if (state.currentItemIndex !== index) {
|
||||
state.lastItemIndex = state.currentItemIndex;
|
||||
state.currentItemIndex = index;
|
||||
if (this._state.currentItemIndex !== index) {
|
||||
this._state.lastItemIndex = this._state.currentItemIndex;
|
||||
this._state.currentItemIndex = index;
|
||||
this.currentTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public get currentMediaSource(): MediaSourceInfo | undefined {
|
||||
return state.currentMediaSource;
|
||||
return this._state.currentMediaSource;
|
||||
}
|
||||
|
||||
public get isMuted(): boolean {
|
||||
return state.isRemotePlayer
|
||||
? state.isRemoteMuted
|
||||
return this._state.isRemotePlayer
|
||||
? this._state.isRemoteMuted
|
||||
: mediaControls.muted.value;
|
||||
}
|
||||
private set isMuted(newValue: boolean) {
|
||||
if (state.isRemotePlayer) {
|
||||
state.isRemoteMuted = newValue;
|
||||
if (this._state.isRemotePlayer) {
|
||||
this._state.isRemoteMuted = newValue;
|
||||
} else {
|
||||
mediaControls.muted.value = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
public get currentVolume(): number {
|
||||
return state.isRemotePlayer
|
||||
? state.remoteCurrentVolume
|
||||
return this._state.isRemotePlayer
|
||||
? this._state.remoteCurrentVolume
|
||||
: mediaControls.volume.value * 100;
|
||||
}
|
||||
public set currentVolume(newVolume: number) {
|
||||
@ -448,8 +462,8 @@ class PlaybackManagerStore {
|
||||
newVolume = newVolume < 0 ? 0 : newVolume;
|
||||
this.isMuted = newVolume === 0 ? true : false;
|
||||
|
||||
if (state.isRemotePlayer) {
|
||||
state.remoteCurrentVolume = newVolume;
|
||||
if (this._state.isRemotePlayer) {
|
||||
this._state.remoteCurrentVolume = newVolume;
|
||||
} else {
|
||||
mediaControls.volume.value = newVolume / 100;
|
||||
}
|
||||
@ -457,7 +471,7 @@ class PlaybackManagerStore {
|
||||
|
||||
private get _pendingProgressReport(): boolean {
|
||||
return (
|
||||
reactiveDate.value.valueOf() - state.lastProgressUpdate >=
|
||||
reactiveDate.value.valueOf() - this._state.lastProgressUpdate >=
|
||||
progressReportInterval &&
|
||||
this.status !== PlaybackStatus.Stopped &&
|
||||
this.status !== PlaybackStatus.Error
|
||||
@ -607,13 +621,13 @@ class PlaybackManagerStore {
|
||||
await remote.sdk.newUserApi(getPlaystateApi).reportPlaybackProgress({
|
||||
playbackProgressInfo: {
|
||||
ItemId: this.currentItem.Id,
|
||||
PlaySessionId: state.playSessionId,
|
||||
PlaySessionId: this._state.playSessionId,
|
||||
IsPaused: this.isPaused,
|
||||
PositionTicks: Math.round(msToTicks(this.currentTime * 1000))
|
||||
}
|
||||
});
|
||||
|
||||
state.lastProgressUpdate = Date.now();
|
||||
this._state.lastProgressUpdate = Date.now();
|
||||
}
|
||||
};
|
||||
|
||||
@ -622,7 +636,7 @@ class PlaybackManagerStore {
|
||||
*/
|
||||
private _reportPlaybackStopped = async (
|
||||
itemId: string,
|
||||
sessionId = state.playSessionId,
|
||||
sessionId = this._state.playSessionId,
|
||||
currentTime = this.currentTime,
|
||||
updateState = true
|
||||
): Promise<void> => {
|
||||
@ -635,7 +649,7 @@ class PlaybackManagerStore {
|
||||
});
|
||||
|
||||
if (updateState) {
|
||||
state.lastProgressUpdate = Date.now();
|
||||
this._state.lastProgressUpdate = Date.now();
|
||||
}
|
||||
};
|
||||
|
||||
@ -647,29 +661,29 @@ class PlaybackManagerStore {
|
||||
playbackStartInfo: {
|
||||
CanSeek: true,
|
||||
ItemId: itemId,
|
||||
PlaySessionId: state.playSessionId,
|
||||
MediaSourceId: state.currentMediaSource?.Id,
|
||||
AudioStreamIndex: state.currentAudioStreamIndex,
|
||||
SubtitleStreamIndex: state.currentSubtitleStreamIndex
|
||||
PlaySessionId: this._state.playSessionId,
|
||||
MediaSourceId: this._state.currentMediaSource?.Id,
|
||||
AudioStreamIndex: this._state.currentAudioStreamIndex,
|
||||
SubtitleStreamIndex: this._state.currentSubtitleStreamIndex
|
||||
}
|
||||
});
|
||||
|
||||
state.lastProgressUpdate = Date.now();
|
||||
this._state.lastProgressUpdate = Date.now();
|
||||
};
|
||||
public addToQueue = async (item: BaseItemDto): Promise<void> => {
|
||||
const translatedItem = await this.translateItemsForPlayback(item);
|
||||
|
||||
state.queue.push(...translatedItem);
|
||||
this._state.queue.push(...translatedItem);
|
||||
};
|
||||
|
||||
public removeFromQueue = (itemId: string): void => {
|
||||
if (state.queue.includes(itemId)) {
|
||||
state.queue.splice(state.queue.indexOf(itemId), 1);
|
||||
if (this._state.queue.includes(itemId)) {
|
||||
this._state.queue.splice(this._state.queue.indexOf(itemId), 1);
|
||||
}
|
||||
};
|
||||
|
||||
public clearQueue = (): void => {
|
||||
state.queue = [];
|
||||
this._state.queue = [];
|
||||
};
|
||||
|
||||
/**
|
||||
@ -695,42 +709,45 @@ class PlaybackManagerStore {
|
||||
startShuffled?: boolean;
|
||||
}): Promise<void> => {
|
||||
try {
|
||||
if (state.status !== PlaybackStatus.Stopped) {
|
||||
if (this._state.status !== PlaybackStatus.Stopped) {
|
||||
this.stop();
|
||||
}
|
||||
|
||||
state.status = PlaybackStatus.Buffering;
|
||||
state.queue = await this.translateItemsForPlayback(item, startShuffled);
|
||||
this._state.status = PlaybackStatus.Buffering;
|
||||
this._state.queue = await this.translateItemsForPlayback(
|
||||
item,
|
||||
startShuffled
|
||||
);
|
||||
|
||||
if (videoTrackIndex !== undefined) {
|
||||
state.currentVideoStreamIndex = videoTrackIndex;
|
||||
this._state.currentVideoStreamIndex = videoTrackIndex;
|
||||
}
|
||||
|
||||
if (audioTrackIndex !== undefined) {
|
||||
state.currentAudioStreamIndex = audioTrackIndex;
|
||||
this._state.currentAudioStreamIndex = audioTrackIndex;
|
||||
}
|
||||
|
||||
if (subtitleTrackIndex !== undefined) {
|
||||
state.currentSubtitleStreamIndex = subtitleTrackIndex;
|
||||
this._state.currentSubtitleStreamIndex = subtitleTrackIndex;
|
||||
}
|
||||
|
||||
state.currentItemIndex = startFromIndex;
|
||||
this._state.currentItemIndex = startFromIndex;
|
||||
this.currentTime = startFromTime;
|
||||
|
||||
if (!startShuffled && initiator) {
|
||||
state.playbackInitMode = InitMode.Item;
|
||||
this._state.playbackInitMode = InitMode.Item;
|
||||
} else if (startShuffled && !initiator) {
|
||||
state.playbackInitMode = InitMode.Shuffle;
|
||||
this._state.playbackInitMode = InitMode.Shuffle;
|
||||
} else if (startShuffled && initiator) {
|
||||
state.playbackInitMode = InitMode.ShuffleItem;
|
||||
this._state.playbackInitMode = InitMode.ShuffleItem;
|
||||
} else {
|
||||
state.playbackInitMode = InitMode.Unknown;
|
||||
this._state.playbackInitMode = InitMode.Unknown;
|
||||
}
|
||||
|
||||
state.playbackInitiator = initiator;
|
||||
state.status = PlaybackStatus.Playing;
|
||||
this._state.playbackInitiator = initiator;
|
||||
this._state.status = PlaybackStatus.Playing;
|
||||
} catch {
|
||||
state.status = PlaybackStatus.Error;
|
||||
this._state.status = PlaybackStatus.Error;
|
||||
}
|
||||
};
|
||||
|
||||
@ -742,50 +759,50 @@ class PlaybackManagerStore {
|
||||
public playNext = async (item: BaseItemDto): Promise<void> => {
|
||||
const translatedItem = await this.translateItemsForPlayback(item);
|
||||
|
||||
if (state.currentItemIndex !== undefined) {
|
||||
if (this._state.currentItemIndex !== undefined) {
|
||||
/**
|
||||
* Removes the elements that already exists and append the new ones next to the currently playing item
|
||||
*/
|
||||
const newQueue = state.queue.filter(
|
||||
const newQueue = this._state.queue.filter(
|
||||
(index) => !translatedItem.includes(index)
|
||||
);
|
||||
|
||||
newQueue.splice(state.currentItemIndex + 1, 0, ...translatedItem);
|
||||
newQueue.splice(this._state.currentItemIndex + 1, 0, ...translatedItem);
|
||||
this.setNewQueue(newQueue);
|
||||
}
|
||||
};
|
||||
|
||||
public pause = (): void => {
|
||||
if (state.status === PlaybackStatus.Playing) {
|
||||
state.status = PlaybackStatus.Paused;
|
||||
if (this._state.status === PlaybackStatus.Playing) {
|
||||
this._state.status = PlaybackStatus.Paused;
|
||||
}
|
||||
};
|
||||
|
||||
public unpause = (): void => {
|
||||
if (state.status === PlaybackStatus.Paused) {
|
||||
state.status = PlaybackStatus.Playing;
|
||||
if (this._state.status === PlaybackStatus.Paused) {
|
||||
this._state.status = PlaybackStatus.Playing;
|
||||
}
|
||||
};
|
||||
|
||||
public playPause = (): void => {
|
||||
if (state.status === PlaybackStatus.Playing) {
|
||||
if (this._state.status === PlaybackStatus.Playing) {
|
||||
this.pause();
|
||||
} else if (state.status === PlaybackStatus.Paused) {
|
||||
} else if (this._state.status === PlaybackStatus.Paused) {
|
||||
this.unpause();
|
||||
}
|
||||
};
|
||||
|
||||
public setNextTrack = (): void => {
|
||||
if (
|
||||
!isNil(state.currentItemIndex) &&
|
||||
state.currentItemIndex + 1 < state.queue.length
|
||||
!isNil(this._state.currentItemIndex) &&
|
||||
this._state.currentItemIndex + 1 < this._state.queue.length
|
||||
) {
|
||||
state.lastItemIndex = state.currentItemIndex;
|
||||
state.currentItemIndex += 1;
|
||||
this._state.lastItemIndex = this._state.currentItemIndex;
|
||||
this._state.currentItemIndex += 1;
|
||||
this.currentTime = 0;
|
||||
} else if (state.repeatMode === RepeatMode.RepeatAll) {
|
||||
state.lastItemIndex = state.currentItemIndex;
|
||||
state.currentItemIndex = 0;
|
||||
} else if (this._state.repeatMode === RepeatMode.RepeatAll) {
|
||||
this._state.lastItemIndex = this._state.currentItemIndex;
|
||||
this._state.currentItemIndex = 0;
|
||||
this.currentTime = 0;
|
||||
} else {
|
||||
this.stop();
|
||||
@ -794,13 +811,13 @@ class PlaybackManagerStore {
|
||||
|
||||
public setPreviousTrack = (): void => {
|
||||
if (
|
||||
!isNil(state.currentItemIndex) &&
|
||||
state.currentItemIndex > 0 &&
|
||||
!isNil(this._state.currentItemIndex) &&
|
||||
this._state.currentItemIndex > 0 &&
|
||||
!isNil(this.currentTime) &&
|
||||
this.currentTime < 2
|
||||
) {
|
||||
state.lastItemIndex = state.currentItemIndex;
|
||||
state.currentItemIndex -= 1;
|
||||
this._state.lastItemIndex = this._state.currentItemIndex;
|
||||
this._state.currentItemIndex -= 1;
|
||||
}
|
||||
|
||||
this.currentTime = 0;
|
||||
@ -810,28 +827,28 @@ class PlaybackManagerStore {
|
||||
let item;
|
||||
let lastItem;
|
||||
|
||||
if (state.currentItemIndex !== undefined) {
|
||||
item = state.queue[state.currentItemIndex];
|
||||
if (this._state.currentItemIndex !== undefined) {
|
||||
item = this._state.queue[this._state.currentItemIndex];
|
||||
}
|
||||
|
||||
if (state.lastItemIndex !== undefined) {
|
||||
lastItem = state.queue[state.lastItemIndex];
|
||||
if (this._state.lastItemIndex !== undefined) {
|
||||
lastItem = this._state.queue[this._state.lastItemIndex];
|
||||
}
|
||||
|
||||
const newIndex = queue?.indexOf(item || '');
|
||||
const lastItemNewIndex = queue?.indexOf(lastItem || '');
|
||||
|
||||
state.queue = queue;
|
||||
state.lastItemIndex = lastItemNewIndex;
|
||||
state.currentItemIndex = newIndex;
|
||||
this._state.queue = queue;
|
||||
this._state.lastItemIndex = lastItemNewIndex;
|
||||
this._state.currentItemIndex = newIndex;
|
||||
};
|
||||
|
||||
public changeItemPosition = (
|
||||
itemId: string | undefined,
|
||||
newIndex: number
|
||||
): void => {
|
||||
if (itemId && state.queue.includes(itemId)) {
|
||||
const newQueue = state.queue.filter((index) => index !== itemId);
|
||||
if (itemId && this._state.queue.includes(itemId)) {
|
||||
const newQueue = this._state.queue.filter((index) => index !== itemId);
|
||||
|
||||
newQueue.splice(newIndex, 0, itemId);
|
||||
this.setNewQueue(newQueue);
|
||||
@ -839,12 +856,12 @@ class PlaybackManagerStore {
|
||||
};
|
||||
|
||||
public stop = (): void => {
|
||||
const sessionId = String(state.playSessionId || '');
|
||||
const sessionId = String(this._state.playSessionId || '');
|
||||
const time = Number(this.currentTime);
|
||||
const itemId = String(this.currentItem?.Id || '');
|
||||
const volume = Number(this.currentVolume);
|
||||
|
||||
Object.assign(state, defaultState);
|
||||
Object.assign(this._state, this._defaultState);
|
||||
this.currentVolume = volume;
|
||||
|
||||
window.setTimeout(async () => {
|
||||
@ -866,30 +883,30 @@ class PlaybackManagerStore {
|
||||
};
|
||||
|
||||
public toggleShuffle = (): void => {
|
||||
if (state.queue && !isNil(state.currentItemIndex)) {
|
||||
if (!state.isShuffling) {
|
||||
const queue = shuffle(state.queue);
|
||||
if (this._state.queue && !isNil(this._state.currentItemIndex)) {
|
||||
if (!this._state.isShuffling) {
|
||||
const queue = shuffle(this._state.queue);
|
||||
|
||||
state.originalQueue = state.queue;
|
||||
this._state.originalQueue = this._state.queue;
|
||||
|
||||
const item = state.queue[state.currentItemIndex];
|
||||
const item = this._state.queue[this._state.currentItemIndex];
|
||||
const itemIndex = queue.indexOf(item);
|
||||
|
||||
queue.splice(itemIndex, 1);
|
||||
queue.unshift(item);
|
||||
|
||||
state.queue = queue;
|
||||
state.currentItemIndex = 0;
|
||||
state.lastItemIndex = undefined;
|
||||
state.isShuffling = true;
|
||||
this._state.queue = queue;
|
||||
this._state.currentItemIndex = 0;
|
||||
this._state.lastItemIndex = undefined;
|
||||
this._state.isShuffling = true;
|
||||
} else {
|
||||
const item = state.queue[state.currentItemIndex];
|
||||
const item = this._state.queue[this._state.currentItemIndex];
|
||||
|
||||
state.currentItemIndex = state.originalQueue.indexOf(item);
|
||||
state.queue = state.originalQueue;
|
||||
state.originalQueue = [];
|
||||
state.lastItemIndex = undefined;
|
||||
state.isShuffling = false;
|
||||
this._state.currentItemIndex = this._state.originalQueue.indexOf(item);
|
||||
this._state.queue = this._state.originalQueue;
|
||||
this._state.originalQueue = [];
|
||||
this._state.lastItemIndex = undefined;
|
||||
this._state.isShuffling = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -900,14 +917,18 @@ class PlaybackManagerStore {
|
||||
* If there's only one item in queue, we only switch between RepeatOne and RepeatNone
|
||||
*/
|
||||
public toggleRepeatMode = (): void => {
|
||||
if (state.repeatMode === RepeatMode.RepeatNone) {
|
||||
state.repeatMode =
|
||||
state.queue.length > 1 ? RepeatMode.RepeatAll : RepeatMode.RepeatOne;
|
||||
} else if (state.repeatMode === RepeatMode.RepeatAll) {
|
||||
state.repeatMode =
|
||||
state.queue.length > 1 ? RepeatMode.RepeatOne : RepeatMode.RepeatNone;
|
||||
if (this._state.repeatMode === RepeatMode.RepeatNone) {
|
||||
this._state.repeatMode =
|
||||
this._state.queue.length > 1
|
||||
? RepeatMode.RepeatAll
|
||||
: RepeatMode.RepeatOne;
|
||||
} else if (this._state.repeatMode === RepeatMode.RepeatAll) {
|
||||
this._state.repeatMode =
|
||||
this._state.queue.length > 1
|
||||
? RepeatMode.RepeatOne
|
||||
: RepeatMode.RepeatNone;
|
||||
} else {
|
||||
state.repeatMode = RepeatMode.RepeatNone;
|
||||
this._state.repeatMode = RepeatMode.RepeatNone;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1097,9 +1118,9 @@ class PlaybackManagerStore {
|
||||
|
||||
useSnackbar(t('errors.cantPlayItem'), 'error');
|
||||
} else {
|
||||
state.playSessionId = playbackInfo?.PlaySessionId || '';
|
||||
state.currentMediaSource = mediaSource;
|
||||
state.currentSourceUrl = this.getItemPlaybackUrl();
|
||||
this._state.playSessionId = playbackInfo?.PlaySessionId || '';
|
||||
this._state.currentMediaSource = mediaSource;
|
||||
this._state.currentSourceUrl = this.getItemPlaybackUrl();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1147,7 +1168,7 @@ class PlaybackManagerStore {
|
||||
async (newIndex) => {
|
||||
await this.fetchCurrentMediaSource();
|
||||
|
||||
if (newIndex && !state.currentSourceUrl) {
|
||||
if (newIndex && !this._state.currentSourceUrl) {
|
||||
const { t } = usei18n();
|
||||
|
||||
useSnackbar(t('errors.cantPlayItem'), 'error');
|
||||
@ -1222,14 +1243,14 @@ class PlaybackManagerStore {
|
||||
|
||||
watch(mediaControls.playing, () => {
|
||||
if (playbackManager.status !== PlaybackStatus.Buffering) {
|
||||
state.status = mediaControls.playing.value
|
||||
this._state.status = mediaControls.playing.value
|
||||
? PlaybackStatus.Playing
|
||||
: PlaybackStatus.Paused;
|
||||
}
|
||||
});
|
||||
|
||||
watch(mediaControls.waiting, () => {
|
||||
state.status = mediaControls.waiting.value
|
||||
this._state.status = mediaControls.waiting.value
|
||||
? PlaybackStatus.Buffering
|
||||
: PlaybackStatus.Playing;
|
||||
});
|
||||
|
@ -11,14 +11,14 @@ import jassubWorker from 'jassub/dist/jassub-worker.js?url';
|
||||
import 'jassub/dist/jassub-worker.wasm?url';
|
||||
import jassubDefaultFont from 'jassub/dist/default.woff2?url';
|
||||
import { mediaElementRef, playbackManagerStore } from '@/store';
|
||||
import { useRouter } from '@/composables';
|
||||
import { useRemote, useRouter } from '@/composables';
|
||||
|
||||
const playbackManager = playbackManagerStore();
|
||||
let jassub: JASSUB | undefined;
|
||||
const fullscreenRoute = '/playback/video';
|
||||
|
||||
/**
|
||||
* == INTERFACES ==
|
||||
* == INTERFACES AND TYPES ==
|
||||
*/
|
||||
interface PlayerElementState {
|
||||
isFullscreenMounted: boolean;
|
||||
@ -26,46 +26,45 @@ interface PlayerElementState {
|
||||
isStretched: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* == STATE VARIABLES ==
|
||||
*/
|
||||
const defaultState: PlayerElementState = {
|
||||
isFullscreenMounted: false,
|
||||
isPiPMounted: false,
|
||||
isStretched: true
|
||||
};
|
||||
|
||||
const state = reactive<PlayerElementState>(cloneDeep(defaultState));
|
||||
|
||||
/**
|
||||
* == CLASS CONSTRUCTOR ==
|
||||
*/
|
||||
class PlayerElementStore {
|
||||
/**
|
||||
* == GETTERS ==
|
||||
* == STATE ==
|
||||
*/
|
||||
private _defaultState: PlayerElementState = {
|
||||
isFullscreenMounted: false,
|
||||
isPiPMounted: false,
|
||||
isStretched: true
|
||||
};
|
||||
|
||||
private _state = reactive<PlayerElementState>(cloneDeep(this._defaultState));
|
||||
/**
|
||||
* == GETTERS AND SETTERS ==
|
||||
*/
|
||||
public get isFullscreenMounted(): boolean {
|
||||
return state.isFullscreenMounted;
|
||||
return this._state.isFullscreenMounted;
|
||||
}
|
||||
|
||||
public set isFullscreenMounted(newIsMounted: boolean) {
|
||||
state.isFullscreenMounted = newIsMounted;
|
||||
this._state.isFullscreenMounted = newIsMounted;
|
||||
}
|
||||
|
||||
public get isPiPMounted(): boolean {
|
||||
return state.isPiPMounted;
|
||||
return this._state.isPiPMounted;
|
||||
}
|
||||
|
||||
public set isPiPMounted(newIsPipMounted: boolean) {
|
||||
state.isPiPMounted = newIsPipMounted;
|
||||
this._state.isPiPMounted = newIsPipMounted;
|
||||
}
|
||||
|
||||
public get isStretched(): boolean {
|
||||
return state.isStretched;
|
||||
return this._state.isStretched;
|
||||
}
|
||||
|
||||
public set isStretched(newIsStretched: boolean) {
|
||||
state.isStretched = newIsStretched;
|
||||
this._state.isStretched = newIsStretched;
|
||||
}
|
||||
|
||||
public get isFullscreenVideoPlayer(): boolean {
|
||||
@ -177,7 +176,13 @@ class PlayerElementStore {
|
||||
}
|
||||
};
|
||||
|
||||
private _clear = (): void => {
|
||||
Object.assign(this._state, this._defaultState);
|
||||
};
|
||||
|
||||
public constructor() {
|
||||
const remote = useRemote();
|
||||
|
||||
watch(
|
||||
() => playbackManager.currentItem,
|
||||
(newValue, oldValue) => {
|
||||
@ -200,6 +205,15 @@ class PlayerElementStore {
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
() => remote.auth.currentUser,
|
||||
() => {
|
||||
if (!remote.auth.currentUser) {
|
||||
this._clear();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ import { mergeExcludingUnknown } from '@/utils/data-manipulation';
|
||||
import { useRemote } from '@/composables';
|
||||
|
||||
/**
|
||||
* == INTERFACES ==
|
||||
* == INTERFACES AND TYPES ==
|
||||
*/
|
||||
|
||||
export enum TaskType {
|
||||
@ -41,39 +41,42 @@ export interface TaskManagerState {
|
||||
}
|
||||
|
||||
/**
|
||||
* == STATE VARIABLES ==
|
||||
* == UTILITY VARIABLES ==
|
||||
*/
|
||||
const storeKey = 'taskManager';
|
||||
const defaultState: TaskManagerState = {
|
||||
tasks: [],
|
||||
finishedTasksTimeout: 5000
|
||||
};
|
||||
|
||||
const state: RemovableRef<TaskManagerState> = useStorage(
|
||||
storeKey,
|
||||
cloneDeep(defaultState),
|
||||
sessionStorage,
|
||||
{
|
||||
mergeDefaults: (storageValue, defaults) =>
|
||||
mergeExcludingUnknown(storageValue, defaults)
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* == CLASS CONSTRUCTOR ==
|
||||
*/
|
||||
class TaskManagerStore {
|
||||
/**
|
||||
* == GETTERS ==
|
||||
* == STATE ==
|
||||
*/
|
||||
public get tasks(): typeof state.value.tasks {
|
||||
return state.value.tasks;
|
||||
private _defaultState: TaskManagerState = {
|
||||
tasks: [],
|
||||
finishedTasksTimeout: 5000
|
||||
};
|
||||
|
||||
private _state: RemovableRef<TaskManagerState> = useStorage(
|
||||
storeKey,
|
||||
cloneDeep(this._defaultState),
|
||||
sessionStorage,
|
||||
{
|
||||
mergeDefaults: (storageValue, defaults) =>
|
||||
mergeExcludingUnknown(storageValue, defaults)
|
||||
}
|
||||
);
|
||||
/**
|
||||
* == GETTERS AND SETTERS ==
|
||||
*/
|
||||
public get tasks(): typeof this._state.value.tasks {
|
||||
return this._state.value.tasks;
|
||||
}
|
||||
public set timeout(newTimeout: number) {
|
||||
state.value.finishedTasksTimeout = newTimeout;
|
||||
this._state.value.finishedTasksTimeout = newTimeout;
|
||||
}
|
||||
public getTask = (id: string): RunningTask | undefined =>
|
||||
state.value.tasks.find((payload) => payload.id === id);
|
||||
this._state.value.tasks.find((payload) => payload.id === id);
|
||||
/**
|
||||
* == ACTIONS ==
|
||||
*/
|
||||
@ -87,33 +90,35 @@ class TaskManagerStore {
|
||||
if (this.getTask(task.id)) {
|
||||
this.updateTask(task);
|
||||
} else {
|
||||
state.value.tasks.push(task);
|
||||
this._state.value.tasks.push(task);
|
||||
}
|
||||
};
|
||||
|
||||
public updateTask = (updatedTask: RunningTask): void => {
|
||||
const taskIndex = state.value.tasks.findIndex(
|
||||
const taskIndex = this._state.value.tasks.findIndex(
|
||||
(task) => task.id === updatedTask.id
|
||||
);
|
||||
|
||||
if (taskIndex >= 0) {
|
||||
state.value.tasks[taskIndex] = updatedTask;
|
||||
this._state.value.tasks[taskIndex] = updatedTask;
|
||||
}
|
||||
};
|
||||
|
||||
public finishTask = (id: string): void => {
|
||||
const clearTask = (): void => {
|
||||
const taskIndex = state.value.tasks.findIndex((task) => task.id === id);
|
||||
const taskIndex = this._state.value.tasks.findIndex(
|
||||
(task) => task.id === id
|
||||
);
|
||||
|
||||
state.value.tasks.splice(taskIndex, 1);
|
||||
this._state.value.tasks.splice(taskIndex, 1);
|
||||
};
|
||||
|
||||
const task = this.getTask(id);
|
||||
|
||||
if (task) {
|
||||
if (state.value.finishedTasksTimeout > 0) {
|
||||
if (this._state.value.finishedTasksTimeout > 0) {
|
||||
task.progress = 100;
|
||||
window.setTimeout(clearTask, state.value.finishedTasksTimeout);
|
||||
window.setTimeout(clearTask, this._state.value.finishedTasksTimeout);
|
||||
} else {
|
||||
clearTask();
|
||||
}
|
||||
@ -131,6 +136,10 @@ class TaskManagerStore {
|
||||
return payload.id;
|
||||
};
|
||||
|
||||
private _clear = (): void => {
|
||||
Object.assign(this._state.value, this._defaultState);
|
||||
};
|
||||
|
||||
public constructor() {
|
||||
const remote = useRemote();
|
||||
|
||||
@ -165,6 +174,15 @@ class TaskManagerStore {
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => remote.auth.currentUser,
|
||||
() => {
|
||||
if (!remote.auth.currentUser) {
|
||||
this._clear();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,9 @@ import { CardShapes } from '@/utils/items';
|
||||
import { usei18n, useRemote, useSnackbar } from '@/composables';
|
||||
import { mergeExcludingUnknown } from '@/utils/data-manipulation';
|
||||
|
||||
/**
|
||||
* == INTERFACES AND TYPES ==
|
||||
*/
|
||||
interface LatestMedia {
|
||||
[key: string]: BaseItemDto[];
|
||||
}
|
||||
@ -41,43 +44,49 @@ interface UserLibrariesState {
|
||||
}
|
||||
|
||||
/**
|
||||
* == STATE VARIABLES ==
|
||||
* == UTILITY VARIABLES ==
|
||||
*/
|
||||
const storeKey = 'userLibraries';
|
||||
const defaultState: UserLibrariesState = {
|
||||
views: [],
|
||||
homeSections: {
|
||||
audioResumes: [],
|
||||
videoResumes: [],
|
||||
upNext: [],
|
||||
latestMedia: {}
|
||||
},
|
||||
carouselItems: [],
|
||||
isReady: false
|
||||
};
|
||||
|
||||
const state: RemovableRef<UserLibrariesState> = useStorage(
|
||||
storeKey,
|
||||
cloneDeep(defaultState),
|
||||
sessionStorage,
|
||||
{
|
||||
mergeDefaults: (storageValue, defaults) =>
|
||||
mergeExcludingUnknown(storageValue, defaults)
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* == CLASS CONSTRUCTOR ==
|
||||
*/
|
||||
class UserLibrariesStore {
|
||||
/**
|
||||
* == GETTERS ==
|
||||
* == STATE ==
|
||||
*/
|
||||
public get libraries(): typeof state.value.views {
|
||||
return state.value.views;
|
||||
private _defaultState: UserLibrariesState = {
|
||||
views: [],
|
||||
homeSections: {
|
||||
audioResumes: [],
|
||||
videoResumes: [],
|
||||
upNext: [],
|
||||
latestMedia: {}
|
||||
},
|
||||
carouselItems: [],
|
||||
isReady: false
|
||||
};
|
||||
|
||||
private _state: RemovableRef<UserLibrariesState> = useStorage(
|
||||
storeKey,
|
||||
cloneDeep(this._defaultState),
|
||||
sessionStorage,
|
||||
{
|
||||
mergeDefaults: (storageValue, defaults) =>
|
||||
mergeExcludingUnknown(storageValue, defaults)
|
||||
}
|
||||
);
|
||||
/**
|
||||
* == GETTERS AND SETTERS==
|
||||
*/
|
||||
public get libraries(): typeof this._state.value.views {
|
||||
return this._state.value.views;
|
||||
}
|
||||
public get isReady(): typeof state.value.isReady {
|
||||
return state.value.isReady;
|
||||
public get isReady(): typeof this._state.value.isReady {
|
||||
return this._state.value.isReady;
|
||||
}
|
||||
public get carouselItems(): typeof state.value.carouselItems {
|
||||
return state.value.carouselItems;
|
||||
public get carouselItems(): typeof this._state.value.carouselItems {
|
||||
return this._state.value.carouselItems;
|
||||
}
|
||||
|
||||
public getHomeSectionContent = (section: HomeSection): BaseItemDto[] => {
|
||||
@ -87,16 +96,16 @@ class UserLibrariesStore {
|
||||
return this.libraries;
|
||||
}
|
||||
case 'resume': {
|
||||
return state.value.homeSections.videoResumes;
|
||||
return this._state.value.homeSections.videoResumes;
|
||||
}
|
||||
case 'resumeaudio': {
|
||||
return state.value.homeSections.audioResumes;
|
||||
return this._state.value.homeSections.audioResumes;
|
||||
}
|
||||
case 'upnext': {
|
||||
return state.value.homeSections.upNext;
|
||||
return this._state.value.homeSections.upNext;
|
||||
}
|
||||
case 'latestmedia': {
|
||||
return state.value.homeSections.latestMedia[section.libraryId];
|
||||
return this._state.value.homeSections.latestMedia[section.libraryId];
|
||||
}
|
||||
default: {
|
||||
return [];
|
||||
@ -125,7 +134,7 @@ class UserLibrariesStore {
|
||||
userId: remote.auth.currentUserId || ''
|
||||
});
|
||||
|
||||
state.value.views = userViewsResponse.data.Items || [];
|
||||
this._state.value.views = userViewsResponse.data.Items || [];
|
||||
} catch (error) {
|
||||
this._onError(error);
|
||||
}
|
||||
@ -152,7 +161,7 @@ class UserLibrariesStore {
|
||||
).data.Items;
|
||||
|
||||
if (audioResumes) {
|
||||
state.value.homeSections.audioResumes = audioResumes;
|
||||
this._state.value.homeSections.audioResumes = audioResumes;
|
||||
}
|
||||
} catch (error) {
|
||||
this._onError(error);
|
||||
@ -180,7 +189,7 @@ class UserLibrariesStore {
|
||||
).data.Items;
|
||||
|
||||
if (videoResumes) {
|
||||
state.value.homeSections.videoResumes = videoResumes;
|
||||
this._state.value.homeSections.videoResumes = videoResumes;
|
||||
}
|
||||
} catch (error) {
|
||||
this._onError(error);
|
||||
@ -207,7 +216,7 @@ class UserLibrariesStore {
|
||||
).data.Items;
|
||||
|
||||
if (upNext) {
|
||||
state.value.homeSections.upNext = upNext;
|
||||
this._state.value.homeSections.upNext = upNext;
|
||||
}
|
||||
} catch (error) {
|
||||
this._onError(error);
|
||||
@ -233,7 +242,7 @@ class UserLibrariesStore {
|
||||
})
|
||||
).data;
|
||||
|
||||
state.value.homeSections.latestMedia[libraryId] = latestMedia;
|
||||
this._state.value.homeSections.latestMedia[libraryId] = latestMedia;
|
||||
} catch (error) {
|
||||
this._onError(error);
|
||||
}
|
||||
@ -254,7 +263,7 @@ class UserLibrariesStore {
|
||||
).data;
|
||||
|
||||
if (carouselItems) {
|
||||
state.value.carouselItems = carouselItems;
|
||||
this._state.value.carouselItems = carouselItems;
|
||||
}
|
||||
} catch (error) {
|
||||
this._onError(error);
|
||||
@ -274,11 +283,11 @@ class UserLibrariesStore {
|
||||
}
|
||||
}
|
||||
|
||||
state.value.isReady = true;
|
||||
this._state.value.isReady = true;
|
||||
};
|
||||
|
||||
public clear = (): void => {
|
||||
Object.assign(state.value, defaultState);
|
||||
private _clear = (): void => {
|
||||
Object.assign(this._state.value, this._defaultState);
|
||||
};
|
||||
|
||||
public constructor() {
|
||||
@ -288,7 +297,7 @@ class UserLibrariesStore {
|
||||
() => remote.auth.currentUser,
|
||||
() => {
|
||||
if (!remote.auth.currentUser) {
|
||||
userLibraries.clear();
|
||||
this._clear();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user