A simple CLI file uploader for multiple file-hosting services, with optional clipboard copy.
You have the option to choose between the standard version (lain-upload) or the desktop version (lain-upload[clipboard]), which adds clipboard support for auto-copying links.
Note
For brevity, the examples below use the desktop version.
pip install "lain-upload[clipboard]"pipx install "lain-upload[clipboard]"The most efficient way to install or run lain-upload.
# Permanent isolated installation
uv tool install "lain-upload[clipboard]"
# Run once without installing
uvx --with "lain-upload[clipboard]" lain-upload <file1> <file2> <file3>
# Run in scripts or ad-hoc environments
uv run --with "lain-upload[clipboard]" lain-upload <file1> <file2> <file3># Clone the repository and navigate to it
git clone git@github.com:NecRaul/lain-upload.git
cd lain-upload
# Install environment and all development dependencies (mandatory and optional)
uv sync --dev
# Install pre-commit hook
uv run pre-commit install
# Optional: Run all linters and type checkers manually
uv run pre-commit run --all-files
# Run the local version
uv run lain-upload <file1> <file2> <file3>
# Run tests
uv run pytest testsSimply provide the path to the file or files you wish to upload.
# Upload a single file (default host: catbox)
lain-upload kuroneko.png
# Upload multiple files from different directories
lain-upload /path/to/kuroneko.png /path/to/another/directory/shironeko.png yamineko.png ../kamineko.png
# Select a specific host
lain-upload --host uguu kuroneko.png
# Use host authentication when supported
lain-upload --host mixdrop --auth necraul@kuroneko.dev:generated_api_key kuroneko.png
# Set temporary file expiration when supported (e.g. 1h, 12h, 24h, 72h, etc.)
lain-upload --host litterbox --expire-after 24h kuroneko.png
# Enable longer generated filenames when supported
lain-upload --host 0x0 --long-filenames -- kuroneko.png shironeko.png
# Upload to every available non-deprecated host
lain-upload --host all kamineko.png
# Display help and version
lain-upload -h
lain-upload -v --host HOST File hosting service to upload to (default: catbox)
--auth AUTH Authentication credentials for the host (format varies per host)
--expire-after DURATION How long before the file expires when supported (e.g. 1h, 24h, 72h)
--long-filenames - Enable longer generated filenames when supported by the host
--config PATH Path to a custom configuration file
--init-config [PATH] Create a default configuration file at the default or given path
--show-config - Print the effective configuration after merging defaults and config file
--no-config - Ignore the configuration file and use only CLI flags
-h, --help - Show help and exit
-v, --version - Show version and exitlain-upload supports a JSON configuration file to set a default host and per-host options. You can create a default config, inspect the effective configuration, and override or ignore the config file at runtime.
- Default path
- Linux/BSD:
$XDG_CONFIG_HOME/necraul/lain-upload.jsonor~/.config/necraul/lain-upload.json - MacOS:
~/Library/Application Support/necraul/lain-upload.json - Windows:
%APPDATA%/necraul/lain-upload.json
- Linux/BSD:
- Basic structure
default_host: host used when--hostflag is omitted (default:"catbox").hosts: per-host configuration (auth,expire_after,long_filenames, etc.), keyed by host name.
{
"default_host": "catbox",
"hosts": {
"catbox": {
"auth": null
},
"litterbox": {
"expire_after": "72h",
"long_filenames": false
},
"gofile": {
"auth": null
}
}
}# Create a default configuration file at the default path
lain-upload --init-config
# Create a default configuration file at a custom path
lain-upload --init-config config.json
# Show the effective configuration (defaults merged with the default config file)
lain-upload --show-config
# Create a default configuration file at the default path and print it
lain-upload --init-config --show-config
# Create a default configuration file at a custom path and print it
lain-upload --init-config /path/to/config.json --show-config
# Show the effective configuration (defaults merged with the custom config file)
lain-upload --config config.json --show-config
# Upload using the config file's default_host (no --host needed)
lain-upload kuroneko.png
# Override the config file's default_host
lain-upload --host uguu shironeko.png
# Use a custom configuration file
lain-upload --config /path/to/config.json kamineko.png
# Ignore the configuration file and use only CLI flags
lain-upload --no-config kuroneko.png
# Override config's host and expiration (CLI flag overrides config)
lain-upload --host litterbox --expire-after 24h kuroneko.png- catbox - Support for user authentication with userhashes.
- litterbox - Support for custom expiration time and longer upload filenames.
- pomf - No extra options (deprecated).
- uguu - No extra options.
- fileditch - No extra options.
- tempditch - No extra options.
- 0x0 - Support for custom expiration time and longer upload filenames.
- x0 - Support for longer upload filenames.
- gofile - Support for user authentication with bearer API tokens.
- pixeldrain - Support for user authentication with API keys (Required).
- buzzheavier - No extra options.
- mixdrop - Support for user authentication with mail and API keys (Required).
- sharey - Support for custom expiration time.
- requests: send the API request for uploading.
- requests-toolbelt: enable memory-efficient streaming and progress tracking for large uploads.
- pyperclip: copy the uploaded files' URLs to the clipboard.
Supported services provide upload endpoints that accept multipart HTTP requests.
This tool automates uploads and adds safety checks and quality-of-life features.
curl -F "file=@kuroneko.png" https://example-upload-service.tld/upload-endpoint- Batch Processing: Upload multiple files in a single command, iterating through each one and reporting results as they complete rather than waiting for the entire batch to finish.
- Validation: Enforces service-specific constraints before sending anything. File size limits, allowed extensions, and authentication requirements are all checked upfront to avoid partial uploads or silent failures.
- API Request: Sends multipart
POSTrequests viarequestsandrequests-toolbelt. The toolbelt layer wraps the file in a streaming encoder so large files are read and sent in chunks rather than loaded fully into memory. - Normalization: Parses each service's unique response format and extracts a clean, shareable URL regardless of how the host structures its JSON or plain-text reply.
- Clipboard (Optional): If
pyperclipis installed, each resulting URL is copied to the clipboard immediately after upload so it is ready to paste without any extra steps.
- To 7666 of https://lain.la/ for running the pomf service that inspired this project.
- To r/a/dio anons for feedback and suggestions.