kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
Fix transcoded track and add info if there are no track sources
rodzic
ab8699783d
commit
34d4f3b25b
|
@ -18,6 +18,7 @@ export interface Sound {
|
||||||
readonly isErrored: Ref<boolean>
|
readonly isErrored: Ref<boolean>
|
||||||
readonly isLoaded: Ref<boolean>
|
readonly isLoaded: Ref<boolean>
|
||||||
readonly currentTime: number
|
readonly currentTime: number
|
||||||
|
readonly playable: boolean
|
||||||
readonly duration: number
|
readonly duration: number
|
||||||
readonly buffered: number
|
readonly buffered: number
|
||||||
looping: boolean
|
looping: boolean
|
||||||
|
@ -54,9 +55,18 @@ export class HTMLSound implements Sound {
|
||||||
onSoundEnd: EventHookOn<HTMLSound>
|
onSoundEnd: EventHookOn<HTMLSound>
|
||||||
|
|
||||||
constructor (sources: SoundSource[]) {
|
constructor (sources: SoundSource[]) {
|
||||||
|
this.onSoundLoop = this.#soundLoopEventHook.on
|
||||||
|
this.onSoundEnd = this.#soundEndEventHook.on
|
||||||
|
|
||||||
// TODO: Quality picker
|
// TODO: Quality picker
|
||||||
|
const source = sources[0]?.url
|
||||||
|
if (!source) {
|
||||||
|
this.isLoaded.value = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
this.#audio.crossOrigin = 'anonymous'
|
this.#audio.crossOrigin = 'anonymous'
|
||||||
this.#audio.src = sources[0].url
|
this.#audio.src = source
|
||||||
this.#audio.preload = 'auto'
|
this.#audio.preload = 'auto'
|
||||||
|
|
||||||
useEventListener(this.#audio, 'ended', () => this.#soundEndEventHook.trigger(this))
|
useEventListener(this.#audio, 'ended', () => this.#soundEndEventHook.trigger(this))
|
||||||
|
@ -75,9 +85,6 @@ export class HTMLSound implements Sound {
|
||||||
this.isErrored.value = true
|
this.isErrored.value = true
|
||||||
this.isLoaded.value = true
|
this.isLoaded.value = true
|
||||||
})
|
})
|
||||||
|
|
||||||
this.onSoundLoop = this.#soundLoopEventHook.on
|
|
||||||
this.onSoundEnd = this.#soundEndEventHook.on
|
|
||||||
}
|
}
|
||||||
|
|
||||||
preload () {
|
preload () {
|
||||||
|
@ -104,6 +111,10 @@ export class HTMLSound implements Sound {
|
||||||
this.#audio.currentTime += seconds
|
this.#audio.currentTime += seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get playable () {
|
||||||
|
return this.#audio.src !== ''
|
||||||
|
}
|
||||||
|
|
||||||
get duration () {
|
get duration () {
|
||||||
const { duration } = this.#audio
|
const { duration } = this.#audio
|
||||||
return isNaN(duration) ? 0 : duration
|
return isNaN(duration) ? 0 : duration
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { useRouter } from 'vue-router'
|
||||||
import { useStore } from '~/store'
|
import { useStore } from '~/store'
|
||||||
|
|
||||||
import { usePlayer } from '~/composables/audio/player'
|
import { usePlayer } from '~/composables/audio/player'
|
||||||
|
import { useTracks } from '~/composables/audio/tracks'
|
||||||
import { useQueue } from '~/composables/audio/queue'
|
import { useQueue } from '~/composables/audio/queue'
|
||||||
|
|
||||||
import time from '~/utils/time'
|
import time from '~/utils/time'
|
||||||
|
@ -42,6 +43,8 @@ const {
|
||||||
clear
|
clear
|
||||||
} = useQueue()
|
} = useQueue()
|
||||||
|
|
||||||
|
const { currentSound } = useTracks()
|
||||||
|
|
||||||
const queueModal = ref()
|
const queueModal = ref()
|
||||||
const { activate, deactivate } = useFocusTrap(queueModal, { allowOutsideClick: true, preventScroll: true })
|
const { activate, deactivate } = useFocusTrap(queueModal, { allowOutsideClick: true, preventScroll: true })
|
||||||
|
|
||||||
|
@ -204,7 +207,7 @@ const hideArtist = () => {
|
||||||
The track cannot be loaded
|
The track cannot be loaded
|
||||||
</translate>
|
</translate>
|
||||||
</h3>
|
</h3>
|
||||||
<p v-if="hasNext && isPlaying && errored">
|
<p v-if="hasNext && isPlaying">
|
||||||
<translate translate-context="Sidebar/Player/Error message.Paragraph">
|
<translate translate-context="Sidebar/Player/Error message.Paragraph">
|
||||||
The next track will play automatically in a few seconds…
|
The next track will play automatically in a few seconds…
|
||||||
</translate>
|
</translate>
|
||||||
|
@ -216,6 +219,22 @@ const hideArtist = () => {
|
||||||
</translate>
|
</translate>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-else-if="currentSound && !currentSound.playable"
|
||||||
|
class="ui small warning message"
|
||||||
|
>
|
||||||
|
<h3 class="header">
|
||||||
|
<translate translate-context="Sidebar/Player/No sources">
|
||||||
|
The track has no available sources
|
||||||
|
</translate>
|
||||||
|
</h3>
|
||||||
|
<p v-if="hasNext && isPlaying">
|
||||||
|
<translate translate-context="Sidebar/Player/Error message.Paragraph">
|
||||||
|
The next track will play automatically in a few seconds…
|
||||||
|
</translate>
|
||||||
|
<i class="loading spinner icon" />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
<div class="additional-controls desktop-and-below">
|
<div class="additional-controls desktop-and-below">
|
||||||
<track-favorite-icon
|
<track-favorite-icon
|
||||||
v-if="$store.state.auth.authenticated"
|
v-if="$store.state.auth.authenticated"
|
||||||
|
|
|
@ -20,9 +20,6 @@ const soundCache = useLRUCache<number, Sound>({ max: 10 })
|
||||||
|
|
||||||
const getTrackSources = (track: QueueTrack): QueueTrackSource[] => {
|
const getTrackSources = (track: QueueTrack): QueueTrackSource[] => {
|
||||||
const sources: QueueTrackSource[] = track.sources
|
const sources: QueueTrackSource[] = track.sources
|
||||||
// NOTE: Filter out repeating and unplayable media types
|
|
||||||
.filter(({ mimetype, bitrate }, index, array) => array.findIndex((upload) => upload.mimetype + upload.bitrate === mimetype + bitrate) === index)
|
|
||||||
.filter(({ mimetype }) => ALLOWED_PLAY_TYPES.includes(AUDIO_ELEMENT.canPlayType(`${mimetype}`)))
|
|
||||||
.map((source) => ({
|
.map((source) => ({
|
||||||
...source,
|
...source,
|
||||||
url: store.getters['instance/absoluteUrl'](source.url) as string
|
url: store.getters['instance/absoluteUrl'](source.url) as string
|
||||||
|
@ -40,6 +37,9 @@ const getTrackSources = (track: QueueTrack): QueueTrackSource[] => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return sources
|
return sources
|
||||||
|
// NOTE: Filter out repeating and unplayable media types
|
||||||
|
.filter(({ mimetype, bitrate }, index, array) => array.findIndex((upload) => upload.mimetype + upload.bitrate === mimetype + bitrate) === index)
|
||||||
|
.filter(({ mimetype }) => ALLOWED_PLAY_TYPES.includes(AUDIO_ELEMENT.canPlayType(`${mimetype}`)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use Tracks
|
// Use Tracks
|
||||||
|
@ -59,12 +59,14 @@ export const useTracks = createGlobalState(() => {
|
||||||
|
|
||||||
const SoundImplementation = soundImplementation.value
|
const SoundImplementation = soundImplementation.value
|
||||||
const sound = new SoundImplementation(sources)
|
const sound = new SoundImplementation(sources)
|
||||||
|
|
||||||
sound.onSoundEnd(() => {
|
sound.onSoundEnd(() => {
|
||||||
console.log('TRACK ENDED, PLAYING NEXT')
|
console.log('TRACK ENDED, PLAYING NEXT')
|
||||||
|
|
||||||
// NOTE: We push it to the end of the job queue
|
// NOTE: We push it to the end of the job queue
|
||||||
setTimeout(() => playNext(), 0)
|
setTimeout(() => playNext(), 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
soundCache.set(track.id, sound)
|
soundCache.set(track.id, sound)
|
||||||
soundPromises.delete(track.id)
|
soundPromises.delete(track.id)
|
||||||
return sound
|
return sound
|
||||||
|
@ -87,12 +89,25 @@ export const useTracks = createGlobalState(() => {
|
||||||
const createTrack = async (index: number) => {
|
const createTrack = async (index: number) => {
|
||||||
stopPreloadTimeout()
|
stopPreloadTimeout()
|
||||||
|
|
||||||
const { queue, currentIndex } = useQueue()
|
const { queue, currentIndex, playNext, hasNext } = useQueue()
|
||||||
if (queue.value.length <= index || index === -1) return
|
if (queue.value.length <= index || index === -1) return
|
||||||
console.log('LOADING TRACK', index)
|
console.log('LOADING TRACK', index)
|
||||||
|
|
||||||
const track = queue.value[index]
|
const track = queue.value[index]
|
||||||
const sound = await createSound(track)
|
const sound = await createSound(track)
|
||||||
|
|
||||||
|
if (!sound.playable) {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (hasNext.value && index !== queue.value.length - 1) {
|
||||||
|
return playNext(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { isPlaying } = usePlayer()
|
||||||
|
isPlaying.value = false
|
||||||
|
}, 3000)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
console.log('CONNECTING NODE')
|
console.log('CONNECTING NODE')
|
||||||
|
|
||||||
sound.audioNode.disconnect()
|
sound.audioNode.disconnect()
|
||||||
|
|
Ładowanie…
Reference in New Issue