Started filtering system

This commit is contained in:
WardPearce
2026-03-04 01:42:21 +13:00
parent 164597d2e7
commit a068f9ad61
5 changed files with 114 additions and 5 deletions
+31 -2
View File
@@ -1,12 +1,12 @@
{
"name": "materialious",
"version": "1.16.7",
"version": "1.16.8",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "materialious",
"version": "1.16.7",
"version": "1.16.8",
"hasInstallScript": true,
"dependencies": {
"@capacitor-community/electron": "^5.0.1",
@@ -49,6 +49,7 @@
"mysql2": "^3.18.2",
"pg": "^8.19.0",
"pg-hstore": "^2.3.4",
"safe-regex2": "^5.0.0",
"sequelize": "^6.37.7",
"shaka-player": "^4.16.14",
"sponsorblock-api": "^0.2.4",
@@ -16051,6 +16052,15 @@
"node": ">=8"
}
},
"node_modules/ret": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/ret/-/ret-0.5.0.tgz",
"integrity": "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==",
"license": "MIT",
"engines": {
"node": ">=10"
}
},
"node_modules/retry": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
@@ -16287,6 +16297,25 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/safe-regex2": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-5.0.0.tgz",
"integrity": "sha512-YwJwe5a51WlK7KbOJREPdjNrpViQBI3p4T50lfwPuDhZnE3XGVTlGvi+aolc5+RvxDD6bnUmjVsU9n1eboLUYw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"license": "MIT",
"dependencies": {
"ret": "~0.5.0"
}
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+2 -1
View File
@@ -87,6 +87,7 @@
"mysql2": "^3.18.2",
"pg": "^8.19.0",
"pg-hstore": "^2.3.4",
"safe-regex2": "^5.0.0",
"sequelize": "^6.37.7",
"shaka-player": "^4.16.14",
"sponsorblock-api": "^0.2.4",
@@ -98,4 +99,4 @@
"youtubei.js": "^16.0.1",
"zod": "^4.3.6"
}
}
}
@@ -4,7 +4,7 @@
import { videoLength } from '$lib/numbers';
import { generateChapterWebVTT, type ParsedDescription } from '$lib/description';
import { Capacitor, SystemBars, SystemBarsStyle, SystemBarType } from '@capacitor/core';
import { error, type Page } from '@sveltejs/kit';
import { error } from '@sveltejs/kit';
import Mousetrap from 'mousetrap';
import { CapacitorMusicControls } from 'capacitor-music-controls-plugin';
import shaka from 'shaka-player/dist/shaka-player.ui';
+79
View File
@@ -0,0 +1,79 @@
import { z } from 'zod';
import type { FeedItem } from './feed';
import isSafeRegex from 'safe-regex2';
const zFilterOperatorEnum = z.enum([
'equals', // equal to
'in', // in a set of values
'like', // contains (string matching)
'gt', // greater than
'lt', // less than
'regex' // regular expression matching
]);
// Filter condition schema
const zFilterCondition = z.object({
field: z.string(), // Field to filter
operator: zFilterOperatorEnum, // Operator
value: z.union([
// Value to compare against
z.string(),
z.number(),
z.array(z.string()),
z.array(z.number()),
z.string().regex(/.*/)
])
});
// Logical grouping operator
const zFilterGroup = z.object({
conditions: z.array(zFilterCondition), // A list of conditions to apply
operator: z.enum(['AND', 'OR']).optional() // Logical grouping of conditions
});
const zBlockListSchema = z.array(zFilterGroup);
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) => {
const fieldValue = item[condition.field as keyof T];
switch (condition.operator) {
case 'equals':
return fieldValue === condition.value;
case 'in':
return (
Array.isArray(condition.value) && (condition.value as any[]).includes(fieldValue)
);
case 'like':
return (
typeof fieldValue === 'string' &&
typeof condition.value === 'string' &&
fieldValue.includes(condition.value)
);
case 'gt':
return (
typeof fieldValue === 'number' &&
typeof condition.value === 'number' &&
fieldValue > condition.value
);
case 'lt':
return (
typeof fieldValue === 'number' &&
typeof condition.value === 'number' &&
fieldValue < condition.value
);
case 'regex':
if (typeof condition.value !== 'string' || !isSafeRegex(condition.value)) return false;
return typeof fieldValue === 'string' && new RegExp(condition.value).test(fieldValue);
default:
return false;
}
});
});
});
}
@@ -14,7 +14,7 @@
</style>
</svelte:head>
{#await navigating.completed}
{#await navigating.complete}
<PageLoading />
<!-- eslint-disable-next-line @typescript-eslint/no-unused-vars -->
{:then _}