Rules drop posters at the header pass: the CelebMovie family (rule set version 3)
Test and deploy / test (push) Successful in 50s
Test and deploy / edge (push) Successful in 1m55s
Test and deploy / deploy (push) Successful in 1m47s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Daan MeijerandClaude Opus 5.5 committed 2026-10-16 11:36:46 +02:00
1 parent 093d0a71ad
commit 3d24db5565
9 files changed
+116 -9

No files matched your search

+2 -2
View File
@@ -48,7 +48,7 @@ export interface ProbeCandidate {
/** What a rule dropped in a batch (REBUILD.md, rules and recovery). */
export interface RuleCount {
rule: 'crosspost' | 'obfuscated' | 'executable' | 'garbage' | 'per-article' | 'incomplete'
rule: 'crosspost' | 'obfuscated' | 'poster' | 'executable' | 'garbage' | 'per-article' | 'incomplete'
key: string
articles: number
files: number
@@ -215,7 +215,7 @@ export class RangeIndexer {
uploadsOf(all).forEach((list, upload) => {
const verdict = this.rules.judge(
key,
list.map((f) => ({ name: f.segments[0].file.name, totalParts: f.segments[0].totalParts, groups: f.segments[0].file.groups, firstMessageId: f.segments[0].messageId }))
list.map((f) => ({ name: f.segments[0].file.name, totalParts: f.segments[0].totalParts, groups: f.segments[0].file.groups, firstMessageId: f.segments[0].messageId, poster: f.segments[0].file.poster }))
)
if (verdict.rule === null) {
this.batch.releases.push(chunkOf(key, list, upload))
+1 -1
View File
@@ -1,2 +1,2 @@
export { uploadTool, signatureGroup, signatureKey, explored } from './upload_tools.js'
export { RuleSet, DEFAULT_RULES, isRandomFile, ownerOf, type Rules, type Verdict } from './rule_set.js'
export { RuleSet, DEFAULT_RULES, isRandomFile, ownerOf, posterWords, type Rules, type Verdict } from './rule_set.js'
+22 -3
View File
@@ -24,6 +24,12 @@ export interface Rules {
* 2026-10-09). Genuine software comes in archives.
*/
dropExecutables: boolean
/**
* Posters whose uploads are dropped whatever they are: fragments of the poster lowercased without punctuation
* ("@__Celeb_Movie__@" → "celebmovie"). The CelebMovie family's scraped celebrity pictures, the same files again and
* again under other titles (119k releases on 2026-10-16; LOG.md 2026-10-16 (65)).
*/
droppedPosters: string[]
}
export const DEFAULT_RULES: Omit<Rules, 'priorities' | 'droppedSignatures'> = {
@@ -32,9 +38,15 @@ export const DEFAULT_RULES: Omit<Rules, 'priorities' | 'droppedSignatures'> = {
perArticleMaxParts: 3,
samplePercent: 1,
dropExecutables: true,
droppedPosters: ['celebmovie', 'celebwow', 'celebfx', 'iluvcelebs', 'nudecelebs', 'celebsextapes'],
}
export type Verdict = { rule: null } | { rule: 'executable' | 'garbage' | 'per-article'; key: string; sample: boolean }
export type Verdict = { rule: null } | { rule: 'poster' | 'executable' | 'garbage' | 'per-article'; key: string; sample: boolean }
/** A poster as droppedPosters matches it: lowercased, letters and digits only. */
export function posterWords(poster: string): string {
return poster.replace(/[^A-Za-z0-9]/g, '').toLowerCase()
}
/** Files that come along with a release's content: they don't make it one of executables or not. */
const SIDECAR = /\.(par2|nfo|sfv|txt|jpe?g|png|nzb)$/i
@@ -57,18 +69,25 @@ export function ownerOf(groups: string[], priorities: Record<string, number>): s
export class RuleSet {
private signatures: Set<string>
private tools: Set<string>
private posters: string[]
constructor(readonly rules: Rules) {
this.posters = rules.droppedPosters ?? []
this.signatures = new Set(rules.droppedSignatures)
this.tools = new Set(rules.droppedTools)
}
/**
* A release's verdict from its files: dropped when its content is bare
* A release's verdict from its files: dropped when its poster is; when its content is bare
* executables; else kept as a whole when any file has a readable name; else dropped as garbage when its signature or tool is
* dropped, as per-article random subjects when every file has few parts.
*/
judge(releaseKey: string, files: { name: string; totalParts: number; groups: string[]; firstMessageId: string }[]): Verdict {
judge(releaseKey: string, files: { name: string; totalParts: number; groups: string[]; firstMessageId: string; poster: string }[]): Verdict {
const sample = explored(releaseKey, this.rules.samplePercent)
if (this.posters.length > 0 && files.length > 0) {
const words = posterWords(files[0].poster)
const dropped = this.posters.find((p) => words.includes(p))
if (dropped) return { rule: 'poster', key: dropped, sample }
}
if (this.rules.dropExecutables) {
const content = files.filter((f) => !SIDECAR.test(f.name))
if (content.length > 0 && content.every((f) => EXECUTABLE.test(f.name))) {