simplify store, add more feats
This commit is contained in:
parent
cd10193d3e
commit
ae187a96ef
5
package-lock.json
generated
5
package-lock.json
generated
@ -3018,11 +3018,6 @@
|
|||||||
"locate-path": "^3.0.0"
|
"locate-path": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"folktale": {
|
|
||||||
"version": "2.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/folktale/-/folktale-2.3.2.tgz",
|
|
||||||
"integrity": "sha512-+8GbtQBwEqutP0v3uajDDoN64K2ehmHd0cjlghhxh0WpcfPzAIjPA03e1VvHlxL02FVGR0A6lwXsNQKn3H1RNQ=="
|
|
||||||
},
|
|
||||||
"for-in": {
|
"for-in": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime-corejs3": "^7.7.7",
|
"@babel/runtime-corejs3": "^7.7.7",
|
||||||
"date-fns": "^2.9.0",
|
"date-fns": "^2.9.0",
|
||||||
"folktale": "^2.3.2",
|
|
||||||
"get-urls": "^9.2.0",
|
"get-urls": "^9.2.0",
|
||||||
"iter-tools": "^7.0.0-rc.0",
|
"iter-tools": "^7.0.0-rc.0",
|
||||||
"yt-player": "^3.4.3"
|
"yt-player": "^3.4.3"
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
<section class="viewer">
|
<section class="viewer">
|
||||||
|
{#if $current}
|
||||||
<Viewer></Viewer>
|
<Viewer></Viewer>
|
||||||
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="queue">
|
<section class="queue">
|
||||||
@ -23,6 +25,8 @@
|
|||||||
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 { current } from '/store.js'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -3,24 +3,34 @@
|
|||||||
<button on:click={() => $muted = !$muted}>
|
<button on:click={() => $muted = !$muted}>
|
||||||
{#if $muted}
|
{#if $muted}
|
||||||
🔇
|
🔇
|
||||||
{:else}
|
{:else if $volume < 20}
|
||||||
{#if $volume < 20}
|
|
||||||
🔈
|
🔈
|
||||||
{:else if $volume < 80}
|
{:else if $volume < 80}
|
||||||
🔉
|
🔉
|
||||||
{:else }
|
{:else }
|
||||||
🔊
|
🔊
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<input type="range" min="0" max="100" bind:value={$volume}>
|
<input type="range" min="0" max="100" bind:value={$volume}>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="controls-group">
|
<div class="controls-group">
|
||||||
<button on:click={() => entry.previous()}>⏮️</button>
|
<button class:cant={!$canPrevious} on:click={() => selectPrevious()}>⏮️</button>
|
||||||
<button on:click={() => $paused = !$paused}>{#if $paused}▶️{:else}⏸️{/if}</button>
|
|
||||||
<button on:click={() => entry.next()}>⏭️</button>
|
<button on:click={() => $paused = !$paused}>
|
||||||
|
{#if $index === null}
|
||||||
|
▶️
|
||||||
|
{:else if $loading}
|
||||||
|
🕒
|
||||||
|
{:else if $paused}
|
||||||
|
▶️
|
||||||
|
{:else }
|
||||||
|
⏸️
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class:cant={!$canNext} on:click={() => selectNext()}>⏭️</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="controls-group">
|
<div class="controls-group">
|
||||||
@ -30,7 +40,18 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { paused, volume, muted, entry } from '/stores.js'
|
import {
|
||||||
|
paused,
|
||||||
|
muted,
|
||||||
|
volume,
|
||||||
|
index,
|
||||||
|
queue,
|
||||||
|
canPrevious,
|
||||||
|
canNext,
|
||||||
|
selectPrevious,
|
||||||
|
selectNext,
|
||||||
|
loading
|
||||||
|
} from '/store.js'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@ -42,4 +63,8 @@
|
|||||||
.controls-group {
|
.controls-group {
|
||||||
margin: 0 1rem;
|
margin: 0 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cant {
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -1,53 +1,58 @@
|
|||||||
<div>
|
<div>
|
||||||
{#each $entries as entry}
|
{#each $queue as track, i}
|
||||||
<div class="entry" class:active={entry === $currentEntry}>
|
<div class="entry" class:active={i === $index}>
|
||||||
<div>
|
<div>
|
||||||
<button on:click={() => toggleEntry(entry)}>
|
<button on:click={() => toggle(i)}>
|
||||||
{#if entry === $currentEntry && !$paused}
|
{#if i != $index}
|
||||||
⏸️
|
|
||||||
{:else}
|
|
||||||
▶️
|
▶️
|
||||||
|
{:else if $loading}
|
||||||
|
🕒
|
||||||
|
{:else if $paused}
|
||||||
|
▶️
|
||||||
|
{:else}
|
||||||
|
⏸️
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div>{entry.metadata.title}</div>
|
<div>{track.metadata.title}</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<b>{entry.status.account.username} <small style="color: dimgray">{entry.status.account.acct}</small></b>
|
<b>{track.status.account.username} <small style="color: dimgray">{track.status.account.acct}</small></b>
|
||||||
{entry.data.url}
|
{track.data.url}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<button on:click={() => entries.load(5)}>LOAD 5 MOAR</button>
|
{#if $enqueueing}
|
||||||
|
LOADING ...
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import { paused, entry as currentEntry, entries } from '/stores.js'
|
import { index, queue, paused, enqueueing, enqueue, loading } from '/store.js'
|
||||||
|
|
||||||
const toggleEntry = (entry) => {
|
const toggle = i => {
|
||||||
if (entry !== $currentEntry) {
|
if (i === $index) {
|
||||||
$currentEntry = entry
|
|
||||||
} else {
|
|
||||||
$paused = !$paused
|
$paused = !$paused
|
||||||
|
} else {
|
||||||
|
$index = i
|
||||||
|
$paused = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const unsubscribe = entries.subscribe(async (xs) => {
|
enqueue().then(() => {
|
||||||
if (xs.length) {
|
$index = 0
|
||||||
const [firstEntry] = xs
|
})
|
||||||
currentEntry.set(firstEntry)
|
|
||||||
unsubscribe()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
entries.load(1)
|
$: if ($index !== null && $index === $queue.length - 1) {
|
||||||
})
|
enqueue()
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -1,12 +1,22 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class:hidden={!duration}>
|
<div class="embed-container" class:hidden={!duration}>
|
||||||
<div bind:this={element}></div>
|
<div bind:this={element}></div>
|
||||||
|
<div class="embed-overlay" on:click={() => $paused = !$paused}></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if duration}
|
{#if duration}
|
||||||
{currentTimeText}
|
{currentTimeText}
|
||||||
<input type="range" min="0" max={duration} value={currentTime} disabled>
|
<input
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max={duration}
|
||||||
|
value={currentTime}
|
||||||
|
on:input={ (e) => updatePlayerCurrentTime(e.target.value) }
|
||||||
|
on:mousedown={() => { if (player && !$paused) player.pause() }}
|
||||||
|
on:mouseup={() => { if (player && !$paused) player.play() }}>
|
||||||
{durationText}
|
{durationText}
|
||||||
|
{:else}
|
||||||
|
LOADING TRACK
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -14,8 +24,8 @@
|
|||||||
import { onMount, onDestroy } from 'svelte'
|
import { onMount, onDestroy } from 'svelte'
|
||||||
import { get } from 'svelte/store'
|
import { get } from 'svelte/store'
|
||||||
import YoutubePlayer from 'yt-player'
|
import YoutubePlayer from 'yt-player'
|
||||||
import { entry, paused, muted, volume } from '/stores.js'
|
|
||||||
import { secondsToElapsedTime } from '/util.js'
|
import { secondsToElapsedTime } from '/util.js'
|
||||||
|
import { paused, muted, volume, current, selectNext, loading } from '/store.js'
|
||||||
|
|
||||||
let element
|
let element
|
||||||
let player
|
let player
|
||||||
@ -29,40 +39,45 @@
|
|||||||
$: currentTimeText = currentTime !== null ? secondsToElapsedTime(currentTime) : null
|
$: currentTimeText = currentTime !== null ? secondsToElapsedTime(currentTime) : null
|
||||||
$: durationText = duration !== null ? secondsToElapsedTime(duration) : null
|
$: durationText = duration !== null ? secondsToElapsedTime(duration) : null
|
||||||
|
|
||||||
$: updateEntry($entry)
|
$: updatePlayerVideoId($current)
|
||||||
$: updatePaused($paused)
|
$: updatePlayerPaused($paused)
|
||||||
$: updateMuted($muted)
|
$: updatePlayerMuted($muted)
|
||||||
$: updateVolume($volume)
|
$: updatePlayerVolume($volume)
|
||||||
|
|
||||||
const updateViewerDurationCallback = () => {
|
const updateViewerDurationCallback = () => {
|
||||||
if (player) {
|
if (player) {
|
||||||
duration = player.getDuration()
|
duration = player.getDuration()
|
||||||
currentTime = player.getCurrentTime()
|
currentTime = player.getCurrentTime()
|
||||||
|
$loading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateEntry = (entry) => {
|
const updatePlayerVideoId = ($current) => {
|
||||||
if (player && entry) {
|
if (player && $current) {
|
||||||
duration = null
|
duration = null
|
||||||
currentTime = null
|
currentTime = null
|
||||||
|
$loading = true
|
||||||
player.off('playing', updateViewerDurationCallback)
|
player.off('playing', updateViewerDurationCallback)
|
||||||
|
|
||||||
player.load(entry.data.id, !$paused)
|
player.load($current.data.id, !$paused)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatePaused = (paused) => {
|
const updatePlayerPaused = (paused) => {
|
||||||
if (player) paused ? player.pause() : player.play()
|
if (player) paused ? player.pause() : player.play()
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateMuted = (muted) => {
|
const updatePlayerMuted = (muted) => {
|
||||||
if (player) muted ? player.mute() : player.unMute()
|
if (player) muted ? player.mute() : player.unMute()
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateVolume = (volume) => {
|
const updatePlayerVolume = (volume) => {
|
||||||
if (player) player.setVolume(volume)
|
if (player) player.setVolume(volume)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updatePlayerCurrentTime = (seconds) => {
|
||||||
|
if (player) player.seek(seconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
@ -77,17 +92,9 @@
|
|||||||
related: false
|
related: false
|
||||||
})
|
})
|
||||||
|
|
||||||
updatePaused($paused)
|
updatePlayerPaused($paused)
|
||||||
updateMuted($muted)
|
updatePlayerMuted($muted)
|
||||||
updateVolume($volume)
|
updatePlayerVolume($volume)
|
||||||
|
|
||||||
// player.on('playing', () => {
|
|
||||||
// $paused = false
|
|
||||||
// })
|
|
||||||
|
|
||||||
// player.on('paused', () => {
|
|
||||||
// $paused = true
|
|
||||||
// })
|
|
||||||
|
|
||||||
player.on('unstarted', () => {
|
player.on('unstarted', () => {
|
||||||
player.once('playing', updateViewerDurationCallback)
|
player.once('playing', updateViewerDurationCallback)
|
||||||
@ -97,16 +104,18 @@
|
|||||||
currentTime = time
|
currentTime = time
|
||||||
})
|
})
|
||||||
|
|
||||||
player.on('ended', () => entry.next())
|
player.on('ended', () => {
|
||||||
|
selectNext()
|
||||||
|
})
|
||||||
|
|
||||||
player.on('unplayable', (...args) => {
|
player.on('unplayable', (...args) => {
|
||||||
console.log('unplayable', ...args)
|
console.log('unplayable', ...args)
|
||||||
entry.next()
|
selectNext()
|
||||||
})
|
})
|
||||||
|
|
||||||
player.on('error', (...args) => {
|
player.on('error', (...args) => {
|
||||||
console.log('error', ...args)
|
console.log('error', ...args)
|
||||||
entry.next()
|
selectNext()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -121,4 +130,16 @@
|
|||||||
.hidden {
|
.hidden {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.embed-container {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.embed-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -1,122 +0,0 @@
|
|||||||
import { writable, get } from 'svelte/store'
|
|
||||||
import { mkTracksIterator } from '/util.js'
|
|
||||||
|
|
||||||
export const writableLocalStorage = (key, value) => {
|
|
||||||
const item = JSON.parse(localStorage.getItem(key))
|
|
||||||
const store = writable(item === null ? value : item)
|
|
||||||
|
|
||||||
store.subscribe(x => localStorage.setItem(key, JSON.stringify(x)))
|
|
||||||
|
|
||||||
return store
|
|
||||||
}
|
|
||||||
|
|
||||||
export const stackStore = (domain, hashtags) => {
|
|
||||||
const tracksIterator = mkTracksIterator(domain, hashtags)
|
|
||||||
|
|
||||||
const store = writable([])
|
|
||||||
const { update, subscribe } = store
|
|
||||||
|
|
||||||
let promise = Promise.resolve()
|
|
||||||
const buffer = []
|
|
||||||
|
|
||||||
const load = async () => {
|
|
||||||
|
|
||||||
|
|
||||||
const n = 5 - buffer.length
|
|
||||||
|
|
||||||
for (let i = 0; i < n; i++) {
|
|
||||||
const iteratorResult = await tracksIterator.next()
|
|
||||||
|
|
||||||
if (iteratorResult.value) {
|
|
||||||
update(entries => [...entries, iteratorResult.value])
|
|
||||||
} else {
|
|
||||||
// iterator don't have new entries for now
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const unshift = async () => {
|
|
||||||
let promise = promise.then(() => {
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
promise = load()
|
|
||||||
|
|
||||||
return { subscribe, unshift }
|
|
||||||
}
|
|
||||||
|
|
||||||
export const entryStore = (entriesStore) => {
|
|
||||||
const store = writable(null)
|
|
||||||
const { set, update, subscribe } = store
|
|
||||||
|
|
||||||
const select = (entry) => {
|
|
||||||
update(() => entry)
|
|
||||||
|
|
||||||
const entriesList = get(entriesStore)
|
|
||||||
const index = entriesList.indexOf(entry)
|
|
||||||
|
|
||||||
if (index === entriesList.length - 1) {
|
|
||||||
entriesStore.load(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const previous = () => {
|
|
||||||
const entriesList = get(entriesStore)
|
|
||||||
|
|
||||||
update(currentEntry => {
|
|
||||||
const index = entriesList.indexOf(currentEntry)
|
|
||||||
|
|
||||||
return index > 0 ? entriesList[index - 1] : null
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const next = () => {
|
|
||||||
const entriesList = get(entriesStore)
|
|
||||||
|
|
||||||
update(oldEntry => {
|
|
||||||
if (entriesList.length === 0) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const index = entriesList.indexOf(oldEntry)
|
|
||||||
|
|
||||||
if (index === -1) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const nextIndex = index + 1
|
|
||||||
|
|
||||||
if (nextIndex === entriesList.length - 1) {
|
|
||||||
entries.load(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return entriesList[nextIndex]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return { subscribe, set: select, previous, next }
|
|
||||||
}
|
|
||||||
|
|
||||||
export const entriesStore = (domain, hashtags) => {
|
|
||||||
const tracksIterator = mkTracksIterator(domain, hashtags)
|
|
||||||
|
|
||||||
const store = writable([])
|
|
||||||
const { update, subscribe } = store
|
|
||||||
|
|
||||||
const load = async (number) => {
|
|
||||||
for (let i = 0; i < number; i++) {
|
|
||||||
const iteratorResult = await tracksIterator.next()
|
|
||||||
|
|
||||||
if (iteratorResult.value) {
|
|
||||||
update(entries => [...entries, iteratorResult.value])
|
|
||||||
} else {
|
|
||||||
// iterator don't have new entries for now
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { subscribe, load }
|
|
||||||
}
|
|
46
src/store.js
Normal file
46
src/store.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { writable, derived, get } from 'svelte/store'
|
||||||
|
import { writableLocalStorage, mkTracksIterator } from '/util.js'
|
||||||
|
|
||||||
|
export const domain = writableLocalStorage('domain', 'eldritch.cafe')
|
||||||
|
|
||||||
|
export const hashtags = writableLocalStorage('hashtags', [
|
||||||
|
'np',
|
||||||
|
'nowplaying',
|
||||||
|
'tootradio',
|
||||||
|
'pouetradio'
|
||||||
|
])
|
||||||
|
|
||||||
|
export const paused = writable(false)
|
||||||
|
export const muted = writableLocalStorage('muted', false)
|
||||||
|
export const volume = writableLocalStorage('volume', 100)
|
||||||
|
|
||||||
|
export const index = writable(null)
|
||||||
|
export const queue = writable([])
|
||||||
|
export const enqueueing = writable(false)
|
||||||
|
export const current = derived([queue, index], ([$queue, $index]) => $queue[$index])
|
||||||
|
|
||||||
|
export const canPrevious = derived([index], ([$index]) => $index !== null && $index > 0)
|
||||||
|
export const canNext = derived([index, queue], ([$index, $queue]) => $index !== null && $index < $queue.length - 1)
|
||||||
|
|
||||||
|
export const loading = writable(false)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const tracksIterator = mkTracksIterator(get(domain), get(hashtags))
|
||||||
|
|
||||||
|
export const selectPrevious = () => { if (get(canPrevious)) index.update($index => $index - 1) }
|
||||||
|
export const selectNext = () => { if (get(canNext)) index.update($index => $index + 1) }
|
||||||
|
|
||||||
|
export const enqueue = async () => {
|
||||||
|
if (!get(enqueueing)) {
|
||||||
|
enqueueing.set(true)
|
||||||
|
|
||||||
|
const { value: newTrack } = await tracksIterator.next()
|
||||||
|
|
||||||
|
if (newTrack) {
|
||||||
|
queue.update($queue => [...$queue, newTrack])
|
||||||
|
}
|
||||||
|
|
||||||
|
enqueueing.set(false)
|
||||||
|
}
|
||||||
|
}
|
@ -1,84 +0,0 @@
|
|||||||
import { writable, get } from 'svelte/store'
|
|
||||||
import { writableLocalStorage, entriesStore, entryStore } from '/services/store.js'
|
|
||||||
|
|
||||||
export const domain = writableLocalStorage('domain', 'eldritch.cafe')
|
|
||||||
|
|
||||||
export const hashtags = writableLocalStorage('hashtags', [
|
|
||||||
'np',
|
|
||||||
'nowplaying',
|
|
||||||
'tootradio',
|
|
||||||
'pouetradio'
|
|
||||||
])
|
|
||||||
|
|
||||||
export const paused = writable(false)
|
|
||||||
export const muted = writableLocalStorage('muted', false)
|
|
||||||
export const volume = writableLocalStorage('volume', 100)
|
|
||||||
|
|
||||||
export const entries = entriesStore(get(domain), get(hashtags))
|
|
||||||
export const entry = entryStore(entries)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const tracksIterator = mkTracksIterator(get(domain), get(hashtags))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const track = writable(null)
|
|
||||||
export const queue = writable([])
|
|
||||||
export const stack = writable([])
|
|
||||||
|
|
||||||
export const state = writable({
|
|
||||||
current: null,
|
|
||||||
queue: []
|
|
||||||
})
|
|
||||||
|
|
||||||
export const enqueue = () => {
|
|
||||||
const { value: newTrack } = await tracksIterator.next()
|
|
||||||
|
|
||||||
if (!newTrack) {
|
|
||||||
state.update(s => ({ ...s, queue: [...s.queue, newTrack] }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const select = (track) => {
|
|
||||||
state.update(s => ({ ...s, current: track }))
|
|
||||||
}
|
|
||||||
|
|
||||||
export const selectPrevious = () => {
|
|
||||||
state.update(s => {
|
|
||||||
if (s.current === null) return s
|
|
||||||
|
|
||||||
const
|
|
||||||
return
|
|
||||||
})
|
|
||||||
|
|
||||||
const tracks = get(queue)
|
|
||||||
|
|
||||||
track.update(oldTrack => {
|
|
||||||
const index = tracks.indexOf(oldTrack)
|
|
||||||
return index > 0 ? tracks[index - 1] : null
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const selectNext = () => {
|
|
||||||
const tracks = get(queue)
|
|
||||||
const oldTrack = get(track)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
track.update(oldTrack => {
|
|
||||||
const index = tracks.indexOf(oldTrack)
|
|
||||||
|
|
||||||
if (index !== -1 && ) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return index !== -1 && index + 1 < tracks.length
|
|
||||||
? tracks[index + 1]
|
|
||||||
: null
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
enqueueIfTrack(track)
|
|
||||||
}
|
|
10
src/util.js
10
src/util.js
@ -1,6 +1,16 @@
|
|||||||
|
import { writable } from 'svelte/store'
|
||||||
import getUrls from 'get-urls'
|
import getUrls from 'get-urls'
|
||||||
import { execPipe, asyncFilter, asyncMap } from 'iter-tools'
|
import { execPipe, asyncFilter, asyncMap } from 'iter-tools'
|
||||||
|
|
||||||
|
export const writableLocalStorage = (key, value) => {
|
||||||
|
const item = JSON.parse(localStorage.getItem(key))
|
||||||
|
const store = writable(item === null ? value : item)
|
||||||
|
|
||||||
|
store.subscribe(x => localStorage.setItem(key, JSON.stringify(x)))
|
||||||
|
|
||||||
|
return store
|
||||||
|
}
|
||||||
|
|
||||||
const millisecond = 1
|
const millisecond = 1
|
||||||
const second = 1000 * millisecond
|
const second = 1000 * millisecond
|
||||||
const minute = 60 * second
|
const minute = 60 * second
|
||||||
|
Loading…
x
Reference in New Issue
Block a user