From 8b9cd8f1cfa811767c9a8e831c243b2783af67aa Mon Sep 17 00:00:00 2001 From: WardPearce Date: Wed, 30 Oct 2024 00:29:54 +1300 Subject: [PATCH 01/10] Add support for @username urls --- docs/BUILDING.md | 6 +----- materialious/src/lib/Comment.svelte | 5 +++-- materialious/src/lib/api/index.ts | 6 ++++++ materialious/src/lib/api/model.ts | 6 ++++++ materialious/src/routes/+layout.ts | 18 +++++++++++++++--- 5 files changed, 31 insertions(+), 10 deletions(-) diff --git a/docs/BUILDING.md b/docs/BUILDING.md index a0e3dbd9..e2f080f2 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -19,11 +19,7 @@ Materialious desktop builds are handled through GitHub using [prod-desktop.yml]( - From here, the process follows standard [electron-builder](https://www.electron.build/) steps to complete the build. ### Desktop Release (via Flatpak) -Flatpak builds for desktop releases are managed via [us.materailio.app](../flatpak/us.materialio.app.json). - -- We generate the necessary remote npm packages with `flatpak-node-generator npm -r ../materialious/package-lock.json -R ../materialious/electron/package-lock.json`, which creates [generated-sources.json](../flatpak/generated-sources.json). -- The Linux x64 runtime is downloaded as part of the Flatpak build sources and placed in `main/materialious/electron/.electron-cache`. The [electron-builder.config.json](../materialious/electron/electron-builder.config.json) is configured to use this cache directory to avoid downloading the runtime again during the build. -- The build process is similar to [prod-desktop.yml](../.github/workflows/prod-desktop.yml), following the guidelines for [Flatpak Electron](https://docs.flatpak.org/en/latest/electron.html). +TODO ### Android Release Android builds are handled using the workflow [prod-android.yml](../.github/workflows/prod-android.yml). diff --git a/materialious/src/lib/Comment.svelte b/materialious/src/lib/Comment.svelte index f1cdf954..3fbc02c1 100644 --- a/materialious/src/lib/Comment.svelte +++ b/materialious/src/lib/Comment.svelte @@ -22,8 +22,8 @@ function commentTimestamps(html: string): string { const regex = - /(\d+:\d+(?::\d+)?)<\/a>\s*(.+)/; - const replacement = `$3`; + /([^<]+)<\/a>\s*(.+)/g; + const replacement = `$3 $4`; const processedHtml = html.replace(regex, replacement); @@ -107,6 +107,7 @@ .comment { display: flex; margin-bottom: 0.8em; + white-space: pre-line; } .channel-owner { diff --git a/materialious/src/lib/api/index.ts b/materialious/src/lib/api/index.ts index d0bbef1b..5b90854f 100644 --- a/materialious/src/lib/api/index.ts +++ b/materialious/src/lib/api/index.ts @@ -22,6 +22,7 @@ import type { Feed, Playlist, PlaylistPage, + ResolvedUrl, ReturnYTDislikes, SearchSuggestion, Subscription, @@ -71,6 +72,11 @@ export async function getPopular(fetchOptions?: RequestInit): Promise { return await resp.json(); } +export async function getResolveUrl(url: string): Promise { + const resp = await fetchErrorHandle(await fetch(`${buildPath('resolveurl')}?url=${url}`)); + return await resp.json(); +} + export async function getVideo(videoId: string, local: boolean = false, fetchOptions?: RequestInit): Promise { const resp = await fetch(setRegion(buildPath(`videos/${videoId}?local=${local}`)), fetchOptions); if ( diff --git a/materialious/src/lib/api/model.ts b/materialious/src/lib/api/model.ts index ffae475d..db048ac7 100644 --- a/materialious/src/lib/api/model.ts +++ b/materialious/src/lib/api/model.ts @@ -21,6 +21,12 @@ export interface VideoBase { viewCountText: string; } +export interface ResolvedUrl { + ucid: string; + params: string; + pageType: string; +} + export interface Video extends VideoBase { type: 'video'; title: string; diff --git a/materialious/src/routes/+layout.ts b/materialious/src/routes/+layout.ts index d7f14dac..2879758a 100644 --- a/materialious/src/routes/+layout.ts +++ b/materialious/src/routes/+layout.ts @@ -1,13 +1,25 @@ import { browser } from '$app/environment'; +import { goto } from '$app/navigation'; +import { getResolveUrl } from '$lib/api'; import '$lib/i18n'; // Import to initialize. Important :) import { locale, waitLocale } from 'svelte-i18n'; -import type { LayoutLoad } from './$types'; export let ssr = false; -export const load: LayoutLoad = async () => { +export async function load({ url }) { + if (url.pathname.startsWith('/@')) { + const username = url.pathname.split('/')[1]; + + try { + const resolvedUrl = await getResolveUrl(`www.youtube.com/${username}`); + if (resolvedUrl.pageType === 'WEB_PAGE_TYPE_CHANNEL') { + goto(`/channel/${resolvedUrl.ucid}`); + } + } catch { } + } + if (browser) { locale.set(window.navigator.language); } await waitLocale(); -}; +} From 09b1314b5bfb743c0c900e31dba85420e311e327 Mon Sep 17 00:00:00 2001 From: WardPearce Date: Wed, 30 Oct 2024 01:03:53 +1300 Subject: [PATCH 02/10] Add hashtag support, minor fixes & case type display --- materialious/android/app/build.gradle | 4 ++-- materialious/electron/package.json | 2 +- materialious/package.json | 2 +- materialious/src/lib/HashtagThumbnail.svelte | 23 +++++++++++++++++++ materialious/src/lib/Settings.svelte | 4 ++-- materialious/src/lib/Thumbnail.svelte | 14 ++++++----- materialious/src/lib/api/index.ts | 8 ++++++- materialious/src/lib/api/model.ts | 8 +++++++ materialious/src/lib/i18n/locales/en.json | 1 + materialious/src/lib/misc.ts | 17 ++++++++++---- .../routes/(app)/hashtag/[slug]/+page.svelte | 7 ++++++ .../src/routes/(app)/hashtag/[slug]/+page.ts | 8 +++++++ .../routes/(app)/search/[slug]/+page.svelte | 3 +++ update_versions.py | 2 +- 14 files changed, 85 insertions(+), 18 deletions(-) create mode 100644 materialious/src/lib/HashtagThumbnail.svelte create mode 100644 materialious/src/routes/(app)/hashtag/[slug]/+page.svelte create mode 100644 materialious/src/routes/(app)/hashtag/[slug]/+page.ts diff --git a/materialious/android/app/build.gradle b/materialious/android/app/build.gradle index 78aa8960..1902a748 100644 --- a/materialious/android/app/build.gradle +++ b/materialious/android/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "us.materialio.app" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 71 - versionName "1.6.20" + versionCode 72 + versionName "1.6.21" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/materialious/electron/package.json b/materialious/electron/package.json index f1c6c59c..5a807d17 100644 --- a/materialious/electron/package.json +++ b/materialious/electron/package.json @@ -1,6 +1,6 @@ { "name": "Materialious", - "version": "1.6.20", + "version": "1.6.21", "description": "Modern material design for Invidious.", "author": { "name": "Ward Pearce", diff --git a/materialious/package.json b/materialious/package.json index 1df19659..1c11eca1 100644 --- a/materialious/package.json +++ b/materialious/package.json @@ -1,6 +1,6 @@ { "name": "materialious", - "version": "1.6.20", + "version": "1.6.21", "private": true, "scripts": { "dev": "vite dev", diff --git a/materialious/src/lib/HashtagThumbnail.svelte b/materialious/src/lib/HashtagThumbnail.svelte new file mode 100644 index 00000000..7a9cec19 --- /dev/null +++ b/materialious/src/lib/HashtagThumbnail.svelte @@ -0,0 +1,23 @@ + + + +
+
{truncate(hashtag.title, 14)}
+
+ {cleanNumber(hashtag.channelCount)} + {$_('channels')} +
+
+ {cleanNumber(hashtag.videoCount)} + {$_('videos')} +
+
+
diff --git a/materialious/src/lib/Settings.svelte b/materialious/src/lib/Settings.svelte index 6c02ccb3..0af63c00 100644 --- a/materialious/src/lib/Settings.svelte +++ b/materialious/src/lib/Settings.svelte @@ -8,7 +8,7 @@ import { onMount } from 'svelte'; import { _ } from 'svelte-i18n'; import { get } from 'svelte/store'; - import { ensureNoTrailingSlash, titleCase, titleCases } from './misc'; + import { ensureNoTrailingSlash, letterCase, titleCases } from './misc'; import { authStore, darkModeStore, @@ -343,7 +343,7 @@ {#each titleCases as caseType} {letterCase(`${caseType}`, caseType)} {/each} diff --git a/materialious/src/lib/Thumbnail.svelte b/materialious/src/lib/Thumbnail.svelte index cbca3b55..5bab9bcc 100644 --- a/materialious/src/lib/Thumbnail.svelte +++ b/materialious/src/lib/Thumbnail.svelte @@ -86,13 +86,15 @@ } async function loadAuthor() { - const channel = await getChannel(video.authorId, { priority: 'low' }); - const img = new Image(); - img.src = proxyGoogleImage(getBestThumbnail(channel.authorThumbnails, 75, 75)); + try { + const channel = await getChannel(video.authorId, { priority: 'low' }); + const img = new Image(); + img.src = proxyGoogleImage(getBestThumbnail(channel.authorThumbnails, 75, 75)); - img.onload = () => { - authorImg = img; - }; + img.onload = () => { + authorImg = img; + }; + } catch {} } onMount(async () => { diff --git a/materialious/src/lib/api/index.ts b/materialious/src/lib/api/index.ts index 5b90854f..2a4f76e1 100644 --- a/materialious/src/lib/api/index.ts +++ b/materialious/src/lib/api/index.ts @@ -20,6 +20,7 @@ import type { Comments, DeArrow, Feed, + HashTag, Playlist, PlaylistPage, ResolvedUrl, @@ -150,6 +151,11 @@ export async function getSearchSuggestions(search: string, fetchOptions?: Reques return await resp.json(); } +export async function getHashtag(tag: string): Promise