Skip to content

Commit ab50a6c

Browse files
committed
fix: deezer playback and add seekeable support
1 parent ba499a9 commit ab50a6c

2 files changed

Lines changed: 213 additions & 103 deletions

File tree

src/playback/player.js

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -263,11 +263,11 @@ export class Player {
263263
EndReasons.LOAD_FAILED
264264
].includes(state.reason)
265265
) {
266-
if (this.isUpdatingTrack && state.reason === 'finished') {
266+
if ((this.isUpdatingTrack || this._isSeeking) && state.reason === 'finished') {
267267
logger(
268268
'debug',
269269
'Player',
270-
`Ignoring spurious idle/finished event during track replacement for guild ${this.guildId}.`
270+
`Ignoring spurious idle/finished event during track replacement/seek for guild ${this.guildId}.`
271271
)
272272
return
273273
}
@@ -456,7 +456,7 @@ export class Player {
456456
async _fetchResource(info, urlData, startTime) {
457457
await getStreamProcessor()
458458

459-
if (startTime)
459+
if (startTime !== undefined)
460460
urlData.additionalData = { startTime, ...urlData.additionalData }
461461

462462
const track = urlData?.newTrack ? urlData?.newTrack?.info : info
@@ -806,7 +806,7 @@ export class Player {
806806
this._isSeeking = true
807807
try {
808808
const sourceName = this.track.info.sourceName
809-
const unsupportedSources = ['deezer', 'local']
809+
const unsupportedSources = ['local']
810810

811811
let seekPromise
812812
if (!this.streamInfo?.url) {
@@ -844,11 +844,20 @@ export class Player {
844844
)
845845
}
846846
}
847-
if (!unsupportedSources.includes(sourceName) && this.streamInfo?.url) {
847+
848+
const source = this.nodelink.sources.getSource(sourceName)
849+
const canNativeSeek = sourceName === 'deezer' || (source && typeof source.loadStream === 'function')
850+
851+
if (!unsupportedSources.includes(sourceName) && this.streamInfo?.url && sourceName !== 'deezer') {
848852
seekPromise = this._seekeableSeek(
849853
seekPosition,
850854
endTime !== undefined ? endTime : this.track.endTime
851855
)
856+
} else if (canNativeSeek) {
857+
seekPromise = this._seekUsingSource(
858+
seekPosition,
859+
endTime !== undefined ? endTime : this.track.endTime
860+
)
852861
} else {
853862
seekPromise = this._legacySeek(
854863
seekPosition,
@@ -867,6 +876,91 @@ export class Player {
867876
}
868877
}
869878

879+
async _seekUsingSource(position, endTime) {
880+
if (!this.track) return false
881+
882+
logger(
883+
'debug',
884+
'Player',
885+
`Seeking using source (native) to ${position}ms for guild ${this.guildId}`
886+
)
887+
888+
this.position = position
889+
this.track.endTime = endTime
890+
891+
const trackInfo = {
892+
...this.track.info,
893+
audioTrackId: this.track.audioTrackId
894+
}
895+
896+
const urlData = await this.nodelink.sources.getTrackUrl(trackInfo)
897+
this.streamInfo = { ...urlData, trackInfo: this.track.info }
898+
899+
if (urlData.exception) {
900+
const err = new Error(urlData.exception.message)
901+
this._onError(err)
902+
return false
903+
}
904+
905+
if (!this.connection) {
906+
this._initConnection()
907+
}
908+
909+
if (
910+
!this.connection ||
911+
!this.connection.udpInfo ||
912+
!this.connection.udpInfo.secretKey
913+
) {
914+
await this.waitEvent(
915+
'stateChange',
916+
(s) => s.status === 'connected' && this.connection?.udpInfo?.secretKey
917+
)
918+
}
919+
920+
if (
921+
!this.connection ||
922+
!this.connection.udpInfo ||
923+
!this.connection.udpInfo.secretKey
924+
) {
925+
const errorMessage = `Voice connection for guild ${this.guildId} is not ready (missing UDP info). Aborting playback.`
926+
logger('error', 'Player', errorMessage)
927+
this._onError(new Error(errorMessage))
928+
return false
929+
}
930+
931+
const fetched = await this._fetchResource(
932+
this.track.info,
933+
urlData,
934+
position
935+
)
936+
if (fetched.exception) {
937+
const err = new Error(fetched.exception.message)
938+
this._onError(err)
939+
return false
940+
}
941+
942+
if (this.connection.audioStream) {
943+
this.connection.audioStream?.destroy()
944+
}
945+
946+
const resource = fetched.stream
947+
if (this.volumePercent !== 100) {
948+
resource.setVolume(this.volumePercent / 100)
949+
}
950+
951+
this.setFilters(this.filters)
952+
953+
logger(
954+
'debug',
955+
'Player',
956+
`Playing resource for guild ${this.guildId} after source seek`
957+
)
958+
this.connection.play(resource)
959+
await this.waitEvent('playerStateChange', (s) => s.status === 'playing')
960+
961+
return true
962+
}
963+
870964
async _seekeableSeek(position, endTime) {
871965
await getStreamProcessor()
872966

0 commit comments

Comments
 (0)