Summary
Create a FeaturePlayerManager registry manager that provides a unified retry system for all player-interacting features, plus add premium quality detection to playerQuality. Inspired by patterns from yt-force-max.
Motivation
Currently, player-related features use inconsistent patterns:
- No retries:
automaticTheaterMode, playerQuality, playerSpeed, automaticallyDisableAmbientMode — single waitForElement, if it times out, the feature silently fails
- Custom retries:
automaticallyDisableAutoPlay has its own clickToggleUntil loop
- No waitForPlayerLoaded: Only 3 features use it; others may interact with the player before it's ready
- No re-apply on player state change: Settings only re-apply on navigation events, not on player state transitions
Plan
Step 1: FeaturePlayerManager — new registry manager
File: src/features/_registry/featurePlayerManager.ts
Integrated into FeatureRegistry as registry.playerManager, following the existing FeatureManagerBase pattern.
type PlayerTask = () => boolean | Promise<boolean>;
type PlayerRetryConfig = {
maxAttempts?: number; // default: 30
interval?: number; // default: 500ms
overallTimeout?: number; // default: 15000ms
waitForLoaded?: boolean; // default: true
onPlayerStateChange?: boolean; // default: false
pageTypes?: string[]; // default: ["watch", "live"]
};
Methods:
executeWithRetries(featureId, tasks, config?) — Uses MutationObserver to detect player element, optionally calls waitForPlayerLoaded, then polls tasks until all return true or maxAttempts reached
cleanup(featureId?) — Clears active retry loops
hookPlayerStateChange(featureId, callback) — Attaches onStateChange listener
Step 2: Premium Quality (playerQuality feature)
New file: src/utils/player/itagDb.ts
Full itag format database (all entries from yt-force-max):
- H.264, VP9, VP9.2 HDR, AV1 SDR, AV1 HDR, audio formats
- Premium itags: 356, 712, 721, 141, 774, 616
- Exported as typed const with
lookupItag(itag) helper
New config: preferPremium: boolean (default: false) added to settings
Integration: Use getAvailableQualityData() to find paygatedQualityDetails, pass premium format ID to setPlaybackQualityRange
Step 3: Refactored Features
| Feature |
Task |
Config |
| automaticTheaterMode |
Click size button, verify theater attribute |
waitForLoaded: false, interval: 300 |
| playerQuality |
Set quality with premium detection |
waitForLoaded: true, onPlayerStateChange: true |
| automaticallyDisableAutoPlay |
Click toggle until aria-checked=false |
waitForLoaded: true, maxAttempts: 10 |
| automaticallyDisableAmbientMode |
Open settings, toggle ambient |
waitForLoaded: false, maxAttempts: 20 |
| automaticallyMaximizePlayer |
Maximize player |
waitForLoaded: true, overallTimeout: 20000 |
| playerSpeed |
Set playback rate |
waitForLoaded: true |
| defaultToOriginalAudioTrack |
Set audio track |
waitForLoaded: true, maxAttempts: 15 |
| scrollWheelSpeedControl |
Attach scroll listener |
waitForLoaded: false |
| scrollWheelVolumeControl |
Attach scroll listener |
waitForLoaded: false |
Step 4: Wire into registry
FeatureNavigationManager.handleNavigation() calls registry.playerManager.cleanup() to abort stale retries on navigation.
Step 5: Enhance waitForPlayerLoaded
Also check videoElement.readyState >= 2 as fallback. Better live stream support.
Migration Commits
- FeaturePlayerManager + itagDb (new files)
- Refactor automaticTheaterMode (simple test case)
- Refactor playerQuality + premium quality (most complex)
- Refactor remaining 6 player features (mechanical)
- Enhance waitForPlayerLoaded
- Final lint + typecheck
Constraints
- All features remain independently toggleable
- FeaturePlayerManager uses same error handling/perf tracking as other managers
- Type-only: no
interface keyword — all types use type aliases
- Zero changes to non-player features or buttonPlacement/featureMenu utilities
Summary
Create a
FeaturePlayerManagerregistry manager that provides a unified retry system for all player-interacting features, plus add premium quality detection toplayerQuality. Inspired by patterns from yt-force-max.Motivation
Currently, player-related features use inconsistent patterns:
automaticTheaterMode,playerQuality,playerSpeed,automaticallyDisableAmbientMode— singlewaitForElement, if it times out, the feature silently failsautomaticallyDisableAutoPlayhas its ownclickToggleUntilloopPlan
Step 1: FeaturePlayerManager — new registry manager
File:
src/features/_registry/featurePlayerManager.tsIntegrated into
FeatureRegistryasregistry.playerManager, following the existingFeatureManagerBasepattern.Methods:
executeWithRetries(featureId, tasks, config?)— Uses MutationObserver to detect player element, optionally callswaitForPlayerLoaded, then polls tasks until all returntrueor maxAttempts reachedcleanup(featureId?)— Clears active retry loopshookPlayerStateChange(featureId, callback)— AttachesonStateChangelistenerStep 2: Premium Quality (playerQuality feature)
New file:
src/utils/player/itagDb.tsFull itag format database (all entries from yt-force-max):
lookupItag(itag)helperNew config:
preferPremium: boolean(default: false) added to settingsIntegration: Use
getAvailableQualityData()to findpaygatedQualityDetails, pass premium format ID tosetPlaybackQualityRangeStep 3: Refactored Features
Step 4: Wire into registry
FeatureNavigationManager.handleNavigation()callsregistry.playerManager.cleanup()to abort stale retries on navigation.Step 5: Enhance waitForPlayerLoaded
Also check
videoElement.readyState >= 2as fallback. Better live stream support.Migration Commits
Constraints
interfacekeyword — all types usetypealiases