mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-26 17:01:20 -08:00
feat: add danmuku plugin and i18n setup documentation - Introduced a new danmuku plugin with multiple run code options in the documentation. - Added language settings documentation for i18n, including default languages, import instructions, and examples for adding and modifying languages. - Implemented input handling for media sources in the artplayer-proxy-mediabunny package, supporting various formats including HLS. - Created m3u8 control functionalities for managing audio and video quality settings in the player. Update mediabunny.js
121 lines
3.3 KiB
JavaScript
121 lines
3.3 KiB
JavaScript
import {
|
|
ALL_FORMATS,
|
|
BlobSource,
|
|
HLS_FORMATS,
|
|
Input,
|
|
ReadableStreamSource,
|
|
UrlSource,
|
|
} from 'mediabunny'
|
|
|
|
const M3U8_RE = /\.m3u8(?:$|[?#])/i
|
|
|
|
export function isHlsSource(src) {
|
|
return typeof src === 'string' && M3U8_RE.test(src)
|
|
}
|
|
|
|
export function normalizeSource(src) {
|
|
if (typeof src === 'string')
|
|
return new UrlSource(src)
|
|
if (src instanceof Blob)
|
|
return new BlobSource(src)
|
|
if (typeof ReadableStream !== 'undefined' && src instanceof ReadableStream) {
|
|
return new ReadableStreamSource(src)
|
|
}
|
|
return src ?? null
|
|
}
|
|
|
|
export function createInput(src) {
|
|
const source = normalizeSource(src)
|
|
if (!source)
|
|
return null
|
|
|
|
return new Input({
|
|
source,
|
|
formats: isHlsSource(src) ? HLS_FORMATS : ALL_FORMATS,
|
|
})
|
|
}
|
|
|
|
export async function resolveDuration({ input, videoTrack, audioTrack }) {
|
|
const tracks = [videoTrack, audioTrack].filter(Boolean)
|
|
const referenceTrack = videoTrack || audioTrack
|
|
const isLive = Boolean(referenceTrack && await referenceTrack.isLive())
|
|
|
|
let duration = Number.NaN
|
|
if (tracks.length > 0) {
|
|
duration = await input.getDurationFromMetadata(tracks, { skipLiveWait: true })
|
|
if (duration === null && !isLive) {
|
|
duration = await input.computeDuration(tracks, { skipLiveWait: true })
|
|
}
|
|
}
|
|
|
|
return isLive ? Number.POSITIVE_INFINITY : duration ?? Number.NaN
|
|
}
|
|
|
|
export async function selectPlaybackTracks(input, src) {
|
|
const videoTrack = await input.getPrimaryVideoTrack()
|
|
const audioTrack = videoTrack
|
|
? await videoTrack.getPrimaryPairableAudioTrack()
|
|
: await input.getPrimaryAudioTrack()
|
|
const duration = await resolveDuration({ input, videoTrack, audioTrack })
|
|
|
|
return {
|
|
input,
|
|
videoTrack,
|
|
audioTrack,
|
|
duration,
|
|
isLive: Number.isFinite(duration) ? false : Boolean((videoTrack || audioTrack) && await (videoTrack || audioTrack).isLive()),
|
|
isHls: isHlsSource(src),
|
|
videoMode: isHlsSource(src) ? 'auto' : 'manual',
|
|
audioMode: isHlsSource(src) ? 'auto' : 'manual',
|
|
}
|
|
}
|
|
|
|
async function getTrackBitrate(track) {
|
|
return await track.getAverageBitrate() ?? await track.getBitrate() ?? 0
|
|
}
|
|
|
|
export async function getHlsState(media) {
|
|
if (!media?.isHls || !media.input)
|
|
return null
|
|
|
|
const [videoTracks, pairableAudioTracks] = await Promise.all([
|
|
media.input.getVideoTracks(),
|
|
media.videoTrack
|
|
? media.videoTrack.getPairableAudioTracks()
|
|
: [],
|
|
])
|
|
|
|
const [levels, audios] = await Promise.all([
|
|
Promise.all(videoTracks.map(async (track, index) => ({
|
|
id: track.id,
|
|
track,
|
|
index,
|
|
name: await track.getName(),
|
|
height: await track.getDisplayHeight(),
|
|
bitrate: await getTrackBitrate(track),
|
|
}))),
|
|
Promise.all(pairableAudioTracks.map(async (track, index) => {
|
|
const name = await track.getName()
|
|
const language = await track.getLanguageCode()
|
|
return {
|
|
id: track.id,
|
|
track,
|
|
index,
|
|
name,
|
|
lang: language,
|
|
language,
|
|
bitrate: await getTrackBitrate(track),
|
|
}
|
|
})),
|
|
])
|
|
|
|
return {
|
|
levels,
|
|
audios,
|
|
currentLevel: media.videoTrack ? levels.find(item => item.id === media.videoTrack.id) ?? null : null,
|
|
currentAudio: media.audioTrack ? audios.find(item => item.id === media.audioTrack.id) ?? null : null,
|
|
videoMode: media.videoMode ?? 'auto',
|
|
audioMode: media.audioMode ?? 'auto',
|
|
}
|
|
}
|