fuc-new/doc/node_modules/vuepress-plugin-md-power/lib/client/composables/audio.js
hellcat 6adbc04d4b 1
2025-10-03 17:17:08 +08:00

172 lines
4.7 KiB
JavaScript

import { onMounted, onUnmounted, ref, toValue, watch } from "vue";
//#region src/client/composables/audio.ts
const mimeTypes = {
"audio/flac": ["flac", "fla"],
"audio/mpeg": ["mp3", "mpga"],
"audio/mp4": ["mp4", "m4a"],
"audio/ogg": ["ogg", "oga"],
"audio/aac": ["aac", "adts"],
"audio/x-ms-wma": ["wma"],
"audio/x-aiff": [
"aiff",
"aif",
"aifc"
],
"audio/webm": ["webm"]
};
const playerList = [];
function useAudioPlayer(source, options = {}) {
let player = null;
let unknownSupport = false;
const isSupported = ref(false);
const loaded = ref(false);
const paused = ref(true);
const currentTime = ref(0);
const duration = ref(0);
const volume = ref(1);
function initialize() {
player = document.createElement("audio");
player.className = "audio-player";
player.style.display = "none";
player.preload = options.autoplay ? "auto" : "none";
player.autoplay = options.autoplay ?? false;
document.body.appendChild(player);
playerList.push(player);
player.onloadedmetadata = () => {
duration.value = player.duration;
currentTime.value = player.currentTime;
volume.value = player.volume;
loaded.value = true;
};
player.oncanplay = (...args) => {
loaded.value = true;
if (unknownSupport) isSupported.value = true;
options.oncanplay?.bind(player)(...args);
};
player.onplay = (...args) => {
paused.value = false;
options.onplay?.bind(player)(...args);
};
player.onpause = (...args) => {
paused.value = true;
options.onpause?.bind(player)(...args);
};
player.ontimeupdate = () => {
if (isValidDuration(player.duration)) {
const lastBufferTime = getLastBufferedTime();
if (lastBufferTime <= player.duration) {
options.ontimeupdate?.bind(player)(lastBufferTime);
currentTime.value = lastBufferTime;
options.onprogress?.bind(player)(lastBufferTime, player.duration);
}
}
};
player.onvolumechange = () => {
volume.value = player.volume;
options.onvolume?.bind(player)(player.volume);
};
player.onended = (...args) => {
paused.value = true;
options.onend?.bind(player)(...args);
};
player.onplaying = options.onplaying;
player.onload = options.onload;
player.onerror = options.onerror;
player.onseeked = options.onseeked;
player.oncanplaythrough = options.oncanplaythrough;
player.onwaiting = options.onwaiting;
isSupported.value = isSupportType();
player.src = toValue(source);
player.load();
}
function isSupportType() {
if (!player) return false;
let type = toValue(options.type);
if (!type) {
const ext = toValue(source).split(".").pop() || "";
type = Object.keys(mimeTypes).filter((type$1) => mimeTypes[type$1].includes(ext))[0];
}
if (!type) {
unknownSupport = true;
return false;
}
const isSupported$1 = player.canPlayType(type) !== "";
if (!isSupported$1) console.warn(`The specified type "${type}" is not supported by the browser.`);
return isSupported$1;
}
function getBufferedRanges() {
if (!player) return [];
const ranges = [];
const seekable = player.buffered || [];
const offset = 0;
for (let i = 0, length = seekable.length; i < length; i++) {
let start = seekable.start(i);
let end = seekable.end(i);
if (!isValidDuration(start)) start = 0;
if (!isValidDuration(end)) {
end = 0;
continue;
}
ranges.push({
start: start + offset,
end: end + offset
});
}
return ranges;
}
function getLastBufferedTime() {
const bufferedRanges = getBufferedRanges();
if (!bufferedRanges.length) return 0;
const buff = bufferedRanges.find((buff$1) => buff$1.start < player.currentTime && buff$1.end > player.currentTime);
if (buff) return buff.end;
return bufferedRanges[bufferedRanges.length - 1].end;
}
function isValidDuration(duration$1) {
if (duration$1 && !Number.isNaN(duration$1) && duration$1 !== Number.POSITIVE_INFINITY && duration$1 !== Number.NEGATIVE_INFINITY) return true;
return false;
}
function destroy() {
player?.pause();
player?.remove();
playerList.splice(playerList.indexOf(player), 1);
player = null;
}
onMounted(() => {
initialize();
watch([source, options.type], () => {
destroy();
loaded.value = false;
paused.value = true;
currentTime.value = 0;
duration.value = 0;
initialize();
});
});
onUnmounted(() => destroy());
return {
isSupported,
paused,
loaded,
currentTime,
duration,
player,
destroy,
play: () => {
if (options.mutex ?? true) {
for (const p of playerList) if (p !== player) p.pause();
}
player?.play();
},
pause: () => player?.pause(),
seek(time) {
if (player) player.currentTime = time;
},
setVolume(volume$1) {
if (player) player.volume = Math.min(1, Math.max(0, volume$1));
}
};
}
//#endregion
export { useAudioPlayer };