-
Notifications
You must be signed in to change notification settings - Fork 14
Home
Complete documentation for the Seedr API Python wrapper.
- Installation
- Quick Start
- Authentication
- API Reference
- Response Models
- Error Handling
- Advanced Usage
- Examples
Install the package using pip:
pip install seedrRequirements:
- Python 3.7 or higher
- requests library (automatically installed)
from seedr import SeedrAPI
# Initialize and authenticate
seedr = SeedrAPI(email='your_email@example.com', password='your_password')
# Get your drive contents
folder = seedr.get_folder_contents()
print(f"Space used: {folder.space_used} / {folder.space_max}")
# Add a torrent
result = seedr.add_torrent('magnet:?xt=urn:btih:...')
print(f"Torrent added: {result}")
# Get file download URL
file_details = seedr.get_file_details(folder_file_id=123)
print(f"Download from: {file_details.url}")The most straightforward authentication method:
from seedr import SeedrAPI
seedr = SeedrAPI(
email='your_email@example.com',
password='your_password'
)Upon successful authentication, access and refresh tokens are automatically stored in the instance.
If you already have a valid access token:
from seedr import SeedrAPI
seedr = SeedrAPI(token='your_access_token')For automatic token renewal:
from seedr import SeedrAPI
seedr = SeedrAPI(
token='your_access_token',
refresh_token='your_refresh_token'
)For devices with limited input capabilities (TVs, IoT devices, etc.):
from seedr import SeedrAPI
# Create instance without authentication
seedr = SeedrAPI.__new__(SeedrAPI)
seedr.token = None
seedr.rft = None
seedr.username = None
seedr.password = None
seedr.devc = None
seedr.usc = None
seedr.on_token_refresh = None
seedr.access_token = None
# Get device code
user_code = seedr.get_device_code()
print(f"Go to https://www.seedr.cc/devices")
print(f"Enter this code: {user_code}")
# Wait for user authorization (implement polling)
import time
time.sleep(30) # Give user time to authorize
# Retrieve access token
try:
token = seedr.get_token(seedr.devc)
print(f"Successfully authenticated! Token: {token}")
except Exception as e:
print(f"Authorization pending or failed: {e}")Automatic token refresh on expiration:
from seedr import SeedrAPI
def save_tokens(access_token, refresh_token):
"""Save tokens to your database or file"""
print(f"New access token: {access_token}")
print(f"New refresh token: {refresh_token}")
# Save to database, file, etc.
with open('tokens.txt', 'w') as f:
f.write(f"{access_token}\n{refresh_token}")
seedr = SeedrAPI(email='email', password='password')
seedr.on_token_refresh = save_tokens
# Tokens will automatically refresh when expired
# Your callback will be called with new tokens
folder = seedr.get_folder_contents()Manual token refresh:
try:
seedr.refresh_token()
print(f"Token refreshed: {seedr.token}")
except Exception as e:
print(f"Failed to refresh: {e}")Constructor:
SeedrAPI(email=None, password=None, token=None, refresh_token=None)Parameters:
-
email(str, optional): Seedr account email -
password(str, optional): Seedr account password -
token(str, optional): Existing access token -
refresh_token(str, optional): Existing refresh token for auto-renewal
Attributes:
-
token(str): Current access token -
access_token(str): Alias fortoken(backward compatibility) -
rft(str): Refresh token -
username(str): Authenticated username -
on_token_refresh(callable): Callback function for token refresh events
Raises:
-
InvalidLogin: Invalid email/password combination -
InvalidToken: Invalid or expired token -
LoginRequired: No authentication credentials provided
Authenticate using username and password.
token = seedr.login('email@example.com', 'password123')
print(f"Access token: {token}")Parameters:
-
username(str): Seedr account email/username -
password(str): Account password
Returns: str - Access token
Raises: InvalidLogin if credentials are invalid
Get a device code for device-based authentication.
user_code = seedr.get_device_code()
print(f"Enter this code at seedr.cc: {user_code}")Returns: str - User code to be entered on the website
Note: Stores device code in seedr.devc attribute
Retrieve access token using device code.
token = seedr.get_token(seedr.devc)Parameters:
-
device_code(str): Device code fromget_device_code()
Returns: str - Access token
Raises: Exception if authorization is pending or failed
Manually refresh the access token.
seedr.refresh_token()
print(f"New token: {seedr.token}")Raises: Exception if no refresh token available or refresh fails
Note: Automatically called by API methods when token expires
Get folder contents with typed response objects.
# Get root folder
root = seedr.get_folder_contents()
print(f"Space: {root.space_used} / {root.space_max} bytes")
# Get specific folder
folder = seedr.get_folder_contents(folder_id=123)
for file in folder.files:
print(f"File: {file.name} ({file.size} bytes)")Parameters:
-
folder_id(int, optional): Folder ID. If None, returns root folder.
Returns: SeedrFolderResponse - Typed object with folder contents
Attributes of returned object:
-
space_max(int): Total storage space in bytes -
space_used(int): Used storage space in bytes -
folder_id(int): Current folder ID -
fullname(str): Full path of folder -
name(str): Folder name -
parent(int or None): Parent folder ID -
folders(List[SeedrFolder]): List of subfolders -
files(List[SeedrFile]): List of files -
torrents(List[SeedrTorrent]): List of active torrents
Legacy method to get root folder contents as dictionary.
drive = seedr.get_drive()
print(drive['space_used'])Returns: dict - Dictionary with drive information
Note: Use get_folder_contents() for typed responses
Legacy method to get folder contents as dictionary.
folder = seedr.get_folder(123)
print(folder['name'])Parameters:
-
folder_id(int): Folder ID
Returns: dict - Dictionary with folder contents
Note: Use get_folder_contents() for typed responses
Delete a folder from your account.
result = seedr.delete_folder(123)
print(result)Parameters:
-
folder_id(int or str): Folder ID to delete
Returns: dict - Result information
Note: This permanently deletes the folder and all its contents
Get detailed file information with typed response.
file = seedr.get_file_details(456)
print(f"Name: {file.name}")
print(f"Download URL: {file.url}")
print(f"Success: {file.result}")Parameters:
-
folder_file_id(int): File ID
Returns: SeedrFileDetails - Typed object with file details
Attributes:
-
url(str): Direct download URL -
name(str): File name -
result(bool): Whether request was successful
Legacy method to get file information as dictionary.
file = seedr.get_file(456)
print(file['url'])Parameters:
-
folder_file_id(int): File ID
Returns: dict - Dictionary with file information
Note: Use get_file_details() for typed responses
Delete a file from your account.
result = seedr.delete_file(456)
print(result)Parameters:
-
file_id(int or str): File ID to delete
Returns: dict - Result information
Add a torrent using magnet link or .torrent file URL.
# Magnet link
result = seedr.add_torrent('magnet:?xt=urn:btih:HASH...')
# .torrent file URL
result = seedr.add_torrent('https://example.com/file.torrent')
print(result)Parameters:
-
torrent(str): Magnet link or direct .torrent file URL
Returns: dict - Result with torrent information
Response fields:
-
result(bool): Whether torrent was added successfully -
user_torrent_id(int): ID of the added torrent (if successful) -
error(str): Error message (if failed)
Alias for add_torrent().
result = seedr.add_magnet('magnet:?xt=urn:btih:...')Parameters:
-
magnet(str): Magnet link or torrent URL
Returns: dict - Result information
Delete an active torrent from your account.
result = seedr.delete_torrent(789)
print(result)Parameters:
-
torrent_id(int or str): Torrent ID to delete
Returns: dict - Result information
Note: This removes the torrent from your active downloads. To delete downloaded content, use delete_folder() or delete_file().
Create a downloadable archive (.zip) from a folder.
archive = seedr.create_archive(123)
print(f"Archive URL: {archive.archive_url}")
print(f"Archive ID: {archive.archive_id}")Parameters:
-
folder_id(int or str): Folder ID to archive
Returns: SeedrArchiveResponse - Typed object with archive information
Attributes:
-
result(bool): Whether archive was created successfully -
archive_id(int): ID of the created archive -
archive_url(str): Direct download URL for the archive
Note: Archives are temporary and may expire. Download them promptly.
All response models have from_json() class method for creating instances from API responses and to_dict() method for converting back to dictionaries.
Complete folder information with all contents.
Attributes:
space_max: int # Maximum storage in bytes
space_used: int # Used storage in bytes
folder_id: int # Current folder ID
fullname: str # Full path
name: str # Folder name
parent: Optional[int] # Parent folder ID (None for root)
folders: List[SeedrFolder] # Subfolders
files: List[SeedrFile] # Files
torrents: List[SeedrTorrent] # Active torrentsExample:
folder = seedr.get_folder_contents()
print(f"Using {folder.space_used / folder.space_max * 100:.1f}% of storage")Folder metadata.
Attributes:
id: int # Folder ID
name: str # Folder name
fullname: str # Full path
size: int # Total size in bytes
last_update: str # Last update timestampExample:
for folder in parent.folders:
print(f"{folder.name}: {folder.size} bytes")File metadata with video playback information.
Attributes:
name: str # File name
size: int # File size in bytes
hash: str # File hash
folder_id: int # Parent folder ID
folder_file_id: int # File ID (use for get_file)
file_id: int # Alternative file ID
last_update: str # Last update timestamp
play_video: bool # Whether video playback is available
video_progress: str # Video playback progress (if applicable)Example:
for file in folder.files:
if file.play_video:
print(f"Video: {file.name}")
print(f" Size: {file.size} bytes")
print(f" ID: {file.folder_file_id}")Active torrent information.
Attributes:
id: int # Torrent ID
name: str # Torrent name
folder: str # Destination folder
size: int # Total size in bytes
hash: str # Torrent hash
progress: str # Download progress (e.g., "100" for complete)
last_update: str # Last update timestampExample:
for torrent in folder.torrents:
print(f"{torrent.name}: {torrent.progress}% complete")
if torrent.progress == "100":
print(f" Ready in folder: {torrent.folder}")File details with download URL.
Attributes:
url: str # Direct download URL
name: str # File name
result: bool # Request success statusExample:
file = seedr.get_file_details(123)
if file.result:
print(f"Download: {file.url}")Archive creation result.
Attributes:
result: bool # Whether archive was created
archive_id: int # Archive ID
archive_url: str # Download URLExample:
archive = seedr.create_archive(folder_id=123)
if archive.result:
print(f"Download archive: {archive.archive_url}")Raised when email/password authentication fails.
from seedr import SeedrAPI
from seedr.errors import InvalidLogin
try:
seedr = SeedrAPI(email='wrong@example.com', password='wrongpass')
except InvalidLogin as e:
print(f"Login failed: {e}")Raised when provided token is invalid.
from seedr.errors import InvalidToken
try:
seedr = SeedrAPI(token='invalid_token')
except InvalidToken as e:
print(f"Invalid token: {e}")Raised when no authentication credentials are provided.
from seedr.errors import LoginRequired
try:
seedr = SeedrAPI()
except LoginRequired as e:
print(f"Authentication required: {e}")Raised when access token has expired (usually auto-handled).
from seedr.errors import TokenExpired
try:
folder = seedr.get_folder_contents()
except TokenExpired:
# Token refresh failed
print("Please re-authenticate")1. Always use try-except blocks:
from seedr import SeedrAPI
from seedr.errors import InvalidLogin, InvalidToken
try:
seedr = SeedrAPI(email='email', password='password')
folder = seedr.get_folder_contents()
except InvalidLogin:
print("Invalid credentials")
except InvalidToken:
print("Token expired, re-authenticating...")
seedr = SeedrAPI(email='email', password='password')
except Exception as e:
print(f"Unexpected error: {e}")2. Implement token refresh callback:
def on_token_refresh(access, refresh):
# Save tokens for future use
save_to_database(access, refresh)
seedr = SeedrAPI(email='email', password='password')
seedr.on_token_refresh = on_token_refresh3. Handle network errors:
import requests
try:
folder = seedr.get_folder_contents()
except requests.exceptions.RequestException as e:
print(f"Network error: {e}")import requests
# Get file download URL
file = seedr.get_file_details(folder_file_id=123)
# Download the file
response = requests.get(file.url, stream=True)
with open(file.name, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
print(f"Downloaded: {file.name}")# Delete multiple files
file_ids = [123, 456, 789]
for file_id in file_ids:
try:
seedr.delete_file(file_id)
print(f"Deleted file {file_id}")
except Exception as e:
print(f"Failed to delete {file_id}: {e}")
# Delete multiple folders
folder_ids = [111, 222, 333]
for folder_id in folder_ids:
seedr.delete_folder(folder_id)def list_all_files(seedr, folder_id=None, indent=0):
"""Recursively list all files in folder tree"""
folder = seedr.get_folder_contents(folder_id)
prefix = " " * indent
print(f"{prefix}Folder: {folder.name}")
for file in folder.files:
print(f"{prefix} - {file.name} ({file.size} bytes)")
for subfolder in folder.folders:
list_all_files(seedr, subfolder.id, indent + 1)
# Usage
list_all_files(seedr)import time
def wait_for_torrent(seedr, torrent_id, timeout=3600):
"""Wait for torrent to complete downloading"""
start_time = time.time()
while time.time() - start_time < timeout:
folder = seedr.get_folder_contents()
for torrent in folder.torrents:
if torrent.id == torrent_id:
progress = float(torrent.progress)
print(f"Progress: {progress}%")
if progress >= 100:
print("Download complete!")
return True
time.sleep(10) # Check every 10 seconds
print("Timeout waiting for torrent")
return False
# Add torrent and monitor
result = seedr.add_torrent('magnet:?...')
if result.get('result'):
torrent_id = result.get('user_torrent_id')
wait_for_torrent(seedr, torrent_id)def archive_and_download(seedr, folder_id, output_path):
"""Create archive and download it"""
import requests
# Create archive
archive = seedr.create_archive(folder_id)
if not archive.result:
print("Failed to create archive")
return False
# Download archive
response = requests.get(archive.archive_url, stream=True)
with open(output_path, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
print(f"Archive downloaded to: {output_path}")
return True
# Usage
archive_and_download(seedr, folder_id=123, output_path='download.zip')from seedr import SeedrAPI
def show_menu():
print("\n1. List files")
print("2. Add torrent")
print("3. Delete file")
print("4. Exit")
return input("Choose option: ")
seedr = SeedrAPI(email='email@example.com', password='password')
while True:
choice = show_menu()
if choice == '1':
folder = seedr.get_folder_contents()
print(f"\nFiles ({folder.space_used / 1e9:.2f} GB used):")
for file in folder.files:
print(f" [{file.folder_file_id}] {file.name}")
elif choice == '2':
magnet = input("Enter magnet link: ")
result = seedr.add_torrent(magnet)
print("Torrent added!" if result.get('result') else "Failed!")
elif choice == '3':
file_id = input("Enter file ID: ")
seedr.delete_file(file_id)
print("File deleted!")
elif choice == '4':
breakimport time
from seedr import SeedrAPI
def auto_download(magnet_links, download_path='/downloads'):
seedr = SeedrAPI(email='email', password='password')
for magnet in magnet_links:
print(f"Adding: {magnet[:50]}...")
result = seedr.add_torrent(magnet)
if not result.get('result'):
print("Failed to add torrent")
continue
# Wait for completion
torrent_id = result.get('user_torrent_id')
while True:
folder = seedr.get_folder_contents()
torrent = next((t for t in folder.torrents if t.id == torrent_id), None)
if not torrent: # Torrent finished and moved to files
print("Download complete!")
break
print(f"Progress: {torrent.progress}%")
time.sleep(30)
# Usage
magnets = [
'magnet:?xt=urn:btih:...',
'magnet:?xt=urn:btih:...'
]
auto_download(magnets)from seedr import SeedrAPI
def check_storage(seedr):
folder = seedr.get_folder_contents()
used_gb = folder.space_used / 1e9
max_gb = folder.space_max / 1e9
percentage = (folder.space_used / folder.space_max) * 100
print(f"Storage: {used_gb:.2f} GB / {max_gb:.2f} GB ({percentage:.1f}%)")
if percentage > 90:
print("⚠️ Storage almost full!")
return False
return True
seedr = SeedrAPI(token='your_token')
check_storage(seedr)from datetime import datetime, timedelta
from seedr import SeedrAPI
def cleanup_old_files(seedr, days=30):
"""Delete files older than specified days"""
cutoff = datetime.now() - timedelta(days=days)
folder = seedr.get_folder_contents()
deleted_count = 0
for file in folder.files:
# Parse last_update timestamp
file_date = datetime.strptime(file.last_update, '%Y-%m-%d %H:%M:%S')
if file_date < cutoff:
print(f"Deleting old file: {file.name}")
seedr.delete_file(file.folder_file_id)
deleted_count += 1
print(f"Deleted {deleted_count} files")
seedr = SeedrAPI(email='email', password='password')
cleanup_old_files(seedr, days=30)- Save refresh tokens: Always save refresh tokens to avoid re-authentication
-
Use typed responses: Prefer
get_folder_contents()overget_drive()for better IDE support - Handle rate limits: Add delays between API calls if making many requests
-
Monitor token expiration: Implement
on_token_refreshcallback to save new tokens - Check progress regularly: Poll torrent status every 10-30 seconds, not more frequently
- Clean up regularly: Delete completed torrents and old files to save space
- Use archives for multiple files: Create archives instead of downloading many small files
Solution: Token may have expired. Re-authenticate or ensure refresh token is provided.
Solution: Provide either email/password or token when initializing SeedrAPI.
Solution: Some torrents take time to be processed. Wait a few seconds and refresh.
Solution: Download URLs are temporary. Get a new URL using get_file_details().
Solution: Refresh token may have expired. Re-authenticate with email/password.
- GitHub Issues: https://github.com/AnjanaMadu/SeedrAPI/issues
- Documentation: https://github.com/AnjanaMadu/SeedrAPI/wiki
- PyPI: https://pypi.org/project/seedr/
GPL 3.0 - See LICENSE file for details.
- Developed by Anjana Madu
- Inspired by theabbie's seedr-api