diff options
Diffstat (limited to 'src/lib/Hololive')
| -rw-r--r-- | src/lib/Hololive/Lives.svelte | 168 | ||||
| -rw-r--r-- | src/lib/Hololive/Stream.svelte | 106 | ||||
| -rw-r--r-- | src/lib/Hololive/hololive.ts | 20 |
3 files changed, 170 insertions, 124 deletions
diff --git a/src/lib/Hololive/Lives.svelte b/src/lib/Hololive/Lives.svelte index c7ecfdf8..38def6fa 100644 --- a/src/lib/Hololive/Lives.svelte +++ b/src/lib/Hololive/Lives.svelte @@ -1,10 +1,8 @@ <script lang="ts"> import Message from '$lib/Loading/Message.svelte'; import root from '$lib/Utility/root'; - import identity from '$stores/identity'; - import locale from '$stores/locale'; - import Icon from '@iconify/svelte'; - import type { ParseResult } from './hololive'; + import type { Live, ParseResult } from './hololive'; + import Stream from './Stream.svelte'; export let schedule: ParseResult; export let closestUpcomingPinnedStreams: Map<string, any>; @@ -18,23 +16,8 @@ 'Content-Type': 'application/json' } }).then(getPinnedStreams); -</script> - -{#if schedule.lives.length === 0} - <Message message="No upcoming streams." loader="ripple" /> -{/if} -<div class="container"> - {#each schedule.lives - .filter((live) => { - try { - $locale().hololive.dateFormatter(new Date(live.time)); - - return true; - } catch { - return false; - } - }) + $: categorisedStreams = schedule.lives .sort((a, b) => new Date(a.time).getTime() - new Date(b.time).getTime()) .sort((a, b) => { const now = Date.now(); @@ -58,111 +41,66 @@ if (bTime > now && !(bTime < now && !bIsLive)) return 1; return bTime - aTime; - }) as live} - <div class="stream card"> - {#if $identity.id !== -2} - <div class="pin-icon"> - <a - href={'#'} - on:click={(e) => { - e.preventDefault(); - pinStream(live.streamer); - }} - > - <Icon - icon={`pajamas:thumbtack${pinnedStreams.includes(live.streamer) ? '-solid' : ''}`} - width="1em" - /> - </a> - </div> - {/if} - - <p class="stream-heading"> - [{#if live.streaming} - <b class="live">{$locale().hololive.live}</b - >{:else if new Date(live.time).getTime() < Date.now()} - <span class="ended">{$locale().hololive.ended}</span>{:else} - <span class="upcoming">{$locale().hololive.upcoming}</span>{/if}] - <b>{live.streamer}</b> <span class="opaque">|</span> - {$locale().hololive.dateFormatter(new Date(live.time))} - {#if live.guests.length > 0} - <br /> - <small> - {$locale().hololive.with}{live.guests - .join($locale().hololive.comma) - .replace( - new RegExp( - `${$locale().hololive.comma}([^${$locale().hololive.commaNoSpace}]+)$`, - 'g' - ), - `${$locale().hololive.comma}${$locale().hololive.ampersand}$1` - )} - </small> - {/if} - </p> - - <a href={live.link} class="preview" target="_blank"> - <img src={live.livePreviewImage} alt="Stream Thumbnail" /> - </a> - </div> + }) + .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} /> {/each} </div> -<style lang="scss"> - .preview { - // margin: 0.15rem; - - img { - border-radius: 8px; - height: 20vh; - object-fit: cover; - transition: transform 0.3s ease; - } - - &:hover { - img { - position: relative; - z-index: 2; - transition: transform 0.3s ease; - transform: scale(1.05); - } - } - - display: flex; - justify-content: center; - align-items: center; - } +<p /> - .live { - color: var(--base0F); - } +<div class="container"> + {#each categorisedStreams.upcoming as live} + <Stream {live} {pinStream} {pinnedStreams} /> + {/each} +</div> - .upcoming { - color: var(--base0C); - } +<p /> - .ended { - color: var(--base0D); - } +<div class="container"> + {#each categorisedStreams.ended as live} + <Stream {live} {pinStream} {pinnedStreams} /> + {/each} +</div> +<style lang="scss"> .container { display: grid; grid-template-columns: repeat(auto-fill, minmax(22.5em, 1fr)); gap: 0.5em; } - - .pin-icon { - position: absolute; - right: 0; - top: 0; - padding: 0.75rem; - } - - .stream { - position: relative; - } - - .stream-heading { - padding-right: 2em; - } </style> diff --git a/src/lib/Hololive/Stream.svelte b/src/lib/Hololive/Stream.svelte new file mode 100644 index 00000000..3d59fd72 --- /dev/null +++ b/src/lib/Hololive/Stream.svelte @@ -0,0 +1,106 @@ +<script lang="ts"> + import identity from '$stores/identity'; + import locale from '$stores/locale'; + import Icon from '@iconify/svelte'; + + export let live: any; + export let pinStream: (streamer: string) => void; + export let pinnedStreams: string[]; +</script> + +<div class="stream card"> + {#if $identity.id !== -2} + <div class="pin-icon"> + <a + href={'#'} + on:click={(e) => { + e.preventDefault(); + pinStream(live.streamer); + }} + > + <Icon + icon={`pajamas:thumbtack${pinnedStreams.includes(live.streamer) ? '-solid' : ''}`} + width="1em" + /> + </a> + </div> + {/if} + + <p class="stream-heading"> + [{#if live.streaming} + <b class="live">{$locale().hololive.live}</b + >{:else if new Date(live.time).getTime() < Date.now()} + <span class="ended">{$locale().hololive.ended}</span>{:else} + <span class="upcoming">{$locale().hololive.upcoming}</span>{/if}] + <b>{live.streamer}</b> <span class="opaque">|</span> + {$locale().hololive.dateFormatter(new Date(live.time))} + {#if live.guests.length > 0} + <br /> + <small> + {$locale().hololive.with}{live.guests + .join($locale().hololive.comma) + .replace( + new RegExp(`${$locale().hololive.comma}([^${$locale().hololive.commaNoSpace}]+)$`, 'g'), + `${$locale().hololive.comma}${$locale().hololive.ampersand}$1` + )} + </small> + {/if} + </p> + + <a href={live.link} class="preview" target="_blank"> + <img src={live.livePreviewImage} alt="Stream Thumbnail" /> + </a> +</div> + +<style lang="scss"> + .preview { + // margin: 0.15rem; + + img { + border-radius: 8px; + height: 20vh; + object-fit: cover; + transition: transform 0.3s ease; + } + + &:hover { + img { + position: relative; + z-index: 2; + transition: transform 0.3s ease; + transform: scale(1.05); + } + } + + display: flex; + justify-content: center; + align-items: center; + } + + .live { + color: var(--base0F); + } + + .upcoming { + color: var(--base0C); + } + + .ended { + color: var(--base0D); + } + + .pin-icon { + position: absolute; + right: 0; + top: 0; + padding: 0.75rem; + } + + .stream { + position: relative; + } + + .stream-heading { + padding-right: 2em; + } +</style> diff --git a/src/lib/Hololive/hololive.ts b/src/lib/Hololive/hololive.ts index 4ba7e46e..6ad97430 100644 --- a/src/lib/Hololive/hololive.ts +++ b/src/lib/Hololive/hololive.ts @@ -1,12 +1,14 @@ +export interface Live { + time: Date; + link: string; + videoId: string; + streamer: string; + livePreviewImage: string; + guests: string[]; + streaming: boolean; +} + export interface ParseResult { - lives: { - time: Date; - link: string; - videoId: string; - streamer: string; - livePreviewImage: string; - guests: string[]; - streaming: boolean; - }[]; + lives: Live[]; dict: Record<string, string>; } |