first commit
Some checks failed
Build / run (push) Has been cancelled

This commit is contained in:
maher
2025-10-29 11:42:25 +01:00
commit 703f50a09d
4595 changed files with 385164 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
import {MediaItem} from '@common/player/media-item';
import {IS_IOS} from '@common/utils/platform';
const hlsRegex = /\.(m3u8)($|\?)/i;
const dashRegex = /\.(mpd)($|\?)/i;
const audioRegex =
/\.(m4a|mp4a|mpga|mp2|mp2a|mp3|m2a|m3a|wav|weba|aac|oga|spx|flac)($|\?)/i;
const youtubeUrlRegex =
/(?:youtu\.be|youtube|youtube\.com|youtube-nocookie\.com)\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=|)((?:\w|-){11})/;
const youtubeIdRegex = /^((?:\w|-){11})$/;
export function guessPlayerProvider(src: string): MediaItem['provider'] {
if (youtubeUrlRegex.test(src) || youtubeIdRegex.test(src)) {
return 'youtube';
} else if (audioRegex.test(src)) {
return 'htmlAudio';
} else if (hlsRegex.test(src)) {
if (IS_IOS) {
return 'htmlVideo';
} else {
return 'hls';
}
} else if (dashRegex.test(src)) {
return 'dash';
} else {
return 'htmlVideo';
}
}

View File

@@ -0,0 +1,35 @@
import {Optional} from 'utility-types';
import {PlayerState} from '@common/player/state/player-state';
import {PlayerStoreOptions} from '@common/player/state/player-store-options';
export function initPlayerMediaSession(
state: () => PlayerState,
options: PlayerStoreOptions
) {
if ('mediaSession' in navigator) {
const actionHandlers: Optional<
Record<MediaSessionAction, MediaSessionActionHandler>
> = {
play: () => state().play(),
pause: () => state().pause(),
previoustrack: () => state().playPrevious(),
nexttrack: () => state().playNext(),
stop: () => state().stop(),
seekbackward: () => state().seek(state().getCurrentTime() - 10),
seekforward: () => state().seek(state().getCurrentTime() + 10),
seekto: details => state().seek(details.seekTime || 0),
};
for (const key in actionHandlers) {
try {
navigator.mediaSession.setActionHandler(
key as MediaSessionAction,
actionHandlers[key as MediaSessionAction]!
);
} catch (error) {}
}
const cuedMedia = state().cuedMedia;
if (cuedMedia) {
options.setMediaSessionMetadata?.(cuedMedia);
}
}
}

View File

@@ -0,0 +1,6 @@
import {MediaItem} from '@common/player/media-item';
export function isSameMedia(a?: MediaItem, b?: MediaItem): boolean {
if (!a || !b) return false;
return a.id === b.id && a.groupId === b.groupId;
}

View File

@@ -0,0 +1,33 @@
import {getFromLocalStorage} from '@common/utils/hooks/local-storage';
import {PlayerStoreOptions} from '@common/player/state/player-store-options';
import {PlayerState} from '@common/player/state/player-state';
export interface PersistablePlayerState {
muted?: PlayerState['muted'];
repeat?: PlayerState['repeat'];
shuffling?: PlayerState['shuffling'];
volume?: PlayerState['volume'];
}
export interface PlayerInitialData {
state?: PersistablePlayerState;
queue?: PlayerState['originalQueue'];
cuedMediaId?: string | number;
}
export function getPlayerStateFromLocalStorage(
id: string | number,
options?: PlayerStoreOptions
): PlayerInitialData {
const defaultVolume = options?.defaultVolume || 30;
return {
state: {
muted: getFromLocalStorage(`player.${id}.muted`) ?? false,
repeat: getFromLocalStorage(`player.${id}.repeat`) ?? 'all',
shuffling: getFromLocalStorage(`player.${id}.shuffling`) ?? false,
volume: getFromLocalStorage(`player.${id}.volume`) ?? defaultVolume,
},
queue: getFromLocalStorage(`player.${id}.queue`, []),
cuedMediaId: getFromLocalStorage(`player.${id}.cuedMediaId`),
};
}

View File

@@ -0,0 +1,19 @@
export function resetMediaSession() {
if ('mediaSession' in navigator) {
const actionHandlers: MediaSessionAction[] = [
'play',
'pause',
'previoustrack',
'nexttrack',
'stop',
'seekbackward',
'seekforward',
'seekto',
];
actionHandlers.forEach(action =>
navigator.mediaSession.setActionHandler(action, null)
);
navigator.mediaSession.metadata = null;
navigator.mediaSession.playbackState = 'none';
}
}

View File

@@ -0,0 +1,3 @@
export function youtubeIdFromSrc(src: string) {
return src.match(/((?:\w|-){11})/)?.[0];
}