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')}
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';