// Simulates the Mopidy JSON-RPC WebSocket API. const TRACKS = [ { uri: 'mock:track:1', name: 'Ocean Drive', artists: [{ name: 'Duke Dumont' }], album: { name: 'Ocean Drive', images: [] }, length: 232000, }, { uri: 'mock:track:2', name: 'Feel It Still', artists: [{ name: 'Portugal. The Man' }], album: { name: 'Woodstock', images: [] }, length: 178000, }, { uri: 'mock:track:3', name: 'Sailing', artists: [{ name: 'Christopher Cross' }], album: { name: 'Christopher Cross', images: [] }, length: 261000, }, { uri: 'mock:track:4', name: 'Beyond the Sea', artists: [{ name: 'Bobby Darin' }], album: { name: 'That\'s All', images: [] }, length: 185000, }, { uri: 'mock:track:5', name: 'Into the Mystic', artists: [{ name: 'Van Morrison' }], album: { name: 'Moondance', images: [] }, length: 215000, }, ] const RADIO_STATIONS = [ { uri: 'http://stream.swr3.de/swr3/mp3-128/stream.mp3', name: 'SWR3' }, { uri: 'http://ndr.de/ndr1welle-nord-128.mp3', name: 'NDR 1 Welle Nord' }, { uri: 'http://live-bauhaus.radiobt.de/bauhaus/mp3-128', name: 'Radio Bauhaus' }, ] export function createMopidyMock() { let state = 'playing' let currentIndex = 0 let position = 0 let positionTimer = null const listeners = {} function emit(event, data) { if (listeners[event]) listeners[event].forEach(fn => fn(data)) } function startTimer() { if (positionTimer) return positionTimer = setInterval(() => { if (state === 'playing') { position += 1000 const track = TRACKS[currentIndex] if (position >= track.length) { currentIndex = (currentIndex + 1) % TRACKS.length position = 0 emit('event:trackPlaybackStarted', { tl_track: { track: TRACKS[currentIndex] } }) } } }, 1000) } startTimer() async function call(method, params = {}) { await new Promise(r => setTimeout(r, 15)) switch (method) { case 'playback.get_current_track': return TRACKS[currentIndex] case 'playback.get_state': return state case 'playback.get_time_position': return position case 'playback.play': state = 'playing' emit('event:playbackStateChanged', { new_state: 'playing' }) return null case 'playback.pause': state = 'paused' emit('event:playbackStateChanged', { new_state: 'paused' }) return null case 'playback.stop': state = 'stopped' position = 0 emit('event:playbackStateChanged', { new_state: 'stopped' }) return null case 'playback.next': currentIndex = (currentIndex + 1) % TRACKS.length position = 0 state = 'playing' emit('event:trackPlaybackStarted', { tl_track: { track: TRACKS[currentIndex] } }) return null case 'playback.previous': currentIndex = (currentIndex - 1 + TRACKS.length) % TRACKS.length position = 0 state = 'playing' emit('event:trackPlaybackStarted', { tl_track: { track: TRACKS[currentIndex] } }) return null case 'playback.seek': position = params.time_position || 0 return null case 'tracklist.get_tracks': return TRACKS case 'library.browse': return TRACKS.map(t => ({ uri: t.uri, name: t.name, type: 'track' })) case 'library.search': return [{ tracks: TRACKS }] default: return null } } return { call, on(event, fn) { if (!listeners[event]) listeners[event] = [] listeners[event].push(fn) }, off(event, fn) { if (listeners[event]) listeners[event] = listeners[event].filter(l => l !== fn) }, getTracks: () => TRACKS, getRadioStations: () => RADIO_STATIONS, } }