Motrix Download Manager

repository·main·Indexed 11 days ago

https://github.com/agalwood/motrix

A modern, full-featured download manager supporting HTTP, FTP, BitTorrent, and magnet links. It utilizes a decoupled architecture with a core engine (aria2) and the MDXP (JSON-RPC 2.0) protocol. The ecosystem includes a desktop app, a headless server deployable via Docker, a command-line client (@motrix/cli), and a sandboxed plugin system using QuickJS.

Tokens
36.2K
Snippets
106
Records
153
Agent score
99%

What's inside Motrix

  1. Overview of Motrix and Motrix Turbo

    main

    Motrix is a modern download manager supporting HTTP, FTP, BitTorrent, and Magnet links.

    Motrix Turbo is the v2 version, rebuilt with Electron, React, and TypeScript. It features a decoupled architecture where the download engine is independent of the UI. Communication between the core and external clients (like browser extensions or CLI tools) is handled via the MDXP (Motrix Download eXchange Protocol), which uses JSON-RPC 2.0.

    The core can run in two modes:

    • Desktop App: A GUI application for macOS, Windows, and Linux.
    • Headless Server: A non-GUI version running via Node.js or Docker, providing a Web interface, ideal for NAS or home servers.
  2. How the Motrix Flatpak browser integration works

    main

    The integration uses two separate layers to maintain security boundaries:

    1. motrix-flatpak-native-host (Outside Sandbox): Runs as the browser's Native Messaging host. It manages browser manifests, launches the Motrix Flatpak, and forwards pairing requests.
    2. motrix-native-host-broker (Inside Sandbox): Runs inside the Motrix Flatpak. It handles endpoint resolution, localhost health checks, and obtaining the one-time nonce.

    This separation ensures the companion does not weaken the security boundary established by the broker.

  3. Important considerations for Bridge E2E testing

    main

    When working with the Bridge E2E tests, keep the following technical constraints in mind:

    • CLI Auto-discovery (macOS/Darwin): On macOS, the CLI is hardcoded to look for the Electron bridge at ~/Library/Application Support/Motrix/bridge/endpoint.json. It will not find the Server bridge automatically. For Server testing, you must explicitly pass the endpoint and token via CLI flags: --endpoint http://127.0.0.1:<mdxp-port> --token <localToken>
    • Pairing Approval: There is no headless auto-approve. The tests drive real approval surfaces: the bridge:resolvePair IPC in Electron and the POST /rpc/command/bridge:resolvePair endpoint on the Server.
    • Path Differences: The current CLI uses an HTTP path. Other specs in this directory (like pair-and-submit or revoke) are stubs for a browser-extension WebSocket pairing path that is not yet implemented.
  4. Understand the Motrix Ecosystem and MDXP protocol

    main

    Motrix is designed as a decoupled system where the download core is independent of the UI. Communication between the core and external clients (like browser extensions or CLI tools) happens via MDXP (Motrix Download eXchange Protocol), an open protocol based on JSON-RPC 2.0.

    Key Ecosystem Components:

    • @motrix/mdxp: npm package defining the JSON-RPC 2.0 wire schemas and Zod types for MDXP.
    • @motrix/cli: The official command-line client.
    • Browser Extensions: Chrome and Firefox extensions (Manifest V3) that hand off downloads to the desktop app via native messaging.
    • Plugin SDK: A suite of four npm packages (@motrix/plugin-manifest-schema, @motrix/plugin-api, @motrix/plugin-cli, and create-motrix-plugin) for building sandboxed extensions.
    • Plugin Registry: A public JSON feed at dl.motrix.app/registry/plugins.json used by the in-app marketplace.
  5. Licensing requirements for settings icons

    main

    The PNG files located in the src/renderer/routes/settings/icons/ directory are proprietary assets from Iconly Pro purchased via UI8. They are not covered by the project's MIT license.

    If you fork or redistribute this project, you must either:

    1. Hold your own valid UI8 license for these specific assets.
    2. Replace these icons with assets that you are legally licensed to distribute.

    For the full legal statement, refer to THIRD_PARTY_NOTICES.md in the project root.

  6. Understand the Motrix Architecture

    main

    Motrix Turbo uses a four-layer architecture designed to decouple the UI from the download engine. This structure allows the core to be reused across both Electron desktop apps and Node.js headless servers.

    The Layers:

    1. Renderer: The React-based user interface.
    2. Core: The application logic (independent of the download engine). It manages tasks, settings, plugins, and the bridge. It communicates with the renderer via IPC (window.motrix).
    3. Engine Adapter: An abstraction layer within the Core that interfaces with the download engine.
    4. Aria2: The actual download engine (a maintained fork of aria2).

    Key Design Principles:

    • Shared Core: The same Core logic is used in both Desktop and Headless environments.
    • Capability-based Security: Plugins must request specific host capabilities (like notifications or secret storage) which are implemented differently depending on the environment (Desktop vs. Headless) but exposed via a consistent API.
  7. How Desktop Kit works: Architecture and Design Principles

    main

    Desktop Kit is a desktop interaction component library for Motrix 2.0 that provides virtual scrolling, marquee selection (box selection), and multi-selection capabilities for any data type.

    Architecture

    The library is built on a decoupled three-layer architecture connected by a single "glue" hook:

    1. SelectionEngine: A pure logic Zustand store with zero DOM/React dependencies. It manages the selection state.
    2. VirtualList: A wrapper around @tanstack/react-virtual that handles rendering but remains unaware of selection logic.
    3. MarqueeOverlay: A UI overlay for box selection that only outputs the range of indices selected.
    4. useSelectableList (Glue Hook): The primary integration point that connects the three modules.

    Design Principles

    • Three-layer Decoupling: SelectionEngine is logic-only, VirtualList is rendering-only, and MarqueeOverlay is index-output only.
    • Generic Adaptation: Uses <T> and a getId function to support any data structure.
    • Mathematical Indexing: Uses Math.floor(offset / rowHeight) for box selection instead of DOM queries, ensuring compatibility with virtualization.
    • Fixed Row Height: Requires a fixed row height to ensure $O(1)$ index calculation.
    • $O(1)$ ID Lookup: Maintains an internal Map<id, index> to avoid linear scans during selection/toggling.
  8. Redistribution requirements for Motrix assets

    main

    While the Motrix source code is MIT-licensed, several third-party assets are NOT covered by the MIT license. If you fork, redistribute, or re-package Motrix, you are responsible for ensuring you hold compatible licenses for all listed assets.

    Key non-MIT assets include:

    • Settings page icons (Iconly Pro): Proprietary (UI8 Standard License). You must either hold a valid UI8 license for redistribution or replace these files with open-source alternatives (e.g., CC-BY-4.0 or Apache-2.0).
    • Apple San Francisco tray font: Proprietary (Apple San Francisco Font License). Redistributors must verify their Apple agreement covers distribution.
    • aria2 download engine: Licensed under GPL-2.0-or-later. Redistributors must meet GPL source-code and notice obligations.
    • GeoIP database: Licensed by MaxMind under CC BY-SA 4.0.
  9. Understand Bridge E2E testing constraints and behavior

    main

    When running Bridge E2E tests, be aware of these specific behaviors:

    • CLI Endpoint Discovery: The @motrix/cli is hardcoded to look for the Electron bridge at ~/Library/Application Support/Motrix/bridge/endpoint.json. It cannot automatically find the Node server. When testing the server leg, you must explicitly pass the endpoint and token via CLI flags: --endpoint http://127.0.0.1:<mdxp-port> --token <localToken>.
    • Pairing Approval: Pairing is not automatically approved in headless mode. The Electron tests use IPC (bridge:resolvePair), while the server tests use the operator-gated POST /rpc/command/bridge:resolvePair endpoint.
    • Aria2 Dependency: The tests use a local, throttled, deterministic HTTP fixture for aria2. You can override the binary used via MOTRIX_ARIA2_BIN.
  10. How Motrix Flatpak Browser Integration Works

    main

    Motrix's Flatpak browser integration uses a two-layer architecture to maintain security boundaries:

    1. motrix-flatpak-native-host (Outside Sandbox): Runs as the browser's Native Messaging host on the host machine. It manages the browser manifest, launches the Motrix Flatpak application, and forwards paired requests with frame boundaries.
    2. motrix-native-host-broker (Inside Sandbox): Runs within the Motrix Flatpak sandbox. It handles parsing the Bridge endpoint, performing localhost health checks, and obtaining a one-time nonce.

    Important Security Notes:

    • The companion only registers the official built-in Motrix extension IDs. Custom extension IDs added within the Flatpak app are not synchronized to the host companion and will not be registered.
    • If your browser is also running in a sandbox, you may need a Native Messaging proxy provided by your browser's distribution; installing this companion alone may not be sufficient to bridge the connection.
  11. Install the Motrix Desktop App

    main

    Download the appropriate package for your operating system from motrix.app.

    Platform Recommendations:

    • macOS: Use the Apple Silicon .dmg for M-series chips; use the Intel build for older Macs.
    • Windows: The .exe (NSIS installer) is recommended for most users.
    • Linux: Use .deb (Debian/Ubuntu), .rpm (Fedora/openSUSE), or .AppImage to run without installation.
  12. Quick Start with useSelectableList

    main

    To implement a selectable virtual list, use the useSelectableList hook to coordinate the VirtualList and MarqueeOverlay components. You must provide items, a getId function, and rowHeight.

    import { useSelectableList } from './hooks/use-selectable-list'
    import { VirtualList } from './virtual-list/virtual-list'
    import { MarqueeOverlay } from './marquee-selection/marquee-overlay'
    
    interface Task {
      id: string
      name: string
    }
    
    function TaskList({ tasks }: { tasks: Task[] }) {
      const {
        listRef,
        listProps,
        marqueeProps,
        getRowProps,
        headerCheckbox,
        onKeyDown,
      } = useSelectableList({
        items: tasks,
        getId: (t) => t.id,
        rowHeight: 40,
      })
    
      return (
        <div onKeyDown={onKeyDown} tabIndex={0} style={{ position: 'relative' }}>
          <VirtualList
            ref={listRef}
            {...listProps}
            style={{ height: 500 }}
            renderHeader={() => (
              <div>
                <input
                  type="checkbox"
                  checked={headerCheckbox.checked}
                  ref={(el) => {
                    if (el) el.indeterminate = headerCheckbox.indeterminate
                  }}
                  onChange={headerCheckbox.onChange}
                />
                Name
              </div>
            )}
            renderRow={({ item, index }) => {
              const rp = getRowProps(index)
              return (
                <div
                  style={{ background: rp.selected ? '#dbeafe' : 'transparent' }}
                  onClick={rp.onClick}
                >
                  <input
                    type="checkbox"
                    checked={rp.selected}
                    onChange={() => {}}
                    onClick={(e) => {
                      e.stopPropagation()
                      rp.onCheckboxChange()
                    }}
                  />
                  {item.name}
                </div>
              )
            }}
          />
          <MarqueeOverlay {...marqueeProps} />
        </div>
      )
    }