More progress on content filtering
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)[];
|
||||
|
||||
Reference in New Issue
Block a user