diff --git a/materialious/package-lock.json b/materialious/package-lock.json index 39050f8a..8e58d9f7 100644 --- a/materialious/package-lock.json +++ b/materialious/package-lock.json @@ -12,6 +12,7 @@ "human-number": "^2.0.4", "media-icons": "^0.10.0", "sponsorblock-api": "^0.2.4", + "svelte-infinite-loading": "^1.3.8", "svelte-persisted-store": "^0.9.1", "vidstack": "^1.11.4" }, @@ -7142,6 +7143,11 @@ "svelte": "^3.19.0 || ^4.0.0" } }, + "node_modules/svelte-infinite-loading": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/svelte-infinite-loading/-/svelte-infinite-loading-1.3.8.tgz", + "integrity": "sha512-hn4o848LKd2Q+M11hiMWnfFxM1GHKVDi92HPZ1FYvfed4bEeRZL+QvFAQzhy1SACq6Si0CAJcQFUZpIYmAEnpQ==" + }, "node_modules/svelte-persisted-store": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/svelte-persisted-store/-/svelte-persisted-store-0.9.1.tgz", diff --git a/materialious/package.json b/materialious/package.json index 2b2894c5..bc11d80b 100644 --- a/materialious/package.json +++ b/materialious/package.json @@ -39,6 +39,7 @@ "human-number": "^2.0.4", "media-icons": "^0.10.0", "sponsorblock-api": "^0.2.4", + "svelte-infinite-loading": "^1.3.8", "svelte-persisted-store": "^0.9.1", "vidstack": "^1.11.4" } diff --git a/materialious/src/lib/Comment.svelte b/materialious/src/lib/Comment.svelte index 72cd0f06..2ebab1d3 100644 --- a/materialious/src/lib/Comment.svelte +++ b/materialious/src/lib/Comment.svelte @@ -37,7 +37,7 @@ {/if}

- {comment.content} + {@html comment.contentHtml}

thumb_up {numberWithCommas(comment.likeCount)}

diff --git a/materialious/src/lib/Player.svelte b/materialious/src/lib/Player.svelte index 53c1faaa..1a77ab34 100644 --- a/materialious/src/lib/Player.svelte +++ b/materialious/src/lib/Player.svelte @@ -169,21 +169,9 @@ const currentTheme = await getDynamicTheme(); - document.documentElement.style.setProperty( - '--video-controls-color', - currentTheme['--secondary'] - ); - document.documentElement.style.setProperty( - '--audio-controls-color', - currentTheme['--secondary'] - ); - document.documentElement.style.setProperty( - '--audio-play-button-bg', - currentTheme['--secondary'] - ); document.documentElement.style.setProperty( '--media-slider-track-fill-bg', - currentTheme['--secondary'] + currentTheme['--primary'] ); document.documentElement.style.setProperty('--media-menu-bg', currentTheme['--background']); document.documentElement.style.setProperty( @@ -191,12 +179,12 @@ currentTheme['--surface'] ); document.documentElement.style.setProperty( - '--media-menu-item-color', - currentTheme['--primary-text'] + '--media-menu-text-color', + currentTheme['--on-background'] ); document.documentElement.style.setProperty( '--media-menu-item-info-color', - currentTheme['--primary-text'] + currentTheme['--on-background'] ); document.documentElement.style.setProperty( '--media-menu-section-bg', diff --git a/materialious/src/lib/Thumbnail.svelte b/materialious/src/lib/Thumbnail.svelte index 951ab8bb..6fb8e6ae 100644 --- a/materialious/src/lib/Thumbnail.svelte +++ b/materialious/src/lib/Thumbnail.svelte @@ -38,7 +38,12 @@ }); - + {#if loading} {:else if loaded} diff --git a/materialious/src/lib/misc.ts b/materialious/src/lib/misc.ts index aad36367..a8099c05 100644 --- a/materialious/src/lib/misc.ts +++ b/materialious/src/lib/misc.ts @@ -40,31 +40,46 @@ export interface PhasedDescription { export function phaseDescription(content: string): PhasedDescription { const timestamps: { title: string; time: number; timePretty: string; }[] = []; + console.log(content); const lines = content.split('\n'); - const regex = /(\d+:\d+(?::\d+)?)(?:\s(.+))?/; - const filteredLines = lines.filter(line => { - const match = regex.exec(line); + const urlRegex = /(\d+:\d+(?::\d+)?)<\/a>\s*(.+)/; - if (match !== null) { - const timestamp = match[1]; - const title = match[2] || ''; - timestamps.push({ - time: convertToSeconds(timestamp), - title: title, - timePretty: timestamp - }); - return false; + let filteredLines: string[] = []; + lines.forEach( + (line) => { + const urlMatch = urlRegex.exec(line); + const timestampMatch = timestampRegex.exec(line); + + if (urlMatch !== null && timestampMatch === null) { + // If line contains a URL but not a timestamp, modify the URL + const modifiedLine = line.replace(/ parseInt(part)); let seconds = 0; diff --git a/materialious/src/routes/+layout.svelte b/materialious/src/routes/+layout.svelte index a066b9f7..6c17fe38 100644 --- a/materialious/src/routes/+layout.svelte +++ b/materialious/src/routes/+layout.svelte @@ -535,7 +535,7 @@ {/each} -
+
diff --git a/materialious/src/routes/+page.svelte b/materialious/src/routes/+page.svelte index 999922cf..3946b935 100644 --- a/materialious/src/routes/+page.svelte +++ b/materialious/src/routes/+page.svelte @@ -1,10 +1,18 @@ - +{#if data.popularDisabled} +
+ + +{:else} + +{/if} diff --git a/materialious/src/routes/+page.ts b/materialious/src/routes/+page.ts index b3b31184..faea9e87 100644 --- a/materialious/src/routes/+page.ts +++ b/materialious/src/routes/+page.ts @@ -1,7 +1,21 @@ import { getPopular } from '$lib/Api/index.js'; +import { error } from '@sveltejs/kit'; -export async function load({ params }) { +export async function load() { + let popular = undefined; + let popularDisabled: boolean = false; + + try { + popular = await getPopular(); + } catch (errorMessage: any) { + if (errorMessage.toString() === 'Error: Administrator has disabled this endpoint.') { + popularDisabled = true; + } else { + error(500, errorMessage); + } + } return { - popular: await getPopular() + popular: popular, + popularDisabled: popularDisabled }; } \ No newline at end of file diff --git a/materialious/src/routes/channel/[slug]/+page.svelte b/materialious/src/routes/channel/[slug]/+page.svelte index 3096b2f3..82a482f0 100644 --- a/materialious/src/routes/channel/[slug]/+page.svelte +++ b/materialious/src/routes/channel/[slug]/+page.svelte @@ -5,7 +5,8 @@ import PlaylistThumbnail from '$lib/PlaylistThumbnail.svelte'; import Thumbnail from '$lib/Thumbnail.svelte'; import { cleanNumber } from '$lib/misc'; - import { onDestroy, onMount } from 'svelte'; + import { onMount } from 'svelte'; + import InfiniteLoading, { type InfiniteEvent } from 'svelte-infinite-loading'; import { get } from 'svelte/store'; import { activePage, auth } from '../../../store'; @@ -19,22 +20,29 @@ let displayContent: ChannelContentPlaylists | ChannelContentVideos | undefined = undefined; - async function handleScroll() { + async function loadMore(event: InfiniteEvent) { if (typeof displayContent === 'undefined') return; - const { scrollTop, clientHeight, scrollHeight } = document.documentElement; - if (scrollTop + clientHeight >= scrollHeight - 5) { - const newContent = await getChannelContent(data.channel.authorId, { - type: tab, - continuation: displayContent.continuation - }); - if ('videos' in newContent && 'videos' in displayContent) { - displayContent.videos = [...displayContent.videos, ...newContent.videos]; - } else if ('playlists' in displayContent && 'playlists' in newContent) { - displayContent.playlists = [...displayContent.playlists, ...newContent.playlists]; + const newContent = await getChannelContent(data.channel.authorId, { + type: tab, + continuation: displayContent.continuation + }); + if ('videos' in newContent && 'videos' in displayContent) { + if (displayContent.continuation === newContent.continuation) { + event.detail.complete(); + } else { + event.detail.loaded(); } - displayContent.continuation = newContent.continuation; + displayContent.videos = [...displayContent.videos, ...newContent.videos]; + } else if ('playlists' in displayContent && 'playlists' in newContent) { + if (displayContent.continuation === newContent.continuation) { + event.detail.complete(); + } else { + event.detail.loaded(); + } + displayContent.playlists = [...displayContent.playlists, ...newContent.playlists]; } + displayContent.continuation = newContent.continuation; } async function changeTab(newTab: 'videos' | 'playlists' | 'streams' | 'shorts') { @@ -49,12 +57,6 @@ if (get(auth)) { isSubscribed = await amSubscribed(data.channel.authorId); } - - window.addEventListener('scroll', handleScroll); - }); - - onDestroy(() => { - window.removeEventListener('scroll', handleScroll); }); async function toggleSubscribed() { @@ -144,6 +146,8 @@ {/if}
+ + {:else} {/if} diff --git a/materialious/src/routes/history/+page.svelte b/materialious/src/routes/history/+page.svelte index ba4328cf..03fba9d4 100644 --- a/materialious/src/routes/history/+page.svelte +++ b/materialious/src/routes/history/+page.svelte @@ -3,7 +3,8 @@ import type { VideoPlay } from '$lib/Api/model'; import VideoList from '$lib/VideoList.svelte'; import { error } from '@sveltejs/kit'; - import { onDestroy, onMount } from 'svelte'; + import { onMount } from 'svelte'; + import InfiniteLoading, { type InfiniteEvent } from 'svelte-infinite-loading'; import { activePage } from '../../store'; activePage.set('history'); @@ -28,23 +29,21 @@ } } - async function handleScroll() { - const { scrollTop, clientHeight, scrollHeight } = document.documentElement; - if (scrollTop + clientHeight >= scrollHeight - 5) { - currentPage += 1; - await loadPageHistory(); + async function loadMore(event: InfiniteEvent) { + const pastHistoryLen = Number(history.length); + + await loadPageHistory(); + + if (pastHistoryLen === history.length) { + event.detail.complete(); + } else { + event.detail.loaded(); } } onMount(async () => { await loadPageHistory(); loaded = true; - - window.addEventListener('scroll', handleScroll); - }); - - onDestroy(() => { - window.removeEventListener('scroll', handleScroll); }); @@ -66,3 +65,5 @@ + + diff --git a/materialious/src/routes/playlist/[slug]/+page.svelte b/materialious/src/routes/playlist/[slug]/+page.svelte index caec99a7..3c76517f 100644 --- a/materialious/src/routes/playlist/[slug]/+page.svelte +++ b/materialious/src/routes/playlist/[slug]/+page.svelte @@ -4,7 +4,7 @@ import VideoList from '$lib/VideoList.svelte'; import { cleanNumber } from '$lib/misc.js'; import { onMount } from 'svelte'; - import { activePage } from '../../../store.js'; + import { activePage } from '../../../store'; export let data; diff --git a/materialious/src/routes/search/[slug]/+page.svelte b/materialious/src/routes/search/[slug]/+page.svelte index 425a7d7d..ed4ed92f 100644 --- a/materialious/src/routes/search/[slug]/+page.svelte +++ b/materialious/src/routes/search/[slug]/+page.svelte @@ -4,7 +4,7 @@ import ChannelThumbnail from '$lib/ChannelThumbnail.svelte'; import PlaylistThumbnail from '$lib/PlaylistThumbnail.svelte'; import Thumbnail from '$lib/Thumbnail.svelte'; - import { onDestroy, onMount } from 'svelte'; + import InfiniteLoading, { type InfiniteEvent } from 'svelte-infinite-loading'; import { activePage } from '../../../store'; export let data; @@ -20,24 +20,20 @@ document.location.href = $page.url.href; } - async function handleScroll() { - const { scrollTop, clientHeight, scrollHeight } = document.documentElement; - if (scrollTop + clientHeight >= scrollHeight - 5) { - currentPage += 1; - search = [ - ...search, - ...(await getSearch(data.slug, { page: currentPage.toString(), type: data.searchType })) - ]; + async function loadMore(event: InfiniteEvent) { + currentPage++; + const newSearch = await getSearch(data.slug, { + page: currentPage.toString(), + type: data.searchType + }); + + if (newSearch.length === 0) { + event.detail.complete(); + } else { + search = [...search, ...newSearch]; + event.detail.loaded(); } } - - onMount(() => { - window.addEventListener('scroll', handleScroll); - }); - - onDestroy(() => { - window.removeEventListener('scroll', handleScroll); - });
@@ -91,3 +87,5 @@ {/each}
+ + diff --git a/materialious/src/routes/subscriptions/+page.svelte b/materialious/src/routes/subscriptions/+page.svelte index d93855a2..81020910 100644 --- a/materialious/src/routes/subscriptions/+page.svelte +++ b/materialious/src/routes/subscriptions/+page.svelte @@ -1,32 +1,28 @@ + + diff --git a/materialious/src/routes/trending/+page.svelte b/materialious/src/routes/trending/+page.svelte index 6bc28178..ca6f269b 100644 --- a/materialious/src/routes/trending/+page.svelte +++ b/materialious/src/routes/trending/+page.svelte @@ -1,6 +1,6 @@