Merge pull request #1543 from Materialious/update/1.16.16
Update/1.16.16
This commit is contained in:
@@ -7,8 +7,8 @@ android {
|
||||
applicationId "us.materialio.app"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 232
|
||||
versionName "1.16.15"
|
||||
versionCode 233
|
||||
versionName "1.16.16"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
aaptOptions {
|
||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||
|
||||
@@ -74,7 +74,11 @@
|
||||
|
||||
|
||||
|
||||
<release version="1.16.15" date="2026-3-08">
|
||||
|
||||
<release version="1.16.16" date="2026-3-08">
|
||||
<url>https://github.com/Materialious/Materialious/releases/tag/1.16.16</url>
|
||||
</release>
|
||||
<release version="1.16.15" date="2026-3-08">
|
||||
<url>https://github.com/Materialious/Materialious/releases/tag/1.16.15</url>
|
||||
</release>
|
||||
<release version="1.16.14" date="2026-3-08">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Materialious",
|
||||
"version": "1.16.15",
|
||||
"version": "1.16.16",
|
||||
"description": "Modern material design for YouTube and Invidious.",
|
||||
"author": {
|
||||
"name": "Ward Pearce",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "materialious",
|
||||
"version": "1.16.15",
|
||||
"version": "1.16.16",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "npm run patch:github && vite dev",
|
||||
|
||||
@@ -15,6 +15,7 @@ import { isOwnBackend } from './shared';
|
||||
import { Browser } from '@capacitor/browser';
|
||||
import { clearFeedYTjs } from './api/youtubejs/subscriptions';
|
||||
import { ensureNoTrailingSlash, isYTBackend } from './misc';
|
||||
import { deleteKeyValue } from './api/backend/keyvalue';
|
||||
|
||||
export function clearCaches() {
|
||||
feedCacheStore.set({});
|
||||
@@ -29,6 +30,12 @@ export function authProtected() {
|
||||
}
|
||||
}
|
||||
|
||||
async function removeAuthFromBackend() {
|
||||
if (!get(rawMasterKeyStore)) return;
|
||||
|
||||
await deleteKeyValue('authToken');
|
||||
}
|
||||
|
||||
export async function setInvidiousInstance(
|
||||
instanceUrl: string | undefined | null
|
||||
): Promise<boolean> {
|
||||
@@ -64,6 +71,8 @@ export async function setInvidiousInstance(
|
||||
invidiousInstanceStore.set(instance);
|
||||
invidiousAuthStore.set(null);
|
||||
|
||||
await removeAuthFromBackend();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -86,6 +95,8 @@ export async function goToInvidiousLogin() {
|
||||
|
||||
export async function invidiousLogout() {
|
||||
invidiousAuthStore.set(null);
|
||||
await removeAuthFromBackend();
|
||||
|
||||
goto(resolve('/', {}));
|
||||
}
|
||||
|
||||
|
||||
@@ -46,11 +46,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<button
|
||||
bind:this={shareButtonElement}
|
||||
class="surface-container-highest"
|
||||
onclick={(event: Event) => event.stopPropagation()}
|
||||
>
|
||||
<button bind:this={shareButtonElement} class="surface-container-highest">
|
||||
<i>share</i>
|
||||
{#if !iconOnly}
|
||||
{$_('player.share.title')}
|
||||
|
||||
@@ -819,9 +819,11 @@
|
||||
{videoLength(currentTime)} / {videoLength(playerMaxKnownTime)}
|
||||
{/if}
|
||||
</p>
|
||||
<p class="chip surface-container-highest">
|
||||
{playerVideoEndTimePretty}
|
||||
</p>
|
||||
{#if playerVideoEndTimePretty && playerVideoEndTimePretty !== ''}
|
||||
<p class="chip surface-container-highest">
|
||||
{playerVideoEndTimePretty}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<TouchControls
|
||||
@@ -833,64 +835,62 @@
|
||||
bind:playerMaxKnownTime
|
||||
bind:playerIsBuffering
|
||||
/>
|
||||
{#if showControls}
|
||||
<div id="player-controls" transition:fade>
|
||||
<Timeline
|
||||
{playerElement}
|
||||
{currentTime}
|
||||
{showPlayerUI}
|
||||
{segments}
|
||||
video={data.video}
|
||||
content={data.content}
|
||||
bind:userManualSeeking
|
||||
bind:playerMaxKnownTime
|
||||
/>
|
||||
<nav>
|
||||
{#if !$isAndroidTvStore}
|
||||
<nav class="no-wrap">
|
||||
<button class="surface-container-highest" onclick={toggleVideoPlaybackStatus}>
|
||||
<i>
|
||||
{#if playerCurrentPlaybackState}
|
||||
pause
|
||||
{:else}
|
||||
play_arrow
|
||||
{/if}
|
||||
</i>
|
||||
</button>
|
||||
{#if !isMobile()}
|
||||
<div class="player-slider volume m l" {...playerVolumeSlider.root}>
|
||||
<div class="track">
|
||||
<div class="range"></div>
|
||||
<div {...playerVolumeSlider.thumb}></div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</nav>
|
||||
{/if}
|
||||
|
||||
<div class="max"></div>
|
||||
|
||||
<div id="player-controls" class="hide" class:show={showControls}>
|
||||
<Timeline
|
||||
{playerElement}
|
||||
{currentTime}
|
||||
{showPlayerUI}
|
||||
{segments}
|
||||
video={data.video}
|
||||
content={data.content}
|
||||
bind:userManualSeeking
|
||||
bind:playerMaxKnownTime
|
||||
/>
|
||||
<nav>
|
||||
{#if !$isAndroidTvStore}
|
||||
<nav class="no-wrap">
|
||||
<p class="chip m l" style="height: 100%;">
|
||||
{#if data.video.liveNow}
|
||||
{$_('thumbnail.live')}
|
||||
{:else}
|
||||
{videoLength(currentTime)} / {videoLength(data.video.lengthSeconds)}
|
||||
{/if}
|
||||
</p>
|
||||
{#if !$isAndroidTvStore}
|
||||
<CaptionSettings video={data.video} />
|
||||
{#if playerElement}
|
||||
<Settings {player} {playerElement} />
|
||||
<Airplay {playerElement} />
|
||||
<Pip {playerElement} />
|
||||
{/if}
|
||||
<FullscreenToggle {toggleFullscreen} {playerIsFullscreen} />
|
||||
<button class="surface-container-highest" onclick={toggleVideoPlaybackStatus}>
|
||||
<i>
|
||||
{#if playerCurrentPlaybackState}
|
||||
pause
|
||||
{:else}
|
||||
play_arrow
|
||||
{/if}
|
||||
</i>
|
||||
</button>
|
||||
{#if !isMobile()}
|
||||
<div class="player-slider volume m l" {...playerVolumeSlider.root}>
|
||||
<div class="track">
|
||||
<div class="range"></div>
|
||||
<div {...playerVolumeSlider.thumb}></div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</nav>
|
||||
{/if}
|
||||
|
||||
<div class="max"></div>
|
||||
|
||||
<nav class="no-wrap">
|
||||
<p class="chip m l" style="height: 100%;">
|
||||
{#if data.video.liveNow}
|
||||
{$_('thumbnail.live')}
|
||||
{:else}
|
||||
{videoLength(currentTime)} / {videoLength(data.video.lengthSeconds)}
|
||||
{/if}
|
||||
</p>
|
||||
{#if !$isAndroidTvStore}
|
||||
<CaptionSettings video={data.video} />
|
||||
{#if playerElement}
|
||||
<Settings {player} {playerElement} />
|
||||
<Airplay {playerElement} />
|
||||
<Pip {playerElement} />
|
||||
{/if}
|
||||
<FullscreenToggle {toggleFullscreen} {playerIsFullscreen} />
|
||||
{/if}
|
||||
</nav>
|
||||
</div>
|
||||
{/if}
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if showVideoRetry}
|
||||
|
||||
@@ -366,15 +366,19 @@
|
||||
{videoLength(timeInSeconds)}
|
||||
{/snippet}
|
||||
<div class="track">
|
||||
{#if !userManualSeeking && playerShowTimelineThumbnail}
|
||||
<div bind:this={playerTimelineTooltip} class="timeline tooltip">
|
||||
{#if !userManualSeeking}
|
||||
<div
|
||||
bind:this={playerTimelineTooltip}
|
||||
class="timeline tooltip"
|
||||
class:hide={!playerShowTimelineThumbnail}
|
||||
>
|
||||
{@render timelineTooltip('timeline', playerTimelineTimeHover)}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="range"></div>
|
||||
<div {...playerTimelineSlider.thumb}>
|
||||
{#if playerSliderInteracted && playerShowTimelineThumbnail}
|
||||
<div class="tooltip thumb">
|
||||
{#if playerSliderInteracted}
|
||||
<div class="tooltip thumb" class:hide={!playerShowTimelineThumbnail}>
|
||||
{@render timelineTooltip('thumb', currentTime)}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -28,7 +28,17 @@ body {
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none !important;
|
||||
opacity: 0 !important;
|
||||
visibility: hidden !important;
|
||||
transition:
|
||||
opacity 300ms linear,
|
||||
visibility 0s linear 300ms !important;
|
||||
}
|
||||
|
||||
.show {
|
||||
opacity: 1 !important;
|
||||
visibility: visible !important;
|
||||
transition: opacity 300ms linear !important;
|
||||
}
|
||||
|
||||
article {
|
||||
|
||||
@@ -9,22 +9,19 @@ import { addOrUpdateKeyValue, getKeyValue } from '$lib/api/backend/keyvalue';
|
||||
import { rawMasterKeyStore } from '$lib/store';
|
||||
import { getPublicEnv } from '$lib/misc';
|
||||
|
||||
const allowNullOverwrite = ['authToken'];
|
||||
const dontAutoSync = ['authToken'];
|
||||
|
||||
export async function syncSettingsToBackend() {
|
||||
if (!isOwnBackend() || !get(rawMasterKeyStore)) return;
|
||||
|
||||
await Promise.all(
|
||||
persistedStores.map(async (store) => {
|
||||
if (store.excludeFromBackendSync) return;
|
||||
if (store.excludeFromBackendSync || dontAutoSync.includes(store.name)) return;
|
||||
|
||||
getKeyValue(store.name).then((currentKeyValue) => {
|
||||
if (currentKeyValue !== null || allowNullOverwrite.includes(store.name)) {
|
||||
if (currentKeyValue !== null) {
|
||||
const currentKeyValueParsed = parseWithSchema(store.schema, currentKeyValue);
|
||||
if (
|
||||
(currentKeyValueParsed !== null && currentKeyValueParsed !== undefined) ||
|
||||
allowNullOverwrite.includes(store.name)
|
||||
) {
|
||||
if (currentKeyValueParsed !== null && currentKeyValueParsed !== undefined) {
|
||||
store.store.set(currentKeyValueParsed);
|
||||
}
|
||||
}
|
||||
@@ -34,7 +31,7 @@ export async function syncSettingsToBackend() {
|
||||
store.store.subscribe((value) => {
|
||||
if (!get(rawMasterKeyStore)) return;
|
||||
|
||||
if (initialLoad && !allowNullOverwrite.includes(store.name)) {
|
||||
if (initialLoad) {
|
||||
initialLoad = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -317,6 +317,7 @@ export class ShakaPlayerAdapter implements SabrPlayerAdapter {
|
||||
}
|
||||
|
||||
if (result) {
|
||||
abortController.abort();
|
||||
return this.createShakaResponse({
|
||||
uri,
|
||||
request,
|
||||
|
||||
@@ -25,6 +25,7 @@ import { isYTBackend } from '$lib/misc';
|
||||
import { isOwnBackend } from '$lib/shared/index';
|
||||
import '$lib/fetchProxy';
|
||||
import { loadContentFilterFromURL } from '$lib/filtering/index.js';
|
||||
import { getKeyValue } from '$lib/api/backend/keyvalue.js';
|
||||
|
||||
export const ssr = false;
|
||||
export const prerender = false;
|
||||
@@ -34,6 +35,13 @@ export async function load({ url }) {
|
||||
await initI18n();
|
||||
}
|
||||
|
||||
if (get(rawMasterKeyStore)) {
|
||||
const authTokenFromCloud = await getKeyValue('authToken');
|
||||
if (typeof authTokenFromCloud === 'string')
|
||||
invidiousAuthStore.set(JSON.parse(authTokenFromCloud));
|
||||
else invidiousAuthStore.set(null);
|
||||
}
|
||||
|
||||
isAndroidTvStore.set((await androidTv.isAndroidTv()).value);
|
||||
|
||||
if (Capacitor.getPlatform() === 'android') {
|
||||
|
||||
@@ -146,12 +146,8 @@ async function proxyRequest(
|
||||
|
||||
const responseHeaders = new Headers(response.headers);
|
||||
responseHeaders.delete('content-encoding');
|
||||
responseHeaders.delete('access-control-allow-origin');
|
||||
responseHeaders.delete('timing-allow-origin');
|
||||
responseHeaders.delete('content-length');
|
||||
|
||||
responseHeaders.set('transfer-encoding', 'chunked');
|
||||
|
||||
return new Response(response.body, {
|
||||
status: response.status,
|
||||
headers: responseHeaders
|
||||
|
||||
@@ -3,7 +3,7 @@ import { getUser } from '$lib/server/user';
|
||||
import { error, json } from '@sveltejs/kit';
|
||||
import z from 'zod';
|
||||
|
||||
async function keyAllowed(key: string) {
|
||||
function keyAllowed(key: string) {
|
||||
if (!persistedStoreKeys.includes(key)) throw error(400);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ export async function DELETE({ locals, params }) {
|
||||
keyAllowed(params.key);
|
||||
|
||||
const user = await getUser(locals.userId);
|
||||
|
||||
await user.deleteKeyValue(params.key);
|
||||
|
||||
return new Response();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { resolve } from '$app/paths';
|
||||
import { addOrUpdateKeyValue } from '$lib/api/backend/keyvalue.js';
|
||||
import { invidiousAuthStore } from '$lib/store';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
|
||||
@@ -7,10 +8,12 @@ export async function load({ url }) {
|
||||
const token = url.searchParams.get('token');
|
||||
|
||||
if (username && token) {
|
||||
invidiousAuthStore.set({
|
||||
const authToken = {
|
||||
username: username,
|
||||
token: token
|
||||
});
|
||||
};
|
||||
invidiousAuthStore.set(authToken);
|
||||
await addOrUpdateKeyValue('authToken', JSON.stringify(authToken));
|
||||
}
|
||||
|
||||
throw redirect(302, resolve('/', {}));
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
@@ -3,7 +3,7 @@ import os
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
LATEST_VERSION = "1.16.15"
|
||||
LATEST_VERSION = "1.16.16"
|
||||
RELEASE_DATE = datetime.now().strftime("%Y-%-m-%d") # Format: YYYY-M-D
|
||||
|
||||
WORKING_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "materialious")
|
||||
|
||||
Reference in New Issue
Block a user