A Discord bot for downloading and extracting content from MKV (Matroska) files. Subxtract automates the process of downloading media files via Aria2 and extracting subtitles, attachments, chapters, and metadata from MKV containers.
- Download Management: Download files using torrents, magnet links, or direct download links via Aria2
- MKV Extraction: Extract the following from MKV files:
- Subtitles (SRT, ASS, SSA formats)
- Attachments (fonts, images, etc.)
- Chapters (XML format)
- Media information and metadata
- Queue System: Manage multiple download requests with a per-user queue
- Channel Permissions: Restrict bot commands to specific Discord channels
- Real-time Progress: Track download progress with live status updates
- Split File Support: Automatically split large zip files to fit Discord's 10MB upload limit
- Cancellation: Stop ongoing downloads and extractions at any time
- Aria2: Download manager with RPC support
- mkvmerge: Part of MKVToolNix for MKV file information
- mkvextract: Part of MKVToolNix for extracting MKV contents
- mediainfo: Media file analysis tool
- Python 3.10+
- discord-py-interactions 5.15.0
- aria2p 0.12.1
- python-dotenv 1.1.1
- jsonschema 4.25.1
- jsonschema-gentypes 2.12.0
Download and install:
Ensure all tools are added to your system PATH.
sudo apt update
sudo apt install aria2 mkvtoolnix mediainfobrew install aria2 mkvtoolnix mediainfogit clone <repository-url>
cd subxtractpython -m venv .venv
# On Windows
.venv\Scripts\activate
# On Linux/macOS
source .venv/bin/activatepip install -r requirements.txtRename .env.example file to .env and edit it:
# Discord Bot Token (required)
DISCORD_TOKEN=your_discord_bot_token_here
APP_ID=your_bot_app_id_here
# Aria2 RPC Configuration
ARIA2_RPC_HOST=http://localhost
ARIA2_RPC_PORT=6800
ARIA2_RPC_SECRET=
# Directory Configuration
TEMP_DIR=./data/temp
DOWNLOAD_DIR=./data/temp/downloads
EXTRACT_DIR=./data/temp/extracted
SCHEMAS_DIR=./schemas
# Data Files
ALLOWED_CHANNELS_FILE=./data/allowed_channels.json
CURRENT_DL_FILE=./data/current_download.json
QUEUE_FILE=./data/queue.json# Basic command
aria2c --enable-rpc --rpc-listen-all=false --rpc-listen-port=6800
# With secret (recommended)
aria2c --enable-rpc --rpc-listen-all=false --rpc-listen-port=6800 --rpc-secret=your_secret_here
# With additional options
aria2c --enable-rpc --rpc-listen-all=false --rpc-listen-port=6800 \
--max-connection-per-server=16 --split=16 --min-split-size=1M
# Using aria2.conf file
aria2c --conf-path="./config/aria2.conf"mkdir -p data schemas temp/downloads temp/extractedpython bot.py/allow_channel- Allow bot commands in the current channel/disallow_channel- Disallow bot commands in the current channel
/extract <url>- Download and extract content from MKV file(s)- Supports: Torrent files, magnet links, direct download URLs
/queue- View your current download queue/add_to_queue <url>- Add a URL to your download queue/remove_from_queue <url>- Remove a URL from your queue/clear_queue- Clear your entire queue/start_queue- Process all items in your queue
/status- Check current download status/stop_all- Stop the current download/extraction/force_stop_all- Force stop all operations and clean up
subxtract/
├── bot.py # Main bot entry point
├── config.py # Configuration management
├── requirements.txt # Python dependencies
├── extensions/ # Discord bot command extensions
│ ├── extractor.py # Main extraction command
│ ├── queue.py # Queue display
│ ├── add_to_queue.py # Add to queue
│ ├── remove_from_queue.py # Remove from queue
│ ├── clear_queue.py # Clear queue
│ ├── start_queue.py # Start processing queue
│ ├── allow_channel.py # Channel permission management
│ ├── disallow_channel.py # Remove channel permissions
│ ├── status.py # Download status
│ ├── stop_all.py # Stop operations
│ └── force_stop_all.py # Force stop operations
├── utils/ # Utility modules
│ ├── aria2_service.py # Aria2 download management
│ ├── mkv_service.py # MKV file operations
│ ├── file_utils.py # File and data management
│ ├── controller.py # Cancellation event management
│ ├── logger.py # Logging configuration
│ └── utils.py # General utilities
├── gen_types/ # Generated type definitions
│ └── mkvmerge_return_type.py
├── schemas/ # JSON schemas for validation
│ └── mkvmerge_schema.json
├── data/ # Runtime data storage
│ ├── allowed_channels.json # Channel permissions
│ ├── current_download.json # Active download state
│ └── queue.json # User download queues
└── temp/ # Temporary files
├── downloads/ # Downloaded files
└── extracted/ # Extracted content
-
Download Phase:
- User submits a URL via
/extractcommand - Aria2 downloads the content (supports torrents, magnets, direct links)
- Bot tracks and displays real-time progress
- Supports cancellation at any point
- User submits a URL via
-
Extraction Phase:
- Scans downloaded files for MKV containers
- Extracts subtitles, attachments, chapters, and metadata
- Packages extracted content into zip files
- Splits large files to meet Discord's upload limit
-
Upload Phase:
- Uploads extracted content to Discord
- Provides merge commands for split files
- Displays extraction statistics
-
Cleanup:
- Removes temporary files
- Clears Aria2 download list
- Resets state for next operation
| Variable | Description | Default |
|---|---|---|
DISCORD_TOKEN |
Discord bot token | Required |
APP_ID |
APP ID | Required |
ARIA2_RPC_HOST |
Aria2 RPC host | http://localhost |
ARIA2_RPC_PORT |
Aria2 RPC port | 6800 |
ARIA2_RPC_SECRET |
Aria2 RPC secret token | YOUR_RPC_SECRET |
TEMP_DIR |
Temporary files directory | ./data/temp |
DOWNLOAD_DIR |
Download storage directory | ./data/temp/downloads |
EXTRACT_DIR |
Extraction output directory | ./data/temp/extracted |
SCHEMAS_DIR |
JSON schemas directory | ./schemas |
ALLOWED_CHANNELS_FILE |
Channel permissions file | ./data/allowed_channels.json |
CURRENT_DL_FILE |
Current download state file | ./data/current_download.json |
QUEUE_FILE |
User queues file | ./data/queue.json |
Create a new extension in the extensions/ directory:
from interactions import Extension, SlashContext, slash_command, check
from utils.utils import is_allowed_channel
class MyCommand(Extension):
@slash_command()
@check(is_allowed_channel)
async def mycommand(self, ctx: SlashContext):
"""Command description"""
await ctx.send("Hello!")
def setup(bot):
MyCommand(bot)The bot automatically loads all extensions in the extensions/ directory.
The project uses a custom logger accessible via:
from utils.logger import get_logger
logger = get_logger("module_name")
logger.info("Info message")
logger.error("Error message")- Verify the bot is running and connected
- Check that the channel is allowed via
/allow_channel - Ensure the bot has proper Discord permissions
- Verify Aria2 RPC server is running
- Check
ARIA2_RPC_HOSTandARIA2_RPC_PORTconfiguration - Ensure
ARIA2_RPC_SECRETmatches if set
- Verify MKVToolNix (
mkvmerge,mkvextract) is installed - Verify MediaInfo is installed
- Check that all tools are in system PATH
- Files larger than 10MB are automatically split
- Use the provided merge commands to reassemble split files
Add your license information here
Add contribution guidelines here
Add support contact information here