Inmprovements to search caching via state

This commit is contained in:
WardPearce
2025-06-01 21:42:52 +12:00
parent f4a1395e59
commit f5b931f4a9
3 changed files with 52 additions and 26 deletions
+4 -1
View File
@@ -4,7 +4,7 @@ import type { DataConnection } from 'peerjs';
import { persisted } from 'svelte-persisted-store';
import { writable, type Writable } from 'svelte/store';
import type { TitleCase } from './letterCasing';
import type { PlaylistPageVideo, Video, VideoBase } from './api/model';
import type { Channel, HashTag, Playlist, PlaylistPageVideo, Video, VideoBase } from './api/model';
function platformDependentDefault(givenValue: any, defaultValue: any): any {
if (typeof givenValue !== 'undefined' && typeof givenValue !== null) {
@@ -115,4 +115,7 @@ export const searchHistoryStore: Writable<string[]> = persisted('searchHistory',
export const feedCacheStore: Writable<{
[key: string]: (VideoBase | Video | PlaylistPageVideo)[];
}> = writable({});
export const searchCacheStore: Writable<{
[searchType: string]: (Channel | Video | Playlist | HashTag)[];
}> = writable({});
export const feedLastItemId: Writable<string | undefined> = writable(undefined);
@@ -6,33 +6,41 @@
import PageLoading from '$lib/components/PageLoading.svelte';
import PlaylistThumbnail from '$lib/components/PlaylistThumbnail.svelte';
import Thumbnail from '$lib/components/Thumbnail.svelte';
import { feedLastItemId, searchCacheStore } from '$lib/store.js';
import { onMount } from 'svelte';
import { _ } from 'svelte-i18n';
import InfiniteLoading, { type InfiniteEvent } from 'svelte-infinite-loading';
let { data } = $props();
let searchResults = $state(data);
let currentType: 'playlist' | 'all' | 'video' | 'channel' = $state('all');
let currentPage = 1;
onMount(() => {
if ($feedLastItemId) {
document.getElementById($feedLastItemId)?.scrollIntoView({ behavior: 'instant' });
}
});
async function changeType(type: 'playlist' | 'all' | 'video' | 'channel') {
searchResults.searchType = type;
currentType = type;
currentPage = 1;
searchResults.search = [];
searchResults.search = await getSearch(searchResults.slug, { type: type });
searchCacheStore.set({ [type]: await getSearch(data.slug, { type: type }) });
}
async function loadMore(event: InfiniteEvent) {
currentPage++;
const newSearch = await getSearch(searchResults.slug, {
const newSearch = await getSearch(data.slug, {
page: currentPage.toString(),
type: searchResults.searchType
type: currentType
});
if (newSearch.length === 0) {
event.detail.complete();
} else {
searchResults.search = [...searchResults.search, ...newSearch];
searchCacheStore.set({
[currentType]: [...($searchCacheStore[currentType] ?? []), ...newSearch]
});
event.detail.loaded();
}
}
@@ -40,16 +48,12 @@
<div style="margin-top: 1em;">
<div class="tabs left-align min scroll">
<a
class:active={searchResults.searchType === 'all'}
href="#all"
onclick={async () => changeType('all')}
>
<a class:active={currentType === 'all'} href="#all" onclick={async () => changeType('all')}>
<i>home</i>
<span>{$_('videoTabs.all')}</span>
</a>
<a
class:active={searchResults.searchType === 'video'}
class:active={currentType === 'video'}
href="#videos"
onclick={async () => changeType('video')}
>
@@ -57,7 +61,7 @@
<span>{$_('videoTabs.videos')}</span>
</a>
<a
class:active={searchResults.searchType === 'playlist'}
class:active={currentType === 'playlist'}
href="#playlists"
onclick={async () => changeType('playlist')}
>
@@ -65,7 +69,7 @@
<span>{$_('videoTabs.playlists')}</span>
</a>
<a
class:active={searchResults.searchType === 'channel'}
class:active={currentType === 'channel'}
href="#channels"
onclick={async () => changeType('channel')}
>
@@ -75,14 +79,26 @@
</div>
</div>
{#if searchResults.search.length > 0}
{#if $searchCacheStore[currentType].length > 0}
<div class="page right active">
<div class="space"></div>
<div class="grid">
{#each searchResults.search as item}
{#each $searchCacheStore[currentType] as item}
<ContentColumn>
{#key item}
<article class="no-padding" style="height: 100%;">
<article
class="no-padding"
style="height: 100%;"
onclick={() =>
feedLastItemId.set(
'videoId' in item ? item.videoId : 'authorId' in item ? item.authorId : item.title
)}
id={'videoId' in item
? item.videoId
: 'authorId' in item
? item.authorId
: item.title}
>
{#if item.type === 'video'}
<Thumbnail video={item} />
{:else if item.type === 'channel'}
@@ -1,5 +1,7 @@
import { getSearch } from '$lib/api/index';
import { searchCacheStore } from '$lib/store.js';
import { error } from '@sveltejs/kit';
import { get } from 'svelte/store';
export async function load({ params, url }) {
let type: 'playlist' | 'all' | 'video' | 'channel';
@@ -11,16 +13,21 @@ export async function load({ params, url }) {
type = 'all';
}
let search;
const search = get(searchCacheStore).all;
try {
search = await getSearch(params.slug, { type: type });
} catch (errorMessage: any) {
error(500, errorMessage);
if (!search) {
try {
searchCacheStore.set({ [type]: await getSearch(params.slug, { type: type }) });
} catch (errorMessage: any) {
error(500, errorMessage);
}
} else {
getSearch(params.slug, { type: type }).then((newSearch) => {
searchCacheStore.set({ [type]: Array.from(new Set({ ...newSearch, ...search })) });
});
}
return {
search: search,
slug: params.slug,
searchType: type
};