2020-02-15 17:41:05 +01:00
|
|
|
<svelte:head>
|
2020-02-22 03:39:15 +01:00
|
|
|
<title>{`${ $current ? `${$current.media.title} ∴ ` : ''}Eldritch Radio`}</title>
|
2020-02-15 17:41:05 +01:00
|
|
|
</svelte:head>
|
|
|
|
|
|
|
|
<div class="app container">
|
|
|
|
<Header></Header>
|
|
|
|
|
2020-02-23 23:18:37 +01:00
|
|
|
<section class="viewer" bind:this={viewerEl}>
|
2020-02-24 09:30:48 +01:00
|
|
|
<Viewer large={large} sticky={sticky}></Viewer>
|
2020-02-15 17:41:05 +01:00
|
|
|
</section>
|
|
|
|
|
|
|
|
<section class="queue">
|
|
|
|
<Queue></Queue>
|
|
|
|
</section>
|
|
|
|
|
|
|
|
<Footer></Footer>
|
2020-02-22 03:50:37 +01:00
|
|
|
|
2020-02-15 17:41:05 +01:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<script>
|
2020-02-23 23:18:37 +01:00
|
|
|
import { setContext, onMount } from 'svelte'
|
2021-11-07 00:11:15 +01:00
|
|
|
import Header from '/src/components/layout/Header.svelte'
|
|
|
|
import Footer from '/src/components/layout/Footer.svelte'
|
|
|
|
import Queue from '/src/components/Queue.svelte'
|
|
|
|
import Viewer from '/src/components/Viewer.svelte'
|
|
|
|
import { get, writable, writableStorage, derived, scan, wait, startWith } from '/src/services/store.js'
|
|
|
|
import { radioIterator, radioShareIterator } from '/src/services/radio.js'
|
|
|
|
import DeepSet from '/src/services/deep-set.js'
|
2020-02-16 17:02:39 +01:00
|
|
|
|
|
|
|
export let share
|
2020-02-23 01:42:09 +01:00
|
|
|
export let large
|
2020-02-23 23:18:37 +01:00
|
|
|
let viewerEl
|
|
|
|
let sticky
|
2020-02-16 17:02:39 +01:00
|
|
|
|
2020-02-20 15:55:22 +01:00
|
|
|
const cache = new DeepSet()
|
|
|
|
|
2021-11-07 00:11:15 +01:00
|
|
|
const domain = writableStorage(localStorage, 'domain', process.env.INSTANCE)
|
2020-02-20 15:55:22 +01:00
|
|
|
|
2020-02-25 17:21:34 +01:00
|
|
|
const hashtags = writableStorage(localStorage, 'hashtags', [
|
2020-02-20 15:55:22 +01:00
|
|
|
'np',
|
|
|
|
'nowplaying',
|
|
|
|
'tootradio',
|
|
|
|
'pouetradio'
|
|
|
|
])
|
|
|
|
|
|
|
|
const paused = writable(true)
|
2020-02-25 17:21:34 +01:00
|
|
|
const volume = writableStorage(localStorage, 'volume', 100)
|
2020-02-20 15:55:22 +01:00
|
|
|
|
|
|
|
const current = writable(null)
|
|
|
|
const enqueueing = writable(false)
|
|
|
|
const loading = writable(false)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const iterator = derived([domain, hashtags], ([$domain, $hashtags], set) => {
|
|
|
|
const iterator = share == null
|
|
|
|
? radioIterator($domain, $hashtags, cache)
|
|
|
|
// this is a bit dump because we always requeue the shared track
|
|
|
|
: radioShareIterator(share, $domain, $hashtags, cache)
|
|
|
|
|
|
|
|
set(iterator)
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
iterator.return()
|
|
|
|
}
|
|
|
|
}, null)
|
|
|
|
|
|
|
|
const next = derived([iterator, current], ([$iterator, $current]) => ({ $iterator, $current }))
|
2020-02-25 17:21:34 +01:00
|
|
|
.pipe(source => {
|
|
|
|
let $next = null
|
|
|
|
|
|
|
|
return writable(undefined, set => {
|
|
|
|
source.subscribe(({ $iterator, $current }) => {
|
|
|
|
if ($current !== null && $next === $current) {
|
|
|
|
$next = null
|
|
|
|
set($next)
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($next === null) {
|
|
|
|
enqueueing.set(true)
|
|
|
|
|
|
|
|
$iterator.next().then(({ done, value }) => {
|
|
|
|
enqueueing.set(false)
|
2020-03-06 13:32:15 +01:00
|
|
|
|
|
|
|
if (done) {
|
|
|
|
console.log('done')
|
|
|
|
set(null)
|
|
|
|
} else {
|
|
|
|
$next = value
|
|
|
|
set($next)
|
|
|
|
}
|
2020-02-25 17:21:34 +01:00
|
|
|
}).catch(console.error)
|
|
|
|
}
|
|
|
|
})
|
2020-02-20 15:55:22 +01:00
|
|
|
})
|
2020-02-25 17:21:34 +01:00
|
|
|
})
|
2020-02-20 15:55:22 +01:00
|
|
|
.pipe(startWith(null))
|
|
|
|
|
|
|
|
|
|
|
|
const queue = next
|
|
|
|
.pipe(scan((a, x) => x == null ? a : [...a, x], []))
|
|
|
|
|
|
|
|
const index = derived([queue, current], ([$queue, $current]) => {
|
|
|
|
const i = $queue.indexOf($current)
|
|
|
|
return i === -1 ? null : i
|
|
|
|
})
|
|
|
|
|
|
|
|
const canPrevious = derived([queue, index], ([$queue, $index]) => $index !== null && $index > 0)
|
|
|
|
const canNext = derived([queue, index], ([$queue, $index]) => $index !== null && $index < $queue.length - 1)
|
|
|
|
|
|
|
|
|
|
|
|
const select = track => {
|
2020-02-22 03:39:15 +01:00
|
|
|
console.log(`Select ${track.media.title}`)
|
2020-02-20 15:55:22 +01:00
|
|
|
current.set(track)
|
|
|
|
}
|
|
|
|
|
|
|
|
const selectPrevious = () => {
|
|
|
|
if (get(canPrevious)) {
|
|
|
|
const $queue = get(queue)
|
|
|
|
const $index = get(index)
|
|
|
|
select($queue[$index - 1])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const selectNext = () => {
|
|
|
|
if (get(canNext)) {
|
|
|
|
const $queue = get(queue)
|
|
|
|
const $index = get(index)
|
|
|
|
select($queue[$index + 1])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setContext('paused', paused)
|
|
|
|
setContext('volume', volume)
|
|
|
|
setContext('domain', domain)
|
|
|
|
setContext('hashtags', hashtags)
|
|
|
|
setContext('current', current)
|
|
|
|
setContext('loading', loading)
|
|
|
|
setContext('enqueueing', enqueueing)
|
|
|
|
setContext('iterator', iterator)
|
|
|
|
setContext('next', next)
|
|
|
|
setContext('queue', queue)
|
|
|
|
setContext('canPrevious', canPrevious)
|
|
|
|
setContext('canNext', canNext)
|
|
|
|
setContext('select', select)
|
|
|
|
setContext('selectPrevious', selectPrevious)
|
|
|
|
setContext('selectNext', selectNext)
|
|
|
|
|
2020-02-18 19:18:46 +01:00
|
|
|
$: if ($queue.length === 1 && $next != null && $current == null) {
|
|
|
|
select($next)
|
|
|
|
}
|
2020-02-23 23:18:37 +01:00
|
|
|
|
|
|
|
onMount(() => {
|
2020-02-25 17:21:34 +01:00
|
|
|
const stickyObserver = new IntersectionObserver(
|
2020-02-23 23:18:37 +01:00
|
|
|
([e]) => {
|
2020-02-25 17:21:34 +01:00
|
|
|
sticky = (e.intersectionRatio === 0)
|
2020-02-23 23:18:37 +01:00
|
|
|
},
|
|
|
|
{threshold: [0]}
|
|
|
|
)
|
|
|
|
|
|
|
|
stickyObserver.observe(viewerEl)
|
|
|
|
})
|
2021-11-05 20:36:19 +01:00
|
|
|
</script>
|