forked from Mastodon/mastoradio-la-radio-di-mastodon
refact store again
This commit is contained in:
parent
9b87708077
commit
dacc31ce77
|
@ -3,3 +3,4 @@ dist
|
||||||
public
|
public
|
||||||
.cache
|
.cache
|
||||||
.env
|
.env
|
||||||
|
.now
|
|
@ -21,11 +21,65 @@
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { onMount, onDestroy } from 'svelte'
|
||||||
|
import { get } from 'svelte/store'
|
||||||
|
|
||||||
import Controls from '/components/Controls.svelte'
|
import Controls from '/components/Controls.svelte'
|
||||||
import Queue from '/components/Queue.svelte'
|
import Queue from '/components/Queue.svelte'
|
||||||
import Viewer from '/components/Viewer.svelte'
|
import Viewer from '/components/Viewer.svelte'
|
||||||
|
import { hashtagIterator } from '/services/mastodon.js'
|
||||||
|
import { mkTracksIterator } from '/services/misc.js'
|
||||||
|
|
||||||
import { current } from '/store.js'
|
import { domain, hashtags, queue, next, current, enqueueing, select } from '/store.js'
|
||||||
|
|
||||||
|
let nextUnsubcribe = null
|
||||||
|
let currentUnsubcribe = null
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
const iterator = mkTracksIterator(hashtagIterator(get(domain), get(hashtags)[0]))
|
||||||
|
|
||||||
|
const { value: first } = await iterator.next()
|
||||||
|
|
||||||
|
queue.set([first])
|
||||||
|
select(first)
|
||||||
|
|
||||||
|
nextUnsubcribe = next.subscribe(async nextValue => {
|
||||||
|
if (nextValue === null) {
|
||||||
|
if (!get(enqueueing)) {
|
||||||
|
enqueueing.set(true)
|
||||||
|
|
||||||
|
const { value: newTrack } = await iterator.next()
|
||||||
|
|
||||||
|
if (newTrack) {
|
||||||
|
queue.update(queueValue => [...queueValue, newTrack])
|
||||||
|
next.set(newTrack)
|
||||||
|
}
|
||||||
|
|
||||||
|
enqueueing.set(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
currentUnsubcribe = current.subscribe(currentValue => {
|
||||||
|
if (currentValue !== null) {
|
||||||
|
next.update(nextValue => {
|
||||||
|
if (nextValue === currentValue) {
|
||||||
|
return null
|
||||||
|
} else {
|
||||||
|
return nextValue
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
for (const unsubcribe of [nextUnsubcribe, currentUnsubcribe]) {
|
||||||
|
if (unsubcribe) {
|
||||||
|
unsubcribe()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<button class:cant={!$canPrevious} on:click={() => selectPrevious()}>⏮️</button>
|
<button class:cant={!$canPrevious} on:click={() => selectPrevious()}>⏮️</button>
|
||||||
|
|
||||||
<button on:click={() => $paused = !$paused}>
|
<button on:click={() => $paused = !$paused}>
|
||||||
{#if $index === null}
|
{#if $current === null}
|
||||||
▶️
|
▶️
|
||||||
{:else if $loading}
|
{:else if $loading}
|
||||||
🕒
|
🕒
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
paused,
|
paused,
|
||||||
muted,
|
muted,
|
||||||
volume,
|
volume,
|
||||||
index,
|
current,
|
||||||
queue,
|
queue,
|
||||||
canPrevious,
|
canPrevious,
|
||||||
canNext,
|
canNext,
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<div>
|
<div>
|
||||||
<h6>PLAY NEXT</h6>
|
<h6>PLAY NEXT</h6>
|
||||||
|
|
||||||
{#if $next}
|
{#if $next}
|
||||||
<div class="entry">
|
<div class="entry" on:click={() => select($next)}>
|
||||||
<div class="title">{$next.metadata.title}</div>
|
<div class="title">{$next.metadata.title}</div>
|
||||||
<div class="user">by {$next.status.account.acct}</div>
|
<div class="user">by {$next.status.account.acct}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -13,54 +14,32 @@
|
||||||
|
|
||||||
|
|
||||||
<h6>HISTORY</h6>
|
<h6>HISTORY</h6>
|
||||||
{#each $queue as track, i (track.status.id)}
|
|
||||||
<div class="entry" class:active={i === $index}>
|
|
||||||
<div>
|
|
||||||
<button on:click={() => toggle(i)}>
|
|
||||||
{#if i != $index}
|
|
||||||
▶️
|
|
||||||
{:else if $loading}
|
|
||||||
🕒
|
|
||||||
{:else if $paused}
|
|
||||||
▶️
|
|
||||||
{:else}
|
|
||||||
⏸️
|
|
||||||
{/if}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="title">{track.metadata.title}</div>
|
{#each history as track (track.status.id)}
|
||||||
<div class="user">by {track.status.account.acct}</div>
|
<div class="entry" class:active={track === $current} on:click={() => select(track)}>
|
||||||
|
<div class>{track.metadata.title}</div>
|
||||||
|
<div class>shared by {track.status.account.acct}</div>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from 'svelte'
|
import { queue, next, current, enqueueing, select } from '/store.js'
|
||||||
import { next, enqueueing, queue, index, paused, loading, canNext, selectNext } from '/store.js'
|
|
||||||
|
|
||||||
const toggle = i => {
|
$: history = $queue.filter(x => x !== $next).reverse()
|
||||||
if (i === $index) {
|
|
||||||
$paused = !$paused
|
|
||||||
} else {
|
|
||||||
$index = i
|
|
||||||
$paused = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$: if ($queue.length === 0 && $index === null && $next !== null) {
|
|
||||||
$queue = [$next]
|
|
||||||
$next = null
|
|
||||||
$index = 0
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.entry {
|
.entry {
|
||||||
padding: 1em 2em;
|
padding: 1em 2em;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.entry.active {
|
.entry.active {
|
||||||
background-color: plum;
|
background-color: plum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.entry.active::before {
|
||||||
|
content: "▶️";
|
||||||
|
}
|
||||||
</style>
|
</style>
|
|
@ -20,20 +20,22 @@
|
||||||
LOADING TRACK
|
LOADING TRACK
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if duration}
|
<div>
|
||||||
{currentTimeText}
|
{currentTimeText}
|
||||||
|
|
||||||
<input
|
<input
|
||||||
type="range"
|
type="range"
|
||||||
min="0"
|
min="0"
|
||||||
max={duration}
|
max={duration}
|
||||||
value="0"
|
value="{currentTime}"
|
||||||
on:input={event => updateCurrentTime(event.target.value, false)}
|
on:input={event => updateCurrentTime(event.target.value, false)}
|
||||||
on:change={event => updateCurrentTime(event.target.value, true)}
|
on:change={event => updateCurrentTime(event.target.value, true)}
|
||||||
|
disabled={currentTime === null || duration === null}
|
||||||
>
|
>
|
||||||
|
|
||||||
{durationText}
|
{durationText}
|
||||||
{/if}
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -49,8 +51,8 @@
|
||||||
let duration = null
|
let duration = null
|
||||||
let seek = null
|
let seek = null
|
||||||
|
|
||||||
$: currentTimeText = currentTime !== null ? secondsToElapsedTime(currentTime) : null
|
$: currentTimeText = currentTime !== null ? secondsToElapsedTime(currentTime) : '--:--'
|
||||||
$: durationText = duration !== null ? secondsToElapsedTime(duration) : null
|
$: durationText = duration !== null ? secondsToElapsedTime(duration) : '--:--'
|
||||||
|
|
||||||
$: if (ended || error) {
|
$: if (ended || error) {
|
||||||
selectNext()
|
selectNext()
|
||||||
|
|
62
src/store.js
62
src/store.js
|
@ -1,7 +1,5 @@
|
||||||
import { writable, derived, get } from 'svelte/store'
|
import { writable, derived, get } from 'svelte/store'
|
||||||
import { writableLocalStorage } from '/services/svelte.js'
|
import { writableLocalStorage } from '/services/svelte.js'
|
||||||
import { hashtagIterator } from '/services/mastodon.js'
|
|
||||||
import { mkTracksIterator } from '/services/misc.js'
|
|
||||||
|
|
||||||
export const domain = writableLocalStorage('domain', 'eldritch.cafe')
|
export const domain = writableLocalStorage('domain', 'eldritch.cafe')
|
||||||
|
|
||||||
|
@ -12,63 +10,43 @@ export const hashtags = writableLocalStorage('hashtags', [
|
||||||
'pouetradio'
|
'pouetradio'
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const tracksIterator = mkTracksIterator(hashtagIterator(get(domain), get(hashtags)[0]))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const paused = writable(true)
|
export const paused = writable(true)
|
||||||
export const muted = writableLocalStorage('muted', false)
|
export const muted = writableLocalStorage('muted', false)
|
||||||
export const volume = writableLocalStorage('volume', 100)
|
export const volume = writableLocalStorage('volume', 100)
|
||||||
|
|
||||||
export const next = writable(null)
|
|
||||||
export const enqueueing = writable(false)
|
|
||||||
|
|
||||||
export const queue = writable([])
|
export const queue = writable([])
|
||||||
export const index = writable(null)
|
export const next = writable(null)
|
||||||
export const current = derived([queue, index], ([$queue, $index]) => $queue[$index])
|
export const current = writable(null)
|
||||||
|
export const enqueueing = writable(false)
|
||||||
export const canPrevious = derived([index, queue], ([$index, $queue]) => $index !== null && $index < $queue.length - 1)
|
|
||||||
export const canNext = derived([index, next], ([$index, $next]) => $index !== null && ($index > 0 || $next !== null))
|
|
||||||
|
|
||||||
export const loading = writable(false)
|
export const loading = writable(false)
|
||||||
|
|
||||||
next.subscribe(async $next => {
|
const index = derived([queue, current], ([$queue, $current]) => {
|
||||||
if ($next === null) {
|
const i = $queue.indexOf($current)
|
||||||
if (!get(enqueueing)) {
|
return i === -1 ? null : i
|
||||||
enqueueing.set(true)
|
|
||||||
|
|
||||||
const { value: newTrack } = await tracksIterator.next()
|
|
||||||
|
|
||||||
if (newTrack) {
|
|
||||||
next.set(newTrack)
|
|
||||||
}
|
|
||||||
|
|
||||||
enqueueing.set(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const canPrevious = derived([queue, index], ([$queue, $index]) => $index !== null && $index > 0)
|
||||||
|
export const canNext = derived([queue, index], ([$queue, $index]) => $index !== null && $index < $queue.length - 1)
|
||||||
|
|
||||||
|
|
||||||
|
export const select = track => {
|
||||||
|
console.log(`Select ${track.metadata.title}`)
|
||||||
|
current.set(track)
|
||||||
|
}
|
||||||
|
|
||||||
export const selectPrevious = () => {
|
export const selectPrevious = () => {
|
||||||
if (get(canPrevious)) {
|
if (get(canPrevious)) {
|
||||||
index.update($index => $index + 1)
|
const $queue = get(queue)
|
||||||
|
const $index = get(index)
|
||||||
|
select($queue[$index - 1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const selectNext = () => {
|
export const selectNext = () => {
|
||||||
if (get(canNext)) {
|
if (get(canNext)) {
|
||||||
|
const $queue = get(queue)
|
||||||
const $index = get(index)
|
const $index = get(index)
|
||||||
|
select($queue[$index + 1])
|
||||||
if ($index === 0) {
|
|
||||||
queue.update($queue => {
|
|
||||||
const $next = get(next)
|
|
||||||
next.set(null)
|
|
||||||
|
|
||||||
return [$next, ...$queue]
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
index.update($index => $index - 1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue