Skip to content

Navigation Menu

Sign in
Sign up

Repository files navigation

DualSub - Dual Language Subtitles for Streaming

DualSub

δΈ­ζ–‡η‰ˆ | Chinese Version

Version Last Commit License Manifest Ask DeepWiki Chrome Web Store

DualSub is a powerful Chrome extension that enhances your streaming experience by displaying dual language subtitles simultaneously. Perfect for language learning, accessibility, or simply enjoying content in multiple languages at once.

πŸ“š Documentation

πŸ“‹ Table of Contents

✨ Highlights

  • Dual subtitles on Netflix and Disney+
  • Multiple translation providers with rate limiting and caching
  • AI Context Analysis (OpenAI, Google Gemini)
  • Flexible layouts, appearance controls, and timing offset
  • Multi-language UI (EN, ES, JA, KO, ZH-CN, ZH-TW)

See details in: features.md, platforms.md, providers.md.

πŸ“¦ Installation & Quick Start

  1. Install from the Chrome Web Store or load unpacked (see installation.md).
  2. Open Netflix or Disney+ and enable subtitles.
  3. Click the DualSub icon β†’ enable dual subtitles and choose target language.
  4. Optional: Configure AI Context (provider, API key, model) in Advanced Settings.

Configuration reference: configuration.md. AI docs: ai-context.md.

Configuration Examples

For Language Learning:

Translation Provider: Microsoft Translate (Free)
Layout: Top/Bottom
Display Order: Original First
Font Size: Large
AI Context: Enabled (OpenAI GPT-5.6 Luna)
Context Types: Cultural, Historical, Linguistic

For Performance:

Request Delay: 100ms
Translation Provider: Google Translate
AI Context: Enabled (Google Gemini Flash)
Context Cache: Enabled

For Advanced Users:

Translation Provider: OpenAI Compatible
AI Context Provider: OpenAI GPT-5.6 Luna
Context Types: All
Rate Limit: 60 requests/minute
Cache TTL: 1 hour
Debug Logging: Enabled

πŸ› οΈ Development Setup

Prerequisites

  • Node.js 24 LTS and npm 11+
  • Google Chrome 116+ with Developer mode enabled
  • Git for version control

Setup Instructions

  1. Clone and Install

    git clone https://github.com/QuellaMC/DualSub.git
    cd DualSub
    npm ci
  2. Development Commands

    # Type-check, lint, and verify formatting
    npm run compile
    npm run lint
    npm run format:check
    # Tests: once, in watch mode, or with the enforced coverage floors
    npm test
    npm run test:watch
    npm run test:coverage
    # Production build, release archive, and archive audit
    npm run build
    npm run zip
    npm run verify:release
  3. Load Extension for Testing

    • Run npm run build (or npm run dev to rebuild on every change)
    • Open chrome://extensions, enable Developer mode, click Load unpacked, and select .output/chrome-mv3
    • Reload the extension after each build

Project Structure

DualSub/
β”œβ”€β”€ src/
β”‚ β”œβ”€β”€ entrypoints/ # Background worker, content scripts, popup, options, side panel
β”‚ β”œβ”€β”€ background/ # Subtitle pipeline, translation, AI context, side panel authority
β”‚ β”œβ”€β”€ content/ # Page bridge, player sessions, renderer, selection, platform adapters
β”‚ β”œβ”€β”€ messaging/ # Cross-context contracts, router, client, sender authentication
β”‚ β”œβ”€β”€ config/ # Settings schema, storage service, migrations
β”‚ β”œβ”€β”€ shared/ # Logger, fetch hardening, provider constants
β”‚ β”œβ”€β”€ ui/ # React popup, options, side panel, shared hooks
β”‚ β”œβ”€β”€ build/ # Manifest golden snapshot and locale parity tests
β”‚ └── test-utils/ # Test helpers
β”œβ”€β”€ public/ # Locale catalogs and icons
β”œβ”€β”€ scripts/ # Release verification
β”œβ”€β”€ docs/ # User documentation (en, zh) and reference material
└── wxt.config.ts # Manifest and build configuration (WXT)

πŸ—οΈ Architecture

DualSub 3 is a TypeScript extension built with WXT, React 19, zod, and Vitest.

Core Architecture

  • One session per video: the content orchestrator keeps exactly one player session for the video on the current route, and every listener, timer, and request of a session ends with one abort signal
  • Page bridge: a declaratively registered main-world script reads subtitle tracks from the platform's own player and talks to the isolated world over a message channel
  • Contract-first messaging: every cross-context message is a zod contract; the router snapshots the payload, authenticates the sender, gates by role, and parses before a typed handler runs
  • Background services: a subtitle pipeline with a CDN allowlist and byte caps, a translation service with per-provider pacing and caching, a fail-closed AI context service, and a side panel authority that keeps the content script the single source of selection truth

Key Components

  • Platform adapters (src/content/platform/): Netflix and Disney+ specifics behind one interface
  • Translation providers (src/background/translation/providers/): one error taxonomy and one pacing seam for every provider
  • Configuration service (src/config/): typed settings schema, strict reads, credentials kept device-local, idempotent migrations
  • Side panel (src/ui/sidepanel/, src/background/sidepanel/): selection sync with two-phase removal

Reference material: audit report, smoke protocol, store review notes.

🀝 Contributing

We welcome contributions! Please follow these guidelines:

Code Standards

  • ESLint + Prettier: Code must pass linting and formatting checks
  • TypeScript strict: no any, exact message contracts, typed settings
  • Testing: All new features require comprehensive tests
  • Documentation: Update relevant documentation for changes

Development Workflow

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Write tests for your changes
  4. Ensure all tests pass (npm test)
  5. Format code (npm run format)
  6. Lint code (npm run lint:fix)
  7. Commit changes (git commit -m 'Add amazing feature')
  8. Push to branch (git push origin feature/amazing-feature)
  9. Open a Pull Request

Adding New Features

New Translation Providers

  1. Add a provider module under src/background/translation/providers/ implementing TranslationProvider
  2. Register it in providers/index.ts and add its id to PROVIDER_IDS in src/shared/providers.ts
  3. Add its options card under src/ui/options/providers/ and its strings to every catalog in public/_locales/
  4. Add tests next to the module

New Streaming Platforms

  1. Add a platform under src/content/platform/ with a descriptor and an adapter
  2. Declare its content scripts in src/entrypoints/
  3. Extend the subtitle policy and parsers in src/background/subtitle/ for its CDN
  4. Update the golden manifest in src/build/manifest.golden.json in a commit that explains the change
  5. Run the smoke protocol on the platform

Code Review Process

  • All submissions require review
  • Tests must pass CI/CD pipeline
  • Documentation must be updated
  • Breaking changes require discussion

πŸ§ͺ Testing

DualSub includes a comprehensive testing framework:

Running Tests

# Run all tests
npm test
# Watch mode for development
npm run test:watch
# Run one directory or file
npm test -- src/config
# Run tests with coverage
npm run test:coverage

Test Structure

  • Unit Tests: Individual component testing
  • Integration Tests: Cross-component functionality
  • Mock Infrastructure: fake-browser for extension APIs, happy-dom for UI
  • Test Utilities: Shared testing helpers and fixtures

Testing Guidelines

  • Coverage: Keep the enforced coverage floors green and add focused regressions for changed behavior
  • Isolation: Tests should not depend on each other
  • Mocking: Use provided mocks for Chrome APIs
  • Assertions: Clear, descriptive test assertions

πŸ“„ License

This project is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License (CC BY-NC-SA 4.0).

CC BY-NC-SA 4.0

License Summary

  • βœ… Share: Copy and redistribute the material
  • βœ… Adapt: Remix, transform, and build upon the material
  • ❌ Commercial Use: Not permitted
  • πŸ“ Attribution: Must give appropriate credit
  • πŸ”„ ShareAlike: Must distribute under same license

For full license terms, see LICENSE file.

πŸ“‹ Changelog

Version 3.0.2 (Current)

  • πŸ› No empty subtitle box over the video between lines

Version 3.0.1

  • πŸ› The side panel keeps a tab's selected words, running analysis, and answer while you visit other tabs and come back

Version 3.0.0

  • πŸ—οΈ Rebuilt from the ground up in TypeScript on WXT, with contract-first messaging and one player session per video
  • 🎬 Netflix player API: subtitle tracks come from the player itself, so DualSub keeps working after Netflix's 2026 player change
  • 🌐 Microsoft Translate moved to Edge's tokenless endpoint after Microsoft retired the free auth endpoint
  • πŸ€– Side panel: clickable words, selection sync, and AI analysis with the failure reason shown in the panel
  • πŸ”’ Credentials never leave the device, provider requests carry no browser cookies, and the AI rate limiter survives worker restarts

Version 2.5.0

  • πŸ€– Unified AI Experience: Integrated AI Context Analysis into the Side Panel for a seamless, persistent workspace.
  • πŸ› Stability Improvements: Fixed desync issues when switching videos or deselecting words in the side panel.
  • ✨ Better UX: Improved word selection ordering to always match sentence structure.

Version 2.4.0

  • πŸŽ‰ Full React Migration: Popup and options pages migrated to React with 100% functional parity
  • ✨ Modern component-based architecture with custom hooks
  • πŸ“¦ Vite build system for optimized production bundles
  • πŸ› Fixed container width consistency and i18n translation keys
  • πŸ“ Comprehensive migration documentation

See CHANGELOG.md for detailed version history.

Version 2.3.2

  • Messaging reliability: Refactored messaging utilities to support both callback- and promise-style chrome.runtime.sendMessage, with wake-up retries for MV3 service worker.
  • Unified resilient message sending across platform adapters (BasePlatformAdapter + Netflix), improving background communication stability and test determinism.
  • AI Context: Provider metrics now correctly reflect success/error; tests updated to tolerate callback/promise messaging; dynamic chrome access prevents stale mocks between tests.
  • Internal refactors and stability improvements.

Version 2.3.1

  • 🧠 Netflix next-episode preload-aware subtitles: buffers subtitle tracks detected before navigation and applies them immediately after SPA route change to the next episode, fixing cases where subtitles did not update on Next Episode.
  • 🧩 Universal improvement: content script now notifies the platform on URL changes, laying the groundwork for cross-platform preload handling.

Version 2.3.0

  • πŸ› οΈ Netflix soft navigation fix: Resolves issue where moving to the next episode (SPA navigation) could continue showing previous episode subtitles. Subtitles now reset and rebind to the new video context.
  • 🎯 Disney+ progress bar update: Adjusted detection to the updated site UI; timing now reads directly from the progress-bar web component’s shadow DOM via aria attributes for accurate sync.

Version 2.2.0

  • 🧩 Modularized documentation with English and Chinese docs under docs/
  • 🧭 AI Context UI/UX refinements (modal, transitions, selection persistence)
  • 🧹 Internal refactors and minor fixes

Version 2.1.0

  • πŸ“ Added vertical position control for precise subtitle placement on screen
  • 🎨 Enhanced appearance customization with new positioning options
  • βš™οΈ Improved user interface with vertical position slider control

Version 2.0.0

  • πŸ€– NEW: AI Context Analysis feature with OpenAI and Google Gemini support
  • 🎯 Interactive subtitle text selection with cultural, historical, and linguistic explanations
  • πŸ”‘ Comprehensive API key management and provider configuration
  • 🧠 Advanced caching and rate limiting for AI context requests

Version 1.4.0

  • ✨ Added Netflix support with official subtitle integration
  • πŸ”„ Implemented multiple selectable translation providers with bounded retries
  • 🌐 Added multi-language UI support (6 languages)
  • βš™οΈ Introduced advanced options page
  • πŸ—οΈ Refactored architecture with Template Method pattern
  • πŸ§ͺ Added comprehensive testing framework
  • πŸ“Š Implemented configurable logging system
  • πŸ”§ Enhanced configuration management

Previous Versions

For detailed version history, see GitHub Releases


πŸ“ž Support & Community


⚠️ Disclaimer: This extension is not officially affiliated with Netflix, Disney+, or any streaming platform. All trademarks belong to their respective owners.

About

Disney+ Dual Subtitles enhances your Disney+ viewing experience by displaying two sets of subtitles simultaneously. This allows you to, for example, view subtitles in their original language alongside a translation in your preferred language. The extension offers customization options for subtitle appearance, timing, and translation preferences.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /