Metadata-Version: 2.4
Name: torrdown
Version: 0.1.1
Summary: A single-session libtorrent download CLI with resume, dedup, and batch support.
Author: aryannxroot
License: MIT
License-File: LICENSE
Keywords: bittorrent,cli,downloader,libtorrent,torrent
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications :: File Sharing
Classifier: Topic :: Internet
Requires-Python: <3.14,>=3.9
Requires-Dist: libtorrent<2.1,>=2.0
Requires-Dist: rich>=13
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == 'dev'
Description-Content-Type: text/markdown

# TorrDown

[![PyPI](https://img.shields.io/pypi/v/torrdown)](https://pypi.org/project/torrdown/)

A command-line torrent downloader built on a single shared `libtorrent` session.
It downloads several torrents at once, survives restarts, and installs as a real
`torrdown` command you can run from anywhere.

TorrDown started as a Google Colab notebook (still in the repo as
`legacy_download_gcollab.ipynb`) and grew into a proper, installable CLI.

## Features

- **Single shared libtorrent session** — all torrents run in one session (the way
  libtorrent is meant to be used), not one session per torrent.
- **Concurrent downloads** with a fairness gate — only a bounded number compete
  for metadata/peers at once; the rest queue, so a stuck magnet can't starve the
  others or unfairly burn its own timeout.
- **Magnet links and `.torrent` files**, individually or in batches.
- **Automatic resume** — Ctrl+C, a crash, or a reboot doesn't lose progress;
  downloads pick up where they left off on the next run (libtorrent resume data
  is checkpointed to disk).
- **Info-hash dedup** — the same torrent won't be added twice.
- **Metadata-fetch timeout** — a magnet with no metadata-holding peers is skipped
  after a while instead of hanging forever.
- **Batch mode** — download every magnet in a file; completed/failed entries are
  commented out in place so re-runs don't repeat them.
- **Graceful shutdown** — Ctrl+C saves state cleanly before exiting.
- **Live progress bars** (via `rich`) for every active download.
- **Per-user config** with sensible defaults and clear override precedence.

## Requirements

- **macOS or Linux.** (Windows isn't supported yet.)
- **Python 3.9-3.13** somewhere on the machine. `libtorrent` publishes binary
  wheels only for these versions, so TorrDown caps at `<3.14`. The installer
  finds a compatible interpreter automatically; if you only have 3.14+, it tells
  you how to get a supported one.

## Install

The easiest way, on a machine with Python 3.9-3.13:

```bash
pipx install torrdown        # isolated, puts `torrdown` on your PATH
# or
pip install torrdown
```

That's it — `torrdown` is now a command you can run from anywhere.

### From source

The source repo is currently private. If you have access, you can clone it and
use the bundled installer (creates an isolated venv and symlinks the command):

```bash
git clone https://github.com/aryannxroot/TorrDown.git
cd TorrDown
./install.sh                 # then ./update.sh / ./uninstall.sh to manage it
```

For development:

```bash
python3.13 -m venv torr
source torr/bin/activate
pip install -e ".[dev]"      # editable install + test deps
pytest                       # run the test suite
```

You can also run it without installing via `python -m torrdown`.

### Cutting a release (maintainers)

Bump `__version__` in `torrdown/__init__.py` (it's the single source of truth), then:

```bash
./torr/bin/pip install build twine   # once
rm -rf dist && python -m build       # build sdist + wheel
twine check dist/*                   # validate metadata
twine upload dist/*                  # username __token__, PyPI token as password
```

A published version number can't be reused, so bump before every upload.

## Usage

```bash
torrdown                       # interactive menu (list files / paste magnet / batch)
torrdown add "magnet:?xt=..."  # add a magnet (quote it - the & chars matter)
torrdown add movie.torrent     # add a local .torrent file
torrdown add 1,3               # add local .torrent files by menu index
torrdown batch                 # download every magnet in the configured magnets.txt
torrdown batch links.txt       # ...or from a specific file
torrdown resume                # resume downloads interrupted by a crash/Ctrl+C
torrdown status                # show tracked torrents with progress (ID, %, size)
torrdown remove <id>           # drop a tracked entry by ID (from status) or label
torrdown clear                 # clear completed/failed entries (--all clears everything)
torrdown list                  # list local .torrent files
torrdown init                  # create the config/download/torrents directories
torrdown config                # show resolved config and file locations
```

`status` shows how far each download got; `remove`/`clear` only edit the tracking
records — your downloaded files are never touched. For live speed on an active
download, use `torrdown resume` (it shows the running progress bars).

Downloads and interrupted work resume automatically on the next run.

## Configuration

Defaults (all overridable):

| Setting | Default |
|---|---|
| Download directory | `~/Downloads/torrdown` |
| Torrents directory (`.torrent` files for the menu / `list`) | `~/Downloads/torrdown/torrents` |
| Config / state directory | `~/.config/torrdown` (`%APPDATA%\torrdown` on Windows) |
| Listen port | 6881 |
| Max concurrent (metadata slots) | 3 |
| Metadata fetch timeout | 180s |

Drop `.torrent` files into the torrents directory to have them show up in the
interactive menu and `torrdown list`. Magnet links don't need any folder — just
`torrdown add "magnet:?..."`.

Precedence, highest first: **CLI flags** (`--download-dir`, `--config-dir`) >
**environment** (`TORRDOWN_DOWNLOAD_DIR`, `TORRDOWN_PORT`, ...) >
**`config.json`** (in the config dir) > **built-in defaults**.

Run `torrdown config` to see the resolved values and where the files live.

## How it works

- **`engine.py`** owns one `libtorrent` session and runs a single alert-driven
  loop on the main thread: it adds torrents, watches libtorrent alerts
  (metadata received, finished, error, resume-data saved), and polls each
  torrent's status for the progress bars. Per-torrent status is read one handle
  at a time on purpose — libtorrent's batched `get_torrent_status()` invokes a
  Python callback from an internal worker thread and segfaults in this build.
- **`state.py`** persists a small `state.json` keyed by info-hash, including
  base64-encoded libtorrent resume data, so interrupted torrents resume without
  re-fetching metadata or re-hashing completed pieces. Writes are atomic and a
  corrupt file is set aside rather than silently wiped.
- **`sources.py`** turns a user token (a magnet, a `.torrent` path, or a menu
  index) into a concrete download source. This is the single seam where future
  fetch adapters (e.g. searching a legitimate index) will plug in.
- **`config.py`** resolves paths and tunables across the precedence layers above.
- **`cli.py`** is the argparse front end (the subcommands above) plus the
  interactive menu when run bare.

## Project layout

```
torrdown/            the package
  cli.py             argparse subcommands + interactive menu
  config.py          path + settings resolution
  sources.py         token -> download source (future fetch seam)
  engine.py          the shared-session libtorrent engine
  state.py           resume-state persistence
  magnets.py         batch magnets file read + archive
tests/               pure-logic pytest suite
install.sh           installer (macOS + Linux)
uninstall.sh         uninstaller
update.sh            updater
pyproject.toml       packaging + dependencies
PLAN.md              what we're building
PROGRESS.md          living status tracker
ROADMAP.md           deferred work (auto-fetch, PyPI, perf notes)
```

## Notes & limitations

- **Speed** is bounded by your internet connection and the swarm, not by
  TorrDown — see [ROADMAP.md](ROADMAP.md) for the full performance discussion.
- **Automated fetching** of torrents from external sources isn't built yet;
  when it is, it will target only legitimate sources (Internet Archive, Linux
  distros, Creative Commons). See [ROADMAP.md](ROADMAP.md).
- **Windows** is not supported yet.
