improve overrides

This commit is contained in:
SrGooglo 2025-02-05 20:28:13 +00:00
parent 3b04ef6044
commit dde659ef01
2 changed files with 165 additions and 149 deletions

View File

@ -2,188 +2,197 @@ import TrackManifest from "./TrackManifest"
import { MediaPlayer } from "dashjs" import { MediaPlayer } from "dashjs"
export default class TrackInstance { export default class TrackInstance {
constructor(player, manifest) { constructor(player, manifest) {
if (!player) { if (!player) {
throw new Error("Player core is required") throw new Error("Player core is required")
} }
if (typeof manifest === "undefined") { if (typeof manifest === "undefined") {
throw new Error("Manifest is required") throw new Error("Manifest is required")
} }
this.player = player this.player = player
this.manifest = manifest this.manifest = manifest
this.id = this.manifest.id ?? this.manifest._id this.id = this.manifest.id ?? this.manifest._id
return this return this
} }
_initialized = false _initialized = false
audio = null audio = null
contextElement = null contextElement = null
abortController = new AbortController() abortController = new AbortController()
attachedProcessors = [] attachedProcessors = []
waitUpdateTimeout = null waitUpdateTimeout = null
mediaEvents = { mediaEvents = {
"ended": () => { ended: () => {
this.player.next() this.player.next()
}, },
"loadeddata": () => { loadeddata: () => {
this.player.state.loading = false this.player.state.loading = false
}, },
"loadedmetadata": () => { loadedmetadata: () => {
// TODO: Detect a livestream and change mode // TODO: Detect a livestream and change mode
// if (instance.media.duration === Infinity) { // if (instance.media.duration === Infinity) {
// instance.manifest.stream = true // instance.manifest.stream = true
// this.state.livestream_mode = true
// }
},
play: () => {
this.player.state.playback_status = "playing"
},
playing: () => {
this.player.state.loading = false
// this.state.livestream_mode = true this.player.state.playback_status = "playing"
// }
},
"play": () => {
this.player.state.playback_status = "playing"
},
"playing": () => {
this.player.state.loading = false
this.player.state.playback_status = "playing" if (typeof this.waitUpdateTimeout !== "undefined") {
clearTimeout(this.waitUpdateTimeout)
this.waitUpdateTimeout = null
}
},
pause: () => {
this.player.state.playback_status = "paused"
},
durationchange: () => {
this.player.eventBus.emit(
`player.durationchange`,
this.audio.duration,
)
},
waiting: () => {
if (this.waitUpdateTimeout) {
clearTimeout(this.waitUpdateTimeout)
this.waitUpdateTimeout = null
}
if (typeof this.waitUpdateTimeout !== "undefined") { // if takes more than 150ms to load, update loading state
clearTimeout(this.waitUpdateTimeout) this.waitUpdateTimeout = setTimeout(() => {
this.waitUpdateTimeout = null this.player.state.loading = true
} }, 150)
}, },
"pause": () => { seeked: () => {
this.player.state.playback_status = "paused" this.player.eventBus.emit(`player.seeked`, this.audio.currentTime)
}, },
"durationchange": () => { }
this.player.eventBus.emit(`player.durationchange`, this.audio.duration)
},
"waiting": () => {
if (this.waitUpdateTimeout) {
clearTimeout(this.waitUpdateTimeout)
this.waitUpdateTimeout = null
}
// if takes more than 150ms to load, update loading state initialize = async () => {
this.waitUpdateTimeout = setTimeout(() => { this.manifest = await this.resolveManifest()
this.player.state.loading = true
}, 150)
},
"seeked": () => {
this.player.eventBus.emit(`player.seeked`, this.audio.currentTime)
},
}
initialize = async () => { this.audio = new Audio()
this.manifest = await this.resolveManifest()
this.audio = new Audio() this.audio.signal = this.abortController.signal
this.audio.crossOrigin = "anonymous"
this.audio.preload = "metadata"
this.audio.signal = this.abortController.signal // support for dash audio streaming
this.audio.crossOrigin = "anonymous" if (this.manifest.source.endsWith(".mpd")) {
this.audio.preload = "metadata" this.muxerPlayer = MediaPlayer().create()
this.muxerPlayer.initialize(this.audio, null, false)
// support for dash audio streaming this.muxerPlayer.attachSource(this.manifest.source)
if (this.manifest.source.endsWith(".mpd")) { } else {
this.muxerPlayer = MediaPlayer().create() this.audio.src = this.manifest.source
this.muxerPlayer.initialize(this.audio, null, false) }
this.muxerPlayer.attachSource(this.manifest.source) for (const [key, value] of Object.entries(this.mediaEvents)) {
} else { this.audio.addEventListener(key, value)
this.audio.src = this.manifest.source }
}
for (const [key, value] of Object.entries(this.mediaEvents)) { this.contextElement = this.player.audioContext.createMediaElementSource(
this.audio.addEventListener(key, value) this.audio,
} )
this.contextElement = this.player.audioContext.createMediaElementSource(this.audio) this._initialized = true
this._initialized = true return this
}
return this stop = () => {
} if (this.audio) {
this.audio.pause()
}
stop = () => { if (this.muxerPlayer) {
if (this.audio) { this.muxerPlayer.destroy()
this.audio.pause() }
}
if (this.muxerPlayer) { const lastProcessor =
this.muxerPlayer.destroy() this.attachedProcessors[this.attachedProcessors.length - 1]
}
const lastProcessor = this.attachedProcessors[this.attachedProcessors.length - 1] if (lastProcessor) {
this.attachedProcessors[
this.attachedProcessors.length - 1
]._destroy(this)
}
if (lastProcessor) { this.attachedProcessors = []
this.attachedProcessors[this.attachedProcessors.length - 1]._destroy(this) }
}
this.attachedProcessors = [] resolveManifest = async () => {
} if (typeof this.manifest === "string") {
this.manifest = {
src: this.manifest,
}
}
resolveManifest = async () => { this.manifest = new TrackManifest(this.manifest, {
if (typeof this.manifest === "string") { serviceProviders: this.player.serviceProviders,
this.manifest = { })
src: this.manifest,
}
}
this.manifest = new TrackManifest(this.manifest, { if (this.manifest.service) {
serviceProviders: this.player.serviceProviders, if (!this.player.serviceProviders.has(this.manifest.service)) {
}) throw new Error(
`Service ${this.manifest.service} is not supported`,
)
}
if (this.manifest.service) { // try to resolve source file
if (!this.player.serviceProviders.has(this.manifest.service)) { if (!this.manifest.source) {
throw new Error(`Service ${this.manifest.service} is not supported`) console.log("Resolving manifest cause no source defined")
}
// try to resolve source file this.manifest = await this.player.serviceProviders.resolve(
if (!this.manifest.source) { this.manifest.service,
console.log("Resolving manifest cause no source defined") this.manifest,
)
this.manifest = await this.player.serviceProviders.resolve(this.manifest.service, this.manifest) console.log("Manifest resolved", this.manifest)
}
}
console.log("Manifest resolved", this.manifest) if (!this.manifest.source) {
} throw new Error("Manifest `source` is required")
} }
if (!this.manifest.source) { // set empty metadata if not provided
throw new Error("Manifest `source` is required") if (!this.manifest.metadata) {
} this.manifest.metadata = {}
}
// set empty metadata if not provided // auto name if a title is not provided
if (!this.manifest.metadata) { if (!this.manifest.metadata.title) {
this.manifest.metadata = {} this.manifest.metadata.title = this.manifest.source.split("/").pop()
} }
// auto name if a title is not provided // process overrides
if (!this.manifest.metadata.title) { const override = await this.manifest.serviceOperations.fetchOverride()
this.manifest.metadata.title = this.manifest.source.split("/").pop()
}
// check if has overrides if (override) {
const override = await this.manifest.serviceOperations.fetchOverride() console.log(
`Override found for track ${this.manifest._id}`,
override,
)
if (override) { this.manifest.overrides = override
console.log(`Override found for track ${this.manifest._id}`, override) }
this.manifest.overrides = override
}
// FIXME: idk why this is here, move somewhere else return this.manifest
// try { }
// this.manifest = await this.manifest.analyzeCoverColor()
// } catch (error) {
// //x
// }
return this.manifest
}
} }

View File

@ -73,10 +73,6 @@ export default class TrackManifest {
lyrics_enabled = false lyrics_enabled = false
liked = null liked = null
// TODO: implement this server feature to fetch some data from the server,
// used for example to fix a incorrect lyrics time
overrides = null
async initialize() { async initialize() {
if (this.params.file) { if (this.params.file) {
this.metadata = await this.analyzeMetadata( this.metadata = await this.analyzeMetadata(
@ -167,11 +163,22 @@ export default class TrackManifest {
return null return null
} }
return await this.ctx.serviceProviders.operation( const result = await this.ctx.serviceProviders.operation(
"resolveLyrics", "resolveLyrics",
this.service, this.service,
this, this,
) )
console.log(this.overrides)
if (this.overrides) {
return {
...result,
...this.overrides,
}
}
return result
}, },
fetchOverride: async () => { fetchOverride: async () => {
if (!this._id) { if (!this._id) {