Modern sync and async Python client for MEGA public file and folder links.
Project description
mega-public-client
mega-public-client is a modern Python 3.11+ library for downloading files and
folders from public MEGA links.
It provides synchronous and asynchronous APIs, local MEGA decryption, resumable chunked downloads, progress callbacks, folder traversal, custom retry handling, and clean typed models.
The library does not depend on abandoned MEGA wrappers and does not use
tenacity. Runtime dependencies are intentionally small:
httpxpycryptodome
Features
- Public MEGA file downloads
- Public MEGA folder downloads
- Original file names from MEGA metadata
- Recursive folder paths preserved on disk
- Sync API via
MegaClient - Async API via
AsyncMegaClient - Parallel chunk downloads
- Resume support through
.partfiles - Streaming helpers for small files
- Progress callbacks
- Custom sync and async retry engine
- Exponential backoff with retry filters
- MEGA AES-CTR file decryption
- MEGA AES-CBC attribute decryption
- Modern public URL parser
- Structured exception hierarchy
- Dataclasses for public models
- Type hints and
py.typed - PyPI-ready
pyproject.toml - Offline unit tests for parser, crypto, retry, and path behavior
Installation
From PyPI, after publishing:
pip install mega-public-client
From a local checkout:
pip install .
For development, install in editable mode:
pip install -e .
With test dependencies:
pip install -e ".[test]"
Quick Start
Download one public file using the original MEGA file name:
from mega_client import MegaClient
url = "https://mega.nz/file/FILE_ID#FILE_KEY"
with MegaClient() as client:
result = client.download_file(url, "downloads")
print(result.path)
If the MEGA file is named movie.mp4, it will be saved as:
downloads/movie.mp4
To force a custom output name, pass a full file path:
from mega_client import MegaClient
with MegaClient() as client:
client.download_file(
"https://mega.nz/file/FILE_ID#FILE_KEY",
"downloads/custom-name.mp4",
)
Download a Folder
Use download_folder() with a public folder URL:
from mega_client import MegaClient
url = "https://mega.nz/folder/FOLDER_ID#FOLDER_KEY"
with MegaClient() as client:
results = client.download_folder(url, "downloads")
for item in results:
print(item.path)
The library preserves folder paths returned by MEGA. For example, a public folder containing:
Videos/
intro.mp4
lessons/
part-1.mp4
will be written as:
downloads/Videos/intro.mp4
downloads/Videos/lessons/part-1.mp4
Async Usage
Use AsyncMegaClient with async with:
import asyncio
from mega_client import AsyncMegaClient
async def main() -> None:
async with AsyncMegaClient() as client:
result = await client.download_file(
"https://mega.nz/file/FILE_ID#FILE_KEY",
"downloads",
)
print(result.path)
asyncio.run(main())
Async folder download:
import asyncio
from mega_client import AsyncMegaClient
async def main() -> None:
async with AsyncMegaClient() as client:
results = await client.download_folder(
"https://mega.nz/folder/FOLDER_ID#FOLDER_KEY",
"downloads",
)
for result in results:
print(result.path)
asyncio.run(main())
Progress Callbacks
Progress callbacks receive two arguments:
done: bytes downloaded and decrypted so fartotal: total bytes when known
Synchronous example:
from mega_client import MegaClient
def progress(done: int, total: int | None) -> None:
if total:
percent = done / total * 100
print(f"{percent:.1f}% ({done}/{total})")
else:
print(done)
with MegaClient() as client:
client.download_file(
"https://mega.nz/file/FILE_ID#FILE_KEY",
"downloads",
progress=progress,
)
Async progress callbacks may be regular functions or async functions:
import asyncio
from mega_client import AsyncMegaClient
async def progress(done: int, total: int | None) -> None:
print(done, total)
async def main() -> None:
async with AsyncMegaClient() as client:
await client.download_file(
"https://mega.nz/file/FILE_ID#FILE_KEY",
"downloads",
progress=progress,
)
asyncio.run(main())
Streaming Small Files
For small files, you can download and decrypt directly into memory:
from mega_client import MegaClient
with MegaClient() as client:
data = client.stream_file("https://mega.nz/file/FILE_ID#FILE_KEY")
print(len(data))
Async:
import asyncio
from mega_client import AsyncMegaClient
async def main() -> None:
async with AsyncMegaClient() as client:
data = await client.stream_file("https://mega.nz/file/FILE_ID#FILE_KEY")
print(len(data))
asyncio.run(main())
For large videos and archives, prefer download_file() so the library writes
chunks to disk instead of keeping the whole file in memory.
Resume Support
Downloads are written to a temporary .part file first. If a download is
interrupted, call download_file() again with the same destination and the
library will resume from the existing .part file when possible.
Resume is enabled by default:
client.download_file(url, "downloads", resume=True)
Disable resume:
client.download_file(url, "downloads", resume=False)
Resume offsets are aligned to AES block boundaries so decryption can continue correctly.
Chunk Size and Parallelism
You can tune chunk size and request concurrency:
from mega_client import MegaClient
with MegaClient() as client:
client.download_file(
"https://mega.nz/file/FILE_ID#FILE_KEY",
"downloads",
chunk_size=2 * 1024 * 1024,
parallelism=6,
)
Defaults:
chunk_size:1 MiBparallelism:4
Higher parallelism may improve throughput, but it can also trigger server-side rate limits or increase memory and disk pressure.
URL Parsing
The parser supports modern and legacy public MEGA links:
from mega_client import parse_mega_url
link = parse_mega_url("https://mega.nz/file/FILE_ID#FILE_KEY")
print(link.type)
print(link.handle)
print(link.key)
Supported examples:
https://mega.nz/file/<file_id>#<file_key>
https://mega.nz/folder/<folder_id>#<folder_key>
https://mega.nz/#F!<folder_id>!<folder_key>
https://mega.nz/#!<file_id>!<file_key>
Malformed or unsupported URLs raise MegaInvalidURLError.
Metadata
Read file metadata without downloading:
from mega_client import MegaClient
with MegaClient() as client:
info = client.get_file_info("https://mega.nz/file/FILE_ID#FILE_KEY")
print(info.name)
print(info.size)
print(info.handle)
Read folder metadata:
from mega_client import MegaClient
with MegaClient() as client:
folder = client.get_folder_info("https://mega.nz/folder/FOLDER_ID#FOLDER_KEY")
for node in folder.nodes:
print(node.name, node.is_file, node.is_folder)
Exceptions
All package-specific exceptions inherit from MegaClientError.
from mega_client import MegaClient, MegaClientError
try:
with MegaClient() as client:
client.download_file(url, "downloads")
except MegaClientError as exc:
print(f"MEGA download failed: {exc}")
Exception classes:
MegaClientError: base classMegaInvalidURLError: invalid or unsupported public URLMegaAPIError: MEGA API returned an error or malformed responseMegaCryptoError: key, attribute, or decryption failureMegaDownloadError: download could not completeMegaIntegrityError: completed file failed validationMegaRetryError: retry loop exhausted unexpectedly
Retry Configuration
The library includes its own retry engine for sync and async code.
from mega_client import MegaClient
from mega_client.retry import RetryConfig
retry = RetryConfig(
attempts=6,
base_delay=0.5,
factor=2.0,
max_delay=15.0,
jitter=0.2,
)
with MegaClient(retry=retry) as client:
client.download_file(url, "downloads")
By default, retries are applied to transient network errors, timeouts, and
server-side HTTP responses such as 429, 500, 502, 503, and 504.
Custom retry filter:
from mega_client.retry import RetryConfig
def retry_filter(exc: BaseException) -> bool:
return isinstance(exc, TimeoutError)
retry = RetryConfig(attempts=3, retry_filter=retry_filter)
Logging
The package uses standard Python logging names:
mega_client.syncmega_client.asyncmega_client
Example:
import logging
logging.basicConfig(level=logging.INFO)
You can pass a custom logger:
import logging
from mega_client import MegaClient
logger = logging.getLogger("my_app.mega")
with MegaClient(logger=logger) as client:
client.download_file(url, "downloads")
Public API
Main imports:
from mega_client import MegaClient
from mega_client import AsyncMegaClient
from mega_client import parse_mega_url
Common models:
from mega_client import FileInfo
from mega_client import FolderInfo
from mega_client import NodeInfo
from mega_client import DownloadResult
DownloadResult fields:
path: final local pathbytes_written: number of bytes writtenresumed: whether an existing.partfile was usedverified: whether final validation passed
FileInfo fields:
name: original file name from MEGA metadatasize: file size in bytesdownload_url: temporary MEGA download URLkey: decoded MEGA file key materialhandle: MEGA file handleattributes: decrypted metadata attributes
NodeInfo fields:
handle: MEGA node handleparent: parent node handle when presentkind: MEGA node typename: decrypted node namesize: file size for file nodeskey: decrypted node keyattributes: decrypted node attributesis_file: convenience propertyis_folder: convenience property
MEGA Protocol Notes
Public-link operations use MEGA's command endpoint:
https://g.api.mega.co.nz/cs
The client sends JSON arrays because the MEGA command server supports batched commands.
Public file metadata is requested with:
[
{
"a": "g",
"g": 1,
"p": "<file_handle>"
}
]
Public folder trees are requested with the folder handle in the request query
parameter n and a folder listing command body:
[
{
"a": "f",
"c": 1,
"r": 1,
"ca": 1
}
]
Downloads for nodes inside public folders also require the public folder handle as API context.
MEGA files are encrypted client-side:
- Public file keys contain eight 32-bit words.
- The AES key is derived by XORing key words with nonce/MAC words.
- File content is decrypted with AES-CTR.
- File and folder attributes are decrypted with AES-CBC and a zero IV.
- Attribute plaintext begins with the literal
MEGAprefix followed by JSON.
Project Layout
mega_client/
client.py # synchronous facade
async_client.py # asynchronous API and MEGA command calls
downloader.py # chunked download and resume logic
crypto.py # MEGA key and AES helpers
parser.py # public URL parser
models.py # dataclasses and enums
retry.py # custom retry engine
exceptions.py # exception hierarchy
progress.py # progress callback helpers
constants.py # defaults and protocol constants
utils.py # small shared helpers
types.py # callback and retry typing aliases
Development
Install locally:
pip install -e ".[test]"
Run tests:
python -m pytest
Run the benchmark helper:
python benchmarks/download_throughput.py "https://mega.nz/file/FILE_ID#FILE_KEY" output.bin
Examples
Example scripts are available in:
examples/download_file.py
examples/download_file_async.py
Limitations
- Only public MEGA file and folder links are supported.
- Account login, private cloud operations, uploads, deletes, and sharing management are outside the scope of this package.
- Integrity validation currently verifies completed file size and correct decryption flow. Full MEGA MAC verification can be added as an additional hardening step.
stream_file()loads the entire decrypted file into memory and should only be used for small files.
License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mega_public_client-0.1.1.tar.gz.
File metadata
- Download URL: mega_public_client-0.1.1.tar.gz
- Upload date:
- Size: 15.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
931fade021589ca1fa8885f477b14597ced0ba32e5b233f79834e5c184751c77
|
|
| MD5 |
219e73ba1df35ea79c73d64b249accc7
|
|
| BLAKE2b-256 |
7ffa84308ee4e1c5ae9b00c4767c5f988550398b773defcead2bf52ea375dbbe
|
File details
Details for the file mega_public_client-0.1.1-py3-none-any.whl.
File metadata
- Download URL: mega_public_client-0.1.1-py3-none-any.whl
- Upload date:
- Size: 20.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f5a95e7c1435a6786e9e8fe5e004241ac25aa35444b33c55e3edb5f15a794797
|
|
| MD5 |
6996d40cba1da3dc3e235db448f5fef3
|
|
| BLAKE2b-256 |
4bef0e2a71d2534a29b03d636ba3b1f4de14d67e7b1511c8e43680204b0f7474
|