Implemented auto load option
This commit is contained in:
@@ -3,10 +3,16 @@
|
||||
import { ChannelSchema, VideoSchema, type SchemaStructure } from '$lib/filtering/schemas';
|
||||
import { _ } from '$lib/i18n';
|
||||
import { titleCase, camelCaseToHuman } from '$lib/letterCasing';
|
||||
import { filterContentListStore } from '$lib/store';
|
||||
import {
|
||||
filterContentListStore,
|
||||
filterContentUrlAutoUpdateStore,
|
||||
filterContentUrlStore
|
||||
} from '$lib/store';
|
||||
import type z from 'zod';
|
||||
import { addToast } from '../Toast.svelte';
|
||||
import { Clipboard } from '@capacitor/clipboard';
|
||||
|
||||
let remoteFilterListUrl: string = $state('');
|
||||
let remoteFilterListUrl: string = $state($filterContentUrlStore ?? '');
|
||||
let remoteError: string = $state('');
|
||||
|
||||
type FilterType = 'channel' | 'video';
|
||||
@@ -33,11 +39,33 @@
|
||||
try {
|
||||
contentFilters = await loadContentFilterFromURL(remoteFilterListUrl);
|
||||
filterContentListStore.set(contentFilters);
|
||||
filterContentUrlStore.set(remoteFilterListUrl);
|
||||
filterContentUrlAutoUpdateStore.set(false);
|
||||
} catch (errorMsg) {
|
||||
remoteError = (errorMsg as Error).message;
|
||||
}
|
||||
}
|
||||
|
||||
async function exportAsJSON() {
|
||||
await Clipboard.write({
|
||||
string: JSON.stringify(
|
||||
{
|
||||
version: 'v1',
|
||||
createdFor: 'materialious',
|
||||
filterBy: contentFilters
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
});
|
||||
|
||||
addToast({
|
||||
data: {
|
||||
text: $_('player.share.copiedSuccess')
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function addFilter(type: FilterType) {
|
||||
if (!contentFilters) contentFilters = [];
|
||||
|
||||
@@ -58,6 +86,10 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<article class="error-container">
|
||||
<p>{$_('layout.backendEngine.warning')}</p>
|
||||
</article>
|
||||
|
||||
<form onsubmit={loadFilterList}>
|
||||
<nav>
|
||||
<div
|
||||
@@ -77,7 +109,33 @@
|
||||
</nav>
|
||||
</form>
|
||||
|
||||
{#if $filterContentUrlStore}
|
||||
<nav class="no-padding">
|
||||
<div class="max">
|
||||
<p>{$_('layout.filter.autoUpdate')}</p>
|
||||
</div>
|
||||
<label class="switch" tabindex="0">
|
||||
<input
|
||||
bind:checked={$filterContentUrlAutoUpdateStore}
|
||||
onclick={() => filterContentUrlAutoUpdateStore.set(!$filterContentUrlAutoUpdateStore)}
|
||||
type="checkbox"
|
||||
role="switch"
|
||||
/>
|
||||
<span></span>
|
||||
</label>
|
||||
</nav>
|
||||
<div class="space"></div>
|
||||
{/if}
|
||||
|
||||
{#if contentFilters}
|
||||
{#if contentFilters.length > 0}
|
||||
<button class="surface-container-highest" onclick={exportAsJSON}>
|
||||
<i>content_copy</i>
|
||||
<span>{$_('copy')}</span>
|
||||
</button>
|
||||
<div class="space"></div>
|
||||
{/if}
|
||||
|
||||
{#each contentFilters as filter (filter)}
|
||||
<article class="no-margin surface-container-high">
|
||||
<div class="grid">
|
||||
@@ -195,7 +253,10 @@
|
||||
<div class="field label border">
|
||||
<input
|
||||
oninput={(event: Event & { currentTarget: HTMLInputElement }) => {
|
||||
condition.value = event.currentTarget.value;
|
||||
condition.value =
|
||||
schema[filter.type][condition.field] === 'number'
|
||||
? Number(event.currentTarget.value)
|
||||
: event.currentTarget.value;
|
||||
filterContentListStore.set(contentFilters);
|
||||
}}
|
||||
name="value"
|
||||
@@ -233,7 +294,7 @@
|
||||
<i>add</i>
|
||||
<span>Add filter</span>
|
||||
</button>
|
||||
<menu class="min">
|
||||
<menu>
|
||||
{#each filterTypes as filterType (filterType)}
|
||||
<li role="presentation" onclick={() => addFilter(filterType)}>{titleCase(filterType)}</li>
|
||||
{/each}
|
||||
|
||||
@@ -51,7 +51,9 @@ import {
|
||||
playerYouTubeJsAlways,
|
||||
interfaceSearchHistoryEnabled,
|
||||
playerPreferredVolumeStore,
|
||||
watchHistoryEnabledStore
|
||||
watchHistoryEnabledStore,
|
||||
filterContentUrlStore,
|
||||
filterContentUrlAutoUpdateStore
|
||||
} from '$lib/store';
|
||||
import { isOwnBackend } from '$lib/shared';
|
||||
|
||||
@@ -258,6 +260,16 @@ export const persistedStores: PersistedStore<any>[] = [
|
||||
name: 'watchHistoryEnabled',
|
||||
store: watchHistoryEnabledStore,
|
||||
schema: zBoolean
|
||||
},
|
||||
{
|
||||
name: 'filterContentUrl',
|
||||
store: filterContentUrlStore,
|
||||
schema: zString
|
||||
},
|
||||
{
|
||||
name: 'filterContentUrlAutoUpdate',
|
||||
store: filterContentUrlAutoUpdateStore,
|
||||
schema: zBoolean
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ export function isItemFiltered(item: FeedItem): boolean {
|
||||
|
||||
switch (condition.operator) {
|
||||
case 'equals':
|
||||
return fieldValue === condition.value;
|
||||
return fieldValue.toString() === condition.value.toString();
|
||||
|
||||
case 'in':
|
||||
return Array.isArray(condition.value) && (condition.value as any[]).includes(fieldValue);
|
||||
|
||||
@@ -261,7 +261,8 @@
|
||||
},
|
||||
"filter": {
|
||||
"title": "Content Filters",
|
||||
"url": "Import Filters from URL"
|
||||
"url": "Import Filters from URL",
|
||||
"autoUpdate": "Automatically update filter from URL"
|
||||
},
|
||||
"deArrow": {
|
||||
"title": "DeArrow",
|
||||
|
||||
@@ -347,6 +347,18 @@ export const filterContentListStore: Writable<z.infer<typeof zFilterSchema> | un
|
||||
'filterContentList'
|
||||
);
|
||||
|
||||
export const filterContentUrlStore: Writable<string | undefined> = persist(
|
||||
writable(),
|
||||
createStorage(),
|
||||
'filterContentUrl'
|
||||
);
|
||||
|
||||
export const filterContentUrlAutoUpdateStore: Writable<boolean> = persist(
|
||||
writable(false),
|
||||
createStorage(),
|
||||
'filterContentUrlAutoUpdate'
|
||||
);
|
||||
|
||||
export const feedLoadingStore: Writable<boolean> = writable(false);
|
||||
export const feedCacheStore: Writable<{
|
||||
[key: string]: (VideoBase | Video | PlaylistPageVideo)[];
|
||||
|
||||
@@ -12,7 +12,10 @@ import {
|
||||
invidiousInstanceStore,
|
||||
interfaceDefaultPage,
|
||||
isAndroidTvStore,
|
||||
rawMasterKeyStore
|
||||
rawMasterKeyStore,
|
||||
filterContentListStore,
|
||||
filterContentUrlStore,
|
||||
filterContentUrlAutoUpdateStore
|
||||
} from '$lib/store';
|
||||
import { get, type Writable } from 'svelte/store';
|
||||
import { Capacitor } from '@capacitor/core';
|
||||
@@ -21,6 +24,7 @@ import { deserialize } from '@macfja/serializer';
|
||||
import { isYTBackend } from '$lib/misc';
|
||||
import { isOwnBackend } from '$lib/shared/index';
|
||||
import '$lib/fetchProxy';
|
||||
import { loadContentFilterFromURL } from '$lib/filtering/index.js';
|
||||
|
||||
export const ssr = false;
|
||||
export const prerender = false;
|
||||
@@ -37,7 +41,10 @@ export async function load({ url }) {
|
||||
invidiousInstance: invidiousInstanceStore,
|
||||
authToken: invidiousAuthStore,
|
||||
backendInUse: backendInUseStore,
|
||||
rawMasterKey: rawMasterKeyStore
|
||||
rawMasterKey: rawMasterKeyStore,
|
||||
filterContentList: filterContentListStore,
|
||||
filterContentUrl: filterContentUrlStore,
|
||||
filterContentUrlAutoUpdate: filterContentUrlAutoUpdateStore
|
||||
};
|
||||
|
||||
for (const [key, store] of Object.entries(preferenceKey)) {
|
||||
@@ -48,6 +55,17 @@ export async function load({ url }) {
|
||||
}
|
||||
}
|
||||
|
||||
if (get(filterContentUrlAutoUpdateStore)) {
|
||||
const filterUrl = get(filterContentUrlStore);
|
||||
if (filterUrl) {
|
||||
try {
|
||||
loadContentFilterFromURL(filterUrl);
|
||||
} catch {
|
||||
// Continue regardless of error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const resolvedRoot = resolve('/', {});
|
||||
|
||||
if (url.pathname.startsWith(resolvedRoot + '@')) {
|
||||
|
||||
Reference in New Issue
Block a user