Brazen Framework - Framework

Main class of the Brazen framework

This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.sleazyfork.org/scripts/416105/1901976/Brazen%20Framework%20-%20Framework.js

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

Author
brazenvoid
Version
14.1.0
Created
2020-11-14
Updated
2026-08-14
Size
214 KB
License
GPL-3.0-only

Brazen Framework — Core (developer guide)

Extend BrazenFramework to build a site userscript. The core owns init order, compliance hiding, filter registration, download queueing, and shared constants. Tiles, hooks, and UI are native HTMLElement (no jQuery on the active stack).

Greasy Fork: Framework core · Changelog: append sections from BrazenFramework.changelog.md when publishing.

Sibling modules: UtilitiesView LayerIndexedDB StorageConfiguration Manager → optional Tag Query Engine (includes Gelbooru-family adapter class) → optional Paginator / Subscriptions Loaderthis script (includes Item Attributes Resolver) → optional Download Manager → your app.


When to use / when not to use

  • Use this module when you are building an app script in the Brazen ecosystem. Your app should extend BrazenFramework and let it own boot order, settings plumbing, UI embedding, and the compliance (filtering/hiding) pipeline.
  • Don’t re-implement configuration, UI shell, or DOM observation in apps unless the site forces it. Prefer plugging into hooks and helpers documented below.

Quick start (minimal app skeleton)

This is the smallest “shape” of a Brazen app: define config in the constructor, then call init() at document-end.

class MyApp extends BrazenFramework {
  constructor() {
    super({
      scriptPrefix: 'myapp-',
      itemListSelectors: ['#results'],
      itemSelectors: '.thumb',
      itemNameSelector: '.title',
      itemLinkSelector: 'a',
      itemDeepAnalysisSelector: '#content',
      tagSelectorGenerator: null,
      requestDelay: 0,
    })

    // Define your settings schema here (constructor only).
    // Then use hooks below to register filters and build UI.
  }
}

new MyApp().init()

Constructor config

Pass one object to super({ ... }):

Key Default Purpose
scriptPrefix (required) localStorage + default ledger key prefix
itemListSelectors (required) List container(s) observed for new tiles
itemSelectors (required) Tile selector inside each list
itemNameSelector (required) Title node; '' disables built-in name attribute
itemLinkSelector '' Link for Item Attributes Resolver deep fetch
itemDeepAnalysisSelector '' Detail-page root selector for deep attrs
itemSelectionMethod 'find' 'find' or 'children' — tile collection in lists
itemWrapperResolver (item) => item Wrapper for show/hide and CSS classes
tagSelectorGenerator null (tag) => selector for tag rules/highlights
isUserLoggedIn false Gates subscription loader
requestDelay 0 ms throttle between deep attribute fetches
downloadsDelay (removed v12) Use downloadInitiationGapMs in Download Manager config
doItemCompliance undefined () => boolean — skip all compliance when falsy
trackComplianceRules false Per-rule hide diagnostics modal
downloadDuplicateLedger undefined Optional duplicate skip (see below)

Framework auto-registers config flags: Disable All Filters. Apps with UI enabled must call configureDock() (and implement composeDockRail) before UI embed.


Features

Building an app (the framework mental model)

What it does: The framework provides a stable, repeatable app structure:

  • A predictable init() lifecycle with “safe points” for page wiring and config-driven behavior
  • A compliance pipeline that (a) resolves tile attributes, (b) runs filters, (c) shows/hides items, and (d) updates statistics
  • A button dock (required when UI is enabled) plus a shared settings panel (#bv-ui) you populate with config fields and custom widgets

The big rule: define configuration fields in the constructor only; do page detection, UI mounting, and filter registration in lifecycle hooks.


Module constants (keys you’ll reference in apps)

CSS classes

Constant Value
CLASS_COMPLIANT_ITEM brazen-compliant-item
CLASS_NON_COMPLIANT_ITEM brazen-noncompliant-item

Paginator config keys

| Constant | Key (stable) | Title (UI label) | |----------|--------------| | CONFIG_PAGINATOR_THRESHOLD | pagination-threshold | Pagination Threshold | | CONFIG_PAGINATOR_LIMIT | pagination-limit | Pagination Limit |

Preset filter keys

| Constant | Key (stable) | Title (UI label) | |----------|--------------| | FILTER_DURATION_RANGE | duration | Duration | | FILTER_PERCENTAGE_RATING_RANGE | rating | Rating | | FILTER_UNRATED | unrated | Unrated | | FILTER_TAG_BLACKLIST | tag-blacklist | Tag Blacklist | | FILTER_TEXT_BLACKLIST | blacklist | Blacklist | | FILTER_TEXT_SEARCH | search | Search | | FILTER_TEXT_SANITIZATION | text-sanitization-rules | Text Sanitization Rules | | FILTER_TEXT_WHITELIST | whitelist | Whitelist | | FILTER_SUBSCRIBED_VIDEOS | hide-subscribed-videos | Hide Subscribed Videos |

Option flags

| Constant | Key (stable) | Title (UI label) | |----------|--------------| | OPTION_DISABLE_COMPLIANCE_VALIDATION | disable-all-filters | Disable All Filters | | OPTION_ENABLE_TEXT_BLACKLIST | enable-text-blacklist | Enable Text Blacklist | | OPTION_ENABLE_TAG_BLACKLIST | enable-tag-blacklist | Enable Tag Blacklist | | OPTION_ENABLE_DOWNLOAD_DUPLICATE_LEDGER | skip-duplicate-downloads | Skip Duplicate Downloads | | OPTION_HIDE_DOWNLOADED_MEDIA | hide-downloaded-media | Hide Downloaded Media |

Item attributes

Constant Normalized key
ITEM_NAME name
ITEM_PROCESSED_ONCE processed_once

Other

Constant Role
STORE_SUBSCRIPTIONS account-subscriptions — Account Subscriptions text field
ICON_RECYCLE &#x267B recycle symbol
OPTION_ENABLE_DOWNLOAD_DUPLICATE_LEDGER_HELP Default ledger tooltip
OPTION_HIDE_DOWNLOADED_MEDIA_HELP Default hide-downloaded tooltip
DOWNLOAD_DUPLICATE_LEDGER_CONFLICT_ACTION 'overwrite' (legacy constant; Download Manager always overwrites)

Lifecycle and init() (where to put your code)

init() runs a three-phase boot pipeline. When the local IndexedDB schema is newer than this script supports (typically after downgrading), getPendingMigrationPlan() drives a schema-too-new panel first (upgrade instructions plus Retry / Reset database). When local IndexedDB migration work is pending, getPendingMigrationPlan() drives a migration consent panel first (planned steps plus Start update / Reset database). After the user starts (or when consent is skipped — healthy boot, peer-wait-only, pending wipe, _disableUI, and not schema-too-new), onMigrationProgress shows the migration slide panel (#bv-migration-panel: group label, detail, progress bar, elapsed timer) during safety backup, setup, backfill, or ruleset migration. On failure, the panel shows downgrade/restore steps plus Retry / Reset database. showDockMigrationStatus / hideDockMigrationStatus are deprecated wrappers around the panel.

Phase 0 (always): detect active pages + resolve layout-aware selectors
Phase 1 (always): run addPageOperation handlers for active pages; halt skips Phase 2
Phase 2 (gated):  full init when (init-set page active OR no pages defined) AND _onValidateInit()

When the subclass defines no pages, Phase 0/1 are no-ops and the gate is just _onValidateInit() (default () => true) — unmigrated scripts keep working.

_onBeforeFullInit[]          // page-aware UI/event wiring (subclass)
configurationManager.initialize({ onMigrationProgress })  // migration panel when setup/backfill/migrate runs
→ downloadManager.initialize() (if configured; tag-discovery restore deferred)
→ load dock orientation; addAttribute(processedOnce); addAttribute(name) if itemNameSelector set
→ paginator.initialize() (if configured)
→ _onBeforeUIBuild[]
→ build #bv-ui + dock (unless _disableUI); force flag keeps migration panel visible for style review
→ _onAfterUIBuild[]
→ configurationManager.updateInterface()
→ downloadManager.restoreTagDiscoveryPanelIfNeeded() (if configured; after dock exists)
→ _validateCompliance(true) + ChildObserver on lists (when compliance enabled + page allowed)
→ _onAfterInitialization[]

Storage-safety: register all config fields unconditionally in the constructor. Use _forPage / lifecycle hooks for page-specific behaviour only — save() replaces the whole settings blob.

Phase 1 operations (addPageOperation) must be config-independent (reload, redirect). Config-dependent work belongs in _onBeforeUIBuild via _forPage (after config load).


Page detection (named pages + page-scoped operations)

What it does: Lets one script support multiple “pages” (search, details, favorites, etc.) without scattering if (...) checks.

How it works (developer-relevant):

  • Detectors run once at the start of init() (Phase 0).
  • Use addPageOperation(...) for Phase 1 actions that may redirect/reload and optionally halt full init.
  • Use _forPage(...) from Phase 2 hooks to do page-aware setup after config is loaded.

Declare pages in the subclass constructor with definePage / definePages. Detectors run once at the start of init() (Phase 0), not in the constructor — use _onBeforeFullInit or _forPage during Phase 2 for page-aware wiring.

Method Role
definePage(name, detectFn) / definePages({...}) Register named pages
isPage(name) / anyPage(...names) Query cached active pages
getActivePages() / getLayout(name?) Active page names / layout variant
addPageOperation(names, fn) Phase 1 boot handler; return truthy to halt full init
setCompliancePages(names) Compliance runs only on listed pages (hard skip elsewhere)
enableCompliance() / disableCompliance() Runtime compliance switch

Protected linkage: _forPage(names, setup), _gatePage(names, callback), _performOperationOnPage, _performTogglableOperationOnPage.

Selector config values (itemListSelectors, etc.) may be a plain selector, a resolver function, or a {pageOrLayout: selector, default?: selector} map — resolved once in Phase 0.


Hook arrays (extension points you’ll use most)

What it does: You extend the framework by pushing callbacks into hook arrays (and optionally overriding _onItemHide). These hooks are where you register filters, mount UI, and wire site behavior.

Push callbacks in the subclass constructor before init(). Page-aware setup that calls _forPage or isPage must run from _onBeforeFullInit (or later hooks), not from the constructor.

Hook Type When
_onValidateInit single fn Phase 2 gate; default () => true
_onBeforeFullInit [] Start of Phase 2, before config load
_onBeforeUIBuild [] After config load; register filters, styles, config-dependent auto-actions
_onAfterUIBuild [] Patch DOM; set userScript on #bv-ui
_onAfterInitialization [] After first compliance pass
_onFirstHitBeforeCompliance [] Once per tile, before first _complyItem
_onBeforeCompliance [] Every _complyItem, before filters
_onFirstHitAfterCompliance [] Once per tile after first compliance
_onAfterComplianceRun [] After full list pass
_onItemShow [] Item passed filters (default: show + compliant class)
_onItemHide single fn Item failed (default: hide + noncompliant class)

Override _onItemHide / push onto _onItemShow when tiles are nested (e.g. table cells) and the default wrapper hide is insufficient.


Protected members apps commonly use

Member Role
_configurationManager Settings schema
_uiGen BrazenViewLayer
_itemAttributesResolver Per-tile metadata
_userInterface HTMLElement[] appended to settings section
_disableUI Skip panel when true
_paginator Set by _setupPaginator
_subscriptionsLoader Set by _setupSubscriptionLoader
_complianceRules ComplianceRuleRecorder when trackComplianceRules

Item Attributes Resolver (embedded)

BrazenItemAttributesResolver is defined in this script. Framework constructs one from itemLinkSelector, itemDeepAnalysisSelector, and requestDelay. Register extractors via this._itemAttributesResolver or read values with this._get(item, name).

Resolved values live on item.scriptAttributes (names lowercased, spaces → _).

Registration When it runs
addAttribute(name, extractor) During resolveAttributes(item) on first compliance pass
addAsyncAttribute(name, extractor) Not auto-invoked — custom/manual only
addDeepAttribute(name, extractor) Lazy when get() misses and deep attrs exist

Deep flow: throttled fetch of the detail page + DOMParser + querySelector(itemDeepAnalysisSelector); deep extractors receive the matched Element, then onDeepAttributesResolution (framework re-runs compliance).

Built-in framework attributes: ITEM_NAME / name (from itemNameSelector when set), ITEM_PROCESSED_ONCE / processed_once.


Compliance pipeline (filtering/hiding)

The framework hides non-compliant tiles. When trackComplianceRules: true, per-rule hide counts feed the Active Hide Rules dock panel via ComplianceRuleRecorder.

_validateCompliance(firstRun)

  • firstRun: ChildObserver on each itemListSelectors node; paginated list also re-runs paginator on add.
  • Re-run: resets compliance rule counts when trackComplianceRules; re-processes all items.
  • Ends with paginator.run(threshold, limit) and completeResolutionRun().

_complyItemsList(list, fromObserver)

  1. Select tiles (find vs children; observer mode merges added nodes).
  2. Fade to opacity: 0.75.
  3. First hit: sanitize name (if enabled), resolveAttributes, _onFirstHitBeforeCompliance.
  4. _complyItem.
  5. First completion: _onFirstHitAfterCompliance, set processedOnce.
  6. _onAfterComplianceRun (and Active Hide Rules panel refresh when open).

_complyItem(item)

Skips when doItemCompliance falsy or Disable All Filters on.

Otherwise: whitelist gate → _onBeforeCompliance → walk _complianceFilters (validate then comply, short-circuit on first fail) → show/hide → clear opacity.

Comply callbacks may return { complies: boolean, rule?: string } for trackComplianceRules.

Filter registration helpers

Method Role
_addItemBlacklistFilter(help, rows?) Text blacklist + enable flag; whole-word regex optimize
_addItemWhitelistFilter(help) Whitelist gate (not in filter chain — runs in _validateItemWhiteList)
_addItemTextSearchFilter(help?) Substring search on name
_addItemTextSanitizationFilter(help) substitute=word,word rules; mutates title on first pass
_addItemTagBlacklistFilter(attribute, useSelectors, rows?, key?, optionKey?, dockTemplateName?) Tag ruleset + enable flag; default template tagBlacklist; pass a CM template name for other enables (e.g. exploredTags)
_addItemHideDownloadedMediaFilter(getItemDownloadId, optionKey?) Enable flag + hideDownloaded dock template + filter hiding tiles already in the ledger (Hide on + ledger field — Skip Duplicate not required); _isDownloadLedgerIdRecorded after per-page primeHits; claims when Skip or Hide is on
`_addItemDurationRangeFilter(selector\ fn, help?, separator?)`
_addItemPercentageRatingRangeFilter(selector, help?, unratedHelp?) Rating % + hide unrated flag
_addItemTagHighlights(config) CSS highlight rules on tag sections
_addItemTagAttribute(key, deep, saveSelectors, extractTags) Register tag list or selector string
_addSubscriptionsFilter(exclusionsFn, getUsernameFn) Hide subscribed channels
_addItemComplianceFilter(key, action?, validate?) Generic; action derived from field type if string
_addItemComplexComplianceFilter(key, validate, comply) Explicit validate + comply

Master bypass: OPTION_DISABLE_COMPLIANCE_VALIDATION.

Compliance modal: trackComplianceRules: true enables _showComplianceRulesModal(). Override _canRemoveComplianceRule / _removeComplianceRule for removable rule rows. _removeComplianceRule may return a Promise; the panel awaits it before refreshing. Override _getComplianceRuleColor for optional per-rule name colors (does not gate which rules appear).

Config-driven comply (when action is attribute name string)

Field type Comply logic
checkboxes values.includes(attribute)
flag attribute truthy or null passes
radios value === attribute
range Validator.isInRange(attribute, min, max)

Default validate from generateValidationCallback(key).

Operation helpers

Method Role
_performOperation(key, action, validate?) Run action when validate passes
_performComplexOperation(key, validate, action) Alias
_performTogglableOperation(flagKey, key, action, validate?) Gated by flag field value
_performTogglableComplexOperation(flagKey, key, validate, action) Gated complex variant

Per-field ruleset add/remove/toggle is on the config object — see BrazenConfigurationManager ruleset field API (field.addRule, field.removeRule, field.hasRule, field.toggleRule, field.clearRules, field.setRules).


UI composition (how your panel is built)

What it does: Your app sets this._userInterface to an array of HTMLElement nodes. The framework embeds #bv-ui and mounts your nodes into it.

Typical workflow:

  • In the constructor: define fields (Configuration Manager).
  • In _onBeforeUIBuild: register filters and config-dependent operations.
  • In _onAfterUIBuild: patch DOM widgets, wire advanced UI, set userScript pointer on #bv-ui.
let filtersPanel = this._uiGen.createTabPanel('Filters', true)
Utilities.appendChildren(filtersPanel, [
  this._configurationManager.createElement(FILTER_TAG_BLACKLIST),
])
this._userInterface = [
  this._uiGen.createTabsSection(['Filters', 'Downloads'], [
    filtersPanel,
  ]),
  this._uiGen.createBottomSection([
    this._createSettingsFormActions(),
    this._createSettingsBackupRestoreFormActions(),
  ]),
]
Protected helper Returns
_createSettingsFormActions() Apply / Save / Reset
_createSettingsBackupRestoreFormActions() Backup file + restore input
_createPaginationControls() Threshold + limit fields
_createSubscriptionLoaderControls() Load Subscriptions button
createDonateTabPanel(options?) Donate tab panel (Patreon link + icon; thin wrapper over View Layer)
createDownloadsTabPanel(options?) Downloads tab: folder/patterns/substitutions/ignore when registered by Download Manager (no Start in Selection Mode — use Behaviours); wires shared pattern builder on _onAfterUIBuild when patternSections / patternSeparators are passed
createBehavioursTabPanel(options?) Behaviours tab: Framework Auto-Hide Settings Panel (auto-hide-settings-pane, default off) when configureDock() ran; then Download Manager flags (download-selection-mode-default, review-ignored-filename-pins, skip-empty-filename-pins, defer-tag-discovery-unattended) when registered — alphabetical title order
createToolboxTabPanel(options?) Toolbox tab: backup/restore; (when ledger + import config) Download Ledger; Database section at the bottom (Reset Tag Discovery + Clear Database)

Tag discovery maintenance (Toolbox → Database): Reset Tag Discovery clears the discovery gate for every tag (isDiscovered: truenull) without changing types or rulesets — use when you want previously confirmed tags to appear in the discovery panel again. Clear Database wipes the entire IndexedDB store and reloads. Both require confirm; Reset shows chunked progress in the button bar. Programmatic: resetAllTagsDiscovered(onProgress?). Conventions: tagging.spec.md. | configureDownloadLedgerImport(config) | Register pattern sections/separators and filename-pattern key for ledger folder import (required for Import Folder) |

Import Folder detail pane follows maintainer conventions for settings detail-pane forms: inline help below fields (no ⓘ), add-mode select, folder picker last, progress bar with counters, flex primary action (× to close).


Download Manager (queueing, paths, discovery)

Requires @require Download Manager after this module and @grant GM_download on the Download Manager script (and typically the app).

Call configureDownloadManager(config) in the constructor after configureDock(). See the Download Manager developer guide for the full config shape (pages/roles, downloadPaths, tagDiscovery, rateLimitHandlers with reopenLabel / humanInteraction, initiation gaps).

this.configureDock({ orientations: ['right'], scriptName: 'My App' })
this.configureDownloadManager({ /* see Download Manager guide */ })

Framework delegation (thin forwards to BrazenDownloadManager):

Method Role
configureDownloadManager(config) Instantiate manager (requires dock first)
getDownloadManager() Active instance or null
handleMediaCloudflarePage(options?) Phase-1 Cloudflare / challenge page (silence or themed reload pane)
enqueueDownload(context) / dequeueDownload(itemId) / isQueued(itemId) Resolution + download queues
confirmTagDiscoveryMappings() Unblock tag review; promote queue item
skipTagDiscoveryInclusion() Skip discovery — drop item without confirming types
openTagDiscoveryMedia() Open media URL for item under review
toggleDownloadManagerPaused() / clearDownloadQueue() Start/pause download queue; clear download queue only
getDownloadManagerProgress() / getDownloadQueueCount() Dock progress and counter
toggleTagDiscoveryMode() / toggleSelectionMode() / toggleCurrentMediaQueued() Dock mode toggles
isDownloadPageRole(role) / isDashboardPage() / isDownloadManagerEnabled() / isDownloadManagerLeaderTab() / requestDownloadManagerLeadership() Page and leader checks / idle-only leader claim (isDashboardPage = DM dashboard role; no auto-claim)
clearDownloadDuplicateLedger() Wipe ledger via Configuration Manager
importDownloadLedgerIds(ids) Append post ids to the download duplicate ledger
replaceDownloadLedgerIds(ids) Replace the download duplicate ledger with supplied post ids
resetAllTagsDiscovered(onProgress?) Bulk isDiscovered reset (truenull) via Configuration Manager
clearScriptDatabase() Wipe entire IndexedDB (pending-wipe flag + reload)

Current-search bookmarks (dock)

Framework-owned toggle for the current search page. Apps register a dock button and supply site config only — no local add/remove/alert handlers.

Method Role
registerCurrentSearchBookmarkDock(actionKey, options?) Dock action field: click toggles, getState / tooltip from bookmark state; options: fieldKey, getCurrentUrl, getTags, formatLabel, normalizeUrl, include, tooltip strings
registerRemovableTagComplianceFilters(options) { fieldKeys, normalizeRuleLine, getRuleColor? } — Active Hide Rules remove for tag ruleset filters
toggleCurrentSearchBookmark(options?) Idempotent URL-keyed toggle (normalized URL identity; raw URL stored on add; empty tags = silent no-op; no alerts)
isCurrentSearchBookmarked(options?) Whether the current URL is bookmarked (widget lastBookmarks or _bookmarkRows URL match)
toggleTagSearchBookmark(tagName, options) / isTagSearchBookmarked(tagName, options) Single-tag search bookmarks (same optimistic write path; status = widget or _bookmarkRows)

Both toggles share _toggleBookmarkAtUrl (optimistic row mutate + widget render + persist lock). Tag bookmark buttons and the dock bookmark refresh chrome immediately and again after persist settles so stars stay filled after a successful add. Wire pageMatch.onMatchChange to refresh dock button state when the bookmarks panel updates — Framework skips rail compose when the dock is not mounted yet (panel createElement / bookmark hydrate can run before _buildDock).

Path/token helpers (buildDownloadPathFromPatterns, substitution parsing, sanitizePathSegment, …) are on getDownloadManager() — removed from Framework in v12.

Immediate download tip: with removeMediaOnSuccess on pictures, capture the URL then clear src/srcset and detach the node before enqueue so the browser does not also decode a full-res bitmap — important for gallery auto-download RAM usage.

DOM polling: _waitForDomElement(selector, predicate, callback, options?) remains on Framework for elements not ready at document-end (e.g. video <source src>).

Override _handleDownloadFailed, _handleDownloadSucceeded, _handleDuplicateDownloadSkipped for failure/success/duplicate hooks.


Download duplicate ledger (skip duplicates safely)

Optional constructor block. Apps that still need one-time GM→IDB settings/bookmarks import should grant @grant GM_getValue and @grant GM_deleteValue.

downloadDuplicateLedger: {
  getDownloadId: (item) => stableId,
  primaryField: 'ids',
  isValidId: (v) => typeof v === 'string' && v.trim().length > 0,
  enableConfigKey: OPTION_ENABLE_DOWNLOAD_DUPLICATE_LEDGER,
  enableHelpText: OPTION_ENABLE_DOWNLOAD_DUPLICATE_LEDGER_HELP,
  enableDefault: true,
}
Behaviour Detail
Enable flag Skip Duplicate Downloads (default on) — applyDockTemplate('skipDuplicates') at ledger init; apps only pushField it on the rail
Hide Downloaded Media Separate flag (OPTION_HIDE_DOWNLOADED_MEDIA, default off). Hides search tiles whose id is in the ledger via _addItemHideDownloadedMediaFilter; does not require Skip Duplicate to be on. Membership is _isDownloadLedgerIdRecorded against a bounded positive cache primed per page by _primeComplianceCaches / ledger primeHits — not a full in-RAM ledger Set
Active Claims run in Download Manager at download time when Skip or Hide is on; skip re-download only when Skip is on
conflictAction Always 'overwrite' — user pattern filenames must not be uniquified
Persist IndexedDB ledgerEntries via addLedgerField('download-ledger'); included in backup (merge on restore). No entry cap.
UI Dock template + Hide Downloaded Media slide-out (DM setDockSlideOut); Toolbox via createToolboxTabPanel() + configureDownloadLedgerImport() (ledger count sentence + Import Folder detail pane + Clear Ledger); Database section (Reset Tag Discovery + Clear Database)

Never use uniquify. Filenames come from user patterns; GM_download must always overwrite.

Protected helpers: _isDownloadDuplicateLedgerActive(), _shouldClaimDownloadDuplicateLedger(), _getDownloadDuplicateLedgerId(item), _isDownloadLedgerIdRecorded(id), _isDownloadDuplicate(id), _isDownloadDuplicateAsync(id), _claimDownloadDuplicateLedgerSlot(id), _reloadDownloadDuplicateLedgerFromStorage().


Optional modules (Paginator, Subscriptions Loader)

this._setupPaginator(() => condition, { /* PaginatorConfiguration */ })
this._setupSubscriptionLoader()  // then addConfig + mount _createSubscriptionLoaderControls()

See Paginator and Subscriptions Loader developer guides.


Public methods (what your app can call)

Method Role
init() Boot pipeline (see lifecycle)
definePage / definePages Register named pages
isPage / anyPage / getActivePages / getLayout Query active pages
addPageOperation Phase 1 page-scoped boot handler
enableCompliance / disableCompliance / isComplianceEnabled Runtime compliance switch
setCompliancePages Restrict compliance to named pages
isUserLoggedIn() Returns config flag
registerHighlightStyleClass(styleClass) Accumulates highlight CSS classes

Public API reference (index)

This is the “jump table” for the APIs you’ll actually touch in apps:

  • Lifecycle/pages: init, definePage, definePages, isPage, anyPage, getActivePages, getLayout, addPageOperation, setCompliancePages, enableCompliance, disableCompliance, isComplianceEnabled
  • Hooks: _onValidateInit, _onBeforeFullInit[], _onBeforeUIBuild[], _onAfterUIBuild[], _onAfterInitialization[], _onFirstHitBeforeCompliance[], _onBeforeCompliance[], _onFirstHitAfterCompliance[], _onAfterComplianceRun[], _onItemShow[], _onItemHide
  • Filter helpers: _addItemBlacklistFilter, _addItemWhitelistFilter, _addItemTextSearchFilter, _addItemTextSanitizationFilter, _addItemTagBlacklistFilter, _addItemHideDownloadedMediaFilter, _addItemDurationRangeFilter, _addItemPercentageRatingRangeFilter, _addItemTagHighlights, _addItemTagAttribute, _addSubscriptionsFilter, _addItemComplianceFilter, _addItemComplexComplianceFilter
  • Operations: _performOperation, _performComplexOperation, _performTogglableOperation, _performTogglableComplexOperation
  • Downloads: configureDownloadManager, getDownloadManager, handleMediaCloudflarePage, enqueueDownload, dequeueDownload, isQueued, confirmTagDiscoveryMappings, skipTagDiscoveryInclusion, openTagDiscoveryMedia, toggleDownloadManagerPaused, clearDownloadQueue, getDownloadManagerProgress, getDownloadQueueCount, toggleTagDiscoveryMode, toggleSelectionMode, toggleCurrentMediaQueued, isDownloadPageRole, isDashboardPage, isDownloadManagerEnabled, isDownloadManagerLeaderTab, requestDownloadManagerLeadership, clearDownloadDuplicateLedger, importDownloadLedgerIds, replaceDownloadLedgerIds — see Download Manager; _waitForDomElement on Framework
  • Bookmarks / tag chrome: registerCurrentSearchBookmarkDock, registerRemovableTagComplianceFilters, toggleCurrentSearchBookmark, isCurrentSearchBookmarked, toggleTagSearchBookmark, isTagSearchBookmarked, createTagBookmarkActionButton, appendTagAttributeActions, refreshTagActionSurfaces (optional discoveryContainsAnyTag handler gates scoped discovery-panel refresh)
  • Optional wiring: _setupPaginator, _setupSubscriptionLoader
  • Accessors: _get(item, attributeName), _getConfig(configDisplayName)
  • Item attributes (embedded BrazenItemAttributesResolver): addAttribute, addAsyncAttribute, addDeepAttribute, resolveAttributes, get, set, completeResolutionRun via _itemAttributesResolver

Class member ordering

All framework classes use a fixed 10-tier member order (static → fields → constructor → instance methods). When writing app-side subclasses or adding helper classes in your app, keep related helpers grouped within their tier. (The full maintainer table lives in the repository workspace documentation, not in the Greasy Fork paste.)


Protected accessors

this._get(item, attributeName)      // item resolver
this._getConfig(configDisplayName)  // configuration value

Publishing

  1. Bump @version on Greasy Fork and publish framework modules.
  2. Bump dependent apps and @require URLs.
  3. Append changelog to listing descriptions.
  4. Publish framework modules before apps that depend on new APIs.

Integration notes (grants, load order, pitfalls)

  • Grants: this module declares none; the Download Manager module declares GM_download. Apps may also grant GM_download, and GM_getValue/GM_deleteValue for one-time legacy GM→IDB settings/bookmarks import.
  • Load order: this core loads after the other base modules listed at the top of this doc. Your app loads last.
  • Pitfall: define all config fields in the constructor. save() writes a full settings blob, so conditional field registration will cause silent data loss.