refact(store): use fp transformations

This commit is contained in:
wryk 2020-02-18 19:18:46 +01:00
parent 7efd05ef3d
commit 2a9a02df54
7 changed files with 87 additions and 84 deletions

11
package-lock.json generated
View File

@ -6293,8 +6293,7 @@
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
},
"lodash.clone": {
"version": "4.5.0",
@ -8675,6 +8674,14 @@
"integrity": "sha1-fRh9tcbNu9ZNdaMvkbiZi94yc8M=",
"dev": true
},
"svelte-pipeable-store": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/svelte-pipeable-store/-/svelte-pipeable-store-1.0.3.tgz",
"integrity": "sha512-VmsVQHPPASqTls53uT0HszKbdn6FTJLdwQvHPA1AJU1U2POYoGnG36+zK0tQzF9F/DHeR2ufvoHV2ozqDiaJ4w==",
"requires": {
"lodash": "^4.17.15"
}
},
"svelte-routing": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/svelte-routing/-/svelte-routing-1.4.0.tgz",

View File

@ -28,6 +28,7 @@
"get-urls": "^9.2.0",
"iter-tools": "^7.0.0-rc.0",
"route-parser": "0.0.5",
"svelte-pipeable-store": "^1.0.3",
"svelte-routing": "^1.4.0"
},
"browserslist": [

View File

@ -6,10 +6,14 @@
<div class="title">{$next.title}</div>
<div class="user">shared by {$next.referer.username} <DistanceDate date={$next.date} /></div>
</div>
{:else}
NO NEXT TRACK
{/if}
{#if $enqueueing}
LOADING NEXT
ENQUEING
{/if}

View File

@ -17,79 +17,16 @@
</div>
<script>
import { onMount, onDestroy } from 'svelte'
import { derived, get } from 'svelte/store'
import Header from '/components/layout/Header.svelte'
import Footer from '/components/layout/Footer.svelte'
import Queue from '/components/Queue.svelte'
import Viewer from '/components/Viewer.svelte'
import { radioIterator, radioShareIterator } from '/services/radio.js'
import { fetchStatus } from '/services/mastodon.js'
import { domain, hashtags, queue, next, current, enqueueing, select } from '/store.js'
import DeepSet from '/services/deep-set.js'
import { queue, next, current, select } from '/store.js'
export let share
const cache = new DeepSet()
let nextUnsubcribe = null
let currentUnsubcribe = null
onMount(async () => {
let iterator
if (share != null) {
const track = await fetchStatus(share.domain, share.id)
iterator = radioShareIterator(track, get(domain), get(hashtags), cache)
} else {
iterator = radioIterator(get(domain), get(hashtags), cache)
}
// generated multiples times cannot usable and don't free resources
// const iterator = derived([domain, hashtags], ([$domain, $hashtags]) => radioIterator($domain, $hashtags))
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()
}
}
})
$: if ($queue.length === 1 && $next != null && $current == null) {
select($next)
}
</script>

26
src/services/store.js Normal file
View File

@ -0,0 +1,26 @@
import { writable, readable } from 'svelte-pipeable-store'
export { get } from 'svelte/store'
export * from 'svelte-pipeable-store'
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 distinct = () => {
return ({ subscribe }) => readable(undefined, set => {
let last
return subscribe(v => {
if (last !== v) {
set(v)
last = v
}
})
})
}

View File

@ -1,10 +0,0 @@
import { writable } from 'svelte/store'
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
}

View File

@ -1,5 +1,10 @@
import { writable, derived, get } from 'svelte/store'
import { writableLocalStorage } from '/services/svelte.js'
import { get, writable, derived, scan, wait, startWith, writableLocalStorage } from '/services/store.js'
import { radioIterator, radioShareIterator } from '/services/radio.js'
import DeepSet from '/services/deep-set.js'
import { distinct } from './services/store'
const cache = new DeepSet()
export const domain = writableLocalStorage('domain', 'eldritch.cafe')
@ -14,11 +19,44 @@ export const paused = writable(true)
export const muted = writableLocalStorage('muted', false)
export const volume = writableLocalStorage('volume', 100)
export const queue = writable([])
export const next = writable(null)
export const current = writable(null)
export const enqueueing = writable(false)
export const iterator = derived([domain, hashtags], ([$domain, $hashtags], set) => {
const iterator = radioIterator($domain, $hashtags, cache)
set(iterator)
return () => {
iterator.return()
}
}, null)
export const next = derived([iterator, current], ([$iterator, $current]) => ({ $iterator, $current }))
.pipe(scan(($nextPromise, { $iterator, $current }) => {
return $nextPromise.then($next => {
if ($next == null || $next === $current) {
enqueueing.set(true)
return $iterator.next().then(({ done, value }) => {
enqueueing.set(false)
return value
})
} else {
return $nextPromise
}
})
}, Promise.resolve(null)))
.pipe(wait(x => x))
// distinct but with strict check
.pipe(distinct())
.pipe(startWith(null))
export const queue = next
.pipe(scan((a, x) => x == null ? a : [...a, x], []))
export const loading = writable(false)
const index = derived([queue, current], ([$queue, $current]) => {