Started using shaka player

This commit is contained in:
WardPearce
2025-02-23 06:23:55 +13:00
parent d8c0de5656
commit 44db93b0ad
9 changed files with 233 additions and 240 deletions
+12 -2
View File
@@ -1,15 +1,16 @@
{
"name": "Materialious",
"version": "1.7.6",
"version": "1.7.15",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "Materialious",
"version": "1.7.6",
"version": "1.7.15",
"license": "MIT",
"dependencies": {
"@capacitor-community/electron": "^5.0.0",
"capacitor-nodejs": "https://github.com/EdenwareApps/Capacitor-NodeJS/releases/download/v1.0.0-beta.7/capacitor6-nodejs.tgz",
"chokidar": "~4.0.3",
"electron-is-dev": "~2.0.0",
"electron-serve": "~1.1.0",
@@ -1724,6 +1725,15 @@
"node": ">=8"
}
},
"node_modules/capacitor-nodejs": {
"version": "1.0.0-beta.7",
"resolved": "https://github.com/EdenwareApps/Capacitor-NodeJS/releases/download/v1.0.0-beta.7/capacitor6-nodejs.tgz",
"integrity": "sha512-7NwSMxE06nqpuFKyQlt3mWo+VG6Od0d6PBxPKVyPmaptE6sSoimzU/uzQXPWoHV5bwbjgcF+R0BSJAZAyy4gsg==",
"license": "MIT",
"peerDependencies": {
"@capacitor/core": "^6.0.0"
}
},
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+2 -1
View File
@@ -23,6 +23,7 @@
},
"dependencies": {
"@capacitor-community/electron": "^5.0.0",
"capacitor-nodejs": "https://github.com/EdenwareApps/Capacitor-NodeJS/releases/download/v1.0.0-beta.7/capacitor6-nodejs.tgz",
"chokidar": "~4.0.3",
"electron-is-dev": "~2.0.0",
"electron-serve": "~1.1.0",
@@ -41,4 +42,4 @@
"capacitor",
"electron"
]
}
}
@@ -1,4 +1,6 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const CapacitorNodejs = require('../../../node_modules/capacitor-nodejs/electron/dist/plugin.js');
module.exports = {
CapacitorNodejs,
}
+19
View File
@@ -33,6 +33,7 @@
"media-icons": "^0.10.0",
"mousetrap": "^1.6.5",
"peerjs": "^1.5.4",
"shaka-player": "^4.13.4",
"sponsorblock-api": "^0.2.4",
"svelte-i18n": "^4.0.1",
"svelte-infinite-loading": "^1.4.0",
@@ -6122,6 +6123,12 @@
"integrity": "sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg==",
"license": "ISC"
},
"node_modules/eme-encryption-scheme-polyfill": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/eme-encryption-scheme-polyfill/-/eme-encryption-scheme-polyfill-2.2.1.tgz",
"integrity": "sha512-GzgrLuZPYGijd8oaKuBqYv3Tc2oruDZM3V2982KOuy/PA1N3zwMe+/oIXJYfZ3BH3PwW5nONdBBE+VY6jlwbrw==",
"license": "Apache-2.0"
},
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -11680,6 +11687,18 @@
"node": ">= 0.4"
}
},
"node_modules/shaka-player": {
"version": "4.13.4",
"resolved": "https://registry.npmjs.org/shaka-player/-/shaka-player-4.13.4.tgz",
"integrity": "sha512-dVEpbTO27gxM7GZO+4Ks9WVcL9xCLiZe9GTmlRIF7E8KaX8NlbCPHKtSK65HmJS1dfBeqd69/Kpm8724bJOWOw==",
"license": "Apache-2.0",
"dependencies": {
"eme-encryption-scheme-polyfill": "^2.2.1"
},
"engines": {
"node": ">=18"
}
},
"node_modules/sharp": {
"version": "0.32.6",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz",
+1
View File
@@ -65,6 +65,7 @@
"media-icons": "^0.10.0",
"mousetrap": "^1.6.5",
"peerjs": "^1.5.4",
"shaka-player": "^4.13.4",
"sponsorblock-api": "^0.2.4",
"svelte-i18n": "^4.0.1",
"svelte-infinite-loading": "^1.4.0",
+1 -10
View File
@@ -34,22 +34,13 @@
interface Props {
data: { video: VideoPlay; content: PhasedDescription; playlistId: string | null };
audioMode?: boolean;
player: MediaPlayerElement;
isSyncing?: boolean;
isEmbed?: boolean;
segments?: Segment[];
}
let {
data,
audioMode = false,
player = $bindable(),
isSyncing = false,
isEmbed = false,
segments = $bindable([])
}: Props = $props();
let { data, audioMode = false, isEmbed = false, segments = $bindable([]) }: Props = $props();
let src: PlayerSrc = $state([]);
let snackBarAlert = $state('');
let playerIsLive = $state(false);
let playerPosSet = false;
@@ -4,18 +4,15 @@
import { VTTCue, parseText, type ParsedCaptionsResult } from 'media-captions';
import { _ } from 'svelte-i18n';
import { get } from 'svelte/store';
import type { MediaTimeUpdateEvent } from 'vidstack';
import type { MediaPlayerElement } from 'vidstack/elements';
import type { VideoPlay } from '../api/model';
import { decodeHtmlCharCodes } from '../misc';
import { instanceStore } from '../store';
interface Props {
video: VideoPlay;
player: MediaPlayerElement;
}
let { video, player = $bindable() }: Props = $props();
let { video }: Props = $props();
let url: string | null = $state(null);
let autoScroll: boolean = $state(true);
@@ -26,21 +23,21 @@
let currentTime = $state(0);
let search: string = $state('');
player.addEventListener('time-update', (event: MediaTimeUpdateEvent) => {
currentTime = event.detail.currentTime;
// player.addEventListener('time-update', (event: MediaTimeUpdateEvent) => {
// currentTime = event.detail.currentTime;
if (autoScroll) {
const currentTranscriptLine = document.querySelector(
'.transcript-line.secondary-container'
) as HTMLElement;
const transcriptScrollable = document.getElementById('transcript');
// if (autoScroll) {
// const currentTranscriptLine = document.querySelector(
// '.transcript-line.secondary-container'
// ) as HTMLElement;
// const transcriptScrollable = document.getElementById('transcript');
if (currentTranscriptLine && transcriptScrollable) {
transcriptScrollable.scrollTop =
currentTranscriptLine.offsetTop - transcriptScrollable.offsetTop - 300;
}
}
});
// if (currentTranscriptLine && transcriptScrollable) {
// transcriptScrollable.scrollTop =
// currentTranscriptLine.offsetTop - transcriptScrollable.offsetTop - 300;
// }
// }
// });
async function loadTranscript() {
if (!url) {
@@ -1,7 +1,4 @@
<script lang="ts">
import { run } from 'svelte/legacy';
import { goto } from '$app/navigation';
import {
addPlaylistVideo,
deleteUnsubscribe,
@@ -19,30 +16,24 @@
import Transcript from '$lib/components/Transcript.svelte';
import { getBestThumbnail, proxyGoogleImage } from '$lib/images';
import { letterCase } from '$lib/letterCasing';
import { truncate, unsafeRandomItem } from '$lib/misc';
import type { PlayerEvents } from '$lib/player';
import { truncate } from '$lib/misc';
import {
activePageStore,
authStore,
interfaceAutoExpandComments,
interfaceAutoExpandDesc,
interfaceLowBandwidthMode,
playerAutoplayNextByDefaultStore,
playerListenByDefaultStore,
playerTheatreModeByDefaultStore,
playlistSettingsStore,
syncPartyConnectionsStore,
syncPartyPeerStore
} from '$lib/store';
import { cleanNumber, humanizeSeconds, numberWithCommas } from '$lib/time';
import ui from 'beercss';
import type { DataConnection } from 'peerjs';
import { type Segment } from 'sponsorblock-api';
import { onDestroy, onMount, tick } from 'svelte';
import { onDestroy, tick } from 'svelte';
import { _ } from 'svelte-i18n';
import { get } from 'svelte/store';
import type { MediaTimeUpdateEvent } from 'vidstack';
import type { MediaPlayerElement } from 'vidstack/elements';
let { data = $bindable() } = $props();
@@ -70,7 +61,6 @@
let theatreMode = $state(get(playerTheatreModeByDefaultStore));
let audioMode = $state(get(playerListenByDefaultStore));
let player: MediaPlayerElement;
let segments: Segment[] = $state([]);
@@ -79,16 +69,6 @@
let showTranscript = $state(false);
let playerCurrentTime: number = $state(0);
// @ts-ignore
run(() => {
if (typeof player !== 'undefined') {
playerCurrentTime = player.currentTime;
player.addEventListener(
'time-update',
(event: MediaTimeUpdateEvent) => (playerCurrentTime = event.detail.currentTime)
);
}
});
playlistSettingsStore.subscribe((playlistSetting) => {
if (!data.playlistId) return;
@@ -98,209 +78,209 @@
}
});
function playerSyncEvents(conn: DataConnection) {
if (player) {
conn.send({
events: [{ type: 'seek', time: player.currentTime }]
} as PlayerEvents);
}
// function playerSyncEvents(conn: DataConnection) {
// if (player) {
// conn.send({
// events: [{ type: 'seek', time: player.currentTime }]
// } as PlayerEvents);
// }
if (data.playlistId) {
conn.send({
events: [
{
type: 'playlist',
playlistId: data.playlistId
}
]
} as PlayerEvents);
}
// if (data.playlistId) {
// conn.send({
// events: [
// {
// type: 'playlist',
// playlistId: data.playlistId
// }
// ]
// } as PlayerEvents);
// }
conn.on('data', (rawData) => {
const events = rawData as PlayerEvents;
// conn.on('data', (rawData) => {
// const events = rawData as PlayerEvents;
events.events.forEach(async (event) => {
if (!player) return;
// events.events.forEach(async (event) => {
// if (!player) return;
if (event.type === 'pause') {
player.pause();
} else if (event.type === 'play') {
player.play();
} else if (event.type === 'seek' && event.time) {
const timeDiff = player.currentTime - event.time;
// if (event.type === 'pause') {
// player.pause();
// } else if (event.type === 'play') {
// player.play();
// } else if (event.type === 'seek' && event.time) {
// const timeDiff = player.currentTime - event.time;
if (timeDiff > 5 || timeDiff < -5) {
player.currentTime = event.time;
}
} else if (
event.type === 'playlist' &&
event.playlistId &&
event.playlistId !== data.playlistId
) {
data.playlistId = event.playlistId;
await loadPlaylist(event.playlistId);
goToCurrentPlaylistItem();
}
});
});
// if (timeDiff > 5 || timeDiff < -5) {
// player.currentTime = event.time;
// }
// } else if (
// event.type === 'playlist' &&
// event.playlistId &&
// event.playlistId !== data.playlistId
// ) {
// data.playlistId = event.playlistId;
// await loadPlaylist(event.playlistId);
// goToCurrentPlaylistItem();
// }
// });
// });
if (!player) return;
// if (!player) return;
player.addEventListener('auto-play-fail', () => {
conn.send({
events: [
{
type: 'pause'
}
]
} as PlayerEvents);
});
// player.addEventListener('auto-play-fail', () => {
// conn.send({
// events: [
// {
// type: 'pause'
// }
// ]
// } as PlayerEvents);
// });
player.addEventListener('auto-play', () => {
if (!player) return;
conn.send({
events: [
{
type: 'seek',
time: player.currentTime
},
{
type: 'play'
}
]
} as PlayerEvents);
});
// player.addEventListener('auto-play', () => {
// if (!player) return;
// conn.send({
// events: [
// {
// type: 'seek',
// time: player.currentTime
// },
// {
// type: 'play'
// }
// ]
// } as PlayerEvents);
// });
player.addEventListener('pause', () => {
conn.send({
events: [
{
type: 'pause'
}
]
} as PlayerEvents);
});
// player.addEventListener('pause', () => {
// conn.send({
// events: [
// {
// type: 'pause'
// }
// ]
// } as PlayerEvents);
// });
player.addEventListener('playing', () => {
if (!player) return;
conn.send({
events: [
{
type: 'seek',
time: player.currentTime
},
{
type: 'play'
}
]
} as PlayerEvents);
});
// player.addEventListener('playing', () => {
// if (!player) return;
// conn.send({
// events: [
// {
// type: 'seek',
// time: player.currentTime
// },
// {
// type: 'play'
// }
// ]
// } as PlayerEvents);
// });
player.addEventListener('play', () => {
if (!player) return;
conn.send({
events: [
{
type: 'seek',
time: player.currentTime
},
{
type: 'play'
}
]
} as PlayerEvents);
});
// player.addEventListener('play', () => {
// if (!player) return;
// conn.send({
// events: [
// {
// type: 'seek',
// time: player.currentTime
// },
// {
// type: 'play'
// }
// ]
// } as PlayerEvents);
// });
player.addEventListener('waiting', () => {
conn.send({
events: [
{
type: 'pause'
}
]
} as PlayerEvents);
});
// player.addEventListener('waiting', () => {
// conn.send({
// events: [
// {
// type: 'pause'
// }
// ]
// } as PlayerEvents);
// });
player.addEventListener('seeked', () => {
if (!player) return;
conn.send({
events: [
{
type: 'seek',
time: player.currentTime
}
]
} as PlayerEvents);
});
}
// player.addEventListener('seeked', () => {
// if (!player) return;
// conn.send({
// events: [
// {
// type: 'seek',
// time: player.currentTime
// }
// ]
// } as PlayerEvents);
// });
// }
syncPartyConnectionsStore.subscribe((connections) => {
if (!connections || !player) return;
playerSyncEvents(connections[connections.length - 1]);
});
// syncPartyConnectionsStore.subscribe((connections) => {
// if (!connections || !player) return;
// playerSyncEvents(connections[connections.length - 1]);
// });
onMount(async () => {
if ($syncPartyConnectionsStore) {
$syncPartyConnectionsStore.forEach((conn) => {
playerSyncEvents(conn);
});
}
// onMount(async () => {
// if ($syncPartyConnectionsStore) {
// $syncPartyConnectionsStore.forEach((conn) => {
// playerSyncEvents(conn);
// });
// }
if (player) {
player.addEventListener('end', async () => {
if (playlistVideos.length === 0) {
if ($playerAutoplayNextByDefaultStore) {
goto(`/watch/${data.video.recommendedVideos[0].videoId}`);
}
return;
}
// if (player) {
// player.addEventListener('end', async () => {
// if (playlistVideos.length === 0) {
// if ($playerAutoplayNextByDefaultStore) {
// goto(`/watch/${data.video.recommendedVideos[0].videoId}`);
// }
// return;
// }
await goToCurrentPlaylistItem();
// await goToCurrentPlaylistItem();
const playlistVideoIds = playlistVideos.map((value) => {
return value.videoId;
});
// const playlistVideoIds = playlistVideos.map((value) => {
// return value.videoId;
// });
let goToVideo: PlaylistPageVideo | undefined;
// let goToVideo: PlaylistPageVideo | undefined;
if (shufflePlaylist) {
goToVideo = unsafeRandomItem(playlistVideos);
} else {
const currentVideoIndex = playlistVideoIds.indexOf(data.video.videoId);
const newIndex = currentVideoIndex + 1;
if (currentVideoIndex !== -1 && newIndex < playlistVideoIds.length) {
goToVideo = playlistVideos[newIndex];
} else if (loopPlaylist) {
// Loop playlist on end
goToVideo = playlistVideos[0];
}
}
// if (shufflePlaylist) {
// goToVideo = unsafeRandomItem(playlistVideos);
// } else {
// const currentVideoIndex = playlistVideoIds.indexOf(data.video.videoId);
// const newIndex = currentVideoIndex + 1;
// if (currentVideoIndex !== -1 && newIndex < playlistVideoIds.length) {
// goToVideo = playlistVideos[newIndex];
// } else if (loopPlaylist) {
// // Loop playlist on end
// goToVideo = playlistVideos[0];
// }
// }
if (typeof goToVideo !== 'undefined') {
if ($syncPartyConnectionsStore) {
$syncPartyConnectionsStore.forEach((conn) => {
if (typeof goToVideo === 'undefined') return;
// if (typeof goToVideo !== 'undefined') {
// if ($syncPartyConnectionsStore) {
// $syncPartyConnectionsStore.forEach((conn) => {
// if (typeof goToVideo === 'undefined') return;
conn.send({
events: [
{ type: 'change-video', videoId: goToVideo.videoId },
{ type: 'playlist', playlistId: data.playlistId }
]
} as PlayerEvents);
});
}
// conn.send({
// events: [
// { type: 'change-video', videoId: goToVideo.videoId },
// { type: 'playlist', playlistId: data.playlistId }
// ]
// } as PlayerEvents);
// });
// }
goto(`/watch/${goToVideo.videoId}?playlist=${data.playlistId}`);
}
});
}
// goto(`/watch/${goToVideo.videoId}?playlist=${data.playlistId}`);
// }
// });
// }
if (!data.playlistId) return;
// if (!data.playlistId) return;
await loadPlaylist(data.playlistId);
// await loadPlaylist(data.playlistId);
await goToCurrentPlaylistItem();
});
// await goToCurrentPlaylistItem();
// });
onDestroy(() => {
// Reset title when page left.
@@ -404,7 +384,7 @@
clearTimeout(pauseTimeout);
}
pauseTimeout = setTimeout(() => {
player.pause();
// player.pause();
pauseTimerSeconds = 0;
clearTimeout(pauseTimeout);
}, pauseTimerSeconds * 1000);
@@ -429,13 +409,7 @@
<div
style="max-height: 80vh;max-width: calc(80vh * 16 / 9);overflow: hidden;position: relative;flex: 1;"
>
<Player
bind:segments
{data}
{audioMode}
isSyncing={$syncPartyPeerStore !== null}
bind:player
/>
<Player bind:segments {data} {audioMode} isSyncing={$syncPartyPeerStore !== null} />
</div>
{/key}
</div>
@@ -665,7 +639,7 @@
{#if !theatreMode}
<div class="s12 m12 l3">
{#if showTranscript}
<Transcript bind:player video={data.video} />
<Transcript video={data.video} />
{/if}
{#if playlist}
<article
-2
View File
@@ -1,6 +1,5 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { SvelteKitPWA } from '@vite-pwa/sveltekit';
import { vite as vidstack } from 'vidstack/plugins';
import { defineConfig } from 'vite';
@@ -34,7 +33,6 @@ export default defineConfig({
name: 'Materialious'
}
}),
vidstack(),
sveltekit()
],
ssr: {