mirror of
https://codeberg.org/Hyperpipe/Hyperpipe
synced 2025-06-28 05:08:00 +02:00
233 lines
6 KiB
Vue
233 lines
6 KiB
Vue
<script setup>
|
|
import { ref, watch, onMounted, onBeforeUnmount, onUnmounted } from 'vue';
|
|
|
|
import muxjs from 'mux.js';
|
|
window.muxjs = muxjs;
|
|
|
|
import { useStore, useRoute, useManifest } from '@/scripts/util.js';
|
|
import { useData, usePlayer } from '@/stores/player.js';
|
|
import { useAlert } from '@/stores/misc';
|
|
|
|
const player = usePlayer(),
|
|
data = useData(),
|
|
store = useStore(),
|
|
a = useAlert();
|
|
|
|
const audio = ref(null);
|
|
|
|
function audioCanPlay() {
|
|
player.state.status = 'pause';
|
|
audio.value.play().catch(err => {
|
|
console.error(err);
|
|
player.state.status = 'play';
|
|
});
|
|
|
|
if (location.pathname != '/playlist') useRoute(data.state.url);
|
|
|
|
document.title = `Playing: ${data.state.title} by ${data.state.artist}`;
|
|
}
|
|
|
|
async function Stream() {
|
|
const res = player.state,
|
|
shaka = import('shaka-player/dist/shaka-player.compiled.js');
|
|
|
|
const { url, mime } = await useManifest(res);
|
|
|
|
if (!window.audioPlayer) {
|
|
shaka
|
|
.then(shaka => shaka.default)
|
|
.then(shaka => {
|
|
shaka.polyfill.installAll();
|
|
|
|
if (shaka.Player.isBrowserSupported()) {
|
|
const audioPlayer = new shaka.Player(audio.value),
|
|
codecs = store.getItem('codec');
|
|
|
|
audioPlayer
|
|
.getNetworkingEngine()
|
|
.registerRequestFilter((_type, req) => {
|
|
const headers = req.headers;
|
|
|
|
let url = new URL(req.uris[0]);
|
|
|
|
if (url.pathname.indexOf('/videoplayback') > -1) {
|
|
if (headers.Range) {
|
|
url.searchParams.set('range', headers.Range.split('=')[1]);
|
|
req.headers = {};
|
|
req.uris[0] = url.toString();
|
|
}
|
|
}
|
|
});
|
|
|
|
window.offline = new shaka.offline.Storage(audioPlayer);
|
|
window.offline.configure({
|
|
offline: {
|
|
progressCallback: ({ appMetadata: { title, artist } }, prog) =>
|
|
a.add(`${title} by ${artist}: ${Math.floor(prog * 100)}%`),
|
|
trackSelectionCallback: tracks => [
|
|
tracks
|
|
.sort((a, b) => a.bandwidth - b.bandwidth)
|
|
.find(i => i.type == 'variant'),
|
|
],
|
|
},
|
|
});
|
|
|
|
audioPlayer.configure({
|
|
preferredAudioCodecs: codecs ? codecs.split(':') : ['opus', 'mp4a'],
|
|
manifest: {
|
|
disableVideo: true,
|
|
},
|
|
streaming: {
|
|
segmentPrefetchLimit: 2,
|
|
},
|
|
});
|
|
|
|
window.audioPlayer = audioPlayer;
|
|
}
|
|
});
|
|
}
|
|
|
|
const quality = store.getItem('quality');
|
|
|
|
if (url) {
|
|
window.audioPlayer
|
|
.load(url, 0, mime)
|
|
.then(() => {
|
|
window.audioPlayer.configure('abr.enabled', true);
|
|
|
|
if (quality && quality != 'auto') {
|
|
window.audioPlayer.configure('abr.enabled', false);
|
|
|
|
const tracks = window.audioPlayer.getVariantTracks(),
|
|
bandwidths = tracks.map(i => i.bandwidth);
|
|
|
|
let sel;
|
|
|
|
if (quality == 'best') sel = Math.max(...bandwidths);
|
|
else if (quality == 'worst') sel = Math.min(...bandwidths);
|
|
|
|
if (sel)
|
|
window.audioPlayer.selectVariantTrack(
|
|
tracks[bandwidths.indexOf(sel)],
|
|
);
|
|
}
|
|
})
|
|
.catch(err => {
|
|
console.error(err);
|
|
a.add('Error: ' + err.code);
|
|
});
|
|
}
|
|
}
|
|
|
|
function destroy() {
|
|
if (window.audioPlayer) {
|
|
window.audioPlayer.destroy();
|
|
window.audioPlayer = undefined;
|
|
}
|
|
if (window.offline) {
|
|
window.offline.destroy();
|
|
window.offline = undefined;
|
|
}
|
|
}
|
|
|
|
const titleState = ['Playing', 'Paused'];
|
|
|
|
watch(
|
|
() => player.state.play,
|
|
() => {
|
|
if (audio.value.paused) {
|
|
player.state.status = 'pause';
|
|
audio.value.play().catch(err => {
|
|
console.error(err);
|
|
player.state.status = 'play';
|
|
});
|
|
} else {
|
|
player.state.status = 'play';
|
|
audio.value.pause();
|
|
}
|
|
|
|
if (
|
|
document.title.startsWith(titleState[0] + ':') ||
|
|
document.title.startsWith(titleState[1] + ':')
|
|
)
|
|
document.title = audio.value.paused
|
|
? document.title.replace(titleState[0], titleState[1])
|
|
: document.title.replace(titleState[1], titleState[0]);
|
|
},
|
|
);
|
|
|
|
watch(() => player.state.streams, Stream);
|
|
|
|
watch(
|
|
() => player.state.currentTime,
|
|
() => {
|
|
console.log(player.state.currentTime);
|
|
audio.value.currentTime = player.state.currentTime;
|
|
},
|
|
);
|
|
|
|
onMounted(() => {
|
|
Stream();
|
|
|
|
if ('mediaSession' in navigator) {
|
|
navigator.mediaSession.setActionHandler('play', () => {
|
|
player.state.status = 'pause';
|
|
document.title = document.title.replace(titleState[1], titleState[0]);
|
|
|
|
audio.value.play().catch(err => {
|
|
console.log(err);
|
|
player.state.status = 'play';
|
|
document.title = document.title.replace(titleState[0], titleState[1]);
|
|
});
|
|
});
|
|
|
|
navigator.mediaSession.setActionHandler('pause', () => {
|
|
audio.value.pause();
|
|
player.state.status = 'play';
|
|
document.title = document.title.replace(titleState[0], titleState[1]);
|
|
});
|
|
|
|
navigator.mediaSession.setActionHandler('previoustrack', () => {
|
|
if (data.state.urls.length > 2) {
|
|
const i = data.state.urls.findIndex(s => s.url == data.state.url);
|
|
|
|
data.play(data.state.urls[i - 1]);
|
|
}
|
|
});
|
|
|
|
navigator.mediaSession.setActionHandler('nexttrack', () => {
|
|
if (data.state.urls.length > 2) {
|
|
const i = data.state.urls.findIndex(s => s.url == data.state.url);
|
|
|
|
data.play(data.state.urls[i + 1]);
|
|
}
|
|
});
|
|
|
|
navigator.mediaSession.setActionHandler('seekbackward', () => {
|
|
audio.value.currentTime -= 10;
|
|
});
|
|
|
|
navigator.mediaSession.setActionHandler('seekforward', () => {
|
|
audio.value.currentTime += 10;
|
|
});
|
|
}
|
|
});
|
|
|
|
onBeforeUnmount(() => {
|
|
destroy();
|
|
});
|
|
onUnmounted(() => {
|
|
destroy();
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<audio
|
|
id="audio"
|
|
ref="audio"
|
|
:volume="player.state.vol"
|
|
@canplay="audioCanPlay"
|
|
@timeupdate="player.setTime($event.target.currentTime)"
|
|
@ended="data.playNext"
|
|
autoplay></audio>
|
|
</template>
|