aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/Database/userConfiguration.ts30
-rw-r--r--src/lib/websocket.ts.bak (renamed from src/lib/websocket.ts)0
-rw-r--r--src/routes/api/configuration/pin/+server.ts32
-rw-r--r--src/routes/hololive/+page.svelte59
4 files changed, 118 insertions, 3 deletions
diff --git a/src/lib/Database/userConfiguration.ts b/src/lib/Database/userConfiguration.ts
index 3a01411e..f1e3ef95 100644
--- a/src/lib/Database/userConfiguration.ts
+++ b/src/lib/Database/userConfiguration.ts
@@ -2,14 +2,16 @@ import supabase from './supabase';
interface UserConfiguration {
user_id: number;
- configuration: JSON;
+ configuration: object;
created_at: string;
updated_at: string;
+ pinned_hololive_streams: string[];
}
interface NewUserConfiguration {
- configuration: JSON;
+ configuration: object;
updated_at?: string;
+ pinned_hololive_streams?: string[];
}
export const getUserConfiguration = async (userId: number) => {
@@ -24,13 +26,17 @@ export const getUserConfiguration = async (userId: number) => {
};
export const setUserConfiguration = async (userId: number, configuration: NewUserConfiguration) => {
+ const userConfiguration = await getUserConfiguration(userId);
const { data, error } = await supabase
.from('user_configuration')
.upsert(
{
user_id: userId,
configuration: configuration.configuration,
- updated_at: configuration.updated_at || new Date().toISOString()
+ updated_at: configuration.updated_at || new Date().toISOString(),
+ pinned_hololive_streams:
+ configuration.pinned_hololive_streams ||
+ (userConfiguration ? userConfiguration.pinned_hololive_streams : [])
},
{ onConflict: 'user_id' }
)
@@ -40,3 +46,21 @@ export const setUserConfiguration = async (userId: number, configuration: NewUse
return data[0].configuration as UserConfiguration;
};
+
+export const toggleHololiveStreamPinning = async (userId: number, streamId: string) => {
+ const userConfiguration = await getUserConfiguration(userId);
+
+ if (!userConfiguration) return null;
+
+ const pinnedStreams = userConfiguration.pinned_hololive_streams;
+ const index = pinnedStreams.indexOf(streamId);
+
+ if (index === -1) pinnedStreams.push(streamId);
+ else pinnedStreams.splice(index, 1);
+
+ return setUserConfiguration(userId, {
+ configuration: userConfiguration.configuration,
+ updated_at: new Date().toISOString(),
+ pinned_hololive_streams: pinnedStreams
+ });
+};
diff --git a/src/lib/websocket.ts b/src/lib/websocket.ts.bak
index 28557415..28557415 100644
--- a/src/lib/websocket.ts
+++ b/src/lib/websocket.ts.bak
diff --git a/src/routes/api/configuration/pin/+server.ts b/src/routes/api/configuration/pin/+server.ts
new file mode 100644
index 00000000..f813d8e8
--- /dev/null
+++ b/src/routes/api/configuration/pin/+server.ts
@@ -0,0 +1,32 @@
+import { userIdentity } from '$lib/Data/AniList/identity';
+import { toggleHololiveStreamPinning } from '$lib/Database/userConfiguration';
+
+const unauthorised = new Response('Unauthorised', { status: 401 });
+
+export const PUT = async ({ cookies, url }) => {
+ const userCookie = cookies.get('user');
+
+ if (!userCookie) return unauthorised;
+
+ const user = JSON.parse(userCookie);
+
+ return Response.json(
+ await toggleHololiveStreamPinning(
+ (
+ await userIdentity({
+ tokenType: user['token_type'],
+ expiresIn: user['expires_in'],
+ accessToken: user['access_token'],
+ refreshToken: user['refresh_token']
+ })
+ ).id,
+ url.searchParams.get('stream') || ''
+ ),
+ {
+ headers: {
+ method: 'PUT',
+ 'Access-Control-Allow-Origin': 'https://due.moe'
+ }
+ }
+ );
+};
diff --git a/src/routes/hololive/+page.svelte b/src/routes/hololive/+page.svelte
index d30766b9..aace56a3 100644
--- a/src/routes/hololive/+page.svelte
+++ b/src/routes/hololive/+page.svelte
@@ -6,6 +6,9 @@
import { parseScheduleHtml } from '$lib/Data/hololive';
import proxy from '$lib/Utility/proxy';
import locale from '$stores/locale';
+ import root from '$lib/Utility/root';
+ import identity from '$stores/identity';
+ import Icon from '@iconify/svelte';
interface ParseResult {
lives: {
@@ -21,6 +24,17 @@
}
let schedulePromise: Promise<Response>;
+ let pinnedStreams: string[] = [];
+
+ $: {
+ pinnedStreams = pinnedStreams;
+
+ schedulePromise = fetch(proxy('https://schedule.hololive.tv'), {
+ headers: {
+ Cookie: 'timezone=Asia/Tokyo'
+ }
+ });
+ }
onMount(async () => {
schedulePromise = fetch(proxy('https://schedule.hololive.tv'), {
@@ -28,9 +42,29 @@
Cookie: 'timezone=Asia/Tokyo'
}
});
+
+ getPinnedStreams();
});
+ const getPinnedStreams = () => {
+ if ($identity.id !== -2)
+ fetch(root(`/api/configuration?id=${$identity.id}`)).then((response) => {
+ if (response.ok)
+ response.json().then((data) => {
+ if (data && data.configuration) pinnedStreams = data.pinned_hololive_streams;
+ });
+ });
+ };
+
const typeSchedule = (schedule: any) => schedule as ParseResult;
+
+ const pinStream = (streamer: string) =>
+ fetch(root(`/api/configuration/pin?stream=${encodeURIComponent(streamer)}`), {
+ method: 'PUT',
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+ }).then(getPinnedStreams);
</script>
<HeadTitle route="hololive Schedule" path="/hololive" />
@@ -60,6 +94,12 @@
return time.getTime() > Date.now() - 12 * 60 * 60 * 1000 || time.getTime() > Date.now() || live.streaming;
})
.sort((a, b) => {
+ if (pinnedStreams.includes(a.streamer) && a.streaming) {
+ return -1;
+ } else if (pinnedStreams.includes(b.streamer) && b.streaming) {
+ return 1;
+ }
+
if (a.streaming && !b.streaming) {
return -1;
} else if (!a.streaming && b.streaming) {
@@ -77,6 +117,18 @@
return aTime - new Date(b.time).getTime();
}) as live}
<div class="stream card">
+ {#if $identity.id !== -2}
+ <div class="pin-icon">
+ <a href={'#'} on:click={() => pinStream(live.streamer)}>
+ <Icon
+ icon={`pajamas:thumbtack${
+ pinnedStreams.includes(live.streamer) ? '-solid' : ''
+ }`}
+ />
+ </a>
+ </div>
+ {/if}
+
<p>
[{#if live.streaming}
<b class="live">{$locale().hololive.live}</b
@@ -167,4 +219,11 @@
grid-template-columns: repeat(auto-fill, minmax(22.5em, 1fr));
gap: 0.5em;
}
+
+ .pin-icon {
+ position: absolute;
+ right: 0;
+ top: 0;
+ padding: 0.75rem;
+ }
</style>