Project Architecture

Technical architecture details of FlowPick, including system design, module breakdown, data flow, and key design decisions.

This document is for developers who want to understand FlowPick's internal design in depth, covering system architecture, module responsibilities, data flow, and key design decisions.


System Architecture Overview

FlowPick consists of two main product forms: Browser Extension and Online Tool Website. Both share the core download engine but differ in media detection and network request handling.

┌─────────────────────────────────────────────────────────┐
│                      FlowPick                           │
│                                                         │
│  ┌──────────────────┐    ┌──────────────────────────┐   │
│  │ Browser Extension │    │   Online Tool Website    │   │
│  │                  │    │                          │   │
│  │ · Network request │    │ · M3U8 Downloader       │   │
│  │   monitoring     │    │ · DASH Downloader       │   │
│  │ · Auto media      │    │ · Documentation System  │   │
│  │   detection      │    │ · Homepage              │   │
│  │ · Popup UI       │    │                          │   │
│  │ · Cross-origin    │    │                          │   │
│  │   request ability│    │                          │   │
│  └────────┬─────────┘    └────────────┬─────────────┘   │
│           │                           │                 │
│           └───────────┬───────────────┘                 │
│                       │                                 │
│           ┌───────────▼───────────────┐                 │
│           │     Core Download Engine   │                 │
│           │                           │                 │
│           │ · useStreamMerge.ts       │                 │
│           │ · useFFmpeg.ts            │                 │
│           │ · Segmented download &    │                 │
│           │   concurrency control     │                 │
│           │ · AES-128 decryption      │                 │
│           │ · Streaming file write    │                 │
│           │ · Format conversion       │                 │
│           └───────────────────────────┘                 │
└─────────────────────────────────────────────────────────┘

Positioning of Two Product Forms:

DimensionBrowser ExtensionOnline Tool Website
Target usersDaily high-frequency usersOccasional users, environments where extension cannot be installed
Core advantageAuto-detection, one-click downloadNo installation needed, cross-platform
Technical constraintsManifest V3 limitationsSame-origin policy restrictions
Access methodClick toolbar iconDirectly visit web URL
For detailed feature differences and selection recommendations between extension and online tools, see Online Tools — Comparison with Extension. For extension installation steps, see Installation Guide.

Module Details

Core Download Engine

Download engine consists of two composables located in app/composables/.

useStreamMerge.ts

Responsible for downloading, decrypting, merging, and writing media segments. This is the most core module of the entire system.

Main Responsibilities:

FeatureImplementation
Concurrent segment downloadWorker Pool pattern with shared task counter
Retry mechanismExponential backoff, max 3 retries
AES-128 decryptionWeb Crypto API
Segment concatenationBinary direct concatenation (TS) or FFmpeg remuxing (MP4)
File writingFSA → StreamSaver → Blob three-tier fallback
Progress trackingSliding window speed calculation + ETA estimation
Memory managementSampling estimation + threshold check + strategy selection

Exported Interface:

export interface StreamMergeOptions {
  segments: ArrayBuffer[] | AsyncGenerator<ArrayBuffer>
  totalSegments: number
  filename: string
  outputFormat?: 'mp4' | 'ts'
  onProgress?: (progress: StreamMergeProgress) => void
  signal?: AbortSignal
}

export interface StreamMergeProgress {
  phase: 'downloading' | 'merging'
  percent: number
  downloadedBytes: number
  totalBytes: number
  speed: string
  eta: string
}
For complete technical implementation of download engine (including concurrency control, retry strategy, memory management, write strategy comparison), see Download Engine Architecture. For three-tier write strategy fallback logic, see Download Engine Architecture — Strategy Comparison Summary.

useFFmpeg.ts

Responsible for FFmpeg WASM loading, lifecycle management, and media processing command execution.

Main Responsibilities:

FeatureImplementation
WASM loadingOn-demand loading, supports multithreading/single-thread auto-switching
Multithreading detectionCheck SharedArrayBuffer and crossOriginIsolated
TS → MP4 remuxingffmpeg -i input.ts -c copy output.mp4
Audio/video mergeWrite to virtual FS separately, execute merge command
FMP4 reassemblyHandle DASH initialization segments + media segments
Progress callbackParse time info from FFmpeg output

Exported Interface:

export const useFFmpeg = () => {
  return {
    ffmpeg: Ref<FFmpegType | null>
    loaded: Ref<boolean>
    loading: Ref<boolean>
    error: Ref<string | null>
    load: () => Promise<void>
    mergeToMP4: (options: MergeOptions) => Promise<ArrayBuffer>
    mergeAudioVideo: (options: MergeAudioVideoOptions) => Promise<ArrayBuffer>
    mergeFmp4: (options: MergeFmp4Options) => Promise<ArrayBuffer>
  }
}
For FFmpeg WASM loading flow, multithreading detection, and performance comparison, see Format Conversion — FFmpeg WASM Engine. For SharedArrayBuffer configuration requirements, see Browser Compatibility — Advanced APIs.

Page Modules

M3U8 Downloader (m3u8-downloader.vue)

Handles HLS streaming protocol download page.

Processing Flow:

User inputs URL
    ↓
fetch M3U8 content
    ↓
m3u8-parser parsing
    ↓
┌─ Master Playlist? ──→ Show quality list → User selects
│
└─ Media Playlist? ──→ Extract segment list
    ↓
Check #EXT-X-KEY (encryption info)
    ↓
Download key file (if present)
    ↓
Concurrent segment download + decrypt
    ↓
Merge/remux
    ↓
Write to disk

Key Dependencies:

  • m3u8-parser: Parse M3U8 manifest
  • useStreamMerge: Segment download & merging
  • useFFmpeg: Format conversion
For difference between HLS Master Playlist and Media Playlist, see Video Sniffing — HLS Streams. For how to use M3U8 downloader in online tools, see Online Tools.

DASH Downloader (dash-downloader.vue)

Handles DASH streaming protocol download page.

Processing Flow:

User inputs URL
    ↓
fetch MPD content
    ↓
mpd-parser parsing
    ↓
Check ContentProtection (DRM)
    ↓
Extract AdaptationSet (video/audio)
    ↓
Show stream list → User selects
    ↓
Download initialization segments (if present)
    ↓
Concurrent media segment download + decrypt
    ↓
FMP4 reassembly / A/V merge
    ↓
Write to disk

Key Dependencies:

  • mpd-parser: Parse MPD manifest
  • useStreamMerge: Segment download & merging
  • useFFmpeg: FMP4 reassembly & A/V merging
For DASH stream detection principles and ContentProtection handling, see Video Sniffing — DASH Streams. For DRM protected content limitation description, see Known Limitations — DRM Protected Content.

Documentation System

Built on Nuxt Content v3, documentation stored as Markdown files under content/ directory.

Directory Structure:

content/zh-Hans/
├── 1.docs/                    # Main documentation
│   ├── 1.getting-started/     # Getting Started
│   ├── 2.features/            # Features
│   ├── 3.advanced/            # Advanced Guide
│   ├── 5.troubleshooting/     # Troubleshooting
│   └── 6.developer/           # Developer Documentation
├── 4.changelog/               # Changelog
└── 6.legal/                   # Legal Terms

Navigation System: Each directory's .navigation.yml defines category title and icon. Nuxt Content automatically collects all documents and generates sidebar navigation.

Document Layout: app/layouts/docs.vue provides unified document page layout, including top navigation, sidebar, and content area.

For documentation writing conventions (Frontmatter, content format, multilingual), see Contributing Guide — Documentation Writing Guide.

Data Flow

Complete Download Flow

┌─────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐
│ Get Manifest│ → │Parse Manifest│ → │Download Segments│ → │Merge & Write│
└─────────┘    └──────────┘    └──────────┘    └──────────┘
     │              │               │               │
     ▼              ▼               ▼               ▼
  fetch()      m3u8-parser    Worker Pool     useStreamMerge
                mpd-parser    AES-128 decrypt useFFmpeg
                              fetch() concurrent FSA/SS/Blob

Detailed Description of Each Stage:

StageInputProcessingOutputPossible Failure Reasons
Get ManifestM3U8/MPD URLHTTP GET requestManifest textNetwork error, URL expired, 404
Parse ManifestManifest textm3u8/mpd-parser parsingSegment list + metadataNon-standard format, DRM protection
Download SegmentsSegment URL listWorker Pool concurrent downloadArrayBuffer arrayCORS, rate limiting, token expired
Merge & WriteArrayBuffer arrayConcatenation/remuxing + writeDisk fileInsufficient memory, write permission
For complete data flow of download engine (including error classification and retry mechanism), see Download Engine Architecture — Full Data Flow View. For troubleshooting methods when each stage fails, see Common Issues Troubleshooting.

Write Strategy Selection Flow

Start writing
    │
    ▼
File System Access API available?
    │
    ├── Yes → Use FSA streaming write (optimal)
    │          · 16MB buffer
    │          · Supports any size
    │
    └── No → StreamSaver available?
                │
                ├── Yes → Use StreamSaver streaming write
                │          · Service Worker proxy
                │          · Supports large files
                │
                └── No → Estimate file size
                            │
                            ├── < 1.5GB → Blob mode
                            │             · Load all into memory
                            │             · Trigger browser download
                            │
                            └── > 1.5GB → Reject download
                                           · Prompt to switch browser
For detailed comparison of three-tier write strategies (including applicable scenarios and limitations of each), see Download Engine Architecture — Strategy Comparison Summary. For each browser's support status for FSA API, see Browser Compatibility — Feature Support Matrix.

Key Design Decisions

Why Choose FFmpeg WASM Instead of Server-side Processing?

Decision: All media processing completed client-side in browser.

Reasons:

  • Privacy protection: User files not uploaded to server
  • Zero server cost: No need to maintain transcoding server cluster
  • Instant availability: No need to wait for upload and queuing
  • Offline capability: Theoretically usable offline in PWA mode

Trade-offs:

  • Performance lower than native FFmpeg (~10-20%)
  • First load requires downloading WASM files (~8MB)
  • Subject to browser memory limitations
For performance comparison data between FFmpeg WASM and native version, see Known Limitations — FFmpeg WASM Performance. For complete privacy protection explanation, see Privacy & Security.

Why Use Three-Tier Write Fallback Strategy?

Decision: Priority chain of FSA → StreamSaver → Blob.

Reasons:

  • FSA API is optimal solution but only supported by Chrome/Edge
  • StreamSaver has wider compatibility but depends on Service Worker
  • Blob is fallback solution ensuring all browsers can download

Trade-offs:

  • Need to maintain three sets of write logic
  • Fallback behavior may lead to inconsistent user experience
For detailed implementation of three-tier strategy and fallback trigger conditions, see Download Engine Architecture — File Writing Module. For comparison of write capabilities across browsers, see Browser Compatibility — Feature Fallback Strategies.

Why Does Concurrent Download Use Worker Pool Instead of Pre-segmentation?

Decision: Use shared counter + dynamic task assignment.

Reasons:

  • When segment sizes are uneven, pre-segmentation causes some Workers to idle
  • Shared counter ensures all Workers keep working until task completion
  • Simple implementation without complex load balancing logic
For concurrent control implementation and performance analysis of Worker Pool, see Download Engine Architecture — Relationship Between Concurrency and Performance. For concurrency configuration method, see Configuration Reference.

Why Do Extension and Online Tools Share Core Engine?

Decision: useStreamMerge and useFFmpeg as independent composables, not dependent on extension APIs.

Reasons:

  • Code reuse, avoid maintaining two sets of download logic
  • Online tools can serve as demo and fallback for extension features
  • Easy testing: core logic debuggable in regular web environment
For differences between extension and online tools in CORS handling, see Known Limitations — CORS Cross-origin Restrictions. For feature comparison of two product forms, see Online Tools — Comparison with Extension.

Dependency Graph

m3u8-downloader.vue ──────┐
                          ├──→ useStreamMerge.ts ──→ Web Crypto API
dash-downloader.vue ──────┤         │                    fetch API
                          │         ├──→ useFFmpeg.ts ──→ @ffmpeg/ffmpeg
Extension Popup ──────────┘         │                    @ffmpeg/util
                                    ├──→ File System Access API
                                    ├──→ StreamSaver.js
                                    └──→ Blob API

Documentation ──→ @nuxt/content ──→ Markdown Files
                └──→ @nuxt/ui ──→ Tailwind CSS

Dependency Relationship Explanation:

DependencyTypeDescription
useStreamMerge → useFFmpegOptional dependencyOnly needed for MP4 output or A/V merging
useStreamMerge → Web Crypto APIConditional dependencyOnly needed for AES-128 encrypted streams
useStreamMerge → FSA / StreamSaver / BlobMutually exclusive selectionSelect one write method by priority
Page → useStreamMergeDirect dependencyAll download pages depend on core engine
Documentation → @nuxt/contentFramework dependencyNuxt Content module

Extension Architecture

Structure of extension part (not in this repository):

flowpick-extension/
├── manifest.json           # Manifest V3 configuration
├── background/
│   └── service-worker.js   # Service Worker (network monitoring)
├── popup/
│   ├── popup.html          # Popup window
│   ├── popup.js            # Popup window logic
│   └── popup.css           # Popup window styles
├── content/
│   └── content.js          # Content script (page injection)
└── assets/
    └── icons/              # Extension icons

Extension monitors network requests via webRequest API, detects media resources, then sends URL list to popup via message passing. Popup reuses online tool's core download logic.

Extension Communication Flow:

Content Script ←→ Background Service Worker ←→ Popup UI
      │                      │                      │
  Page DOM access        Network request monitor  User interaction UI
  Media element detect   M3U8/MPD filtering      Download trigger & manage
For Manifest V3 restrictions on extensions and countermeasures, see Known Limitations — Manifest V3 Restrictions. For extension installation and permission explanation, see Installation Guide.