181 lines
4.3 KiB
Vue
181 lines
4.3 KiB
Vue
<template>
|
|
<audio
|
|
v-if="isPlaying"
|
|
ref="$audio"
|
|
:title="title"
|
|
/>
|
|
</template>
|
|
|
|
<script setup>
|
|
import getLogarithmicVolume from '~/functions/getLogarithmicVolume.js';
|
|
import Hls from 'hls.js';
|
|
import {usePlayerStore} from "~/store.js";
|
|
import {nextTick, onMounted, ref, toRef, watch} from "vue";
|
|
|
|
const props = defineProps({
|
|
title: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
volume: {
|
|
type: Number,
|
|
default: 55
|
|
},
|
|
isMuted: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
});
|
|
|
|
const $audio = ref(null);
|
|
const hls = ref(null);
|
|
const duration = ref(0);
|
|
const currentTime = ref(0);
|
|
|
|
const store = usePlayerStore();
|
|
const isPlaying = toRef(store, 'isPlaying');
|
|
const current = toRef(store, 'current');
|
|
|
|
watch(toRef(props, 'volume'), (newVol) => {
|
|
if ($audio.value !== null) {
|
|
$audio.value.volume = getLogarithmicVolume(newVol);
|
|
}
|
|
});
|
|
|
|
watch(toRef(props, 'isMuted'), (newMuted) => {
|
|
if ($audio.value !== null) {
|
|
$audio.value.muted = newMuted;
|
|
}
|
|
});
|
|
|
|
const stop = () => {
|
|
if ($audio.value !== null) {
|
|
$audio.value.pause();
|
|
$audio.value.src = '';
|
|
}
|
|
|
|
if (hls.value !== null) {
|
|
hls.value.destroy();
|
|
hls.value = null;
|
|
}
|
|
|
|
duration.value = 0;
|
|
currentTime.value = 0;
|
|
|
|
store.stopPlaying();
|
|
};
|
|
|
|
const play = () => {
|
|
if (isPlaying.value) {
|
|
stop();
|
|
nextTick(() => {
|
|
play();
|
|
});
|
|
return;
|
|
}
|
|
|
|
store.startPlaying();
|
|
|
|
nextTick(() => {
|
|
// Handle audio errors.
|
|
$audio.value.onerror = (e) => {
|
|
if (e.target.error.code === e.target.error.MEDIA_ERR_NETWORK && $audio.value.src !== '') {
|
|
console.log('Network interrupted stream. Automatically reconnecting shortly...');
|
|
setTimeout(() => {
|
|
play();
|
|
}, 5000);
|
|
}
|
|
};
|
|
|
|
$audio.value.onended = () => {
|
|
stop();
|
|
};
|
|
|
|
$audio.value.ontimeupdate = () => {
|
|
const audioDuration = $audio.value?.duration ?? 0;
|
|
duration.value = (audioDuration !== Infinity && !isNaN(audioDuration)) ? audioDuration : 0;
|
|
|
|
currentTime.value = $audio.value?.currentTime ?? null;
|
|
};
|
|
|
|
$audio.value.volume = getLogarithmicVolume(props.volume);
|
|
$audio.value.muted = props.isMuted;
|
|
|
|
if (current.value.isHls) {
|
|
// HLS playback support
|
|
if (Hls.isSupported()) {
|
|
hls.value = new Hls();
|
|
hls.value.loadSource(current.value.url);
|
|
hls.value.attachMedia($audio.value);
|
|
} else if ($audio.value.canPlayType('application/vnd.apple.mpegurl')) {
|
|
$audio.value.src = current.value.url;
|
|
} else {
|
|
console.log('Your browser does not support HLS.');
|
|
}
|
|
} else {
|
|
// Standard streams
|
|
$audio.value.src = current.value.url;
|
|
|
|
// Firefox caches the downloaded stream, this causes playback issues.
|
|
// Giving the browser a new url on each start bypasses the old cache/buffer
|
|
if (navigator.userAgent.includes("Firefox")) {
|
|
$audio.value.src += "?refresh=" + Date.now();
|
|
}
|
|
}
|
|
|
|
$audio.value.load();
|
|
$audio.value.play();
|
|
});
|
|
};
|
|
|
|
const toggle = (url, isStream, isHls) => {
|
|
store.toggle({
|
|
url: url,
|
|
isStream: isStream,
|
|
isHls: isHls,
|
|
});
|
|
};
|
|
|
|
watch(current, (newCurrent) => {
|
|
if (newCurrent.url === null) {
|
|
stop();
|
|
} else {
|
|
play();
|
|
}
|
|
});
|
|
|
|
const getCurrentTime = () => currentTime.value;
|
|
const getDuration = () => duration.value;
|
|
|
|
const getProgress = () => {
|
|
return (duration.value !== 0)
|
|
? +((currentTime.value / duration.value) * 100).toFixed(2)
|
|
: 0;
|
|
};
|
|
|
|
const setProgress = (progress) => {
|
|
if ($audio.value !== null) {
|
|
$audio.value.currentTime = (progress / 100) * duration.value;
|
|
}
|
|
};
|
|
|
|
onMounted(() => {
|
|
// Allow pausing from the mobile metadata update.
|
|
if ('mediaSession' in navigator) {
|
|
navigator.mediaSession.setActionHandler('pause', () => {
|
|
stop();
|
|
});
|
|
}
|
|
});
|
|
|
|
defineExpose({
|
|
play,
|
|
stop,
|
|
toggle,
|
|
getCurrentTime,
|
|
getDuration,
|
|
getProgress,
|
|
setProgress
|
|
});
|
|
</script>
|