Skip to content

feat: add AI ad detection and harden YouTube blocking - #1

Open
Edmon02 wants to merge 6 commits into
mainfrom
feat/ai-powered-ad-detection
Open

Edmon02 wants to merge 6 commits into
mainfrom
feat/ai-powered-ad-detection

Conversation

@Edmon02

@Edmon02 Edmon02 commented Apr 24, 2026 •

Copy link
Copy Markdown
Owner

Summary

This branch takes AdEclipse from rule-based YouTube and site blocking to an optional LLM-assisted blocker, and it fixes the YouTube playback and scrolling regressions that showed up while ads were being removed.

Six commits on feat/ai-powered-ad-detection, 43 files, +7,775 / −1,224 against main.

AI ad detection

Users can connect their own key for OpenAI, Anthropic, OpenRouter, Groq, or a custom OpenAI-compatible endpoint. The extension classifies page elements from metadata (tag, classes, size) and removes matches above a confidence threshold.

  • src/ml/ai-provider.js — multi-provider client with retries and normalized responses
  • src/ml/ai-detector.js — batching, confidence thresholds, and scan modes (smart, AI-only, AI-assist)
  • src/ml/ai-cache.js — LRU verdict cache with domain-level pattern reuse
  • src/ml/prompt-templates.js — few-shot classification prompts
  • src/content/ai-scanner.js — content-script scanner with fade-out and collapse, including empty parent containers
  • Options UI for provider, model picker (OpenRouter pricing), masked key preview, cache, and connection test
  • Background messages: AI_SCAN_ELEMENTS, AI_GET_CONFIG, AI_TEST_CONNECTION, AI_FETCH_MODELS, AI_GET_USAGE, AI_CLEAR_CACHE

Keys stay in local extension storage. Diagnostics and AI traffic go only to the provider the user chose.

Video pre-roll interception

  • src/content/player-mainworld-patch.js patches JW Player, Video.js, Hls.js, and Shaka in the page world so ad queues are cleared before playback
  • src/content/video-ad-interceptor.js blocks ad requests at fetch / XHR and coordinates player suppression

YouTube playback and scroll fixes

These commits address regressions after ad skip/removal:

  • Keep preview and resume positions instead of resetting currentTime to 0 (realVideoStartTime)
  • Unlock scroll after ad removal when YouTube reapplies overflow: hidden, overlay backdrops, or scrollTo resets
  • Treat wheel, keyboard, and drag scrolling as user input so position restoration does not fight the user
  • Retry video.play() and fall back to the player play button when autoplay is rejected

YouTube hardening

  • Document-start content-script registration, gated by settings
  • MAIN-world payload sanitization in src/content/youtube-mainworld.js
  • Runtime Declarative Net Request session rules from src/background/youtube-session-rules.js, plus extra domains in rules/ad-domains.json
  • Local-only diagnostics in src/background/youtube-diagnostics.js, with export and clear from the options page (YOUTUBE_DIAGNOSTIC_EVENT, GET_YOUTUBE_DIAGNOSTICS, EXPORT_YOUTUBE_DIAGNOSTICS, CLEAR_YOUTUBE_DIAGNOSTICS)
  • Storage defaults backfill the new YouTube and AI settings on existing installs

UI, docs, and tests

  • Options and popup layouts updated for AI settings, YouTube controls, and diagnostics
  • README covers the AI pipeline, YouTube hardening, settings, and project layout
  • New unit tests for the AI provider, cache, detector, scanner, YouTube utils, diagnostics, session rules, and storage

Test plan

  • npx jest --runInBand
  • Load the unpacked extension and confirm options save and reload for provider, model, API key, scan mode, and confidence
  • Test connection and model fetch against one configured provider
  • On a normal site, confirm AI scan removes a known ad slot and collapses the empty parent
  • On YouTube, confirm a pre-roll is skipped, playback resumes at the real position, and the video does not pause after a second or two
  • Scroll the YouTube home and watch pages with wheel, scrollbar, and keyboard; confirm the page does not snap back
  • Export YouTube diagnostics from options and confirm the file stays local; then clear diagnostics
  • Reload with an existing settings blob and confirm new YouTube and AI defaults appear without wiping current settings

Edmon02 and others added 6 commits March 14, 2026 13:29
Fixes three critical issues affecting user experience:

1. **Preview watch time reset (Issue #1)**: When hovering over a video on YouTube
   main page and then clicking to watch, the extension now preserves the preview
   watch time instead of resetting to 0. This is fixed by saving the real video's
   currentTime before the ad takes over (realVideoStartTime).

2. **Resume functionality broken (Issue #2)**: When resuming a partially watched
   video, the ad blocker no longer resets to the beginning. The video now resumes
   from where it was paused, maintaining the user's playback position across
   page reloads or ad interruptions.

3. **Scroll lock after ad removal (Issue #3)**: Fixed scroll locking that occurred
   after ad removal. Now using setProperty with 'important' flag to forcefully
   unlock overflow and pointer-events, and added continuous monitoring in the
   safety poll to prevent YouTube from re-locking scrolling.

Technical changes:
- Add realVideoStartTime state variable to track video position before ads
- Restore video.currentTime to realVideoStartTime instead of getUrlStartTime()
- Use setProperty('overflow', 'auto', 'important') instead of removeProperty
- Add proactive scroll unlock in safety poll every 500ms
- Remove overly aggressive time-reset logic that assumed all times >2s were wrong

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolved persistent scroll snapping issue where scrolling would snap back
to previous position. The problem was that YouTube continuously re-applies
overflow:hidden and the previous 500ms polling was too slow to catch it.

Improvements implemented:

1. **Real-time MutationObserver on html/body**: Instead of polling every 500ms,
   now watches for any style attribute changes on html and body elements.
   Immediately forces overflow to 'auto' if YouTube tries to set it to 'hidden'.

2. **CSS-level scroll lock prevention**: Injected critical CSS rules that force
   all html and body elements to have overflow:auto and pointer-events:auto
   with !important flags. This acts as a safety net against inline styles.

3. **Enhanced modal backdrop removal**:
   - Added visibility:hidden and opacity:0 for extra safety
   - Also watching for modal backdrop children being added in real-time
   - Backdrops are now completely neutered instead of just hidden

4. **Event capture on backdrops**: Added wheel and touchmove event listeners
   that prevent scroll events from being captured by modal backdrops,
   ensuring scroll always reaches the page body.

5. **Max-height/max-width unlock**: Also remove height constraints that
   YouTube might apply to prevent scrolling (100% or 100vh).

6. **Multiple approaches to body unlock**:
   - overflow: 'visible' on body (stronger than 'auto')
   - No max-height/max-width constraints
   - Continuous monitoring prevents re-application

The combination of real-time observation + CSS rules + event interception
ensures YouTube can never lock scrolling again, no matter when or how often
it tries to re-apply the constraints.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… scroll manipulation

Deep analysis revealed the root cause: YouTube actively resets window.scrollY
using JavaScript, not just CSS overflow locking. The previous polling approach
couldn't catch these rapid, repeated scroll position resets.

NEW AGGRESSIVE APPROACH:
=========================

1. **window.scrollTo/scroll Override** (Lines 553-570)
   Intercepts YouTube's scrollTo() calls and blocks attempts to scroll backwards
   (below the user's last valid scroll position). This directly prevents YouTube's
   JavaScript from resetting scroll position.

2. **Scroll Position Monitoring** (Lines 588-610)
   Real-time 100ms monitor that:
   - Tracks lastValidScrollY when user scrolls
   - Detects when YouTube forcibly resets scroll backwards (>100px jump)
   - Immediately restores the correct position via window.scrollTo

3. **User Scroll Detection** (Lines 613-622)
   Differentiates between user-initiated scrolls and YouTube's automatic resets
   by tracking scroll events. Only user scrolls update the "valid" position.

4. **Enhanced CSS Injection** (Lines 503-538)
   Much more comprehensive CSS rules:
   - overflow-y: scroll for explicit scrollbar
   - scroll-behavior: smooth for better UX
   - height: auto to prevent height constraints
   - ytd-rich-grid-renderer for feed scrolling
   - position: static to prevent fixed positioning issues

5. **CSS-level Scroll Rules** (Lines 652-663)
   Added dynamic stylesheet that catches any element trying to set overflow:hidden
   and immediately overrides it with overflow:visible.

6. **Style Attribute Monitoring** (Lines 625-650)
   200ms interval checking for height/overflow/pointer-events changes
   and forcing them back to scrollable state.

7. **Backdrop Killer** (Lines 666-676)
   150ms interval specifically targeting tp-yt-iron-overlay-backdrop
   to ensure backdrops never interfere with scrolling.

MULTIPLE LAYERS ENSURE SUCCESS:
- Layer 1: CSS (first line of defense)
- Layer 2: window.scrollTo override (blocks YouTube at source)
- Layer 3: Position monitoring (detects and corrects resets)
- Layer 4: Style monitoring (prevents CSS re-application)
- Layer 5: Backdrop removal (removes UI obstacles)

The combination of scroll interception + position monitoring + CSS rules
ensures YouTube can NEVER reset scroll position again.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two new issues were found and fixed:

1. VIDEO PAUSING AFTER 1-2 SECONDS (Issue #4)
   Root cause: video.play() promise was failing silently due to autoplay
   restrictions or timing issues, causing videos to pause after briefly playing.

   Fix implemented:
   - Handle play() promise properly instead of silently catching errors
   - When autoplay fails, attempt to click the play button as fallback
   - Multiple play attempts at 50ms, 150ms, 400ms, 1000ms intervals
   - Increased from 3 attempts to 4 attempts with better timing
   - Applied to both endAdLoop() and attachVideoSafety()

2. MOUSE WHEEL SCROLLING NOT WORKING (Issue #5)
   Root cause: Wheel events were not being properly captured and tracked,
   and the scroll position monitoring wasn't accounting for wheel-based scrolls.

   Fix implemented:
   - Add explicit wheel event listener with proper tracking
   - Track wheel events just like scroll events to update isUserScrolling flag
   - Removed scroll event prevention - only position monitoring prevents resets
   - Added scroll listeners on document, window, AND body for all scroll methods
   - Allow wheel events to scroll naturally while monitoring handles reset blocking

Changes:
1. Enhanced autoplay logic with proper promise handling
   - Check if video.play() returns a promise
   - On rejection, find and click play button as fallback
   - Multiple staggered attempts ensure video starts

2. Fixed wheel scrolling support
   - Wheel events now properly tracked for user scroll detection
   - Position monitoring handles YouTube resets, not event blocking
   - Added explicit scroll listeners on body element
   - wheel events are captured and tracked but not prevented

Result:
- Videos now play reliably after ad removal without pausing
- Mouse wheel scrolling works while position resets are still blocked
- All scroll methods (wheel, click+drag, keyboard) work properly

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduce a comprehensive AI ad detection system that leverages user-provided
LLM API keys (OpenAI, Anthropic, OpenRouter, Groq, or custom endpoints) to
intelligently classify and remove advertisements across all websites.

Core additions:
- Multi-provider LLM client with retry logic and response normalization
- LRU verdict cache with domain-level pattern learning
- Prompt engineering with few-shot examples for ad classification
- AI detection orchestrator with batching and confidence thresholds
- Content-side element scanner with smooth fade-out/collapse animations
- Recursive empty-space elimination for parent containers
- Video pre-roll ad interception via main-world player patching
  (JWPlayer, Video.js, Hls.js, Shaka Player)
- Network-level fetch/XHR interception to block ad requests
- Searchable model picker with live OpenRouter pricing
- Masked API key preview for security
- Full options UI section for AI configuration
- 62 unit tests covering provider, cache, detector, and scanner modules

Updated README with AI feature documentation, changelog, and project structure.

Made-with: Cursor
@Edmon02 Edmon02 changed the title feat: AI-Powered Ad Detection with LLM API Integration feat: expand AI ad detection and harden YouTube blocking May 5, 2026
@Edmon02 Edmon02 added the enhancement New feature or request label Oct 19, 2026
@Edmon02 Edmon02 self-assigned this Oct 19, 2026
@Edmon02 Edmon02 added bug Something isn't working documentation Improvements or additions to documentation labels Oct 19, 2026
@Edmon02 Edmon02 changed the title feat: expand AI ad detection and harden YouTube blocking feat: add AI ad detection and harden YouTube blocking Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant