Cross-tab download queue, resolution pipeline, and immediate downloads for Brazen user scripts
Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greasyfork.org/scripts/587126/1877680/Brazen%20Framework%20-%20Download%20Manager.js
Cross-tab batch downloads, page resolution, immediate GM_download orchestration, optional tag discovery review, and human-interaction rate-limit handling. Apps extend BrazenFramework, call configureDownloadManager() after configureDock(), and @require this module after Framework core.
Greasy Fork: Download Manager · Requires: Framework core, IndexedDB Storage (v1.1.0+ download queue stores) · Grant on this module: GM_download
GM_download with no queue, no cross-tab state, and no path tokens — that is rare; most Brazen apps still benefit from ledger + path helpers here.configureDownloadManager() throws if configureDock() was not called first.Load order (after Framework core):
// @require … Brazen Framework - Framework.js
// @require … Brazen Framework - Download Manager.js
In the app constructor (after configureDock):
this.configureDock({ orientations: ['right'], scriptName: 'My App', showBranding: true })
this.configureDownloadManager({
enableConfigKey: 'enable-download-manager',
downloadPaths: {
folderConfigKey: 'download-folder',
filenamePatternConfigKey: 'filename-pattern',
subfolderPatternConfigKey: 'subfolder-pattern',
defaultFolder: 'my-downloads',
getPatternResolver: () => ({
chips, tagTypes, ignore, substitutions, unknownDefault,
}),
extractMediaData: (el) => ({ id, md5, ext }),
extractTagGroups: () => ({ author: [], character: [], general: [] }),
extractTagIncidences: () => ({ 'tag name': 12 }), // optional; discovery panel counts
appendExtension: true,
nameFallback: (data) => data.id || 'media',
},
pages: {
search: {
roles: ['selection'],
itemSelector: 'span.thumb',
resolveItem: (item) => ({ itemId, sourceUrl }),
setItemProgress: (item, progress) => { /* optional tile overlay */ },
},
media: {
roles: ['enqueueMedia', 'immediateDownload'],
defaultDownloadType: 'post',
},
},
downloadTypes: {
post: {
resolveFromSearch: (ctx) => ({ nextUrl: ctx.sourceUrl }),
resolveFromMedia: (doc, ctx) => ({ mediaUrl, tagGroups, downloadId, data }),
},
},
getQueueItemId: (ctx) => ctx.itemId,
resolutionInitiationGapMs: 2000,
downloadInitiationGapMs: 2000,
linkQueues: false, // default; set true when site + CDN share rate limits
})
BrazenDownloadManager.initialize() runs from Framework init() after Configuration Manager setup.
| Key | Role |
|---|---|
enableConfigKey |
Flag field key for Enable Download Manager (auto-registered unless enabled: true) |
enableDefault |
Default for enable flag when auto-registered |
enabled |
When true, skip enable-flag registration and treat manager as always on |
linkQueues |
When true, one serial resolution-first loop; tag discovery and any human-interaction block both pipelines. Default false: concurrent loops; tag discovery pauses resolution only; human-interaction blocks only its humanInteractionContext pipeline. Use true when site and download CDN share rate limits. |
selectionModeDefaultConfigKey |
Optional override for Start in Selection Mode (OPTION_DOWNLOAD_SELECTION_MODE_DEFAULT) |
downloadPaths |
Path/token extraction and pattern resolver (see below) |
pages |
Named page configs with roles (see below) |
downloadTypes |
Per-type resolution handlers (resolveFromSearch, resolveFromMedia, …) |
getQueueItemId |
(context) => string stable queue id |
resolutionInitiationGapMs |
ms between resolution fetches (default 2000) |
downloadInitiationGapMs |
ms between GM_download calls (default 2000; replaces Framework downloadsDelay) |
tagDiscovery |
Optional review panel config (see below) |
rateLimitHandlers |
Per-context rate-limit strategies (see below) |
downloadPaths| Key | Role |
|---|---|
folderConfigKey / filenamePatternConfigKey / subfolderPatternConfigKey |
Configuration Manager keys for folder and patterns |
defaultFolder |
Fallback root folder |
getPatternResolver |
() => { chips, tagTypes, ignore, substitutions, unknownDefault, … } — tag-type tokens use registry attributes when TagRuntime is warmed |
extractMediaData(el) |
Metadata object for pattern chips (id, md5, ext, …) |
extractTagGroups() |
{ typeKey: string[] } tag lists for path tokens |
extractTagIncidences() |
Optional { tagName: count } map for discovery panel incidence meta |
appendExtension |
Append data.ext to filename when set |
nameFallback(data) |
When pattern resolves empty |
Path helpers (buildDownloadPathFromPatterns, buildDownloadPath, sanitizePathSegment, substitution parse/map) live on the manager instance — use getDownloadManager() from the app.
pages and rolesEach pages[pageName] entry:
| Key | Role |
|---|---|
roles |
Capability flags for the active page (see table) |
itemSelector |
Search tiles for selection mode |
resolveItem(item) |
{ itemId, sourceUrl, … } for enqueue |
defaultDownloadType |
Fallback type key for media enqueue |
setItemProgress(item, progress) |
Optional hook for per-tile pipeline UI |
| Role | Enables |
|---|---|
selection |
Selection mode + click-to-enqueue on search tiles |
enqueueMedia |
Media-page add/remove queue toggle |
immediateDownload |
downloadImmediate() on media pages |
tagDiscoveryToggle |
Dock tag-discovery mode button |
Query with isDownloadPageRole('selection') (delegated on Framework).
tagDiscovery (optional)| Key | Role |
|---|---|
discoverAt |
Steps that scan pattern-relevant types, e.g. ['resolution', 'immediate'] |
tagTypes |
Panel grouping: { label, rowClass, color } per type — colors via View Layer applyTagDiscoveryTypeColors |
panel |
Extra options forwarded to renderTagDiscoveryPanelContent (section labels, groupOrder, …) |
actions |
Incidence options for tag-attribute buttons (buildUrl, field keys, CSS, explore gate) — framework owns button chrome |
isTagKnown(tagName) |
Optional override; default checks tag registry |
When discovery is on, unknown tags set resolutionBlocked and open #bv-tag-discovery-panel. With default linkQueues: false, that pauses resolution only (downloads continue). With linkQueues: true, both pipelines pause. Confirm promotes types; Skip drops the item without confirming; Open media opens the source URL. State fields discoveryPanelTags and discoveryPanelKnownTags persist in downloadManagerState.
rateLimitHandlersKeyed by context (resolution, download, …). Each context may define:
| Handler | Role |
|---|---|
humanInteraction |
{ detect(ctx), openUrl?(ctx), confirmTitle?, confirmMessage?, confirmLabel?, reopenLabel? } — opens verification tab (brazen_hi=1 query + hash, rel=opener), sets humanInteractionBlocked + humanInteractionOpenUrl, shows processor-leader panel. Runs before timedReload. |
timedReload |
{ detect(doc, ctx), reloadDelayMs? } — document detect only (not bare HTTP 429) |
reopenLabel defaults to Reopen verification tab on the human-interaction panel. humanInteractionOpenUrl is stored in shared DM state for Reopen.
resolutionInitiationGapMs and downloadInitiationGapMs pace resolution fetches and GM_download respectively (defaults 2000 each; configure independently per app). Both use separate in-tab clocks hydrated from lastResolutionInitiationAt / lastDownloadInitiationAt in shared state so concurrent IDB writes cannot erase the gap. Resolution paces before every fetch attempt (including rate-limit retries). Confirming a human-interaction rate limit stamps only the blocked pipeline's clock so the next initiation waits a full gap without affecting the other queue.
Framework delegates most calls; you can also use this.getDownloadManager() for path helpers.
| Method | Role |
|---|---|
downloadImmediate({ mediaElement, removeMediaOnSuccess?, source? }) |
Immediate download; registers path tags; optional discovery gate |
enqueueDownload(context) |
Add to resolution queue; returns whether added |
dequeueDownload(itemId) |
Remove from either queue |
isQueued(itemId) |
Cross-tab pipeline membership |
toggleDownloadManagerPaused() |
Start/pause download queue only; no-op when download pending is 0 |
clearDownloadQueue() |
Wipe download queue only; clears download-context human-interaction block |
toggleCurrentMediaQueued() |
Media-page enqueue toggle |
toggleSelectionMode() |
Local session selection mode (search) |
| Method | Role |
|---|---|
confirmTagDiscoveryMappings() |
Confirm types; promote resolution item or run pending immediate |
skipTagDiscoveryInclusion() |
Skip review — drop item and clear selection progress; do not confirm types |
openTagDiscoveryMedia() |
Open media URL for item under review |
toggleTagDiscoveryMode() |
Cross-tab discovery enable toggle |
| Method | Role |
|---|---|
getDownloadManagerProgress() |
{ resolution: {current, total}, download: {current, total} } — both always live (dock panel shows while either queue has pending work) |
getDownloadQueueCount() |
Dock counter; excludes resolution queue when discovery mode is on |
getPendingPipelineCount() |
Non-terminal items in both queues |
isDownloadManagerEnabled() |
Enable flag + dock active |
isDownloadPageRole(role) |
Page role gate |
isDownloadManagerLeaderTab() |
This tab owns processingTabId |
isDownloadManagerRunning() |
Pipeline active (queues, blocked state, or in-tab processing) |
| Method | Role |
|---|---|
BrazenDownloadManager.peekHumanInteractionBlockedMirror(scriptPrefix) |
Static. Sync localStorage mirror — usable in Phase-1 page ops before initialize() |
BrazenDownloadManager.peekHumanInteractionBlockedIdb(scriptPrefix) |
Static. Async IndexedDB read of humanInteractionBlocked — Phase-1 fallback when query/hash/mirror/opener were stripped |
BrazenDownloadManager.hasBrazenHumanInteractionMarker() |
Static. Query or hash still has brazen_hi |
BrazenDownloadManager.isQueueOpenedVerificationTab() |
Static. Same-origin opener (queue-opened tab) |
BrazenDownloadManager.shouldSilenceMediaCloudflarePrompt(scriptPrefix, instance?) |
Static. Whether a challenge page should stay silent |
handleMediaCloudflarePage(options?) |
Phase-1 Cloudflare / challenge page: silence queue tabs; standalone shows themed Done — reload pane |
shouldSilenceMediaCloudflarePrompt() |
Instance wrapper around the static silence gate |
isHumanInteractionBlockedSync() |
Instance: IDB state humanInteractionBlocked |
getDownloadManager())| Method | Role |
|---|---|
buildDownloadPathFromPatterns(data, tagGroups) |
Token path assembly |
buildDownloadPath(folder, name) |
Sanitized folder + filename |
sanitizePathSegment(segment) |
Illegal char strip + entity decode |
decodeHtmlEntities(text) |
DOM textarea decode |
parseDownloadTagSubstitutionLines(lines, normalizeToken) |
Substitution parser |
buildDownloadTagSubstitutionMap(rules) |
Map<subject, replacement> |
One leader tab (processingTabId) owns both pipelines. With default linkQueues: false, resolution and download run as concurrent loops on that tab. With linkQueues: true, one serial loop prefers resolution then download.
| Behaviour | Detail |
|---|---|
paused |
Pauses the download queue only. Resolution auto-runs on enqueue. Start/Pause disabled when download queue is empty. When download queue drains to 0 (and, if unlinked, resolution is also idle), paused returns to true. |
resolutionBlocked |
Tag discovery gate. Unlinked: stops resolution only (downloads continue). Linked: stops both pipelines. |
humanInteractionBlocked |
Rate-limit gate. Unlinked: stops only the pipeline in humanInteractionContext (second pipeline yields if it also hits HI until the first clears). Linked: stops both. |
| Leadership | Heartbeat processingHeartbeatAt (~3 s) + sync localStorage mirror. Stale steal ~12 s or immediate after pagehide mirror clear. Steal requeues in-flight resolving / downloading rows (never requeues this tab's active item). |
| Claims | Items move queued → resolving / downloading before work; in-tab active-item guards abort terminal puts after steal or clear. |
| Ledger | Duplicate claim at download time in Download Manager when Skip or Hide is on; ledgerClaimed on download rows prevents double-claim after lock steal. |
| UI cadence | Queue/state puts do not rebuild dock; one UI reset per resolution/download task. Full _syncFromStorage on init, enqueue, Start, tab focus. |
Scans pattern-relevant tag types only. Always registers path tags via _registerResolvedTagGroups (discovery on → seen-only; off → confirm as typeEntryId). Panel lists unknown then known tags with incidence counts; framework maps tag-attribute actions internally. Reload / tab focus restores panel when review pending. Promote / Confirm wake the download processor so Ready rows are not stranded.
Shown only on the processor-leader tab when humanInteractionBlocked. Verification tab stays silent (brazen_hi query + hash, localStorage mirror, preserved window.opener, or peekHumanInteractionBlockedIdb). Done — resume clears block; Reopen uses humanInteractionOpenUrl. Cross-tab enqueue while blocked still writes queued rows; processors resume after confirm. Only one HI panel at a time — a second pipeline that hits verification while the first is open requeues and waits.
| Topic | Detail |
|---|---|
| Grant | @grant GM_download on this module (and typically on the app too) |
| Load order | After Framework core; before app script |
| Dock | Manager registers dock fields (selection, enqueue, start/pause, clear, progress, discovery). Apps pushField enable key on the rail. |
| Ledger | Constructor downloadDuplicateLedger on Framework; claims happen in Download Manager — see Framework developer guide |
| View Layer | Progress slot, item progress overlays, discovery/human-interaction panels — View Layer |
| IndexedDB | downloadResolutionQueue, downloadQueue, downloadManagerState — IndexedDB Storage |
configureDownloadManager, getDownloadManagerdownloadImmediate, enqueueDownload, dequeueDownload, isQueued, toggleDownloadManagerPaused, clearDownloadQueue, toggleSelectionMode, toggleCurrentMediaQueuedconfirmTagDiscoveryMappings, skipTagDiscoveryInclusion, openTagDiscoveryMedia, toggleTagDiscoveryModegetDownloadManagerProgress, getDownloadQueueCount, isDownloadPageRole, isDownloadManagerEnabled, isDownloadManagerLeaderTab, handleMediaCloudflarePage, shouldSilenceMediaCloudflarePrompt, peekHumanInteractionBlockedMirror, peekHumanInteractionBlockedIdb, hasBrazenHumanInteractionMarker, isQueueOpenedVerificationTab, isHumanInteractionBlockedSyncbuildDownloadPathFromPatterns, parseDownloadTagSubstitutionLines, buildDownloadTagSubstitutionMap, buildDownloadPath