Merge pull request #31 from WardPearce/fix/minor-fixes

Fix/minor fixes
This commit is contained in:
Ward
2024-04-03 04:56:46 +13:00
committed by GitHub
18 changed files with 181 additions and 128 deletions
+6
View File
@@ -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",
+1
View File
@@ -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"
}
+1 -1
View File
@@ -37,7 +37,7 @@
{/if}
</div>
<p style="margin-bottom: 0;">
{comment.content}
{@html comment.contentHtml}
</p>
<div style="display: flex;">
<p><i>thumb_up</i> {numberWithCommas(comment.likeCount)}</p>
+4 -16
View File
@@ -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',
+6 -1
View File
@@ -38,7 +38,12 @@
});
</script>
<a class="wave" style="width: 100%; overflow: hidden;min-height:100px;" href={watchUrl}>
<a
class="wave"
style="width: 100%; overflow: hidden;min-height:100px;"
href={watchUrl}
data-sveltekit-preload-data="off"
>
{#if loading}
<progress class="circle"></progress>
{:else if loaded}
+29 -14
View File
@@ -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 = /<a href="([^"]+)"/;
const timestampRegex = /<a href="([^"]+)" data-onclick="jump_to_time" data-jump-time="(\d+)">(\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(/<a href="([^"]+)"/, '<a href="$1" target="_blank" rel="noopener noreferrer" class="link"');
filteredLines.push(modifiedLine);
} else if (timestampMatch !== null) {
// If line contains a timestamp, extract details and push into timestamps array
const time = timestampMatch[2];
const timestamp = timestampMatch[3];
const title = timestampMatch[4] || '';
timestamps.push({
time: parseInt(time),
title: title,
timePretty: timestamp
});
} else {
filteredLines.push(line);
}
}
);
return true;
});
const filteredContent = filteredLines.join('\n');
return { description: filteredContent, timestamps: timestamps };
}
function convertToSeconds(time: string): number {
const parts = time.split(':').map(part => parseInt(part));
let seconds = 0;
+1 -1
View File
@@ -535,7 +535,7 @@
{/each}
</dialog>
<main class="responsive max">
<main class="responsive max root">
<slot />
</main>
+10 -2
View File
@@ -1,10 +1,18 @@
<script lang="ts">
import VideoList from '$lib/VideoList.svelte';
import { activePage } from '../store.js';
import { activePage } from '../store';
export let data;
activePage.set('home');
</script>
<VideoList videos={data.popular} />
{#if data.popularDisabled}
<div class="space"></div>
<nav class="center-align">
<h3>Popular page has been disabled</h3>
</nav>
{:else}
<VideoList videos={data.popular} />
{/if}
+16 -2
View File
@@ -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
};
}
@@ -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}
</div>
</div>
<InfiniteLoading on:infinite={loadMore} />
{:else}
<PageLoading />
{/if}
+13 -12
View File
@@ -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);
});
</script>
@@ -66,3 +65,5 @@
</div>
<VideoList videos={history} />
<InfiniteLoading on:infinite={loadMore} />
@@ -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;
@@ -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);
});
</script>
<div class="space" style="margin-bottom: 1em;">
@@ -91,3 +87,5 @@
{/each}
</div>
</div>
<InfiniteLoading on:infinite={loadMore} />
@@ -1,32 +1,28 @@
<script lang="ts">
import { getFeed } from '$lib/Api/index.js';
import VideoList from '$lib/VideoList.svelte';
import { onDestroy, onMount } from 'svelte';
import { activePage } from '../../store.js';
import InfiniteLoading, { type InfiniteEvent } from 'svelte-infinite-loading';
import { activePage } from '../../store';
export let data;
let currentPage = 1;
let videos = [...data.feed.videos, ...data.feed.notifications];
$: videos = [...data.feed.videos, ...data.feed.notifications];
activePage.set('subscriptions');
async function handleScroll() {
const { scrollTop, clientHeight, scrollHeight } = document.documentElement;
if (scrollTop + clientHeight >= scrollHeight - 5) {
currentPage += 1;
const feed = await getFeed(100, currentPage);
async function loadMore(event: InfiniteEvent) {
currentPage++;
const feed = await getFeed(100, currentPage);
if (feed.notifications.length === 0) {
event.detail.complete();
} else {
videos = [...videos, ...feed.notifications];
event.detail.loaded();
}
}
onMount(() => {
window.addEventListener('scroll', handleScroll);
});
onDestroy(() => {
window.removeEventListener('scroll', handleScroll);
});
</script>
<VideoList bind:videos />
<InfiniteLoading on:infinite={loadMore} />
@@ -1,6 +1,6 @@
<script lang="ts">
import VideoList from '$lib/VideoList.svelte';
import { activePage } from '../../store.js';
import { activePage } from '../../store';
export let data;
@@ -15,7 +15,7 @@
import { cleanNumber, numberWithCommas } from '$lib/misc.js';
import { onMount } from 'svelte';
import { get } from 'svelte/store';
import { activePage, auth, playerListenByDefault } from '../../../store.js';
import { activePage, auth, playerListenByDefault } from '../../../store';
export let data;
@@ -213,28 +213,40 @@
</div>
</div>
<article class="medium scroll">
<p class="bold">
{numberWithCommas(data.video.viewCount)} views • {data.video.publishedText}
</p>
<p style="white-space: pre-line;word-wrap: break-word;">{data.content.description}</p>
{#if data.content}
{#if data.content.timestamps.length > 0}
<h6 style="margin-bottom: .3em;">Chapters</h6>
{#each data.content.timestamps as timestamp}
<button
on:click={() => seekTo(timestamp.time)}
class="timestamps"
class:primary={timestamp.time <= currentTime}
>{timestamp.timePretty}
{#if !timestamp.title.startsWith('-')}
-
{/if}
{timestamp.title}</button
>
{/each}
{/if}
{/if}
<article>
<details>
<summary class="bold none">
<nav>
<div class="max">
{numberWithCommas(data.video.viewCount)} views • {data.video.publishedText}
</div>
<i>expand_more</i>
</nav>
</summary>
<div class="space"></div>
<div class="medium scroll">
<div style="white-space: pre-line; overflow-wrap: break-word;">
{@html data.content.description}
</div>
{#if data.content}
{#if data.content.timestamps.length > 0}
<h6 style="margin-bottom: .3em;">Chapters</h6>
{#each data.content.timestamps as timestamp}
<button
on:click={() => seekTo(timestamp.time)}
class="timestamps"
class:primary={timestamp.time <= currentTime}
>{timestamp.timePretty}
{#if !timestamp.title.startsWith('-')}
-
{/if}
{timestamp.title}</button
>
{/each}
{/if}
{/if}
</div>
</details>
</article>
<div class="space"></div>
@@ -247,7 +259,7 @@
<button on:click={loadMoreComments} class="margin">Load more</button>
{/if}
{:else}
<h6>Comments disabled</h6>
<h6>Unable to load comments</h6>
{/if}
</div>
<div class="s12 m12 l2">
@@ -45,7 +45,7 @@ export async function load({ params, url }) {
returnYTDislikes: returnYTDislikes,
comments: comments,
subscribed: await amSubscribed(video.authorId),
content: phaseDescription(video.description),
content: phaseDescription(video.descriptionHtml),
playlistId: url.searchParams.get('playlist'),
personalPlaylists: personalPlaylists
};
+5
View File
@@ -7,4 +7,9 @@
padding-left: .1em !important;
padding-right: .1em !important;
}
}
main.root {
max-height: 100vh;
overflow-y: scroll;
}