Merge pull request #567 from Materialious/update/1.5.0

Update/1.5.0
This commit is contained in:
Ward
2024-09-20 19:48:53 +12:00
committed by GitHub
29 changed files with 20340 additions and 587 deletions
+7
View File
@@ -43,6 +43,13 @@
- PWA support.
- YT path redirects (So your redirect plugins should still work!)
# Support table
| | Dash | HLS | Local video fallback | API-Extended | ffmpeg download merging | Dearrow | RYD |
|---------|------|-----|----------------------|--------------|-------------------------|---------|-----|
| Web | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ |
| Desktop | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| Android | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
# Public instances
[Public instances are listed here](./docs/INSTANCES.md).
+2 -2
View File
@@ -7,8 +7,8 @@ android {
applicationId "us.materialio.app"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 40
versionName "1.4.3"
versionCode 41
versionName "1.5.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
@@ -11,6 +11,8 @@ apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies {
implementation project(':capacitor-app')
implementation project(':capacitor-browser')
implementation project(':capgo-inappbrowser')
implementation project(':capacitor-nodejs')
}
@@ -5,6 +5,7 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:theme="@style/AppTheme">
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
@@ -7,3 +7,9 @@ project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/
include ':capacitor-browser'
project(':capacitor-browser').projectDir = new File('../node_modules/@capacitor/browser/android')
include ':capgo-inappbrowser'
project(':capgo-inappbrowser').projectDir = new File('../node_modules/@capgo/inappbrowser/android')
include ':capacitor-nodejs'
project(':capacitor-nodejs').projectDir = new File('../node_modules/capacitor-nodejs/android')
+2 -3
View File
@@ -4,10 +4,9 @@ const config: CapacitorConfig = {
appId: 'us.materialio.app',
appName: 'Materialious',
webDir: 'build',
bundledWebRuntime: false,
plugins: {
CapacitorHttp: {
enabled: true
CapacitorNodeJS: {
nodeDir: 'nodejs-android'
}
},
};
+2 -3
View File
@@ -4,10 +4,9 @@ const config: CapacitorConfig = {
appId: 'us.materialio.app',
appName: 'Materialious',
webDir: 'build',
bundledWebRuntime: false,
plugins: {
CapacitorHttp: {
enabled: true
CapacitorNodeJS: {
nodeDir: 'nodejs-android'
}
},
};
+3 -2
View File
@@ -1,6 +1,6 @@
{
"name": "Materialious",
"version": "1.4.3",
"version": "1.5.0",
"description": "Modern material design for Invidious.",
"author": {
"name": "Ward Pearce",
@@ -21,6 +21,7 @@
},
"dependencies": {
"@capacitor-community/electron": "^5.0.0",
"capacitor-nodejs": "https://github.com/EdenwareApps/Capacitor-NodeJS/releases/download/v1.0.0-beta.7/capacitor6-nodejs.tgz",
"chokidar": "~3.6.0",
"electron-is-dev": "~2.0.0",
"electron-serve": "~1.1.0",
@@ -40,4 +41,4 @@
"capacitor",
"electron"
]
}
}
@@ -1,4 +1,6 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const CapacitorNodejs = require('../../../node_modules/capacitor-nodejs/electron/dist/plugin.js');
module.exports = {
CapacitorNodejs,
}
+1033 -467
View File
File diff suppressed because it is too large Load Diff
+7 -2
View File
@@ -1,6 +1,6 @@
{
"name": "materialious",
"version": "1.4.3",
"version": "1.5.0",
"private": true,
"scripts": {
"dev": "vite dev",
@@ -31,6 +31,7 @@
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.44.0",
"i": "^0.3.7",
"jsdom": "^25.0.0",
"npm": "^10.8.3",
"prettier": "^3.3.3",
"prettier-plugin-svelte": "^3.2.6",
@@ -49,8 +50,11 @@
"@capacitor/browser": "^6.0.2",
"@capacitor/cli": "6.1.2",
"@capacitor/core": "^6.1.2",
"@capgo/inappbrowser": "^6.6.8",
"@ffmpeg/ffmpeg": "^0.12.10",
"beercss": "^3.7.7",
"capacitor-nodejs": "https://github.com/EdenwareApps/Capacitor-NodeJS/releases/download/v1.0.0-beta.7/capacitor6-nodejs.tgz",
"dashjs": "^4.7.4",
"fuse.js": "^7.0.0",
"he": "^1.2.0",
"human-number": "^2.0.4",
@@ -64,6 +68,7 @@
"svelte-i18n": "^4.0.0",
"svelte-infinite-loading": "^1.4.0",
"svelte-persisted-store": "^0.11.0",
"terser": "^5.33.0",
"vidstack": "^1.12.9"
}
}
}
+1 -1
View File
@@ -72,7 +72,7 @@ export async function getPopular(): Promise<Video[]> {
export async function getVideo(videoId: string, local: boolean = false): Promise<VideoPlay> {
const resp = await fetch(setRegion(buildPath(`videos/${videoId}?local=${local}`)));
if (!resp.ok && Capacitor.getPlatform() === 'electron' && get(playerYouTubeJsFallback)) {
if (!resp.ok && Capacitor.isNativePlatform() && get(playerYouTubeJsFallback)) {
return await patchYoutubeJs(videoId);
} else {
await fetchErrorHandle(resp);
+1
View File
@@ -102,6 +102,7 @@ export interface VideoPlay extends Video {
storyboardHeight: number;
storyboardCount: number;
}[];
fallbackPatch?: 'youtubejs' | 'piped';
}
export interface ReturnYTDislikes {
+1 -1
View File
@@ -27,7 +27,7 @@
}
</script>
{#if $miniPlayerSrcStore}
{#if $miniPlayerSrcStore && $miniPlayerSrcStore.video.formatStreams.length > 0}
<nav class="bottom no-padding">
<article class="surface-bright">
<button on:click={() => miniPlayerSrcStore.set(null)} class="s circle transparent no-margin">
+26 -41
View File
@@ -8,13 +8,12 @@
import { onDestroy, onMount } from 'svelte';
import { _ } from 'svelte-i18n';
import { get } from 'svelte/store';
import type { MediaTimeUpdateEvent, PlayerSrc, VideoSrc } from 'vidstack';
import type { MediaTimeUpdateEvent, PlayerSrc } from 'vidstack';
import type { MediaPlayerElement } from 'vidstack/elements';
import { deleteVideoProgress, getVideoProgress, saveVideoProgress } from './Api';
import type { VideoPlay } from './Api/model';
import {
getBestThumbnail,
proxyVideoUrl,
pullBitratePreference,
videoLength,
type PhasedDescription
@@ -25,7 +24,6 @@
miniPlayerSrcStore,
playerAlwaysLoopStore,
playerAutoPlayStore,
playerDashStore,
playerProxyVideosStore,
playerSavePlaybackPositionStore,
silenceSkipperStore,
@@ -47,7 +45,7 @@
export let segments: Segment[] = [];
let src: PlayerSrc = [];
let categoryBeingSkipped = '';
let snackBarAlert = '';
let playerIsLive = false;
let playerPosSet = false;
@@ -261,10 +259,11 @@
});
player.addEventListener('provider-change', (event) => {
const provider = event.detail;
const provider = event.detail as any;
const bitrate = pullBitratePreference();
if (provider?.type === 'dash') {
(provider as any).config = {
provider.library = () => import('dashjs');
provider.config = {
streaming: {
abr: {
ABRStrategy: 'abrBola',
@@ -312,9 +311,11 @@
if (Math.round(player.currentTime) >= Math.round(player.duration)) {
return;
}
categoryBeingSkipped = segment.category;
player.currentTime = segment.endTime + 1;
ui('#sponsorblock-alert');
if (!get(sponsorBlockDisplayToastStore)) {
snackBarAlert = `${get(_)('skipping')} ${segment.category}`;
ui('#snackbar-alert');
}
}
});
});
@@ -322,38 +323,20 @@
}
}
if (get(playerDashStore)) {
src = [{ src: data.video.dashUrl, type: 'application/dash+xml' }];
src = [{ src: data.video.dashUrl, type: 'application/dash+xml' }];
if (!data.video.fallbackPatch) {
if (Capacitor.getPlatform() !== 'electron' || proxyVideos) {
(src[0] as { src: string }).src += '?local=true';
}
player.addEventListener('dash-can-play', async () => {
if (get(playerAutoPlayStore)) {
player.play();
}
await loadPlayerPos();
});
} else {
let formattedSrc;
src = data.video.formatStreams.map((format) => {
if (proxyVideos) {
formattedSrc = proxyVideoUrl(format.url);
} else {
formattedSrc = format.url;
}
const quality = format.size.split('x');
return {
src: formattedSrc,
type: format.type.split(';')[0],
height: Number(quality[1]),
width: Number(quality[0])
};
}) as VideoSrc[];
await loadPlayerPos();
}
player.addEventListener('dash-can-play', async () => {
if (get(playerAutoPlayStore)) {
player.play();
}
await loadPlayerPos();
});
} else {
playerIsLive = true;
src = [
@@ -368,6 +351,11 @@
const currentTheme = await getDynamicTheme();
if (data.video.fallbackPatch === 'youtubejs') {
snackBarAlert = get(_)('player.youtubeJsFallBack');
ui('#snackbar-alert');
}
document.documentElement.style.setProperty(
'--media-slider-track-fill-bg',
currentTheme['--primary']
@@ -488,11 +476,8 @@
{/if}
</media-player>
{#if !isEmbed && !$sponsorBlockDisplayToastStore}
<div class="snackbar" id="sponsorblock-alert">
<span
>{$_('skipping')}
<span class="bold" style="text-transform: capitalize;">{categoryBeingSkipped}</span></span
>
{#if !isEmbed}
<div class="snackbar" id="snackbar-alert">
<span class="bold" style="text-transform: capitalize;">{snackBarAlert}</span>
</div>
{/if}
+6 -42
View File
@@ -1,4 +1,5 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { bookmarkletSaveToUrl } from '$lib/externalSettings';
import { Capacitor } from '@capacitor/core';
import ui from 'beercss';
@@ -21,10 +22,8 @@
interfaceRegionStore,
interfaceSearchSuggestionsStore,
playerAlwaysLoopStore,
playerAndroidBackgroundPlayStore,
playerAutoPlayStore,
playerAutoplayNextByDefaultStore,
playerDashStore,
playerListenByDefaultStore,
playerMiniPlayerStore,
playerProxyVideosStore,
@@ -125,8 +124,10 @@
<h6>Invidious</h6>
<form
on:submit|preventDefault={() => {
authStore.set(null);
instanceStore.set(ensureNoTrailingSlash(invidiousInstance));
authStore.set(null);
goto('/', { replaceState: true });
ui('#dialog-settings');
}}
>
<nav>
@@ -305,7 +306,7 @@
</nav>
</div>
{#if Capacitor.getPlatform() !== 'android'}
{#if Capacitor.isNativePlatform()}
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
@@ -388,43 +389,6 @@
</nav>
</div>
{#if Capacitor.getPlatform() === 'android'}
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.player.backgroundPlay')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerAndroidBackgroundPlayStore}
on:click={() =>
playerAndroidBackgroundPlayStore.set(!$playerAndroidBackgroundPlayStore)}
/>
<span></span>
</label>
</nav>
</div>
{/if}
{#if Capacitor.getPlatform() !== 'android'}
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.player.dash')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerDashStore}
on:click={() => playerDashStore.set(!$playerDashStore)}
/>
<span></span>
</label>
</nav>
</div>
{/if}
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
@@ -441,7 +405,7 @@
</nav>
</div>
{#if Capacitor.getPlatform() === 'electron'}
{#if Capacitor.isNativePlatform()}
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
-6
View File
@@ -14,7 +14,6 @@ import {
playerAlwaysLoopStore,
playerAutoPlayStore,
playerAutoplayNextByDefaultStore,
playerDashStore,
playerListenByDefaultStore,
playerMiniPlayerStore,
playerProxyVideosStore,
@@ -74,11 +73,6 @@ const persistedStores = [
store: playerSavePlaybackPositionStore,
type: 'boolean'
},
{
name: 'dashEnabled',
store: playerDashStore,
type: 'boolean'
},
{
name: 'theatreModeByDefault',
store: playerTheatreModeByDefaultStore,
+3 -2
View File
@@ -82,7 +82,8 @@
},
"noPlaylists": "No playlists",
"unableToLoadComments": "Unable to load comments",
"addToPlaylist": "Add to playlist"
"addToPlaylist": "Add to playlist",
"youtubeJsFallBack": "Local video fallback being used"
},
"layout": {
"interface": "Interface",
@@ -124,7 +125,7 @@
"backgroundPlay": "Play audio in background",
"dash": "Dash",
"silenceSkipper": "Silence skipper (Experimental)",
"youtubeJsFallback": "Locally video processing fallback"
"youtubeJsFallback": "Local video processing fallback"
},
"bookmarklet": "Bookmarklet",
"instanceUrl": "Instance URL",
@@ -0,0 +1,41 @@
import { goto } from "$app/navigation";
import { Capacitor } from "@capacitor/core";
if (Capacitor.getPlatform() === 'android') {
const originalFetch = window.fetch;
// CORS-Anywhere proxy URL
const corsAnywhereProxyUrl: string = 'http://localhost:3000/';
// Overwrite fetch to use CORS-Anywhere proxy
window.fetch = async (requestInput: RequestInfo | URL, requestOptions: RequestInit = {}): Promise<Response> => {
const requestUrl: string =
typeof requestInput === 'string' ? requestInput : requestInput.toString();
// Check if the URL is already proxied, to avoid double proxying
if (!requestUrl.startsWith(corsAnywhereProxyUrl)) {
requestInput = corsAnywhereProxyUrl + requestUrl;
}
// Ensure options.method is set to a valid value
requestOptions.method = requestOptions.method ? requestOptions.method.toUpperCase() : 'GET';
// Use the original fetch with the proxied URL and options
return originalFetch(requestInput, requestOptions);
};
const currentOrigin: string = window.location.protocol + '//' + window.location.host;
const originalXhrOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function (...args: any[]): void {
const targetOriginMatch = /^https?:\/\/([^\/]+)/i.exec(args[1]);
if (targetOriginMatch && targetOriginMatch[0].toLowerCase() !== currentOrigin) {
args[1] = corsAnywhereProxyUrl + args[1];
}
/* @ts-ignore */
return originalXhrOpen.apply(this, args);
};
// Must reload page after patches
goto('/', { replaceState: true });
}
@@ -0,0 +1,122 @@
import { InAppBrowser } from '@capgo/inappbrowser';
import { minify } from 'terser';
export interface PoTokens {
visitor_data: string;
po_token: string;
}
const headers = {
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'accept-language': 'en-US;q=0.9',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko)',
};
// Inspired by https://github.com/YunzheZJU/youtube-po-token-generator & https://github.com/YunzheZJU/youtube-po-token-generator
export async function getPoToken(): Promise<PoTokens> {
let visitorData: string;
return new Promise((resolve, reject) => {
const messageListener = async (data: any) => {
if (!data.po_token) {
visitorData = data.visitor_data;
const injectPlayer = await fetch('/po-token-youtube/inject.js');
await InAppBrowser.executeScript({
code: (await minify(`
window.onPoToken = (poToken) => {
window.mobileApp.postMessage({po_token: poToken});
}
ytcfg.set({
'INNERTUBE_CONTEXT': {
...ytcfg.get('INNERTUBE_CONTEXT'),
client: {
...ytcfg.get('INNERTUBE_CONTEXT').client,
visitorData: "${visitorData}",
},
},
'VISITOR_DATA': "${visitorData}",
'IDENTITY_MEMENTO': {
'visitor_data': "${visitorData}",
},
})
${await injectPlayer.text()}`)).code as string
});
} else if (visitorData && data.po_token) {
await InAppBrowser.removeAllListeners();
await InAppBrowser.close();
resolve({ visitor_data: visitorData, po_token: data.po_token });
}
};
const closeListener = async () => {
await InAppBrowser.removeAllListeners();
};
const urlChangeListener = async () => {
// Code must be minified to ensure runs correctly.
await InAppBrowser.executeScript({
code: (await minify(`const headers = {"accept": "${headers.accept}", "accept-language": "${headers['accept-language']}", "user-agent": "${headers['user-agent']}"};
Object.defineProperty(window.navigator, 'userAgent', { value: headers["user-agent"], writable: false });
const originalOpen = XMLHttpRequest.prototype.open;
const originalSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function (method, url) {
this._url = url;
originalOpen.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function (body) {
const xhr = this;
if (this._url.includes("/youtubei/v1/player")) {
for (const [key, value] of Object.entries(headers)) {
this.setRequestHeader(key, value);
}
this.addEventListener("load", function () {
try {
const postJson = JSON.parse(body);
window.mobileApp.postMessage({visitor_data: postJson.context.client.visitorData});
} catch (error) {
console.error("Error parsing request body:", error);
}
});
}
originalSend.apply(this, arguments);
};
function attemptClickPlayButton() {
const interval = setInterval(() => {
const playButtons = document.getElementsByClassName("ytp-play-button");
if (playButtons.length > 0) {
playButtons[0].click();
clearInterval(interval);
}
}, 100);
}
attemptClickPlayButton();
`)).code as string
});
};
InAppBrowser.addListener('messageFromWebview', messageListener);
InAppBrowser.addListener('closeEvent', closeListener);
InAppBrowser.addListener('urlChangeEvent', urlChangeListener);
setTimeout(() => {
reject(new Error('Timeout trying to pull Po tokens'));
InAppBrowser.removeAllListeners();
}, 30000);
InAppBrowser.openWebView({
url: 'https://www.youtube.com/embed/jNQXAC9IVRw',
title: 'Pulling po tokens',
headers: headers
});
});
}
+28 -8
View File
@@ -1,14 +1,33 @@
import type { Image, Thumbnail, VideoBase, VideoPlay } from '$lib/Api/model';
import { numberWithCommas } from '$lib/misc';
import { poTokenCacheStore } from '$lib/store';
import { Capacitor } from '@capacitor/core';
import { get } from 'svelte/store';
import { type PoTokens } from './poTokenAndroid';
export async function patchYoutubeJs(videoId: string): Promise<VideoPlay> {
const innertube = (await import('youtubei.js')).Innertube;
const tokens = await (window as any).electron.generatePoToken();
let tokens: PoTokens;
const poTokenCache = get(poTokenCacheStore);
if (!poTokenCache) {
if (Capacitor.getPlatform() === 'electron') {
tokens = await (window as any).electron.generatePoToken();
} else if (Capacitor.getPlatform() === 'android') {
tokens = await (await import('../../lib/patches/poTokenAndroid')).getPoToken();
} else {
throw new Error('This platform cant generate po tokens');
}
poTokenCacheStore.set(tokens);
} else {
tokens = poTokenCache;
}
const youtube = await innertube.create({
visitor_data: tokens.visitorData,
po_token: tokens.poToken
visitor_data: tokens.visitor_data,
po_token: tokens.po_token,
});
const video = await youtube.getInfo(videoId);
@@ -52,9 +71,9 @@ export async function patchYoutubeJs(videoId: string): Promise<VideoPlay> {
return {
type: 'video',
title: video.primary_info.title.toString(),
viewCount: Number(video.primary_info.view_count.toString().replace(/\D/g, '')),
viewCountText: video.primary_info.view_count.toString(),
title: video.primary_info.title ? video.primary_info.title.toString() : '',
viewCount: video.primary_info.view_count ? Number(video.primary_info.view_count.toString().replace(/\D/g, '')) : 0,
viewCountText: video.primary_info.view_count ? video.primary_info.view_count.toString() : '',
likeCount: video.basic_info.like_count || 0,
dislikeCount: 0,
allowRatings: false,
@@ -75,7 +94,7 @@ export async function patchYoutubeJs(videoId: string): Promise<VideoPlay> {
description: descString,
descriptionHtml: video.secondary_info.description.toHTML() || descString,
published: 0,
publishedText: video.primary_info.published.toString(),
publishedText: video.primary_info.published ? video.primary_info.published.toString() : '',
premiereTimestamp: 0,
hlsUrl: video.streaming_data?.hls_manifest_url || undefined,
liveNow: video.basic_info.is_live || false,
@@ -87,6 +106,7 @@ export async function patchYoutubeJs(videoId: string): Promise<VideoPlay> {
lengthSeconds: video.basic_info.duration || 0,
subCountText: '',
keywords: video.basic_info.keywords || [],
allowedRegions: []
allowedRegions: [],
fallbackPatch: 'youtubejs'
};
}
+4 -3
View File
@@ -5,6 +5,7 @@ import type { DataConnection } from 'peerjs';
import { persisted } from 'svelte-persisted-store';
import { writable, type Writable } from 'svelte/store';
import type { TitleCase } from './misc';
import type { PoTokens } from './patches/poTokenAndroid';
function platformDependentDefault(givenValue: any, defaultValue: any): any {
if (typeof givenValue !== 'undefined' && typeof givenValue !== null) {
@@ -31,14 +32,12 @@ export const activePageStore: Writable<string | null> = writable('home');
export const playerAutoPlayStore = persisted('autoPlay', true);
export const playerAlwaysLoopStore = persisted('alwaysLoop', false);
export const playerProxyVideosStore = persisted('proxyVideos', false);
export const playerProxyVideosStore = persisted('proxyVideos', true);
export const playerListenByDefaultStore = persisted('listenByDefault', false);
export const playerSavePlaybackPositionStore = persisted('savePlaybackPosition', true);
export const playerDashStore = persisted('dashEnabled', false);
export const playerTheatreModeByDefaultStore = persisted('theatreModeByDefault', false);
export const playerAutoplayNextByDefaultStore = persisted('autoplayNextByDefault', false);
export const playerMiniPlayerStore = persisted('miniPlayer', true);
export const playerAndroidBackgroundPlayStore = persisted('androidBackgroundPlayer', true);
export const playerYouTubeJsFallback = persisted('youTubeJsFallback', true);
export const returnYtDislikesStore = persisted('returnYtDislikes', false);
@@ -99,3 +98,5 @@ export const miniPlayerSrcStore: Writable<{ video: VideoPlay; time: number; } |
writable(null);
export const silenceSkipperStore: Writable<boolean> = persisted('silenceSkipper', false);
export const poTokenCacheStore: Writable<PoTokens> = writable();
@@ -11,6 +11,7 @@
import SyncParty from '$lib/SyncParty.svelte';
import Thumbnail from '$lib/Thumbnail.svelte';
import { bookmarkletLoadFromUrl, loadSettingsFromEnv } from '$lib/externalSettings';
import '$lib/patches/androidRequests';
import {
activePageStore,
authStore,
@@ -9,7 +9,6 @@ import {
import { phaseDescription } from '$lib/misc';
import {
authStore,
playerDashStore,
playerProxyVideosStore,
returnYTDislikesInstanceStore,
returnYtDislikesStore
@@ -56,7 +55,7 @@ export async function load({ params, url }) {
if (
import.meta.env.VITE_DEFAULT_DOWNLOAD_ENABLED &&
import.meta.env.VITE_DEFAULT_DOWNLOAD_ENABLED.toString().toLowerCase() === 'true' &&
!video.liveNow && get(playerDashStore)
!video.liveNow
) {
downloadQualitiesDash = listCombinedQualities(video.dashUrl);
}
@@ -0,0 +1,5 @@
const corsAnywhere = require('cors-anywhere');
corsAnywhere.createServer({
originWhitelist: [],
}).listen(3000, 'localhost');
@@ -0,0 +1,8 @@
{
"name": "cors-patch",
"version": "0.0.1",
"main": "./index.js",
"dependencies": {
"cors-anywhere": "^0.4.4"
}
}
File diff suppressed because it is too large Load Diff
+4 -1
View File
@@ -8,6 +8,9 @@ export default defineConfig({
plugins: [
SvelteKitPWA({
injectRegister: 'inline',
workbox: {
maximumFileSizeToCacheInBytes: 4000000
},
manifest: {
description: 'Modern material design for Invidious.',
theme_color: '#8936FF',
@@ -36,5 +39,5 @@ export default defineConfig({
],
optimizeDeps: {
exclude: ['@ffmpeg/ffmpeg', '@ffmpeg/util']
},
}
});
+1 -1
View File
@@ -5,7 +5,7 @@ import json
import os
import re
LATEST_VERSION = "1.4.3"
LATEST_VERSION = "1.5.0"
WORKING_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "materialious")
ROOT_PACKAGE = os.path.join(WORKING_DIR, "package.json")