Brazen Framework - Framework

Main class of the Brazen framework

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.sleazyfork.org/scripts/416105/1858230/Brazen%20Framework%20-%20Framework.js

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

Advertisement:

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

Advertisement:

作者
brazenvoid
版本
7.4.2
建立日期
2020-11-14
更新日期
2026-06-23
尺寸
64.6 KB
授權條款
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, statistics, and shared constants.

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

Sibling modules: UtilitiesView LayerConfiguration ManagerItem Attributes Resolver → optional Tag Query Engine / Gelbooru Family Search Adapter → optional Paginator / Subscriptions Loaderthis script → your app.


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 undefined Pause between GM_download queue items (ms)
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, Always Show Settings Pane.


Module constants

CSS classes

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

Paginator config keys

Constant Display name
CONFIG_PAGINATOR_THRESHOLD Pagination Threshold
CONFIG_PAGINATOR_LIMIT Pagination Limit

Preset filter keys

Constant Display name
FILTER_DURATION_RANGE Duration
FILTER_PERCENTAGE_RATING_RANGE Rating
FILTER_UNRATED Unrated
FILTER_TAG_BLACKLIST Tag Blacklist
FILTER_TEXT_BLACKLIST Blacklist
FILTER_TEXT_SEARCH Search
FILTER_TEXT_SANITIZATION Text Sanitization Rules
FILTER_TEXT_WHITELIST Whitelist
FILTER_SUBSCRIBED_VIDEOS Hide Subscribed Videos

Option flags

Constant Display name
OPTION_DISABLE_COMPLIANCE_VALIDATION Disable All Filters
OPTION_ENABLE_TEXT_BLACKLIST Enable Text Blacklist
OPTION_ENABLE_TAG_BLACKLIST Enable Tag Blacklist
OPTION_ALWAYS_SHOW_SETTINGS_PANE Always Show Settings Pane
OPTION_ENABLE_DOWNLOAD_DUPLICATE_LEDGER Skip Duplicate Downloads
OPTION_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 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
DEFAULT_DOWNLOAD_DUPLICATE_LEDGER_MAX_ENTRIES 25000
DOWNLOAD_DUPLICATE_LEDGER_CONFLICT_ACTION 'overwrite' when ledger on

Lifecycle and init()

Runs only when _onValidateInit() is truthy (assign a function returning false to skip init on wrong pages).

configurationManager.initialize()
→ addAttribute(processedOnce); addAttribute(name) if itemNameSelector set
→ paginator.initialize() (if configured)
→ _onBeforeUIBuild[]
→ build #bv-ui (unless _disableUI)
→ _onAfterUIBuild[]
→ configurationManager.updateInterface()
→ _validateCompliance(true) + ChildObserver on lists
→ _onAfterInitialization[]

Hook arrays

Push callbacks in the subclass constructor before init().

Hook Type When
_onValidateInit single fn Before any init; return false to abort
_onBeforeUIBuild [] Register filters, styles, auto-download
_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 use

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

Compliance pipeline

The framework hides non-compliant tiles and records statistics (counts = items removed).

_validateCompliance(firstRun)

  • firstRun: ChildObserver on each itemListSelectors node; paginated list also re-runs paginator on add.
  • Re-run: resets statistics (+ compliance rules); 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. statistics.updateUI(), _onAfterComplianceRun.

_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(helpText, rows?) Text blacklist + enable flag; whole-word regex optimize
_addItemWhitelistFilter(helpText) Whitelist gate (not in filter chain — runs in _validateItemWhiteList)
_addItemTextSearchFilter(helpText?) Substring search on name
_addItemTextSanitizationFilter(helpText) substitute=word,word rules; mutates title on first pass
_addItemTagBlacklistFilter(attribute, useSelectors, rows?, help?, key?, optionKey?) Tag ruleset + enable flag
_addItemHideDownloadedMediaFilter(getItemDownloadId, helpText?, optionKey?) Enable flag + filter hiding tiles already in the download ledger; inert unless Skip Duplicate Downloads 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.

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

Tag-blacklist routing helpers

For apps with a primary and a secondary ("temporary"/"explore") tag blacklist, these route active-list data operations so the app keeps only its visuals (sidebar icons, clear buttons, indicator state). Register once with _setTagBlacklistRouting({primaryKey, primaryOptionKey, secondaryKey, secondaryOptionKey, normalizeTagLine, normalizeRuleLine}); the normalizers are app-supplied for site-specific tag canonicalization.

Method Role
_getActiveTagBlacklistFieldKey() Secondary key when its option is on, else primary
_isTagInTagBlacklist(fieldKey, name) Single-token membership in a specific list
_isTagInActiveTagBlacklist(name) Membership in the active list
_toggleTagInActiveTagBlacklist(name) Enable active option if off, add/remove token, save + re-run compliance
_clearTagBlacklistField(fieldKey) Empty a list, save + re-run compliance
_updateRulesetField(field, lines) Generic ruleset updater (translate/sort/optimize + re-render)

UI composition

this._userInterface = [
  this._uiGen.createTabsSection(['Filters', 'Downloads'], [
    this._uiGen.createTabPanel('Filters', true).append([
      this._configurationManager.createElement(FILTER_TAG_BLACKLIST),
      this._uiGen.createStatisticsFormGroup(FILTER_TAG_BLACKLIST),
    ]),
  ]),
  this._uiGen.createBottomSection([
    this._uiGen.createStatisticsTotalsGroup(),
    this._createSettingsFormActions(),
    this._createSettingsBackupRestoreFormActions(),
  ]),
]
Protected helper Returns
_createSettingsFormActions() Apply / Save / Reset
_createSettingsBackupRestoreFormActions() Backup file + restore input
_createPaginationControls() Threshold + limit fields
_createSubscriptionLoaderControls() Load Subscriptions button

Downloads

Requires @grant GM_download on the application script.

this._addDownload(mediaElement, folder, filename, removeMediaOnSuccess?)
  • Serial queue; await Utilities.sleep(downloadsDelay) between tasks.
  • Path: folder truncated to 120 chars; illegal <>:"/\|?*-.
  • Pictures with removeMediaOnSuccess: capture URL, then _removeDownloadMediaElement before enqueue.
  • Why remove the picture? It saves data and memory, not for cosmetics: clearing src/srcset and detaching the node aborts the browser's own full-res fetch (the image is then pulled only once, by GM_download) and frees the decoded bitmap. This lets a workflow open hundreds to thousands of image pages back-to-back (e.g. auto-download across a gallery) without exhausting RAM. Hiding the element instead (display:none) would not help — a hidden <img> still downloads and decodes its bytes.
  • Override _handleDownloadFailed, _handleDuplicateDownloadSkipped.

Nested paths: _buildDownloadPath(folder, name) sanitizes each /-separated segment via _sanitizePathSegment (HTML entity decode + illegal char strip). Apps override _addDownload when token-resolved subfolders need / between segments.

Token filenames: _resolveDownloadPattern(pattern, data, tagGroups, resolverConfig) replaces chip labels using _joinTagsForDownloadPath for tag-type tokens. Pass substitutions map, ignore set, unknownDefault, etc. in resolverConfig.

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


Download duplicate ledger

Optional constructor block; requires @grant GM_getValue and @grant GM_setValue.

downloadDuplicateLedger: {
  getDownloadId: (item) => stableId,
  storageKey: 'myapp-download-registry',
  primaryField: 'ids',
  legacyIdFields: ['legacyIds'],
  maxEntries: 25000,
  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)
Active _claimDownloadDuplicateLedgerSlot in _addDownload before _wrapDownloadTask; skip if duplicate
conflictAction 'overwrite' when ledger on; 'uniquify' when off
Persist Per-id atomic GM_setValue ({storageKey}/e/{id}) for duplicate skip; {primaryField} array is a FIFO index for hide-filter bulk load; pagehide flushes index append
UI createElement(OPTION_ENABLE_DOWNLOAD_DUPLICATE_LEDGER)

Never use uniquify as the primary duplicate strategy when the ledger is enabled.

Protected helpers: _isDownloadDuplicateLedgerActive(), _getDownloadDuplicateLedgerId(item), _isDownloadDuplicate(id), _mergeDownloadDuplicateLedgerFromStorage().


Optional modules

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

See Paginator and Subscriptions Loader developer guides.


Public methods

Method Role
init() Full startup (see lifecycle)
isUserLoggedIn() Returns config flag
registerHighlightStyleClass(styleClass) Accumulates highlight CSS classes

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.