Add the picked providers and a Must include group
This commit is contained in:
@@ -50,21 +50,32 @@ export function resolutionCondition(preset: string): string | null {
|
||||
}
|
||||
|
||||
/**
|
||||
* The providers that dominate the archive, for the "Do not include" shortcuts.
|
||||
* The providers that dominate the archive, for the "Do not include" and "Must include" shortcuts.
|
||||
* Aggregated 2026-09-17 over media-scrape/db (`provider` column, distinct URLs; discord folds in
|
||||
* cdn.discordapp.com and media.discordapp.net). Matching is a case-insensitive substring on
|
||||
* `provider`, so "twitter" also covers fxtwitter.com. The 4chan hosts stay out: the default URL
|
||||
* host exclusion already hides them.
|
||||
* cdn.discordapp.com, media.discordapp.net, and images-ext-*.discordapp.net). Matching is a
|
||||
* case-insensitive substring on `provider`, so "twitter" also covers fxtwitter.com, vxtwitter.com,
|
||||
* and twitfix; "reddit" covers www.reddit.com and vxreddit. Entries with several substrings are
|
||||
* joined with a comma and the UI shows "Giphy/Tenor": checking it applies both. 4chan's CDN hosts
|
||||
* are hidden by the default URL host exclusion, so 2ch.hk stands in for the provider box.
|
||||
*/
|
||||
export const PROVIDER_FILTERS = [
|
||||
"discord",
|
||||
"youtube",
|
||||
"tenor",
|
||||
"giphy,tenor",
|
||||
"twitch",
|
||||
"twitter",
|
||||
"reddit",
|
||||
"streamable",
|
||||
"instagram",
|
||||
"facebook",
|
||||
"steam",
|
||||
"gyazo",
|
||||
"tiktok",
|
||||
"medal",
|
||||
"sketchfab",
|
||||
"gfycat",
|
||||
"imgur"
|
||||
"2ch.hk",
|
||||
"imgur",
|
||||
"funnyjunk",
|
||||
"internet archive"
|
||||
] as const;
|
||||
|
||||
@@ -119,6 +119,10 @@ export interface MediaFilterOptions {
|
||||
excludeProviders?: string[];
|
||||
/** Row sources to hide (attachment, sticker, embed). */
|
||||
excludeSources?: string[];
|
||||
/** Keep only providers matching one of these substrings; empty keeps all. */
|
||||
includeProviders?: string[];
|
||||
/** Keep only these row sources; empty keeps all. */
|
||||
includeSources?: string[];
|
||||
/** Bytes; rows with no known size drop out while this is set. */
|
||||
sizeLessThan?: number;
|
||||
sizeGreaterThan?: number;
|
||||
@@ -609,6 +613,17 @@ export class ScrapeStore {
|
||||
conditions.push(`COALESCE(source, '') NOT IN (${options.excludeSources.map(() => "?").join(", ")})`);
|
||||
values.push(...options.excludeSources);
|
||||
}
|
||||
if (options.includeProviders?.length) {
|
||||
const clauses = options.includeProviders.map(() => "lower(COALESCE(provider, '')) LIKE ?");
|
||||
conditions.push(`(${clauses.join(" OR ")})`);
|
||||
for (const provider of options.includeProviders) {
|
||||
values.push(`%${provider.toLowerCase()}%`);
|
||||
}
|
||||
}
|
||||
if (options.includeSources?.length) {
|
||||
conditions.push(`COALESCE(source, '') IN (${options.includeSources.map(() => "?").join(", ")})`);
|
||||
values.push(...options.includeSources);
|
||||
}
|
||||
if (options.sizeLessThan !== undefined) {
|
||||
conditions.push("COALESCE(file_bytes, size) < ?");
|
||||
values.push(options.sizeLessThan);
|
||||
|
||||
@@ -1348,20 +1348,34 @@ void (async () => {
|
||||
});
|
||||
|
||||
await test("provider filters are the curated archive list", () => {
|
||||
assert.ok(
|
||||
PROVIDER_FILTERS.length >= 8 && PROVIDER_FILTERS.length <= 12,
|
||||
`provider list has ${PROVIDER_FILTERS.length} entries`
|
||||
);
|
||||
assert.ok(PROVIDER_FILTERS.length >= 12, `provider list has ${PROVIDER_FILTERS.length} entries`);
|
||||
assert.equal(new Set(PROVIDER_FILTERS).size, PROVIDER_FILTERS.length);
|
||||
|
||||
for (const value of PROVIDER_FILTERS) {
|
||||
assert.equal(value, value.toLowerCase());
|
||||
assert.ok(!value.includes(" ") && !value.includes("."), `host-like entry: ${value}`);
|
||||
for (const entry of PROVIDER_FILTERS) {
|
||||
const values = entry.split(",");
|
||||
assert.ok(values.length >= 1 && values.every(value => value.length > 0), entry);
|
||||
for (const value of values) assert.equal(value, value.toLowerCase(), entry);
|
||||
}
|
||||
|
||||
for (const required of ["discord", "youtube", "twitch", "tenor"]) {
|
||||
for (const required of [
|
||||
"discord",
|
||||
"youtube",
|
||||
"twitch",
|
||||
"twitter",
|
||||
"reddit",
|
||||
"instagram",
|
||||
"tiktok",
|
||||
"streamable",
|
||||
"facebook",
|
||||
"gyazo",
|
||||
"funnyjunk",
|
||||
"internet archive",
|
||||
"2ch.hk"
|
||||
]) {
|
||||
assert.ok((PROVIDER_FILTERS as readonly string[]).includes(required), required);
|
||||
}
|
||||
|
||||
assert.ok((PROVIDER_FILTERS as readonly string[]).includes("giphy,tenor"), "giphy/tenor merged");
|
||||
});
|
||||
|
||||
await test("store exclusion, size, and length filters", () => {
|
||||
@@ -1417,6 +1431,10 @@ void (async () => {
|
||||
assert.deepEqual(ids({ lengthGreaterThan: 10 }), [5]);
|
||||
// Unknown lengths drop out while a length range is set.
|
||||
assert.deepEqual(ids({ lengthLessThan: 10 }), []);
|
||||
assert.deepEqual(ids({ includeProviders: ["youtube"] }), [3]);
|
||||
assert.deepEqual(ids({ includeProviders: ["youtube", "twitch"] }), [3, 4]);
|
||||
assert.deepEqual(ids({ includeSources: ["embed"] }), [3, 4]);
|
||||
assert.deepEqual(ids({ includeSources: ["attachment"] }), [1, 2, 5]);
|
||||
store.close();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user