@@ -7,8 +7,8 @@ android {
|
||||
applicationId "us.materialio.app"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 167
|
||||
versionName "1.11.7"
|
||||
versionCode 168
|
||||
versionName "1.11.8"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
aaptOptions {
|
||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||
|
||||
@@ -77,7 +77,11 @@
|
||||
|
||||
|
||||
|
||||
<release version="1.11.7" date="2025-11-20">
|
||||
|
||||
<release version="1.11.8" date="2025-11-25">
|
||||
<url>https://github.com/Materialious/Materialious/releases/tag/1.11.8</url>
|
||||
</release>
|
||||
<release version="1.11.7" date="2025-11-20">
|
||||
<url>https://github.com/Materialious/Materialious/releases/tag/1.11.7</url>
|
||||
</release>
|
||||
<release version="1.11.6" date="2025-11-13">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Materialious",
|
||||
"version": "1.11.7",
|
||||
"version": "1.11.8",
|
||||
"description": "Modern material design for Invidious.",
|
||||
"author": {
|
||||
"name": "Ward Pearce",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "materialious",
|
||||
"version": "1.11.7",
|
||||
"version": "1.11.8",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
@@ -70,4 +70,4 @@
|
||||
"svelte-persisted-store": "^0.12.0",
|
||||
"youtubei.js": "^16.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,6 +195,8 @@
|
||||
} else if ($feedLastItemId) {
|
||||
const element = document.getElementById($feedLastItemId);
|
||||
|
||||
feedLastItemId.set(undefined);
|
||||
|
||||
if (element) {
|
||||
element.scrollIntoView({
|
||||
behavior: 'instant',
|
||||
@@ -236,7 +238,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
<div class="grid" bind:this={gridElement}>
|
||||
{#each items as item, index}
|
||||
{#each items as item, index (index)}
|
||||
<ContentColumn>
|
||||
<article
|
||||
class="no-padding android-tv-item border"
|
||||
@@ -245,11 +247,12 @@
|
||||
id={extractUniqueId(item)}
|
||||
role="presentation"
|
||||
onclick={() => {
|
||||
feedLastItemId.set(extractUniqueId(item));
|
||||
const uniqueItemId = extractUniqueId(item);
|
||||
feedLastItemId.set(uniqueItemId);
|
||||
|
||||
// Required to pass click through to thumbnail component on Android TV
|
||||
if ($isAndroidTvStore) {
|
||||
const articleElement = document.getElementById(extractUniqueId(item));
|
||||
const articleElement = document.getElementById(uniqueItemId);
|
||||
if (articleElement) {
|
||||
const clickable = articleElement.querySelector('a, button');
|
||||
if (clickable instanceof HTMLElement) {
|
||||
|
||||
@@ -72,11 +72,20 @@
|
||||
const direction = event.key === 'ArrowUp' ? -1 : 1;
|
||||
const container = document.querySelector('.suggestions-container');
|
||||
if (container) {
|
||||
const children = Array.from(container.children);
|
||||
const currentIndex = selectedSuggestionIndex !== -1 ? selectedSuggestionIndex : 0;
|
||||
// Filter to ensure only list items are used.
|
||||
const children = Array.from(container.children).filter((child) => {
|
||||
return child.tagName === 'LI';
|
||||
});
|
||||
let currentIndex = selectedSuggestionIndex;
|
||||
|
||||
if (selectedSuggestionIndex !== -1) {
|
||||
children[currentIndex].classList.remove('primary-border');
|
||||
}
|
||||
|
||||
const newIndex = Math.min(Math.max(currentIndex + direction, 0), children.length - 1);
|
||||
const selectedItem = children[newIndex];
|
||||
if (selectedItem) {
|
||||
selectedItem.classList.add('primary-border');
|
||||
selectedItem.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
selectedSuggestionIndex = newIndex;
|
||||
}
|
||||
@@ -132,7 +141,7 @@
|
||||
class="rounded"
|
||||
/>
|
||||
{#if showSearchBox}
|
||||
<menu class="min suggestions-container rounded">
|
||||
<menu class="min rounded suggestions-container">
|
||||
<div class="field large prefix suffix no-margin fixed">
|
||||
<i class="front" role="presentation" onclick={() => dispatch('searchCancelled')}
|
||||
>arrow_back</i
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
<a
|
||||
tabindex="-1"
|
||||
class="wave thumbnail"
|
||||
href={watchUrl.toString()}
|
||||
href={resolve(watchUrl.toString(), {})}
|
||||
data-sveltekit-preload-data="off"
|
||||
onclick={syncChangeVideo}
|
||||
>
|
||||
@@ -207,18 +207,22 @@
|
||||
style="padding-left: 1px;"
|
||||
class="video-title"
|
||||
data-sveltekit-preload-data="off"
|
||||
href={watchUrl.toString()}
|
||||
href={resolve(watchUrl.toString(), {})}
|
||||
>
|
||||
<span class="bold">{letterCase(video.title.trimEnd())}</span>
|
||||
</a>
|
||||
|
||||
<div>
|
||||
<a
|
||||
tabindex="-1"
|
||||
class:author={!sideways}
|
||||
href={resolve(`/channel/[authorId]`, { authorId: video.authorId })}
|
||||
>{video.author}
|
||||
</a>
|
||||
{#if video.authorId}
|
||||
<a
|
||||
tabindex="-1"
|
||||
class:author={!sideways}
|
||||
href={resolve(`/channel/[authorId]`, { authorId: video.authorId })}
|
||||
>{video.author}
|
||||
</a>
|
||||
{:else}
|
||||
<p>{video.author}</p>
|
||||
{/if}
|
||||
|
||||
{#if !('publishedText' in video) && 'viewCountText' in video}
|
||||
•
|
||||
|
||||
@@ -15,7 +15,10 @@ article {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
a,
|
||||
.primary-border {
|
||||
border: 0.5px solid var(--primary);
|
||||
}
|
||||
|
||||
button,
|
||||
.button {
|
||||
border-radius: 0.5rem !important;
|
||||
|
||||
@@ -118,17 +118,19 @@
|
||||
{/if}
|
||||
<div class="description">
|
||||
{#if !$interfaceLowBandwidthMode}
|
||||
{#if channelPfp}
|
||||
<img
|
||||
loading="lazy"
|
||||
style="margin-right: 1em;"
|
||||
class="circle extra m l"
|
||||
src={channelPfp}
|
||||
alt="Channel profile"
|
||||
/>
|
||||
{:else}
|
||||
<progress style="padding: 15px;" class="circle"></progress>
|
||||
{/if}
|
||||
<div class="m l">
|
||||
{#if channelPfp}
|
||||
<img
|
||||
loading="lazy"
|
||||
style="margin-right: 1em;"
|
||||
class="circle extra"
|
||||
src={channelPfp}
|
||||
alt="Channel profile"
|
||||
/>
|
||||
{:else}
|
||||
<progress style="padding: 15px;" class="circle"></progress>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div>
|
||||
@@ -191,76 +193,70 @@
|
||||
|
||||
<div class="tabs left-align scroll">
|
||||
{#if data.channel.tabs.includes('videos')}
|
||||
<a class:active={tab === 'videos'} onclick={() => changeTab('videos')} href={`#video`}>
|
||||
<a class:active={tab === 'videos'} onclick={() => changeTab('videos')} href="#video">
|
||||
<i>movie</i>
|
||||
<span>{$_('videoTabs.videos')}</span>
|
||||
</a>
|
||||
{/if}
|
||||
{#if data.channel.tabs.includes('shorts')}
|
||||
<a class:active={tab === 'shorts'} onclick={() => changeTab('shorts')} href={`#short`}>
|
||||
<a class:active={tab === 'shorts'} onclick={() => changeTab('shorts')} href="#short">
|
||||
<i>smartphone</i>
|
||||
<span>{$_('videoTabs.shorts')}</span>
|
||||
</a>
|
||||
{/if}
|
||||
{#if data.channel.tabs.includes('streams')}
|
||||
<a class:active={tab === 'streams'} onclick={() => changeTab('streams')} href={`#stream`}>
|
||||
<a class:active={tab === 'streams'} onclick={() => changeTab('streams')} href="#stream">
|
||||
<i>stream</i>
|
||||
<span>{$_('videoTabs.streams')}</span>
|
||||
</a>
|
||||
{/if}
|
||||
{#if data.channel.tabs.includes('playlists')}
|
||||
<a
|
||||
class:active={tab === 'playlists'}
|
||||
onclick={() => changeTab('playlists')}
|
||||
href={`#playlist`}
|
||||
>
|
||||
<a class:active={tab === 'playlists'} onclick={() => changeTab('playlists')} href="#playlist">
|
||||
<i>playlist_add_check</i>
|
||||
<span>{$_('videoTabs.playlists')}</span>
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
<div class="s12 m6 l6">
|
||||
<nav class="group">
|
||||
{#each sortByOptions as sortingOption (sortingOption)}
|
||||
<button
|
||||
class="no-round"
|
||||
onclick={async () => {
|
||||
sortBy = sortingOption;
|
||||
<div class="grid">
|
||||
<div class="s12 m6 l6">
|
||||
<nav class="group">
|
||||
{#each sortByOptions as sortingOption (sortingOption)}
|
||||
<button
|
||||
class="no-round"
|
||||
onclick={async () => {
|
||||
sortBy = sortingOption;
|
||||
|
||||
displayContent = await getChannelContent(data.channel.authorId, {
|
||||
type: tab,
|
||||
sortBy: sortBy
|
||||
});
|
||||
}}
|
||||
class:active={sortBy === sortingOption}>{$_(sortingOption)}</button
|
||||
>
|
||||
{/each}
|
||||
</nav>
|
||||
</div>
|
||||
<div class="s12 m6 l6">
|
||||
{#if showSearch}
|
||||
<div class="max field suffix prefix small no-margin surface-variant">
|
||||
<i class="front">search</i><input
|
||||
bind:value={channelSearch}
|
||||
oninput={searchChannel}
|
||||
type="text"
|
||||
placeholder={$_('searchPlaceholder')}
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
<nav class="right-align m l">
|
||||
<button onclick={() => (showSearch = true)}><i>search</i></button>
|
||||
displayContent = await getChannelContent(data.channel.authorId, {
|
||||
type: tab,
|
||||
sortBy: sortBy
|
||||
});
|
||||
}}
|
||||
class:active={sortBy === sortingOption}>{$_(sortingOption)}</button
|
||||
>
|
||||
{/each}
|
||||
</nav>
|
||||
<button class="s" onclick={() => (showSearch = true)}><i>search</i></button>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="s12 m6 l6">
|
||||
{#if showSearch}
|
||||
<div class="max field suffix prefix small no-margin surface-variant">
|
||||
<i class="front">search</i><input
|
||||
bind:value={channelSearch}
|
||||
oninput={searchChannel}
|
||||
type="text"
|
||||
placeholder={$_('searchPlaceholder')}
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
<nav class="right-align m l">
|
||||
<button onclick={() => (showSearch = true)}><i>search</i></button>
|
||||
</nav>
|
||||
<button class="s" onclick={() => (showSearch = true)}><i>search</i></button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space"></div>
|
||||
|
||||
{#if displayContent}
|
||||
{#if 'videos' in displayContent}
|
||||
<ItemsList items={displayContent.videos} />
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import os
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
LATEST_VERSION = "1.11.7"
|
||||
LATEST_VERSION = "1.11.8"
|
||||
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