77 lines
2.1 KiB
JavaScript
77 lines
2.1 KiB
JavaScript
|
|
import subsonic from '../subsonic/index.js'
|
||
|
|
import { playTracks } from '../actions/index.js'
|
||
|
|
|
||
|
|
const shuffleArray = (array) => {
|
||
|
|
const shuffled = [...array]
|
||
|
|
for (let i = shuffled.length - 1; i > 0; i--) {
|
||
|
|
const j = Math.floor(Math.random() * (i + 1))
|
||
|
|
;[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]
|
||
|
|
}
|
||
|
|
return shuffled
|
||
|
|
}
|
||
|
|
|
||
|
|
const mapReplayGain = (song) => {
|
||
|
|
const { replayGain: rg } = song
|
||
|
|
if (!rg) {
|
||
|
|
return song
|
||
|
|
}
|
||
|
|
|
||
|
|
return {
|
||
|
|
...song,
|
||
|
|
...(rg.albumGain !== undefined && { rgAlbumGain: rg.albumGain }),
|
||
|
|
...(rg.albumPeak !== undefined && { rgAlbumPeak: rg.albumPeak }),
|
||
|
|
...(rg.trackGain !== undefined && { rgTrackGain: rg.trackGain }),
|
||
|
|
...(rg.trackPeak !== undefined && { rgTrackPeak: rg.trackPeak }),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export const processSongsForPlayback = (songs) => {
|
||
|
|
const songData = {}
|
||
|
|
const ids = []
|
||
|
|
songs.forEach((s) => {
|
||
|
|
const song = mapReplayGain(s)
|
||
|
|
songData[song.id] = song
|
||
|
|
ids.push(song.id)
|
||
|
|
})
|
||
|
|
return { songData, ids }
|
||
|
|
}
|
||
|
|
|
||
|
|
export const playSimilar = async (dispatch, notify, id, options = {}) => {
|
||
|
|
const { seedRecord = null, shuffle = false } = options
|
||
|
|
|
||
|
|
const res = await subsonic.getSimilarSongs2(id, 100)
|
||
|
|
const data = res.json['subsonic-response']
|
||
|
|
|
||
|
|
if (data.status !== 'ok') {
|
||
|
|
throw new Error(
|
||
|
|
`Error fetching similar songs: ${data.error?.message || 'Unknown error'} (Code: ${data.error?.code || 'unknown'})`,
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
let songs = data.similarSongs2?.song || []
|
||
|
|
|
||
|
|
// Randomize similar songs if requested
|
||
|
|
if (shuffle) {
|
||
|
|
songs = shuffleArray(songs)
|
||
|
|
}
|
||
|
|
|
||
|
|
// If no similar songs found and no seed, show warning
|
||
|
|
if (!songs.length && !seedRecord) {
|
||
|
|
notify('message.noSimilarSongsFound', 'warning')
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
const { songData, ids } = processSongsForPlayback(songs)
|
||
|
|
|
||
|
|
// Prepend seed song if provided
|
||
|
|
if (seedRecord) {
|
||
|
|
const seedId = seedRecord.mediaFileId || seedRecord.id
|
||
|
|
// Remove seed from similar songs if it appears there
|
||
|
|
const filteredIds = ids.filter((songId) => songId !== seedId)
|
||
|
|
songData[seedId] = mapReplayGain(seedRecord)
|
||
|
|
dispatch(playTracks(songData, [seedId, ...filteredIds]))
|
||
|
|
} else {
|
||
|
|
dispatch(playTracks(songData, ids))
|
||
|
|
}
|
||
|
|
}
|