Remove YouTube Suggestions

repository·main·Indexed 20 days ago

https://github.com/lawrencehook/remove-youtube-suggestions

A browser extension for Firefox and Chrome that allows users to hide YouTube recommendations and customize the interface to mitigate the effects of the recommendation algorithm. The project includes the extension source code and the rys-premium-server (v1.0.0), a subscription server providing API endpoints for authentication, license checking, and Stripe billing management.

Tokens
9.3K
Snippets
23
Records
42
Agent score
64%

What's inside RYS

  1. Overview of RYS — Remove YouTube Suggestions

    main
    RYS (Remove YouTube Suggestions) is a browser extension designed to help users take control of their YouTube experience. It allows you to hide recommendations and customize the YouTube interface to avoid the recommendation algorithm's 'rabbit holes'. The extension is free to use, with optional premium features available.
  2. RYS Premium Server File Structure

    main

    Understanding the project layout:

    • src/: Contains the core logic.
      • index.js: The server entry point.
      • config.js: Configuration logic.
      • routes/: Express route definitions.
      • services/: Business logic for Stripe, JWT, and email.
      • storage/: File-based storage implementation.
    • data/: Local data storage.
      • grandfathered.json: List of donor emails.
      • auth-requests/: Directory for pending authentication requests (auto-created).
      • rate-limits/: Directory for rate limit counters (auto-created).
    • tests/: Test suites.
    • package.json: Project dependencies and scripts.
    server/
    ├── src/
    │   ├── index.js        # Entry point
    │   ├── config.js       # Configuration
    │   ├── routes/         # Express routes
    │   ├── services/       # Stripe, JWT, email
    │   └── storage/        # File-based storage
    ├── data/
    │   ├── grandfathered.json   # Donor emails (gitignored)
    │   ├── auth-requests/       # Pending auth (auto-created)
    │   └── rate-limits/         # Rate limit counters (auto-created)
    ├── tests/
    └── package.json
  3. Transition Behavior for License and Tier Changes

    main

    The following table describes how the extension handles different states to ensure user data is preserved even during connectivity or authentication issues:

    TransitionStored preferencesEffective behavior
    Refresh pending or transient errorUnchangedKeep the current view when available; otherwise use a non-destructive fallback
    Confirmed premiumUnchangedReapply all stored preferences
    Confirmed signed-in freeUnchangedApply the allowed slot budget
    Sign-out or session 401UnchangedDisable premium behavior in memory

    Note on Staleness: In the current implementation (Phase 1), tier changes (like sign-out or downgrade) may not propagate instantly to already-open YouTube tabs or options pages. Changes will take effect upon the next page load or context initialization.

  4. Understand the RYS Settings Philosophy: Stored vs. Effective

    main

    The extension distinguishes between stored preferences (what the user has toggled in settings) and effective behavior (what the extension actually does based on the user's current subscription tier).

    • Stored Preferences: These are the user's actual settings saved in browser.storage.local. They should never be overwritten by tier-based logic (e.g., a downgrade should not delete a user's preference for a premium feature).
    • Effective Behavior: This is the in-memory application of settings. If a user is on the free tier, the extension applies a 'slot budget' (e.g., only allowing two premium features to be active) by clamping the settings in memory during the apply/render phase, without modifying the underlying stored data.

    This separation ensures that if a user re-upgrades their subscription, their previous premium choices are immediately restored without needing to re-import settings.

  5. Understand the Settings Reset issue and Root Cause

    main

    Users may experience an intermittent 'reset' where locally stored premium preferences are reverted to defaults. This is caused by a destructive write-back mechanism that occurs when the client's premium tier cannot be verified.

    Root Cause

    Premium tier status is inferred from a locally cached license JWT which expires every 3 days (LICENSE_TOKEN_LIFETIME_DAYS). If the license token expires and the client cannot immediately refresh it (due to the user not opening the options page, network errors, or transient server issues), the system treats the user as being on a free_signed_in tier.

    When this happens, the function enforceSlotBudget(settings, 2) is triggered, which generates a write-back map that persists false for premium settings exceeding the allowed slot budget. This permanently overwrites the user's stored preferences in browser.storage.local.

    Key Failure Scenarios

    • Expired License + No Refresh: The content script only reads the license; it does not renew it. Only the options page performs a refresh via refreshLicense. If a user browses YouTube for >3 days without opening the options page, the expired token triggers the budget enforcement.
    • Options Page Initialization: The options page (src/options/main.js) performs synchronous initialization before the asynchronous refreshLicense(true) can confirm premium status, potentially wiping settings upon opening the page if the token is expired.
    • Transient Renewal Failures: If License.checkLicense() encounters a network error, it returns { isPremium: false, error: true }. The UI does not distinguish this from a confirmed free account and proceeds to call pruneToSlotBudget(), persisting the pruned values.
    • Session Expiry: When a 30-day session token expires (401 error), updatePremiumUI calls disableAllPremiumFeatures(), which persists false for all premium features.
  6. Verify premium feature clamping and preference persistence

    main

    When testing or implementing logic around premium features, ensure that the distinction between 'effective behavior' and 'stored preferences' is maintained.

    Even if a user's premium license has expired or they are in an offline state, the extension should clamp the effective view (the features actually active in the UI/content script) without modifying the stored preference keys in browser.storage.local. This ensures that once a license is renewed, the user's previously selected preferences are still intact.

  7. Planned Background License Renewal Logic

    main

    Future updates will implement a background-owned scheduled path for license renewal to improve continuity.

    Key Implementation Details:

    • Trigger: Uses the alarms permission to trigger a check when the token is near expiry (defined by LICENSE_REFRESH_THRESHOLD_MS, currently 24h).
    • Execution: The background context (Service Worker in Chrome, Background Script in Firefox) will call License.checkLicense().
    • CORS & Permissions: Background fetches use the extension origin, which is permitted by the server's CORS policy. No additional host_permissions are required.
    • Error Handling:
      • Transient/Non-401 errors: Leave existing auth tokens untouched.
      • 401 errors: Explicitly invoke Auth.signOut() and remove auth tokens.
      • Crucially: Neither outcome should ever write to any preference key in storage.
  8. Implementation Guide: Preventing Preference Destruction (Phase 1)

    main

    To fix the bug where tier demotions were overwriting user preferences, the following architectural changes must be implemented to ensure tier enforcement happens only in memory:

    1. Content Script (src/content-script/main.js): Keep enforceSlotBudget(settings, limit) but remove the browser.storage.local.set(writeBack) call. This ensures the budget is enforced in the current session without persisting the demotion to storage.
    2. Options Page (src/options/main.js): Perform the same change: clamp the local settings copy without writing the returned map back to storage.
    3. Slot Pruning (pruneToSlotBudget()): Retain the helper and UI updates, but use updateSetting(id, false, { write: false }) to ensure the change is not persisted.
    4. Feature Disabling (disableAllPremiumFeatures()): Retain the helper and its callers, but use updateSetting(id, false, { write: false }) to prevent storage writes.

    Key Rule: Tier logic should never write to storage. It should only coerce values (e.g., value === true) in memory during the application of settings.

  9. Set up a local development environment

    main

    To develop the extension locally, clone the repository, install the web-ext tool globally, and use the provided dev.sh script to launch the extension in your preferred browser.

    Prerequisites

    • npm installed
    • git installed

    Steps

    1. Clone the repository.
    2. Install web-ext globally via npm.
    3. Run the development script for either Firefox or Chrome.
    git clone https://github.com/lawrencehook/remove-youtube-suggestions.git
    cd remove-youtube-suggestions
    npm install --global web-ext
    
    ./dev.sh firefox     # opens Firefox with the extension loaded
    ./dev.sh chrome      # builds dist/chrome/ — load as unpacked in chrome://extensions
  10. Quick Start for RYS Premium Server

    main

    Follow these steps to set up and run the RYS Premium Server locally:

    1. Install dependencies: Use npm to install required packages.
    2. Configure environment: Copy the example environment file to .env and fill in the necessary values.
    3. Verify installation: Run the test suite to ensure everything is working correctly.
    4. Run the server: Use the development command for local work or the start command for production mode.
    # Install dependencies
    npm install
    
    # Copy env and fill in values
    cp .env.example .env
    
    # Run tests
    npm test
    
    # Start development server
    npm run dev
    
    # Start production server
    npm start