~ d e s i g n ~
This commit is contained in:
commit
8633b8534b
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"plugins": [
|
||||
["@babel/plugin-transform-runtime", {
|
||||
"corejs": 3
|
||||
}]
|
||||
]
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
node_modules
|
||||
dist
|
||||
.cache
|
||||
.env
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "eldritch-cafe-radio",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"dev": "parcel src/index.html",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.7.7",
|
||||
"@babel/plugin-transform-runtime": "^7.7.6",
|
||||
"parcel": "^1.12.4",
|
||||
"parcel-plugin-svelte": "^4.0.5",
|
||||
"svelte": "^3.16.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime-corejs3": "^7.7.7",
|
||||
"get-urls": "^9.2.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"last 1 chrome versions"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
<main class="app">
|
||||
<header class="header">
|
||||
<h1>
|
||||
Eldritch Radio
|
||||
</h1>
|
||||
</header>
|
||||
|
||||
<section class="player">
|
||||
{#if selectedEntry}
|
||||
Playing <a href={selectedEntry.url}>{selectedEntry.url}</a>
|
||||
{:else}
|
||||
Loading ...
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<section class="queue">
|
||||
{#await entriesPromise}
|
||||
Loading radio please wait
|
||||
{:then entries}
|
||||
<ul>
|
||||
{#each entries as entry}
|
||||
<li>
|
||||
<a href={entry.url}>{entry.url}</a>
|
||||
<small>{entry.tags}</small>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{:catch error}
|
||||
Oops, something went wrong : {error}
|
||||
{/await}
|
||||
|
||||
<header>
|
||||
<a href="https://{domain}/">{domain}</a> - {@html hashtags.map(hashtag => `<a href="https://${domain}/tags/${hashtag}">#${hashtag}</a>`)}
|
||||
</header>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { fetchEntries } from './util.js'
|
||||
|
||||
export let domain
|
||||
export let hashtags
|
||||
|
||||
let entriesPromise = new Promise(() => {})
|
||||
let selectedEntry = null
|
||||
|
||||
onMount(() => {
|
||||
entriesPromise = fetchEntries(domain, hashtags)
|
||||
|
||||
entriesPromise.then(entries => {
|
||||
[selectedEntry] = entries
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.app {
|
||||
display: grid;
|
||||
|
||||
grid-template-columns: 1fr;
|
||||
|
||||
grid-template-areas:
|
||||
"header"
|
||||
"player"
|
||||
"queue";
|
||||
}
|
||||
|
||||
.header {
|
||||
grid-area: header;
|
||||
}
|
||||
|
||||
.player {
|
||||
grid-area: player;
|
||||
}
|
||||
|
||||
.queue {
|
||||
grid-area: queue;
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.app {
|
||||
grid-template-columns: 2fr 3fr;
|
||||
grid-template-rows: auto 1fr;
|
||||
|
||||
grid-template-areas:
|
||||
"header queue"
|
||||
"player queue"
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="main.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,16 @@
|
|||
import App from './App.svelte'
|
||||
|
||||
const app = new App({
|
||||
target: document.body,
|
||||
props: {
|
||||
domain: 'eldritch.cafe',
|
||||
hashtags: [
|
||||
'np',
|
||||
'nowplaying',
|
||||
'tootradio',
|
||||
'pouetradio'
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
export default app
|
|
@ -0,0 +1,25 @@
|
|||
import getUrls from 'get-urls'
|
||||
|
||||
export async function fetchEntries(domain, hashtags) {
|
||||
const response = await fetch(`https://${domain}/api/v1/timelines/tag/${hashtags[0]}`)
|
||||
const statuses = await response.json()
|
||||
|
||||
const entries = statuses
|
||||
.map(status => {
|
||||
const [url] = Array.from(getUrls(status.content)).filter(isSupportedUrl)
|
||||
const tags = intersection(status.tags.map(tag => tag.name), hashtags)
|
||||
|
||||
return { status, url, tags }
|
||||
})
|
||||
.filter(entry => entry.url != null)
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
function isSupportedUrl(url) {
|
||||
return (new URL(url)).hostname === 'youtube.com'
|
||||
}
|
||||
|
||||
function intersection(xs, ys) {
|
||||
return xs.filter(x => ys.includes(x));
|
||||
}
|
Loading…
Reference in New Issue