Python library and CLI app for the Mega.nz and Transfer.it API
Supports:
- Login (with credentials or creating a temporary account)
- Upload
- Download (files and folders)
- Delete
- Search
- Export (public sharing)
- Import public files to your account
- Renaming
- Moving files
- Add/remove contacts
- Get account stats (storage quota, transfer quota, balance (PRO accounts only))
TODO:
- Support multifactor authentication (MFA) login
Please check src/mega/data_structures.py for details about the objects returned by the API
Tip
You can run the commands bellow in an interactive python (the asyncio REPL). Try them in real time as is, using async/await keywords!
uv run -p3.12 --with async-mega-py python -m asyncio
from mega.client import MegaNzClient
email = "my_email@email.com"
password = "12345"
async with MegaNzClient() as mega:
await mega.login(email, password)Login should always be the first thing you do. Almost all operations require a valid account. You can call login without params to create a temporary account:
from mega.client import MegaNzClient
# Also works without using it as a context manager, but you have the responsability to close the session at the end
mega = MegaNzClient()
await mega.login() # login using a temporary anonymous account
# await mega.close() Check src/mega/client.py and src/mega/data_structures.pyto view the details of all public methods and which objects each one return.
The client deserializes the raw responses from the API and always returns dataclasses for objects (except for get_user which returns a normal dict)
Tip
All dataclasses returned by the client have a dump method to convert them to a dict if required
# Get user details
# Includes email, user id, history of all emails, creation timestamp, etc...
await mega.get_user()
# Get account stats
# ex: Balance, storage quota, transfer quota, usage metrics, etc...
await mega.get_account_stats()
# Add/remove contacts
contact = "test@mega.nz"
await mega.add_contact(contact)
await mega.remove_contact(contact)
async def view_paths():
fs = await mega.get_filesystem()
print (fs.paths.values())
# Create a folder
await mega.create_folder('new_folder')
await mega.create_folder('new_folder/sub_folder/subsub_folder')
await view_paths()
# Rename a file or a folder
folder = await mega.find('new_folder/sub_folder/subsub_folder')
await mega.rename(folder, new_name='my_new_name')
await view_paths()
# Send this node to the trash bin (still counts towards your quota)
await mega.delete(folder.id)
await view_paths()
# This removes it completely from your account
await mega.destroy(folder.id)
await view_paths()# Upload a file, and get its public link
my_real_file = '/home/user/myfile.doc' # Change this to a real file path!
uploaded_file = await mega.upload(my_real_file) # Upload returns the Node that represents the file you just uploaded
await mega.export(uploaded_file) # This only works with real accounts. Temp accounts can't create public links
# Download a file from your account
output_dir = "my downloads"
await mega.download(uploaded_file, output_dir)
# Download a public file
file_url = "https://mega.nz/file/vJ9EBJBC#vA1XpbngXcnN7lqXEWGQFPDc5ZlG6yltCHwGN-0O2LQ"
public_handle, public_key = mega.parse_file_url(file_url)
await mega.download_public_file(public_handle, public_key, output_dir)
# Download a public folder
folder_url = "https://mega.nz/folder/CJ8y1SDJ#KX8YfTd526P4o_hDH02jLQ"
public_handle, public_key, selected_node = mega.parse_folder_url(folder_url)
results = await mega.download_public_folder(public_handle, public_key, output_dir, selected_node)
for node_id, result in results.items():
print ((node_id, result))
# Import a file from URL
public_handle, public_key = mega.parse_file_url(file_url)
await mega.import_public_file(public_handle, public_key, dest_node_id=folder.id)
# How do you know if an URL is a file or folder?
result = mega.parse_url(url)
print (result.is_folder)Tip
You can show a progress bar on the terminal for each download/upload by calling them within the progress_bar context manager (needs optional dependency rich to be installed):
with mega.progress_bar:
success, fails = await mega.download_public_folder(public_handle, public_key, output_dir / "with_bar")The filesystem is a read only copy of your account's file structure.
Important
mega.py caches your filesystem until you make a request to modify it. ex: create_dir or upload
That means calls to mega.get_filesystem() will not reflect changes made by third parties (ex: MegaNZ's website or the MegaNZ's app)
You can force it to fetch current data by using mega.get_filesystem(force=True)
# Get a read only copy of your filesystem
fs = await mega.get_filesystem()
# save a copy of your filesystem as json
import json
from pathlib import Path
dump = json.dumps(fs.dump(), indent=2, ensure_ascii=False)
Path("my_fs.json").write_text(dump)We are gonna use the example filesystem found at tests/fake_fs.json which has this structure:
"paths": {
"qCZrYJVK": "/",
"FeWnQouH": "/backup.sql",
"coJ3yMOW": "/docker-compose.yml",
"FzL3QdIj": "/Inbox",
"2gL2GPaJ": "/index.html",
"msinsVCj": "/logo.png",
"MBlNlb2P": "/styles.css",
"7N9QiWZ9": "/tests",
"RDJJI2lv": "/tests/logo.png",
"pHWVIQLd": "/tests/logo.png",
"oImwb6nN": "/tests/script.js",
"FIXitv4F": "/tests/scripts",
"0fPFklV3": "/tests/scripts/notes.txt",
"l9zkz1GU": "/tests/scripts/script.js",
"E4LqT4EF": "/tests/scripts/styles.css",
"i6ry53xV": "/tests/setup.sh",
"Iri7NRCx": "/tests/utils.py",
"2Tae8amE": "/Trash Bin",
"t8HkzBH2": "/Trash Bin/data",
"8EwHVJna": "/Trash Bin/data/docker-compose.yml"
}from mega.filesystem import UserFileSystem
dump = Path("tests/fake_fs.json").read_text()
fs = UserFileSystem.from_dump(json.loads(dump))
# Search for nodes
query = "tests/script"
for node_id, path in fs.search(query):
print (node_id)
print (path)
# or
dict(fs.search(query))The output will be:
{
"oImwb6nN": "/tests/script.js",
"FIXitv4F": "/tests/scripts",
"0fPFklV3": "/tests/scripts/notes.txt",
"l9zkz1GU": "/tests/scripts/script.js",
"E4LqT4EF": "/tests/scripts/styles.css",
}# Get the path to a node
fs.absolute_path("0fPFklV3") # /tests/scripts/notes.txt
# Find a node by its *exact* path
result = fs.find("/tests/scripts/notes.txt")
print (result.id) # "0fPFklV3"# Get deleted files and folders (on the trash bin)
list(fs.deleted)
# List all the children of a folder (resursive)
folder = fs.find("/tests")
for node in fs.iterdir(folder.id, recursive=True):
print(fs.absolute_path(node.id))Output will be:
[
"/tests/logo.png",
"/tests/logo.png",
"/tests/script.js",
"/tests/scripts",
"/tests/scripts/notes.txt",
"/tests/scripts/script.js",
"/tests/scripts/styles.css",
"/tests/setup.sh",
"/tests/utils.py",
]Important
Mega's filesystem is not POSIX-compliant: multiple nodes may have the same path.
If 2 nodes have the same path, find will throw an error.
fs.find("/tests/logo.png") # This will fail
# You will have to call search and choose which one you actually want
dict(fs.search("/tests/logo.png"))Note
The transfer.it client does not support uploads (yet!)
from mega.transfer_it import TransferItClient
async with TransferItClient() as client:
transfer_id = client.parse_url(url)
# This is the same filesystem object as mega's,
# but it does not have root, inbox or trash_bin nodes
fs = await client.get_filesystem(transfer_id)
output_dir = "My downloads"
results = await client.download_transfer(transfer_id, output_dir)
print (results)You can use async-mega-py as a stand alone CLI app! Just install it with the optional [cli] dependencies. The CLI offers 2 commands: mega-py and async-mega-py. Both are just aliases for the same app.
# Install it with:
uv tool install async-mega-py[cli]
#Run it
mega-py --helpUsage: mega-py [OPTIONS] COMMAND [ARGS]...
CLI app for the Mega.nz and Transfer.it. Set MEGA_NZ_EMAIL and MEGA_NZ_PASSWORD
enviroment variables to use them as credentials for Mega
โญโ Options โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ --verbose -v Increase verbosity (-v shows debug logs, -vv โ
โ shows HTTP traffic) โ
โ --help Show this message and exit. โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
โญโ Commands โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ download Download a public file or folder by its URL (transfer.it / mega.nz) โ
โ dump Dump a copy of your filesystem to disk โ
โ stats Show account stats โ
โ upload Upload a file to your account โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏTip
The CLI app does not accept login credentials, but you can still use your account by setting up the MEGA_EMAIL and MEGA_PWD enviroment variables
It will also read them from an .env file (if found)