Metadata-Version: 2.4
Name: qrtransfer-lite
Version: 0.1.0
Summary: Transfer files over your local network by scanning a QR code
Project-URL: Homepage, https://github.com/rkriad585/qrtransfer
Project-URL: Repository, https://github.com/rkriad585/qrtransfer
Project-URL: Issues, https://github.com/rkriad585/qrtransfer/issues
Project-URL: Documentation, https://rkriad585.github.io/qrtransfer/
Project-URL: Website, https://rkriad585.github.io/
Author: rkriad585
License: MIT
License-File: LICENSE
Keywords: cli,file-sharing,file-transfer,lan,qr,qrcode,wifi
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
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 :: Utilities
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: platformdirs>=3
Requires-Dist: psutil>=5.9
Requires-Dist: qrcode-terminal>=0.8
Provides-Extra: clipboard
Requires-Dist: pyperclip>=1.8; extra == 'clipboard'
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: matplotlib>=3.7; extra == 'dev'
Requires-Dist: pyright>=1.1; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
Requires-Dist: mkdocs>=1.6; extra == 'docs'
Provides-Extra: tls
Requires-Dist: cryptography>=42; extra == 'tls'
Provides-Extra: web
Description-Content-Type: text/markdown

<p align="center">
  <img src="https://raw.githubusercontent.com/rkriad585/qrtransfer/main/logo/logo.svg" alt="QR File Transfer" height="150">
</p>

<h1 align="center">QR File Transfer</h1>

<p align="center"><strong>Share files over your local network by scanning a QR code.</strong></p>

<p align="center">
  <img src="https://img.shields.io/badge/python-3.9%2B-blue" alt="Python 3.9+">
  <img src="https://img.shields.io/github/actions/workflow/status/rkriad585/qrtransfer/ci.yml?branch=main" alt="CI status">
  <img src="https://img.shields.io/badge/license-MIT-green" alt="MIT license">
  <img src="https://img.shields.io/badge/made%20by-rkriad585-ff69b4" alt="Made by rkriad585">
</p>

<!-- TODO: add a PyPI version badge once v0.1.0 is published:
     <img src="https://img.shields.io/pypi/v/qrtransfer-lite.svg" alt="PyPI version"> -->

## Overview

`qrtransfer` serves one or more files, directories, or text snippets over HTTP on
your LAN and prints a scannable QR code in the terminal. Scan it with your phone's
camera and the download starts immediately — no cloud, no accounts, no third-party
uploads. It also works in reverse: `qrtransfer receive` prints a QR code that opens
a page where your phone can upload files straight to your computer.

## Screenshot

<p align="center">
  <img src="https://raw.githubusercontent.com/rkriad585/qrtransfer/main/Screenshots/home.png" alt="home screen" width="80%">
</p>

<p align="center">
  <em>More screenshots:
    <a href="https://github.com/rkriad585/qrtransfer/blob/main/docs/screenshots.md">View all screenshots</a>
  </em>
</p>

## Table of Contents

1. [Key Features](#key-features)
2. [Installation](#installation)
3. [Quick Start](#quick-start)
4. [Usage Examples](#usage-examples)
5. [Documentation](#documentation)
6. [Interface](#interface)
7. [Architecture](#architecture)
8. [Requirements](#requirements)
9. [Prerequisites](#prerequisites)
10. [Development](#development)
11. [Contributing](#contributing)
12. [Security](#security)
13. [License](#license)
14. [Acknowledgments](#acknowledgments)

## Key Features

- **Send anything** — files, whole directories (auto-zipped), or text snippets.
- **Receive mode** — upload files to your computer from your phone via a web page
  with drag-and-drop and multi-file support.
- **Password protection** — via URL param `?passed=SECRET` or the `X-Password`
  header; the QR code embeds the param so scanning still works.
- **Link expiration** — the link dies (`HTTP 410`) after a configurable number of
  seconds.
- **Download counting** — stop after the first download (default), after `N`, or
  keep serving until you stop it.
- **Unguessable URLs** — random tokens from Python's `secrets` module.
- **Self-signed TLS** (`--tls`) and IPv6 support.
- **Persistent settings** — your interface and port are remembered across runs
  (`--force` to ignore).
- **Transfer history** — the last 200 transfers, viewable with `--history`.
- **Streaming uploads** — receive mode parses `multipart/form-data` incrementally,
  sanitizes filenames (no path traversal), and enforces a size cap.
- **No web framework, no database** — stdlib `http.server` plus a few small
  packages (`platformdirs`, `psutil`, `qrcode-terminal`).

## Installation

Requires **Python 3.9 or newer**.

```bash
pip install qrtransfer-lite
```

Optional extras:

```bash
pip install "qrtransfer-lite[clipboard]"   # --clipboard support (pyperclip)
pip install "qrtransfer-lite[tls]"         # auto-generate self-signed certs
```

The PyPI distribution name is `qrtransfer-lite`; the import package and console
script are both `qrtransfer`. You can also run it without installing:

```bash
python -m qrtransfer --help
```

### From source

```bash
git clone https://github.com/rkriad585/qrtransfer.git
cd qrtransfer
python -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
```

See [docs/installation.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/installation.md)
for details.

### Docker

A container image is published to the GitHub Container Registry:

```bash
docker run --rm --network host ghcr.io/rkriad585/qrtransfer /data/myfile.pdf
```

`--network host` is required so the printed IP/port refer to the host. See
[docs/deployment.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/deployment.md).

## Quick Start

Serve a single file (no password, never expires):

```bash
qrtransfer myphoto.jpg
```

You'll see a QR code and the download URL:

```text
Scan this QR code to download:
[   QR CODE PRINTED HERE   ]
URL: http://192.168.1.5:41234/f9aX23_qY8M
Press Enter or Ctrl+C to stop transfer...
```

Scan with your phone — the file downloads immediately and the session exits after
the first successful download. Press `Enter` or `Ctrl+C` to stop early.

Send a whole folder (zipped automatically):

```bash
qrtransfer builds/
```

Receive files from your phone:

```bash
qrtransfer receive
```

A step-by-step walkthrough is in
[docs/getting-started.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/getting-started.md).

## Usage Examples

```bash
# Send files
qrtransfer file1.pdf file2.pdf        # multiple files are zipped automatically
qrtransfer -z photo.jpg               # force-zip even a single file
qrtransfer --text "hello world"       # share a text snippet instead of a file

# Protect a transfer
qrtransfer -p mysecret --expire 300 holiday.jpg

# Keep serving
qrtransfer --keep-alive builds/       # stay up until you stop it
qrtransfer --max-downloads 5 docs/    # stop after 5 downloads

# Network options
qrtransfer --interface wlan0 file     # pick a specific interface
qrtransfer --port 8080 file           # fixed port (remembered for next time)
qrtransfer --ipv6 file                # advertise an IPv6 address
qrtransfer --tls file                 # serve over HTTPS (self-signed cert)

# Utilities
qrtransfer --clipboard file           # copy the URL to the clipboard
qrtransfer --history                  # show past transfers

# Receive files
qrtransfer receive                    # save to ~/Downloads (or the current dir)
qrtransfer receive ~/incoming -p pw   # custom destination + password
qrtransfer receive --max-upload-size 100
```

More examples, including Windows `cmd`/PowerShell variants, live in
[docs/usage.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/usage.md).

## Using as a Library

The package can be embedded in other Python programs. `qrtransfer.api` exposes a
small public surface: build a `Session`, start the server in a background thread,
and stop it when done.

```python
from qrtransfer.api import Session, start, stop

session = Session(
    token="an-unguessable-token",
    ip="0.0.0.0",
    port=8000,
    file_path="/home/me/photo.jpg",
    filename="photo.jpg",
    directory="/home/me",
    max_downloads=1,  # stop after one download
)
server = start(session)  # serves in a background thread
# ... do other work ...
stop(server)  # shutdown + close
```

Helpers such as `get_ip`, `find_free_port`, `zip_content`, `load_config`,
`save_config`, `add_entry`, and `load_history` are re-exported from the same
module. The full reference (including receive mode and network helpers) is in
[docs/api.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/api.md).

## Documentation

The full documentation set is also published to GitHub Pages at
<https://rkriad585.github.io/qrtransfer/>.

| Page | Purpose |
| --- | --- |
| [docs/index.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/index.md) | Documentation home |
| [docs/getting-started.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/getting-started.md) | First transfers, end to end |
| [docs/installation.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/installation.md) | pip, extras, and source installs |
| [docs/usage.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/usage.md) | Everyday examples for Linux/macOS, `cmd`, and PowerShell |
| [docs/cli.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/cli.md) | Every command, option, and exit code |
| [docs/api.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/api.md) | Using qrtransfer as a Python library |
| [docs/configuration.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/configuration.md) | Config file, history, and TLS cache locations |
| [docs/architecture.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/architecture.md) | How the server, session, and auth flow work |
| [docs/deployment.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/deployment.md) | Long-running setups, Docker, and this docs site |
| [docs/faq.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/faq.md) | Common questions |
| [docs/troubleshooting.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/troubleshooting.md) | Solving common problems |
| [docs/development.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/development.md) | Contributing, tests, and releases |
| [docs/screenshots.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/screenshots.md) | Screenshots of the send/receive pages |

## Interface

### `qrtransfer` (send)

```
qrtransfer [OPTIONS] [PATHS...]
```

| Argument / Option | Description |
| --- | --- |
| `PATHS` | One or more files or directories to serve. A directory, or more than one path, is zipped automatically. |
| `-z`, `--zip` | Force zipping even for a single file. |
| `--text TEXT` | Share a text snippet as a temporary `.txt` file instead of `PATHS`. |
| `--once` | Stop after the first successful download (this is the default; the flag exists for explicitness). |
| `-k`, `--keep-alive` | Keep serving after transfers complete. |
| `--max-downloads N` | Stop after `N` successful downloads. |

### `qrtransfer receive`

```
qrtransfer receive [DEST_DIR] [OPTIONS]
```

| Argument / Option | Description |
| --- | --- |
| `DEST_DIR` | Directory to save uploads (default: `~/Downloads`, else the current directory). |
| `-k`, `--keep-alive` | Keep serving after uploads complete. |
| `--max-downloads N` | Stop after `N` successful uploads. |
| `--max-upload-size MB` | Reject uploads larger than `MB` megabytes (default: 1024). |

### Common options (both commands)

| Option | Description |
| --- | --- |
| `-i`, `--interface IFACE` | Network interface to bind (remembered for next run). |
| `--port PORT` | Port to bind (remembered for next run). |
| `--force` | Ignore saved configuration. |
| `-e`, `--expire SECONDS` | Link expires after `SECONDS` (0 = never). |
| `-p`, `--password SECRET` | Require a password (`?passed=SECRET` or header `X-Password`). |
| `--tls` | Serve over HTTPS with a self-signed certificate. |
| `--cert FILE` / `--key FILE` | Custom TLS certificate/key (with `--tls`). |
| `--ipv6` | Prefer IPv6 addresses. |
| `--clipboard` | Copy the URL to the clipboard (needs the `clipboard` extra). |
| `--max-clients N` | Cap concurrent connections (0 = unlimited). |
| `-v`, `--verbose` | Log every HTTP request. |
| `-q`, `--quiet` | Suppress non-essential output. |
| `--history` | Show past transfers and exit. |
| `--version` | Print version and exit. |
| `-h`, `--help` | Show help and exit. |

## Architecture

```
src/qrtransfer/
├── __init__.py     # __version__
├── __main__.py     # python -m qrtransfer
├── api.py          # public library surface (start/stop + re-exports)
├── cli.py          # argparse, orchestration, session lifecycle
├── session.py      # Session dataclass (token, limits, expiry, ...)
├── server.py       # threaded HTTP server + handler, auth flow
├── network.py      # interface listing, IP detection, free ports
├── config.py       # persistent interface/port settings (JSON)
├── history.py      # last-200-transfers JSON store
├── zipper.py       # temporary zip creation
├── upload.py       # streaming multipart parser + sanitization
├── web.py          # dependency-free send/receive HTML pages
├── qr.py           # QR rendering (qrcode-terminal)
└── tls.py          # self-signed cert generation + SSL context
```

A single mutable `Session` object carries the token, password, expiry, and limits;
the HTTP handler reads it from an instance attribute (no module globals). Every
request is authorized in this order: expiry (`410`) → token (`404`) → password
(`401`) → limit (`403`). A wrong token never reveals whether a password exists.
See [docs/architecture.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/architecture.md)
for the full flow.

## Requirements

- Python **3.9 or newer** (tested on 3.9, 3.11, 3.13).
- Runtime dependencies: `platformdirs>=3`, `psutil>=5.9`, `qrcode-terminal>=0.8`.
- Optional extras: `pyperclip>=1.8` (`clipboard`), `cryptography>=42` (`tls`).
- Platforms: Linux, macOS, Windows (wherever Python 3.9+ runs).

## Prerequisites

- Python 3.9+ and `pip` installed.
- A network interface that is up (Wi-Fi or Ethernet) and a device (phone/tablet)
  with a camera and browser on the **same network**.
- A terminal with a monospaced font for the QR code (Windows Terminal works well).

## Development

```bash
git clone https://github.com/rkriad585/qrtransfer.git
cd qrtransfer
python -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
pip install -e ".[dev]"

pytest -v           # run the test suite
ruff check .        # lint
ruff format --check .   # check formatting
pyright             # type-check
python -m build     # build sdist + wheel
mkdocs serve        # preview the docs site (needs ".[docs]")
```

The test suite covers unit, integration (a real in-process server on
`127.0.0.1`), and CLI end-to-end tests. CI runs on Ubuntu, Windows, and macOS.
See [docs/development.md](https://github.com/rkriad585/qrtransfer/blob/main/docs/development.md)
for details.

## Contributing

Contributions are welcome. Please read
[CONTRIBUTING.md](https://github.com/rkriad585/qrtransfer/blob/main/CONTRIBUTING.md)
and the
[Code of Conduct](https://github.com/rkriad585/qrtransfer/blob/main/CODE_OF_CONDUCT.md)
before opening a pull request.

## Security

Please report security vulnerabilities privately per
[SECURITY.md](https://github.com/rkriad585/qrtransfer/blob/main/SECURITY.md).
For context: files never leave your LAN unless you deliberately port-forward;
URLs use unguessable tokens; passwords and expiration gate access to links (use
`--tls` on hostile networks); and receive mode sanitizes filenames and enforces
upload limits.

## License

This project is released under the **MIT License**. See
[LICENSE](https://github.com/rkriad585/qrtransfer/blob/main/LICENSE) for the
full text.

## Acknowledgments

- The original [Go `qr-filetransfer`](https://github.com/claudiodangelis/qr-filetransfer)
  project this tool reimplements.
- `psutil`, `platformdirs`, `qrcode-terminal`, `cryptography`, and `pyperclip`
  for network/platform/QR/TLS/clipboard support.
