Skip to main content

Nami

Deterministic media downloader for Instagram, TikTok, Facebook, and X

CI PyPI Version Python Version Architecture License: MIT

Nami coordinates gallery-dl and yt-dlp through a pure functional planning core and isolated execution shell. Engineered for batch extraction, atomic deduplication, classified retry loops, and headless pipelines.

Platform Matrix · Architecture · Installation · Quickstart · CLI Reference · Configuration · Diagnostics


Architecture

Nami separates pure domain logic from side effects using narrow module seams.

Dual-Engine Routing — Directs photos, stories, and highlights to gallery-dl and routes videos to gallery-dl with automatic extractor fallback to yt-dlp (ADR-0001).

Atomic Containment & Locking — Per-target PID-keyed archive.lock blocks concurrent process contention. Strict safe_target_dir prevents path traversal and drive escapes.

Pure Functional Planning — Planning core converts inputs to deterministic PlanStep sequences without disk or network I/O, enabling offline unit testing in <0.2s.

Universal Invocation — Run interactively via Rich terminal UI or headlessly in CI/CD automation using nami or python -m nami with structured --json stdout.

Data flow

flowchart TD
    subgraph Core ["Pure Domain Core (No Side Effects)"]
        A[Target URLs / Profiles] -->|parse_target| B[targets.py]
        B -->|build_plan| C[planner.py]
    end

    subgraph Shell ["Stateful Imperative Shell"]
        D{NamiService Orchestrator}
        D -->|Lock Archive| E[archive.py]
        D -->|Execute Command| F[process.py]
        F --> G[gallery-dl / yt-dlp]
        F -->|Capture Output| H[failures.py]
        H -->|Evaluate Decision| I[retry.py]
    end

    C --> D
    D --> J[BatchResult: Exit Code & JSON]

Module seams

Module Public interface Encapsulated complexity
targets.py parse_target(), safe_target_dir(), resolve_target_endpoints() URL regex decomposition, host mapping, path traversal prevention, endpoint derivation
planner.py build_plan(DownloadRequest) -> tuple[PlanStep, ...] Side-effect-free step generation, media kind expansion, destination path mapping
archive.py ArchiveLock, discover_archives(), reset_archives() Non-blocking PID-keyed locking, stale lock identification, .bak file generation
process.py SubprocessRunner.run(CommandSpec) -> CommandResult Zero-shell execution (shell=False), credential sanitization, cross-platform process tree termination
failures.py classify_failure(), failure_message() Error stream parsing, diagnostic precedence ranking, typed FailureKind categorization
retry.py RetryPolicy.decide() -> RetryDecision Bounded exponential backoff with deterministic pseudo-random jitter

Platform Support Matrix

Platform Photos & Posts Videos & Reels Stories Highlights Authentication Primary Backend
Instagram Supported Supported Supported Supported Netscape Cookie / Anonymous gallery-dl / yt-dlp (Fallback)
TikTok Limited Supported Browser DB / Netscape Cookie yt-dlp / gallery-dl
Facebook Limited Supported Netscape Cookie / Anonymous gallery-dl / yt-dlp
X (Twitter) Limited Supported Netscape Cookie / Anonymous gallery-dl / yt-dlp

[!NOTE] Unsupported platform/media combinations return structured Outcome.UNSUPPORTED records and exit with status 3.


Installation

Requires Python 3.10 or newer.

# Install from PyPI
python -m pip install nami

# Upgrade existing install
python -m pip install --upgrade nami

Quickstart

Interactive mode

Run nami (or python -m nami if Python Scripts directory is not on system PATH):

nami
╭─ Nami ───────────────────────────────────────────────────────────── v5.0.6 ─╮
│ What do you want to download?                                               │
│                                                                             │
│  1  Photos only                                                             │
│  2  Videos only                                                             │
│  3  Stories only                                                            │
│  4  Highlights only                                                         │
│  5  Photos + Videos                                                         │
│  6  Stories + Highlights                                                    │
│  7  All                                                                     │
│  8  Settings                                                                │
│  0  Exit                                                                    │
│                                                                             │
│  Save: ~/Nami/downloads                                                     │
╰─────────────────────────────────────────────────────────────────────────────╯

CLI batch invocations

# Download direct posts and reels
nami download https://www.instagram.com/p/C_EXAMPLE/ https://x.com/OpenAI/status/1234567890

# Target specific profile media
nami download https://www.instagram.com/natgeo/ --media photos,videos

# Headless batch processing with JSON stdout
nami download --profiles --platform instagram --media all --json

Workspace layout

Nami/
├── downloads/                     # Output directory organized by platform & account
│   ├── instagram/
│   │   └── natgeo/
│   │       ├── Photos/
│   │       │   └── archive.txt    # Deduplication ledger
│   │       ├── Videos/
│   │       │   └── archive.txt
│   │       └── Stories/
│   │           └── archive.txt
│   └── tiktok/
│       └── example_user/
│           └── Videos/
│               └── archive.txt
├── cookies/                       # Netscape-format cookie files
│   ├── instagram_cookies.txt
│   ├── tiktok_cookies.txt
│   ├── facebook_cookies.txt
│   └── x_cookies.txt
└── profiles/                      # Target profile lists
    ├── instagram_profiles.txt
    ├── tiktok_profiles.txt
    ├── facebook_profiles.txt
    └── x_profiles.txt

CLI Reference

nami download

Plan and execute downloads for individual URLs or profile lists.

nami download [URL ...] [OPTIONS]
Flag Type Description
URL ... Positional One or more content or profile URLs
--profiles Flag Batch download all targets listed in profiles_dir
--platform Option Disambiguate platform (instagram, tiktok, facebook, x)
--media Option Comma-separated kinds: photos, videos, stories, highlights, all
--json Flag Output structured JSON result for automated pipelines

nami setup

Initialize directory layout and write configuration.

nami setup [OPTIONS]
Flag Type Description
--root <PATH> Option Target parent directory for the workspace
--cookie-templates Flag Create empty Netscape cookie templates in cookies/
--json Flag Output initialization result as JSON

nami doctor

Run read-only system diagnostic checks without network access.

nami doctor [OPTIONS]
Flag Type Description
--json Flag Output structured health checks and remediation steps in JSON

Example output:

PASS  config: Configuration loaded successfully
PASS  python: Python 3.14.7 (>= 3.10 required)
PASS  dependencies: All required packages are installed
PASS  workspace: Base directory is writable
PASS  browser: Brave is installed and unlocked
PASS  cookies: Netscape cookies valid
PASS  urllib3: Clean namespace (no conflicts)
PASS  archive_locks: No stale locks detected

nami config

Manage persistent settings in ~/.nami/nami_config.json.

nami config show [--json]
nami config get <KEY> [--json]
nami config set <KEY> <VALUE> [--json]
nami config unset <KEY> [--json]
Key Valid Values Description
base_dir Path string Root directory for downloaded media
cookies_dir Path string Directory containing Netscape cookie files
profiles_dir Path string Directory containing *_profiles.txt lists
browser brave, chrome, edge, firefox Browser for automated cookie extraction
user_agent String HTTP User-Agent header passed to child engines
timeout_seconds Integer (> 0) Subprocess execution deadline in seconds

nami archive reset

Manage download tracking records (archive.txt) safely without data loss.

nami archive reset [OPTIONS]
Flag Type Description
--all Flag Target all archives across all platforms
--platform <NAME> Option Filter archives by platform
--target <KEY> Option Filter archives by target account
--media <KIND> Option Filter archives by media kind
--dry-run Flag Preview affected archives without modifying disk
--delete Flag Permanently delete matching archives (default: creates .bak)
--yes Flag Confirm action without interactive prompt
--json Flag Output affected archive paths in JSON

Authentication & Cookies

Netscape cookie files

Save exported cookies into cookies_dir. Nami verifies that files contain genuine 7-column rows before passing them to child engines:

  • instagram_cookies.txt or instagram.com_cookies.txt
  • tiktok_cookies.txt or tiktok.com_cookies.txt
  • facebook_cookies.txt or facebook.com_cookies.txt
  • x_cookies.txt or x.com_cookies.txt

Browser database extraction

For TikTok downloads without a cookie file, Nami extracts session tokens from local browser databases (brave, chrome, edge, firefox).


Failure Taxonomy & Recovery Matrix

failures.py maps subprocess output to deterministic FailureKind categories:

Failure Kind Diagnostic Indicator Recovery Strategy
AUTH HTTP 401, login required 1 anonymous retry if credentials were provided
COOKIE Corrupt or undecryptable cookie file 1 anonymous retry if credentials were provided
RATE_LIMIT HTTP 429, temporary platform throttle Stop immediately without cross-engine churn
NETWORK Connection reset, TLS error, DNS timeout Up to 3 attempts with exponential jittered backoff
EXTRACTOR Route failure, extractor deprecation 1 retry on alternate engine (yt-dlp)
NOT_FOUND HTTP 404, account deleted, private media Stop immediately with Outcome.NO_RESULTS
DEPENDENCY Missing binary or unimportable module Stop immediately
TIMEOUT Subprocess deadline exceeded Up to 3 attempts with exponential backoff
LOCKED Archive lock contention or account challenge Stop immediately

Deterministic Exit Codes

Code Outcome Meaning
0 SUCCESS All operations downloaded or already up to date
1 FAILED Unrecoverable error occurred on one or more operations
2 INVALID Malformed CLI syntax, invalid URL, or corrupted configuration
3 PARTIAL Mixed outcomes, unsupported operations, or doctor warnings
4 NO_RESULTS Extractor completed successfully but found zero downloadable items
130 CANCELLED Execution interrupted via SIGINT (Ctrl+C)

Configuration & Environment Variables

Setting Key Environment Variable Default Description
base_dir NAMI_BASE_DIR ~/Nami/downloads Root directory for downloads
cookies_dir NAMI_COOKIES_DIR ~/Nami/cookies Directory for Netscape cookies
profiles_dir NAMI_PROFILES_DIR ~/Nami/profiles Directory for target profile lists
browser NAMI_BROWSER brave Browser for automated cookie extraction
user_agent NAMI_USER_AGENT Chrome default HTTP User-Agent header
timeout_seconds NAMI_TIMEOUT_SECONDS 1800 Process execution deadline in seconds
NAMI_THEME auto Terminal styling theme (dark, light, auto)
NAMI_SKIP_ENV_CHECK 0 Set to 1 to bypass startup environment checks

Development & Verification

Local environment setup

git clone https://github.com/OpenSelena/nami.git
cd nami
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"

Verification commands

# Run pytest unit test suite
python -m pytest

# Run Ruff linter and code formatter checks
python -m ruff check src tests
python -m ruff format --check src tests

# Verify package build & metadata
python -m build
python -m twine check dist/*

License

Distributed under the MIT License. Developed and maintained by Igect under OpenSelena.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nami-5.0.6.tar.gz (71.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nami-5.0.6-py3-none-any.whl (56.3 kB view details)

Uploaded Python 3

File details

Details for the file nami-5.0.6.tar.gz.

File metadata

  • Download URL: nami-5.0.6.tar.gz
  • Upload date:
  • Size: 71.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for nami-5.0.6.tar.gz
Algorithm Hash digest
SHA256 e7aa7af72c503f2bd8a9bf108764db608d2ba4cb8fac27ea0688be6ca0a99e75
MD5 a815d6a1d8d4fe80ff1c2d5f2d89f1cf
BLAKE2b-256 cac3fb4ed2601087228fa22ba5d63085917d7dd9c2e31df243912aba17137296

See more details on using hashes here.

Provenance

The following attestation bundles were made for nami-5.0.6.tar.gz:

Publisher: publish.yml on OpenSelena/nami

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nami-5.0.6-py3-none-any.whl.

File metadata

  • Download URL: nami-5.0.6-py3-none-any.whl
  • Upload date:
  • Size: 56.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for nami-5.0.6-py3-none-any.whl
Algorithm Hash digest
SHA256 e3cb1288e655a4e4904d160e879f1ee33299e7c4e8e2fc10a36864ff2a139c88
MD5 754c8a970ae19ef44dc15cd926f1b986
BLAKE2b-256 e5de7e7821df36d588f0437532121cc93d0caf7187317a3e4b82aeec405a6b3c

See more details on using hashes here.

Provenance

The following attestation bundles were made for nami-5.0.6-py3-none-any.whl:

Publisher: publish.yml on OpenSelena/nami

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

5.0.6 This release

2 files

5.0.4

2 files

5.0.3

2 files

5.0.2

2 files

5.0.1

2 files

5.0.0

2 files

4.0.0

2 files

3.0.4

2 files

3.0.3

2 files

3.0.2

2 files

3.0.1

2 files

3.0.0

2 files

2.5.2

2 files

2.5.1

2 files

2.5.0

2 files

2.4.1

2 files

2.4.0

2 files

2.3.9

2 files

2.3.8

2 files

2.3.7

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page