From b930ea7c34fd973a4a94fc93f96d02aa1758a828 Mon Sep 17 00:00:00 2001 From: tree Date: Fri, 27 May 2022 13:28:15 +0200 Subject: [PATCH] UTXO.TV --- package-lock.json | 15 ++++ package.json | 1 + src/lib/EventTypeLabel.svelte | 2 +- src/lib/YouTube.svelte | 145 +++++++++++++++++++++++++++++++++ src/lib/header/Header.svelte | 33 +++++++- src/lib/periods.js | 17 ++++ src/routes/prakticke.svelte | 22 +++-- src/routes/program.svelte | 19 +---- src/routes/tv.svelte | 146 +++++++++++++++++++++++++++++----- static/img/utxo-tv.svg | 80 +++++++++++++++++++ 10 files changed, 431 insertions(+), 49 deletions(-) create mode 100644 src/lib/YouTube.svelte create mode 100644 src/lib/periods.js create mode 100644 static/img/utxo-tv.svg diff --git a/package-lock.json b/package-lock.json index cedcdf4..9ce2609 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "fuse.js": "^6.5.3", "lodash": "^4.17.21", "remove-markdown": "^0.3.0", + "svelte-scrolling": "^1.1.1", "svelte-youtube": "^0.0.2" }, "devDependencies": { @@ -1953,6 +1954,14 @@ "svelte": "^3.0.0" } }, + "node_modules/svelte-scrolling": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/svelte-scrolling/-/svelte-scrolling-1.1.1.tgz", + "integrity": "sha512-QnVZZnF+SPZVDCV9RVvgjSQm50gNuJil+XO/fmuR9gkSA7z5UdT+XW48MZAlV1zrUdWwChyDGUU4xzmJkdN9jg==", + "peerDependencies": { + "svelte": "^3.38.3" + } + }, "node_modules/svelte-youtube": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/svelte-youtube/-/svelte-youtube-0.0.2.tgz", @@ -3352,6 +3361,12 @@ "marked": "^4.0.10" } }, + "svelte-scrolling": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/svelte-scrolling/-/svelte-scrolling-1.1.1.tgz", + "integrity": "sha512-QnVZZnF+SPZVDCV9RVvgjSQm50gNuJil+XO/fmuR9gkSA7z5UdT+XW48MZAlV1zrUdWwChyDGUU4xzmJkdN9jg==", + "requires": {} + }, "svelte-youtube": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/svelte-youtube/-/svelte-youtube-0.0.2.tgz", diff --git a/package.json b/package.json index 4724e84..a0e9684 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "fuse.js": "^6.5.3", "lodash": "^4.17.21", "remove-markdown": "^0.3.0", + "svelte-scrolling": "^1.1.1", "svelte-youtube": "^0.0.2" } } diff --git a/src/lib/EventTypeLabel.svelte b/src/lib/EventTypeLabel.svelte index e2722e5..9a6c1ef 100644 --- a/src/lib/EventTypeLabel.svelte +++ b/src/lib/EventTypeLabel.svelte @@ -21,7 +21,7 @@ $: current = config[event.type]; -
+
+ /** + * Expose PlayerState constants for convenience. These constants can also be + * accessed through the global YT object after the YouTube IFrame API is instantiated. + * https://developers.google.com/youtube/iframe_api_reference#onStateChange + */ + export const PlayerState = { + UNSTARTED: -1, + ENDED: 0, + PLAYING: 1, + PAUSED: 2, + BUFFERING: 3, + CUED: 5, + }; + + + + +
+
+
diff --git a/src/lib/header/Header.svelte b/src/lib/header/Header.svelte index aa6da51..26d6920 100644 --- a/src/lib/header/Header.svelte +++ b/src/lib/header/Header.svelte @@ -13,7 +13,7 @@
@@ -22,7 +22,7 @@ >
- {#if !["/", "/tv"].includes($page.url.pathname)} + {#if !["/","/tv"].includes($page.url.pathname)}
@@ -36,30 +36,54 @@ >
- {:else} -
+ {:else if $page.url.pathname === '/tv'} +
+
+ UTXO.TV +
+
{/if}
+ {#if $page.url.pathname === '/tv'} + O konferenci + {:else} Úvod + {/if} + {#if $page.url.pathname !== '/tv'} Livestreamy + {/if} Program + {#if $page.url.pathname !== '/tv'} + {/if}
{#if $page.url.pathname === '/'}
start ? date : format(addDays(new Date(date), 1), 'yyyy-MM-dd') + return { + date, + name, + period: { + start: new Date(`${date}T${start}`), + end: new Date(`${endDate}T${end}`), + }, + }; + } diff --git a/src/routes/prakticke.svelte b/src/routes/prakticke.svelte index f8b5a9d..eb8144c 100644 --- a/src/routes/prakticke.svelte +++ b/src/routes/prakticke.svelte @@ -1,10 +1,13 @@ @@ -14,7 +17,16 @@

Praktické informace

-
- TBA -
+ {#if bundle} + {#each $bundle.spec['practical-info'] as item} + + {/each} + {:else} + Načítám .. + {/if}
diff --git a/src/routes/program.svelte b/src/routes/program.svelte index 29d6cc9..1ec47e6 100644 --- a/src/routes/program.svelte +++ b/src/routes/program.svelte @@ -6,9 +6,10 @@ import { onMount, onDestroy } from "svelte"; import { goto } from "$app/navigation"; import { page } from "$app/stores"; - import { format, compareAsc, compareDesc, addDays } from "date-fns"; + import { format, compareAsc, compareDesc } from "date-fns"; import { bundle, userData, loadInfo, schedulePref } from "$lib/stores.js"; import { cs } from "date-fns/locale/index.js"; + import { parsePeriod } from '$lib/periods.js'; import SvelteMarkdown from "svelte-markdown"; const renderers = { link: Link }; import Link from "$lib/Link.svelte"; @@ -181,22 +182,6 @@ return showSpeakers(bundle, ev); } - function parsePeriod(bundle, str) { - const [dayNumber, times, name] = str.split("/"); - const [start, end] = times.split("-"); - const date = bundle.dates[dayNumber - 1]; - - const endDate = end > start ? date : format(addDays(new Date(date), 1), 'yyyy-MM-dd') - return { - date, - name, - period: { - start: new Date(`${date}T${start}`), - end: new Date(`${endDate}T${end}`), - }, - }; - } - function scheduleTimes(bundle, filter = false) { let arr = bundle.scheduleTimes.map((item, i) => { const out = parsePeriod(bundle, item); diff --git a/src/routes/tv.svelte b/src/routes/tv.svelte index a5bf97e..7cf6401 100644 --- a/src/routes/tv.svelte +++ b/src/routes/tv.svelte @@ -6,17 +6,44 @@ import { onMount, onDestroy } from "svelte"; import { bundle, userData } from "$lib/stores.js"; import { format, formatDistanceToNow } from "date-fns"; + import { parsePeriod } from '$lib/periods.js'; import EventTypeLabel from "$lib/EventTypeLabel.svelte"; import Avatar from "$lib/Avatar.svelte"; - import YouTube from 'svelte-youtube'; + import YouTube from '$lib/YouTube.svelte'; import SvelteMarkdown from "svelte-markdown"; import Link from "$lib/Link.svelte"; + import { scrollTo, scrollRef, scrollTop } from 'svelte-scrolling'; const renderers = { link: Link }; + const YToptions = { + playerVars: { + autoplay: 0 + } + } const stageStatus = {} + const stagePlayers = {} let events = [] let cachedBundle = [] + function typeColor (type) { + let color = null + switch (type) { + case 'talk': + color = 'bg-custom-green/70' + break + case 'panel': + color = 'bg-orange-400/70' + break + case 'lightning-series': + color = 'bg-yellow-400/70' + break + case 'other': + color = 'bg-rose-400/70' + break + } + return color + } + bundle.subscribe(_bundle => { events = _bundle.spec['schedule-candidates'][0].schedule cachedBundle = _bundle @@ -34,6 +61,23 @@ clearInterval(interval) }) + function startStream (stageId) { + const player = stagePlayers[stageId] + if (!player) { + return null + } + player.playVideo() + } + + function youtubePlayed (stageId) { + for (const pi of Object.keys(stagePlayers)) { + if (pi !== stageId) { + console.log(`stopping player: ${pi}`) + stagePlayers[pi].stopVideo() + } + } + } + function findSpeaker (sp, _bundle) { return _bundle.spec.speakers.find(s => s.id === sp) } @@ -46,7 +90,9 @@ } function genStatus(_bundle) { - const now = new Date(`2022-06-04T${format(new Date(), 'HH:mm')}`) + const now = new Date(`2022-06-04T${format(new Date(), 'HH:mm:ss')}`) + //const now = new Date() + //const now = new Date(`2022-06-04T13:25`) let globalNextEvents = events.filter(ev => { return new Date(ev.period.end).getTime() > now.getTime() @@ -56,13 +102,36 @@ for (const stage of stages.filter(s => s.livestream)) { let nextEvents = [...globalNextEvents.filter(e => e.stage === stage.id)] let current = null - if (new Date(nextEvents[0].period.start).getTime() <= now.getTime()) { + if (nextEvents.length > 0 && new Date(nextEvents[0].period.start).getTime() <= now.getTime()) { current = nextEvents[0] nextEvents = nextEvents.slice(1) } + + const allStreams = stage.streams.map(st => parsePeriod(_bundle, st)) + const nextStreams = allStreams.filter(s => s.period.end.getTime() >= now.getTime()) + if (nextStreams.length === 0) { + nextStreams.push(allStreams[allStreams.length-1]) + } + let currentPercentage = null + if (current) { + let duration = (new Date(current.period.end).getTime() - new Date(current.period.start).getTime()) / 1000 + let elapsed = Math.floor((now.getTime() - new Date(current.period.start).getTime()) / 1000) + currentPercentage = elapsed/(duration/100) + } + + const day = format(new Date(nextStreams[0].period.start), 'yyyy-MM-dd') + let ctime = 0 + if (day === '2022-06-05') { + ctime = 2 + } + const scheduleLink = `/program?time=${ctime}&stage=${stage.id}&desc=true` + stageStatus[stage.id] = { current: current ? extendEvents([current], _bundle)[0] : null, - next: extendEvents(nextEvents.slice(0,2), _bundle) + currentPercentage, + next: extendEvents(nextEvents.slice(0,2), _bundle), + stream: nextStreams[0], + scheduleLink } } console.log(stageStatus) @@ -86,24 +155,55 @@
-
- {#if $bundle} + {#if $bundle} +
+
+ {#each $bundle.spec.stages.filter(s => s.livestream) as stage, i} +
startStream(stage.id)}> +
#{i+1} {stage.name}
+
+ {#each [stageStatus[stage.id]] as ss} + {#if ss.current} +
+
+
+
+
{format(new Date(ss.current.period.start), 'HH:mm')}-{format(new Date(ss.current.period.end), 'HH:mm')} {ss.current._event.name}
+ {:else} + ☕ Přestávka {#if ss.next[0]}do {format(new Date(ss.next[0].period.start), 'HH:mm')}{/if} + {/if} + {/each} +
+
+ {/each} +
+
+
{#each $bundle.spec.stages.filter(s => s.livestream) as stage, i} -
-

#{i+1} | {stage.name}

+
+
- + youtubePlayed(stage.id)} />
{#each [stageStatus[stage.id]] as ss}
{#if ss.current} -
Právě probíhá
-
{format(new Date(ss.current.period.start), 'HH:mm')}-{format(new Date(ss.current.period.end), 'HH:mm')} {ss.current._event.name}
+
+
Právě probíhá
+
+
+
+
+
+
{format(new Date(ss.current.period.start), 'HH:mm')}-{format(new Date(ss.current.period.end), 'HH:mm')} {ss.current._event.name}
{#each ss.current._event.speakers.map(sp => findSpeaker(sp, $bundle)) as speaker} - + {/each}
{#if ss.current._event.description} @@ -112,30 +212,32 @@ {#if spoiler.stripped} {/if}
{/each} {/if} -
{@html ss.current._event.tags.map(t => `#${t}`).join(' ')}
+
{@html ss.current._event.tags.map(t => `#${t}`).join(' ')}
+ {:else} -
☕ Přestávka
+
☕ Přestávka {#if ss.next[0]}do {format(new Date(ss.next[0].period.start), 'HH:mm')}{/if}
{/if}
{/each} -
Následuje
-
{/each} - {:else} - Načítám ... - {/if} -
+
+ {:else} + Načítám ... + {/if}
diff --git a/static/img/utxo-tv.svg b/static/img/utxo-tv.svg new file mode 100644 index 0000000..d36fabd --- /dev/null +++ b/static/img/utxo-tv.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +