More progress on content filtering

This commit is contained in:
WardPearce
2026-03-04 02:01:38 +13:00
parent a068f9ad61
commit 7b8065ff38
3 changed files with 46 additions and 5 deletions
@@ -14,6 +14,7 @@
import { SpatialMenu } from 'melt/builders';
import { mergeAttrs } from 'melt';
import { Capacitor } from '@capacitor/core';
import { filterByBlocklist } from '$lib/filtering';
interface Props {
items?: FeedItems;
@@ -35,6 +36,8 @@
}
onMount(async () => {
items = filterByBlocklist(items);
if (!$feedLastItemId) return;
const element = document.getElementById($feedLastItemId);
+35 -5
View File
@@ -1,6 +1,8 @@
import { z } from 'zod';
import type { FeedItem } from './feed';
import isSafeRegex from 'safe-regex2';
import { blocklistStore } from './store';
import { get } from 'svelte/store';
const zFilterOperatorEnum = z.enum([
'equals', // equal to
@@ -31,15 +33,23 @@ const zFilterGroup = z.object({
operator: z.enum(['AND', 'OR']).optional() // Logical grouping of conditions
});
const zBlockListSchema = z.array(zFilterGroup);
export const zBlockListSchema = z.array(zFilterGroup);
const zBlocklistRootSchema = z.object({
version: z.literal('v1'),
for: z.literal('materialious'),
blocklist: zBlockListSchema
});
export function filterByBlocklist<T extends FeedItem>(data: T[]): T[] {
const blocklist = get(blocklistStore);
if (!blocklist) return data;
export function filterByBlocklist<T extends FeedItem>(
data: T[],
blocklist: z.infer<typeof zBlockListSchema>
): T[] {
return data.filter((item) => {
return blocklist.every((filterGroup) => {
return filterGroup.conditions.every((condition) => {
if (!(condition.field in item)) return false;
const fieldValue = item[condition.field as keyof T];
switch (condition.operator) {
@@ -77,3 +87,23 @@ export function filterByBlocklist<T extends FeedItem>(
});
});
}
export async function loadBlockListFromRemote(url: string) {
const resp = await fetch(url, { method: 'GET', credentials: 'omit' });
if (!resp.ok) throw new Error('Response status code');
let respJson;
try {
respJson = await resp.json();
} catch {
// Handled outside of catch
}
if (!respJson) throw new Error('Invalid JSON');
const parsedBlocklist = zBlocklistRootSchema.safeParse(respJson);
if (!parsedBlocklist.success) throw new Error(parsedBlocklist.error.message);
blocklistStore.set(parsedBlocklist.data.blocklist);
}
+8
View File
@@ -22,6 +22,8 @@ import type {
import type { ParsedDescription } from './description';
import { ensureNoTrailingSlash, getPublicEnv } from './misc';
import type { EngineFallback } from './api/misc';
import type z from 'zod';
import type { zBlockListSchema } from './filtering';
function createListenerFunctions(): {
callListeners: (eventKey: string, newValue: any) => void;
@@ -339,6 +341,12 @@ export const searchHistoryStore: Writable<string[]> = persist(
'searchHistory'
);
export const blocklistStore: Writable<z.infer<typeof zBlockListSchema> | undefined> = persist(
writable(),
createStorage(),
'blocklist'
);
export const feedLoadingStore: Writable<boolean> = writable(false);
export const feedCacheStore: Writable<{
[key: string]: (VideoBase | Video | PlaylistPageVideo)[];