Implemented channel caching

This commit is contained in:
WardPearce
2025-12-13 12:25:26 +13:00
parent 7698b7ecdd
commit 045390f1bb
3 changed files with 68 additions and 28 deletions
+10
View File
@@ -13,6 +13,9 @@ import type { TitleCase } from './letterCasing';
import { serialize, deserialize } from '@macfja/serializer';
import type {
Channel,
ChannelContentPlaylists,
ChannelContentVideos,
ChannelPage,
HashTag,
Playlist,
PlaylistPage,
@@ -334,3 +337,10 @@ export const playlistCacheStore: Writable<{
}> = writable({});
export const isAndroidTvStore: Writable<boolean> = writable(false);
export const channelCacheStore: Writable<{
[key: string]: {
channel: ChannelPage;
displayContent: { [key: string]: ChannelContentVideos | ChannelContentPlaylists };
};
}> = writable({});
@@ -9,16 +9,15 @@
import PageLoading from '$lib/components/PageLoading.svelte';
import { proxyGoogleImage } from '$lib/images';
import { cleanNumber } from '$lib/numbers';
import { interfaceLowBandwidthMode, isAndroidTvStore } from '$lib/store';
import { channelCacheStore, interfaceLowBandwidthMode, isAndroidTvStore } from '$lib/store';
import { Clipboard } from '@capacitor/clipboard';
import { Capacitor } from '@capacitor/core';
import { onMount } from 'svelte';
import { _ } from '$lib/i18n';
import InfiniteLoading, { type InfiniteEvent } from 'svelte-infinite-loading';
import ItemsList from '$lib/components/ItemsList.svelte';
import Author from '$lib/components/Author.svelte';
let { data } = $props();
import { onMount } from 'svelte';
import { page } from '$app/state';
let tab: channelContentTypes = $state('videos');
@@ -31,8 +30,12 @@
let displayContent: ChannelContentPlaylists | ChannelContentVideos | undefined =
$state(undefined);
onMount(() => {
displayContent = $channelCacheStore[page.params.slug].displayContent.videos;
});
async function searchChannel() {
displayContent = await searchChannelContent(data.channel.authorId, channelSearch);
displayContent = await searchChannelContent(page.params.slug, channelSearch);
}
async function loadMore(event: InfiniteEvent) {
@@ -43,7 +46,7 @@
return;
}
const newContent = await getChannelContent(data.channel.authorId, {
const newContent = await getChannelContent(page.params.slug, {
type: tab,
continuation: displayContent.continuation,
sortBy: sortBy
@@ -69,30 +72,28 @@
async function changeTab(newTab: 'videos' | 'playlists' | 'streams' | 'shorts') {
tab = newTab;
displayContent = undefined;
displayContent = await getChannelContent(data.channel.authorId, { type: tab });
displayContent = await getChannelContent(page.params.slug, { type: tab });
}
onMount(async () => {
displayContent = await getChannelContent(data.channel.authorId, {
type: 'videos',
sortBy: sortBy
});
});
</script>
<div class="padding">
{#if data.channel.authorBanners.length > 0 && !$interfaceLowBandwidthMode}
{#if $channelCacheStore[page.params.slug].channel.authorBanners.length > 0 && !$interfaceLowBandwidthMode}
<img
loading="lazy"
src={proxyGoogleImage(data.channel.authorBanners[0].url)}
src={proxyGoogleImage($channelCacheStore[page.params.slug].channel.authorBanners[0].url)}
width="100%"
alt="Channel banner"
/>
{/if}
<div class="description">
<div>
<Author channel={{ ...data.channel, subCountText: cleanNumber(data.channel.subCount) }} />
<p style="width: 60vw;">{data.channel.description}</p>
<Author
channel={{
...$channelCacheStore[page.params.slug].channel,
subCountText: cleanNumber($channelCacheStore[page.params.slug].channel.subCount)
}}
/>
<p style="width: 60vw;">{$channelCacheStore[page.params.slug].channel.description}</p>
</div>
{#if !$isAndroidTvStore}
<button class="border">
@@ -117,7 +118,7 @@
role="presentation"
onclick={async () => {
await Clipboard.write({
string: `https://www.youtube.com/channel/${data.channel.authorId}`
string: `https://www.youtube.com/channel/${page.params.slug}`
});
(document.activeElement as HTMLElement)?.blur();
}}
@@ -130,25 +131,25 @@
</div>
<div class="tabs left-align scroll">
{#if data.channel.tabs.includes('videos')}
{#if $channelCacheStore[page.params.slug].channel.tabs.includes('videos')}
<a class:active={tab === 'videos'} onclick={() => changeTab('videos')} href="#video">
<i>movie</i>
<span>{$_('videoTabs.videos')}</span>
</a>
{/if}
{#if data.channel.tabs.includes('shorts')}
{#if $channelCacheStore[page.params.slug].channel.tabs.includes('shorts')}
<a class:active={tab === 'shorts'} onclick={() => changeTab('shorts')} href="#short">
<i>smartphone</i>
<span>{$_('videoTabs.shorts')}</span>
</a>
{/if}
{#if data.channel.tabs.includes('streams')}
{#if $channelCacheStore[page.params.slug].channel.tabs.includes('streams')}
<a class:active={tab === 'streams'} onclick={() => changeTab('streams')} href="#stream">
<i>stream</i>
<span>{$_('videoTabs.streams')}</span>
</a>
{/if}
{#if data.channel.tabs.includes('playlists')}
{#if $channelCacheStore[page.params.slug].channel.tabs.includes('playlists')}
<a class:active={tab === 'playlists'} onclick={() => changeTab('playlists')} href="#playlist">
<i>playlist_add_check</i>
<span>{$_('videoTabs.playlists')}</span>
@@ -165,7 +166,7 @@
onclick={async () => {
sortBy = sortingOption;
displayContent = await getChannelContent(data.channel.authorId, {
displayContent = await getChannelContent(page.params.slug, {
type: tab,
sortBy: sortBy
});
@@ -1,7 +1,28 @@
import { getChannel } from '$lib/api/index';
import { getChannel, getChannelContent } from '$lib/api/index';
import type { ChannelContentVideos, Video } from '$lib/api/model';
import { excludeDuplicateFeeds } from '$lib/misc.js';
import { channelCacheStore } from '$lib/store.js';
import { error } from '@sveltejs/kit';
import { get } from 'svelte/store';
export async function load({ params }) {
const currentChannelCache = get(channelCacheStore);
if (params.slug in currentChannelCache) {
getChannelContent(params.slug, {
type: 'videos'
}).then((channelContent) => {
if (!('videos' in currentChannelCache[params.slug].displayContent)) return;
(currentChannelCache[params.slug].displayContent.videos as ChannelContentVideos).videos =
excludeDuplicateFeeds(
(currentChannelCache[params.slug].displayContent.videos as ChannelContentVideos).videos,
(channelContent as ChannelContentVideos).videos
) as Video[];
});
return;
}
let channel;
try {
@@ -10,7 +31,15 @@ export async function load({ params }) {
error(500, errorMessage);
}
return {
channel: channel
};
const displayContent = await getChannelContent(params.slug, {
type: 'videos'
});
channelCacheStore.set({
...currentChannelCache,
[params.slug]: {
channel: channel,
displayContent: { videos: displayContent }
}
});
}