From e418e729d646e195f721bf23119b9554b92ddc3c Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Mon, 22 Jun 2026 15:00:01 -0400 Subject: [PATCH] nip71: add FEATURE_NIP71_INGEST admin toggle (default on) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Foundation for inbound NIP-71 ingest. Adds a single admin switch in the instance config (config/instance-config.js, default true), re-exported through config.js and surfaced as a runtime-overridable flag in constants.js — same pattern as FEATURE_NIP71_MIRROR / ALLOW_NSFW_CONTENT. A deployer flips one constant to disable all inbound ingest if it ever causes problems (spam, low-quality content, performance). The ingest adapter + service (gated on this flag) land in follow-up commits; its behavioral test will assert the service is inert when the flag is off. Co-Authored-By: Claude Opus 4.8 --- config/instance-config.js | 15 +++++++++++++++ js/config.js | 2 ++ js/constants.js | 10 ++++++++++ 3 files changed, 27 insertions(+) diff --git a/config/instance-config.js b/config/instance-config.js index 49e36ea6..6a22e0ef 100644 --- a/config/instance-config.js +++ b/config/instance-config.js @@ -234,6 +234,21 @@ export const DEFAULT_WHITELIST_MODE_ENABLED = true; */ export const ALLOW_NSFW_CONTENT = false; +/** + * Whether the client ingests NIP-71 video events published by *other* Nostr + * apps (kinds 21/22 and addressable 34235/34236) and surfaces them in bitvid's + * feeds. + * + * Defaults to `true` so bitvid discovers videos from the wider Nostr ecosystem + * (Nostube, Flotilla, etc.). bitvid's own outbound mirrors are skipped to avoid + * duplicate listings, and ingested NSFW content still respects + * `ALLOW_NSFW_CONTENT` plus the standard trust/blacklist/mute gating. + * + * Set to `false` to disable all inbound NIP-71 ingest with a single switch if it + * ever causes problems (spam, low-quality content, performance). + */ +export const FEATURE_NIP71_INGEST = true; + /** * Emergency fallback accounts for seeding the moderation graph. * diff --git a/js/config.js b/js/config.js index 4f9e6b98..d4e20286 100644 --- a/js/config.js +++ b/js/config.js @@ -24,6 +24,7 @@ import { ADMIN_WHITELIST_MODE_STORAGE_KEY, DEFAULT_WHITELIST_MODE_ENABLED, ALLOW_NSFW_CONTENT, + FEATURE_NIP71_INGEST, DEFAULT_TRUST_SEED_NPUBS, DEFAULT_BLUR_THRESHOLD, DEFAULT_AUTOPLAY_BLOCK_THRESHOLD, @@ -117,6 +118,7 @@ export const ADMIN_LIST_NAMESPACE = "bitvid:admin"; // Reserved for Nostr lists export const ADMIN_COMMUNITY_BLACKLIST_SOURCES = "community:blacklist:sources"; export const ADMIN_COMMUNITY_BLACKLIST_PREFIX = "community:blacklist"; export { ALLOW_NSFW_CONTENT }; +export { FEATURE_NIP71_INGEST }; export { DEFAULT_TRUST_SEED_NPUBS }; export { DEFAULT_BLUR_THRESHOLD }; export { DEFAULT_AUTOPLAY_BLOCK_THRESHOLD }; diff --git a/js/constants.js b/js/constants.js index f6a9c202..63d2b534 100644 --- a/js/constants.js +++ b/js/constants.js @@ -6,6 +6,7 @@ import { DEFAULT_TRUSTED_SPAM_HIDE_THRESHOLD as CONFIG_DEFAULT_TRUSTED_SPAM_HIDE_THRESHOLD, DEFAULT_PLAYBACK_SOURCE, DEFAULT_PLAYBACK_START_TIMEOUT, + FEATURE_NIP71_INGEST as CONFIG_FEATURE_NIP71_INGEST, IS_DEV_MODE, } from "./config.js"; @@ -185,6 +186,9 @@ const DEFAULT_FLAGS = Object.freeze({ // Opt-in NIP-71 *mirror* (addressable 34235/36) managed per-video from the // My Videos tab. Independent of FEATURE_PUBLISH_NIP71 (legacy 21/22 auto-publish). FEATURE_NIP71_MIRROR: true, + // Inbound ingest of NIP-71 videos published by other Nostr apps. Sourced from + // the admin instance config so a deployer flips it in one place. + FEATURE_NIP71_INGEST: CONFIG_FEATURE_NIP71_INGEST !== false, FEATURE_HASHTAG_PREFERENCES: false, FEATURE_SEARCH_FILTERS: Boolean(IS_DEV_MODE), FEATURE_TRUST_SEEDS: true, // Rollback: disable to drop baseline trust seeds without code changes. @@ -206,6 +210,7 @@ const runtimeFlags = (() => { FEATURE_WATCH_HISTORY_V2: DEFAULT_FLAGS.FEATURE_WATCH_HISTORY_V2, FEATURE_PUBLISH_NIP71: DEFAULT_FLAGS.FEATURE_PUBLISH_NIP71, FEATURE_NIP71_MIRROR: DEFAULT_FLAGS.FEATURE_NIP71_MIRROR, + FEATURE_NIP71_INGEST: DEFAULT_FLAGS.FEATURE_NIP71_INGEST, FEATURE_HASHTAG_PREFERENCES: DEFAULT_FLAGS.FEATURE_HASHTAG_PREFERENCES, FEATURE_SEARCH_FILTERS: DEFAULT_FLAGS.FEATURE_SEARCH_FILTERS, FEATURE_TRUST_SEEDS: DEFAULT_FLAGS.FEATURE_TRUST_SEEDS, @@ -242,6 +247,11 @@ export let FEATURE_NIP71_MIRROR = coerceBoolean( DEFAULT_FLAGS.FEATURE_NIP71_MIRROR ); +export let FEATURE_NIP71_INGEST = coerceBoolean( + runtimeFlags.FEATURE_NIP71_INGEST, + DEFAULT_FLAGS.FEATURE_NIP71_INGEST +); + export let FEATURE_HASHTAG_PREFERENCES = coerceBoolean( runtimeFlags.FEATURE_HASHTAG_PREFERENCES, DEFAULT_FLAGS.FEATURE_HASHTAG_PREFERENCES