aboutsummaryrefslogtreecommitdiff
path: root/src/lib/Hololive/Lives.svelte
blob: 1969fa4ffa687d337673a0c68684071a73bd032d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<script lang="ts">
import Spacer from "$lib/Layout/Spacer.svelte";
import Message from "$lib/Loading/Message.svelte";
import root from "$lib/Utility/root";
import type { Live, ParseResult } from "./hololive";
import Stream from "./Stream.svelte";

export let schedule: ParseResult;
export let pinnedStreams: string[];
export let getPinnedStreams: () => void;
export let filter: string | undefined;

const pinStream = (streamer: string) =>
	fetch(root(`/api/preferences/pin?stream=${encodeURIComponent(streamer)}`), {
		method: "PUT",
		headers: {
			"Content-Type": "application/json",
		},
	}).then(getPinnedStreams);

$: categorisedStreams = schedule.lives
	.filter((live) => (filter ? live.streamer === filter : true))
	.sort((a, b) => new Date(a.time).getTime() - new Date(b.time).getTime())
	.sort((a, b) => {
		const aPinned = pinnedStreams.includes(a.streamer);
		const bPinned = pinnedStreams.includes(b.streamer);

		if (aPinned && !bPinned) return -1;
		if (!aPinned && bPinned) return 1;

		return 0;
	})
	.reduce(
		(
			acc: {
				live: Live[];
				upcoming: Live[];
				ended: Live[];
			},
			live,
		) => {
			const now = Date.now();
			const time = new Date(live.time).getTime();
			const isLive = live.streaming;
			const isUpcoming = time > now && !isLive;
			const isEnded = time < now && !isLive;

			if (isLive) {
				acc.live.push(live);
			} else if (isUpcoming) {
				acc.upcoming.push(live);
			} else if (isEnded) {
				acc.ended.push(live);
			}

			return acc;
		},
		{ live: [], upcoming: [], ended: [] },
	);
</script>

{#if schedule.lives.length === 0}
  <Message message="No upcoming streams." loader="ripple" />
{/if}

<div class="container">
  {#each categorisedStreams.live as live}
    <Stream {live} {pinStream} {pinnedStreams} icon={schedule.dict[live.streamer]} />
  {/each}
</div>

<Spacer />

<div class="container">
  {#each categorisedStreams.upcoming as live}
    <Stream {live} {pinStream} {pinnedStreams} icon={schedule.dict[live.streamer]} />
  {/each}
</div>

<Spacer />

<div class="container">
  {#each categorisedStreams.ended as live}
    <Stream {live} {pinStream} {pinnedStreams} icon={schedule.dict[live.streamer]} />
  {/each}
</div>

<style lang="scss">
  .container {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(22em, 1fr));
    gap: 0.5em;
  }
</style>