diff --git a/materialious/android/app/capacitor.build.gradle b/materialious/android/app/capacitor.build.gradle index b9764570..6bea4029 100644 --- a/materialious/android/app/capacitor.build.gradle +++ b/materialious/android/app/capacitor.build.gradle @@ -14,7 +14,6 @@ dependencies { implementation project(':capacitor-clipboard') implementation project(':capacitor-screen-orientation') implementation project(':capacitor-status-bar') - implementation project(':capgo-inappbrowser') implementation project(':hugotomazi-capacitor-navigation-bar') implementation project(':capacitor-nodejs') diff --git a/materialious/android/capacitor.settings.gradle b/materialious/android/capacitor.settings.gradle index 2fd2c8fd..ef0cb561 100644 --- a/materialious/android/capacitor.settings.gradle +++ b/materialious/android/capacitor.settings.gradle @@ -17,9 +17,6 @@ project(':capacitor-screen-orientation').projectDir = new File('../node_modules/ include ':capacitor-status-bar' project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android') -include ':capgo-inappbrowser' -project(':capgo-inappbrowser').projectDir = new File('../node_modules/@capgo/inappbrowser/android') - include ':hugotomazi-capacitor-navigation-bar' project(':hugotomazi-capacitor-navigation-bar').projectDir = new File('../node_modules/@hugotomazi/capacitor-navigation-bar/android') diff --git a/materialious/electron/package-lock.json b/materialious/electron/package-lock.json index a35b9373..c4d30472 100644 --- a/materialious/electron/package-lock.json +++ b/materialious/electron/package-lock.json @@ -1,12 +1,12 @@ { "name": "Materialious", - "version": "1.7.19", + "version": "1.7.20", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "Materialious", - "version": "1.7.19", + "version": "1.7.20", "license": "MIT", "dependencies": { "@capacitor-community/electron": "^5.0.0", diff --git a/materialious/electron/src/setup.ts b/materialious/electron/src/setup.ts index 49b8dfb3..b8b328c7 100644 --- a/materialious/electron/src/setup.ts +++ b/materialious/electron/src/setup.ts @@ -196,7 +196,6 @@ export class ElectronCapacitorApp { event.preventDefault(); } }); - // Link electron plugins into the system. setupCapacitorElectronPlugins(); diff --git a/materialious/package.json b/materialious/package.json index 5105baf4..13101be0 100644 --- a/materialious/package.json +++ b/materialious/package.json @@ -72,4 +72,4 @@ "terser": "^5.34.1", "youtubei.js": "^13.3.0" } -} \ No newline at end of file +} diff --git a/materialious/src/lib/components/Player.svelte b/materialious/src/lib/components/Player.svelte index d50d1848..b825589d 100644 --- a/materialious/src/lib/components/Player.svelte +++ b/materialious/src/lib/components/Player.svelte @@ -3,6 +3,7 @@ import '$lib/css/shaka-player-theme.css'; import { getBestThumbnail } from '$lib/images'; import { padTime, videoLength } from '$lib/time'; + import { type PhasedDescription } from '$lib/timestamps'; import { Capacitor } from '@capacitor/core'; import { ScreenOrientation, type ScreenOrientationResult } from '@capacitor/screen-orientation'; import { StatusBar, Style } from '@capacitor/status-bar'; @@ -19,7 +20,6 @@ import { get } from 'svelte/store'; import { deleteVideoProgress, getVideoProgress, saveVideoProgress } from '../api'; import type { VideoPlay } from '../api/model'; - import { type PhasedDescription } from '../misc'; import { authStore, instanceStore, diff --git a/materialious/src/lib/misc.ts b/materialious/src/lib/misc.ts index a4f00eba..f33c18c0 100644 --- a/materialious/src/lib/misc.ts +++ b/materialious/src/lib/misc.ts @@ -9,11 +9,6 @@ export function truncate(value: string, maxLength: number = 50): string { return value.length > maxLength ? `${value.substring(0, maxLength)}...` : value; } -export interface PhasedDescription { - description: string; - timestamps: { title: string; time: number; timePretty: string; }[]; -} - export function decodeHtmlCharCodes(str: string): string { const { decode } = he; return decode(str); diff --git a/materialious/src/lib/timestamps.ts b/materialious/src/lib/timestamps.ts index ed1c58fa..553fdabf 100644 --- a/materialious/src/lib/timestamps.ts +++ b/materialious/src/lib/timestamps.ts @@ -1,33 +1,69 @@ -import { type PhasedDescription, decodeHtmlCharCodes } from "./misc"; +import { decodeHtmlCharCodes } from "./misc"; import { convertToSeconds } from "./time"; -export function phaseDescription(content: string, usingYoutubeJs: boolean = false): PhasedDescription { +export interface PhasedDescription { + description: string; + timestamps: { title: string; time: number; timePretty: string; }[]; +} + +export function extractActualLink(url: string): string { + const urlParams = new URLSearchParams(url.split('?')[1]); + const actualLink = urlParams.get('q'); + if (actualLink) { + return decodeURIComponent(actualLink); + } + return url; +} + +export function processYoutubeLink(line: string): string { + // Regex to match the tag and extract the href (YouTube redirect link) + const urlRegex = /(\d+:\d+(?::\d+)?)<\/a>\s*(.+)/; - const timestampRegexYtJs = /&(?:\S*?&)?t=(\d+)\s*s.*?]*>([^<]*)<\/span>.*?>(.*?)<\/span>/; + const timestampRegexYtJs = new RegExp( + `href="https://www\\.youtube\\.com/watch\\?v=${videoId}(?:&t=(\\d+)s)?"[^>]*>\\s*]*>\\s*([^<]+)\\s*\\s*\\s*]*>\\s*([^<]+)\\s*`, + 'i' + ); let filteredLines: string[] = []; lines.forEach((line) => { const urlMatch = urlRegex.exec(line); // Use appropriate regex based on the `usingYoutubeJs` flag - const timestampMatch = (usingYoutubeJs ? timestampRegexYtJs : timestampRegexInvidious).exec(usingYoutubeJs ? line + '' : line); + const timestampMatch = (fallbackPatch === 'youtubejs' ? timestampRegexYtJs : timestampRegexInvidious).exec(fallbackPatch === 'youtubejs' ? line + '' : line); if (urlMatch !== null && timestampMatch === null) { // If line contains a URL but not a timestamp, modify the URL - const modifiedLine = line.replace( + const modifiedLine = processYoutubeLink(line).replace( / { ui(); + document.addEventListener('click', linkClickOverwrite); + scrollableRoot = document.querySelector('.root'); loadSettingsFromEnv(); @@ -183,6 +185,21 @@ } }); + function linkClickOverwrite(event: MouseEvent) { + // Handles opening links in browser for android. + + if (Capacitor.getPlatform() !== 'android') return; + + const link = (event.target as HTMLElement).closest('a'); + + if (link && link.href) { + if (link.href && link.href.startsWith('http') && link.target === '_blank') { + event.preventDefault(); + Browser.open({ url: link.href }); + } + } + } + let webManifestLink = $derived(pwaInfo ? pwaInfo.webManifest.linkTag : ''); diff --git a/materialious/src/routes/(app)/channel/[slug]/+page.svelte b/materialious/src/routes/(app)/channel/[slug]/+page.svelte index 71c951b4..7287370d 100644 --- a/materialious/src/routes/(app)/channel/[slug]/+page.svelte +++ b/materialious/src/routes/(app)/channel/[slug]/+page.svelte @@ -137,21 +137,24 @@ {$_('player.share.title')} {#if !Capacitor.isNativePlatform()} - { await Clipboard.write({ string: location.href }); - }}>{$_('player.share.materialiousLink')}{$_('player.share.materialiousLink')} + {/if} + + {#if true} + {/if} - { - await Clipboard.write({ - string: `https://www.youtube.com/channel/${data.channel.authorId}` - }); - }}>{$_('player.share.youtubeLink')} diff --git a/materialious/src/routes/(app)/watch/[slug]/+page.ts b/materialious/src/routes/(app)/watch/[slug]/+page.ts index 594305d7..80639185 100644 --- a/materialious/src/routes/(app)/watch/[slug]/+page.ts +++ b/materialious/src/routes/(app)/watch/[slug]/+page.ts @@ -52,7 +52,7 @@ export async function load({ params, url }) { return { video: video, - content: phaseDescription(video.descriptionHtml, video.fallbackPatch === 'youtubejs'), + content: phaseDescription(video.videoId, video.descriptionHtml, video.fallbackPatch), playlistId: url.searchParams.get('playlist'), streamed: { personalPlaylists: personalPlaylists, diff --git a/materialious/src/routes/(no-layout)/embed/[slug]/+page.ts b/materialious/src/routes/(no-layout)/embed/[slug]/+page.ts index b5d1f10c..dad2562f 100644 --- a/materialious/src/routes/(no-layout)/embed/[slug]/+page.ts +++ b/materialious/src/routes/(no-layout)/embed/[slug]/+page.ts @@ -1,6 +1,6 @@ import { getVideo } from '$lib/api/index'; -import type { PhasedDescription } from '$lib/misc'; import { playerProxyVideosStore } from '$lib/store'; +import type { PhasedDescription } from '$lib/timestamps'; import { error } from '@sveltejs/kit'; import { get } from 'svelte/store';