Merge pull request #363 from Materialious/update/1.1.1

Update/1.1.1
This commit is contained in:
Ward
2024-06-22 15:57:25 +12:00
committed by GitHub
15 changed files with 2128 additions and 1943 deletions
+2 -2
View File
@@ -7,8 +7,8 @@ android {
applicationId "us.materialio.app"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 12
versionName "1.1.0"
versionCode 13
versionName "1.1.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "Materialious",
"version": "1.1.0",
"version": "1.1.1",
"description": "Modern material design for Invidious.",
"author": {
"name": "Ward Pearce",
+1869 -1814
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "materialious",
"version": "1.1.0",
"version": "1.1.1",
"private": true,
"scripts": {
"dev": "vite dev",
@@ -60,4 +60,4 @@
"svelte-persisted-store": "^0.11.0",
"vidstack": "^1.11.21"
}
}
}
-1
View File
@@ -1,2 +1 @@
declare module 'virtual:pwa-info';
declare type ui = import('beercss').ui;
+50
View File
@@ -1,6 +1,7 @@
<script lang="ts">
import { bookmarkletSaveToUrl } from '$lib/externalSettings';
import { Capacitor } from '@capacitor/core';
import ui from 'beercss';
import { iso31661 } from 'iso-3166';
import { _ } from 'svelte-i18n';
import { get } from 'svelte/store';
@@ -11,7 +12,10 @@
deArrowEnabledStore,
deArrowInstanceStore,
deArrowThumbnailInstanceStore,
deArrowTitlesOnly,
instanceStore,
interfaceAutoExpandComments,
interfaceAutoExpandDesc,
interfaceForceCase,
interfacePreviewVideoOnHoverStore,
interfaceRegionStore,
@@ -170,6 +174,38 @@
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.expandDescription')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$interfaceAutoExpandDesc}
on:click={() => interfaceAutoExpandDesc.set(!$interfaceAutoExpandDesc)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.expandComments')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$interfaceAutoExpandComments}
on:click={() => interfaceAutoExpandComments.set(!$interfaceAutoExpandComments)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field label suffix border">
<select name="region" bind:value={region} on:change={() => interfaceRegionStore.set(region)}>
{#each iso31661 as region}
@@ -533,6 +569,20 @@
</nav>
</form>
<nav class="no-padding">
<div class="max">
<p>{$_('layout.deArrow.titleOnly')}</p>
</div>
<label class="switch">
<input
bind:checked={$deArrowTitlesOnly}
on:click={() => deArrowTitlesOnly.set(!$deArrowTitlesOnly)}
type="checkbox"
/>
<span></span>
</label>
</nav>
<nav class="no-padding">
<div class="max">
<p>{$_('enabled')}</p>
+170 -117
View File
@@ -1,15 +1,23 @@
<script lang="ts">
import { createEventDispatcher, onMount } from 'svelte';
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
import { _ } from 'svelte-i18n';
import { get } from 'svelte/store';
import { getDeArrow, getThumbnail, getVideo, getVideoProgress } from './Api';
import type { Notification, PlaylistPageVideo, Video, VideoBase, VideoPlay } from './Api/model';
import ShareVideo from './ShareVideo.svelte';
import { cleanNumber, getBestThumbnail, letterCase, proxyVideoUrl, videoLength } from './misc';
import {
cleanNumber,
getBestThumbnail,
letterCase,
proxyVideoUrl,
truncate,
videoLength
} from './misc';
import type { PlayerEvents } from './player';
import {
authStore,
deArrowEnabledStore,
deArrowTitlesOnly,
interfacePreviewVideoOnHoverStore,
playerProxyVideosStore,
playerSavePlaybackPositionStore,
@@ -22,6 +30,7 @@
export let video: VideoBase | Video | Notification | PlaylistPageVideo;
export let playlistId: string = '';
export let sideways: boolean = false;
let thumbnailHidden: boolean = false;
let showVideoPreview: boolean = false;
@@ -60,6 +69,14 @@
progress = null;
}
let startedSideways = sideways === true;
function disableSideways() {
if (!startedSideways) return;
if (window.innerWidth <= 1000) sideways = false;
else sideways = true;
}
onMount(async () => {
try {
thumbnailHidden = localStorage.getItem(`v_h_${video.videoId}`) === '1';
@@ -70,6 +87,8 @@
return;
}
addEventListener('resize', disableSideways);
let imageSrc = getBestThumbnail(video.videoThumbnails) as string;
if (get(deArrowEnabledStore)) {
@@ -95,7 +114,7 @@
}
} catch {}
if (!locatedThumbnail) {
if (!locatedThumbnail && !get(deArrowTitlesOnly)) {
// Process thumbnail locally.
const canvas = document.getElementById('canvas') as HTMLCanvasElement | null;
function generateThumbnail(): Promise<string> {
@@ -154,6 +173,10 @@
}
});
onDestroy(() => {
removeEventListener('resize', disableSideways);
});
function syncChangeVideo() {
if ($syncPartyConnectionsStore) {
const events = {
@@ -206,124 +229,129 @@
</script>
{#if !thumbnailHidden}
<div
style="position: relative;"
on:mouseover={previewVideo}
on:mouseleave={() => (showVideoPreview = false)}
on:focus={() => {}}
bind:clientHeight={imgHeight}
role="region"
>
<a
class="wave thumbnail"
href={watchUrl.toString()}
data-sveltekit-preload-data="off"
on:click={syncChangeVideo}
<div class:side-ways={sideways}>
<div
style="position: relative;"
on:mouseover={previewVideo}
on:mouseleave={() => (showVideoPreview = false)}
on:focus={() => {}}
bind:clientHeight={imgHeight}
role="region"
>
{#if loading}
<progress class="circle"></progress>
{:else if loaded}
{#if showVideoPreview && videoPreview}
<div style="max-width: 100%; max-height: {imgHeight}px;">
<video
style="max-width: 100%; height: {imgHeight}px;"
autoplay
poster={img.src}
width="100%"
height="100%"
muted={videoPreviewMuted}
controls={false}
volume={videoPreviewVolume}
src={proxyVideos
? proxyVideoUrl(videoPreview.formatStreams[0].url)
: videoPreview.formatStreams[0].url}
>
</video>
</div>
{:else}
<img class="responsive" src={img.src} alt="Thumbnail for video" />
{/if}
{:else}
<p>{$_('thumbnail.failedToLoadImage')}</p>
{/if}
{#if progress}
<progress
class="absolute right bottom"
style="z-index: 1;"
value={progress}
max={video.lengthSeconds}
></progress>
{/if}
{#if !('liveVideo' in video) || !video.liveVideo}
{#if video.lengthSeconds !== 0}
<div
class="absolute right bottom small-margin black white-text small-text thumbnail-corner"
>
&nbsp;{videoLength(video.lengthSeconds)}&nbsp;
</div>
{/if}
{:else}
<div class="absolute right bottom small-margin red white-text small-text thumbnail-corner">
{$_('thumbnail.live')}
</div>
{/if}
</a>
{#if showVideoPreview && videoPreview}
<button
class="no-padding"
style="position: absolute; bottom: 10px; left: 10px; width: 30px; height: 30px;"
on:click={() => {
videoPreviewMuted = !videoPreviewMuted;
}}
<a
class="wave thumbnail"
href={watchUrl.toString()}
data-sveltekit-preload-data="off"
on:click={syncChangeVideo}
>
<i>
{#if videoPreviewMuted}
volume_off
{:else}
volume_up
{/if}
</i>
</button>
{/if}
</div>
<div class="small-padding">
<nav class="no-margin">
<div class="max">
<a
href={watchUrl.toString()}
data-sveltekit-preload-data="off"
style="display: flex; justify-content:flex-start; position: absolute; width: 100%;"
><div class="bold" style="white-space: nowrap; overflow: hidden;text-overflow: ellipsis;">
{letterCase(video.title)}
</div>
<div class="tooltip bottom small">{letterCase(video.title)}</div>
</a>
<div style="margin-top: 1.4em;">
<a href={`/channel/${video.authorId}`}>{video.author}</a
>{#if !('publishedText' in video) && 'viewCountText' in video}
&nbsp;• {video.viewCountText}{/if}
</div>
<nav class="no-margin">
{#if 'publishedText' in video}
<div class="max">
{cleanNumber(video.viewCount)} • {video.publishedText}
{#if loading}
<progress class="circle"></progress>
{:else if loaded}
{#if showVideoPreview && videoPreview}
<div style="max-width: 100%; max-height: {imgHeight}px;">
<video
style="max-width: 100%; height: {imgHeight}px;"
autoplay
poster={img.src}
width="100%"
height="100%"
muted={videoPreviewMuted}
controls={false}
volume={videoPreviewVolume}
src={proxyVideos
? proxyVideoUrl(videoPreview.formatStreams[0].url)
: videoPreview.formatStreams[0].url}
>
</video>
</div>
<button class="transparent circle">
<i>more_vert</i>
<menu class="left no-wrap">
<a href="#hide" on:click={hideVideo}>
{$_('hideVideo')}
</a>
<div class="divider"></div>
<ShareVideo {video} />
</menu>
</button>
{:else}
<img class="responsive" src={img.src} alt="Thumbnail for video" />
{/if}
</nav>
</div>
</nav>
{:else}
<p>{$_('thumbnail.failedToLoadImage')}</p>
{/if}
{#if progress}
<progress
class="absolute right bottom"
style="z-index: 1;"
value={progress}
max={video.lengthSeconds}
></progress>
{/if}
{#if !('liveVideo' in video) || !video.liveVideo}
{#if video.lengthSeconds !== 0}
<div
class="absolute right bottom small-margin black white-text small-text thumbnail-corner"
>
&nbsp;{videoLength(video.lengthSeconds)}&nbsp;
</div>
{/if}
{:else}
<div
class="absolute right bottom small-margin red white-text small-text thumbnail-corner"
>
{$_('thumbnail.live')}
</div>
{/if}
</a>
{#if showVideoPreview && videoPreview}
<button
class="no-padding"
style="position: absolute; bottom: 10px; left: 10px; width: 30px; height: 30px;"
on:click={() => {
videoPreviewMuted = !videoPreviewMuted;
}}
>
<i>
{#if videoPreviewMuted}
volume_off
{:else}
volume_up
{/if}
</i>
</button>
{/if}
</div>
<div class="small-padding">
<nav class="no-margin">
<div class="max">
<a
href={watchUrl.toString()}
data-sveltekit-preload-data="off"
class:ellipsis-root={!sideways}
><div class="bold" class:ellipsis={!sideways}>
{truncate(letterCase(video.title.trim()), 40)}
</div>
<div class="tooltip bottom small">{letterCase(video.title)}</div>
</a>
<a class:author={!sideways} href={`/channel/${video.authorId}`}>{video.author}</a>
<span>
{#if !('publishedText' in video) && 'viewCountText' in video}
&nbsp;• {video.viewCountText}{/if}
</span>
<nav class="no-margin">
{#if 'publishedText' in video}
<div class="max">
{cleanNumber(video.viewCount)} • {video.publishedText}
</div>
<button class="transparent circle">
<i>more_vert</i>
<menu class="left no-wrap">
<a href="#hide" on:click={hideVideo}>
{$_('hideVideo')}
</a>
<div class="divider"></div>
<ShareVideo {video} />
</menu>
</button>
{/if}
</nav>
</div>
</nav>
</div>
</div>
{/if}
@@ -331,6 +359,31 @@
<div id="video-container" style="display: none;"></div>
<style>
.side-ways {
display: flex;
}
.side-ways img {
width: 200px;
}
.ellipsis-root {
display: flex;
justify-content: flex-start;
position: absolute;
width: 100%;
}
.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.author {
margin-top: 1.4em;
}
.thumbnail {
width: 100%;
overflow: hidden;
+18
View File
@@ -4,6 +4,9 @@ import {
deArrowEnabledStore,
deArrowInstanceStore,
deArrowThumbnailInstanceStore,
deArrowTitlesOnly,
interfaceAutoExpandComments,
interfaceAutoExpandDesc,
interfaceForceCase,
interfacePreviewVideoOnHoverStore,
interfaceRegionStore,
@@ -153,6 +156,21 @@ const persistedStores = [
name: 'forceCase',
store: interfaceForceCase,
type: 'string'
},
{
name: 'autoExpandComments',
store: interfaceAutoExpandComments,
type: 'boolean'
},
{
name: 'autoExpandDesc',
store: interfaceAutoExpandDesc,
type: 'boolean'
},
{
name: 'deArrowTitlesOnly',
store: deArrowTitlesOnly,
type: 'boolean'
}
];
+4 -1
View File
@@ -93,6 +93,8 @@
},
"searchSuggestions": "Search suggestions",
"previewVideoOnHover": "Preview video on hover",
"expandDescription": "Expand description by default",
"expandComments": "Expand comments by default",
"dataPreferences": {
"content": "Looking to import/export subscriptions, change password or delete account? Click here and scroll to the bottom of the page.",
"dataPreferences": "Data preferences"
@@ -123,7 +125,8 @@
},
"deArrow": {
"title": "DeArrow",
"thumbnailInstanceUrl": "Thumbnail instance URL"
"thumbnailInstanceUrl": "Thumbnail instance URL",
"titleOnly": "Title only"
}
},
"subscribe": "Subscribe"
+3
View File
@@ -47,6 +47,8 @@ export const interfaceRegionStore: Writable<string> = persisted('interfaceRegion
export const interfaceSearchSuggestionsStore = persisted('searchSuggestions', true);
export const interfacePreviewVideoOnHoverStore = persisted('previewVideoOnHover', true);
export const interfaceForceCase: Writable<TitleCase> = persisted('forceCase', null);
export const interfaceAutoExpandComments: Writable<boolean> = persisted('autoExpandComments', true);
export const interfaceAutoExpandDesc: Writable<boolean> = persisted('autoExpandDesc', false);
export const sponsorBlockStore = persisted('sponsorBlock', true);
export const sponsorBlockUrlStore: Writable<string | null | undefined> = persisted(
@@ -63,6 +65,7 @@ export const deArrowInstanceStore = persisted(
import.meta.env.VITE_DEFAULT_DEARROW_INSTANCE || 'https://sponsor.ajay.app'
);
export const deArrowEnabledStore = persisted('deArrowEnabled', false);
export const deArrowTitlesOnly = persisted('deArrowTitlesOnly', true);
export const deArrowThumbnailInstanceStore = persisted(
'deArrowThumbnailInstance',
import.meta.env.VITE_DEFAULT_DEARROW_THUMBNAIL_INSTANCE || 'https://dearrow-thumb.ajay.app'
+3 -1
View File
@@ -1,5 +1,7 @@
import ui from 'beercss';
export async function getDynamicTheme(mode?: string): Promise<Record<string, string>> {
const givenSettings = (await window.ui('theme')) as IBeerCssTheme;
const givenSettings = (await ui('theme'));
// @ts-ignore
const themes: string = givenSettings[mode ? mode : (ui('mode') as string)];
@@ -26,6 +26,8 @@
import {
activePageStore,
authStore,
interfaceAutoExpandComments,
interfaceAutoExpandDesc,
miniPlayerSrcStore,
playerAutoplayNextByDefaultStore,
playerListenByDefaultStore,
@@ -555,7 +557,7 @@
</div>
<article>
<details>
<details open={$interfaceAutoExpandDesc}>
<summary class="bold none">
<nav>
<div class="max">
@@ -597,7 +599,7 @@
{#if comments && comments.comments.length > 0}
<article>
<details open>
<details open={$interfaceAutoExpandComments}>
<summary class="none bold">
<nav>
<div class="max">{numberWithCommas(comments.commentCount)} comments</div>
@@ -631,7 +633,7 @@
{#each data.video.recommendedVideos as recommendedVideo}
<article class="no-padding">
{#key recommendedVideo.videoId}
<Thumbnail video={recommendedVideo} />
<Thumbnail video={recommendedVideo} sideways={true} />
{/key}
</article>
{/each}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 995 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 854 KiB

+1 -1
View File
@@ -5,7 +5,7 @@ import json
import os
import re
LATEST_VERSION = "1.1.0"
LATEST_VERSION = "1.1.1"
WORKING_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "materialious")
ROOT_PACKAGE = os.path.join(WORKING_DIR, "package.json")