# pybalt [![cobalt.tools](https://img.shields.io/badge/wrapper/cli-gray.svg?logo=data:image/jpeg;base64, )](https://cobalt.tools)  [![Get on PyPI](https://img.shields.io/pypi/v/pybalt.svg)](https://pypi.org/project/pybalt/) [![Pip module installs total downloads](https://img.shields.io/pypi/dm/pybalt.svg)](https://pypi.org/project/pybalt/) [![cobalt.tools](https://img.shields.io/badge/made%20by-nichind-white.svg)](https://nichind.dev) [![https://github.com/nichind/pybalt](https://img.shields.io/github/stars/nichind/pybalt)](https://github.com/nichind/pybalt)

[![Run Tests](https://github.com/nichind/pybalt/actions/workflows/build.yml/badge.svg)](https://github.com/nichind/pybalt/actions/workflows/build.yml) [![Upload Python Package to PyPI when a Release is Created](https://github.com/nichind/pybalt/actions/workflows/publish.yml/badge.svg)](https://github.com/nichind/pybalt/actions/workflows/publish.yml)

<img src="./assets/cli-preview2.gif" align="right" alt="pybalt cli preview gif" height="240">

### Features

**pybalt** is a powerful and flexible tool for downloading media files from various platforms, including YouTube, X (formerly Twitter), Reddit, Instagram, TikTok, and more. It works using [cobalt processing instances](https://github.com/imputnet/cobalt) and serves both as a CLI and a Python module.

* Download media files to your desktop effortlessly using pybalt as a [**command-line interface**](#%EF%B8%8F-quickstart)
* Support for [**playlists**, **bulk downloads**, and processing **links from text files**](#%EF%B8%8F-quickstart)
* Runable [**web api**](#-api-server) that allows to try multiple instances at once for best latency
* Integrate pybalt into your Python projects with ease with [**just a few lines of code**](#-python-module-integration)
* [**Host your own local cobalt instance**](#%EF%B8%8F-local-instance) for improved privacy and reliability
* [**Customize configuration**](#%EF%B8%8F-configuration-system) with environment variables or the built-in config system

https://github.com/user-attachments/assets/cf5fd9a9-520b-4970-b8c2-42baa80d7523

# ⚙️ Installation

Install pybalt with pip:

```sh
pip install pybalt -U
```

Or install pybalt on Windows with the [bat file](./install.bat) included in the repo (if you don't have Python installed):

1. Open PowerShell or Command Prompt with administrator rights (to allow pip to create aliases `cobalt` and `pybalt` in the terminal, and install python if needed)
2. Type this command:

```sh
powershell -Command "Invoke-WebRequest -Uri https://raw.githubusercontent.com/nichind/pybalt/main/install.bat -OutFile install.bat; .\install.bat"
```

# ⚡️ Quickstart

> [!NOTE]
> pybalt will automatically detect if you're running a local cobalt instance and use it first before trying public instances.

> [!NOTE]
> If the `cobalt` alias isn't working in your terminal, use `python -m pybalt <command>` instead.

> [!CAUTION]
> Remuxing (`-r`) requires ffmpeg to be installed on your device and added to your system path.

## Command Line Usage

The CLI is intuitive and easy to use! Here are some examples:

1. Download a YouTube video at maximum resolution (`-vQ max`) and remux it (`-remux`):
```sh
cobalt "https://youtube.com/watch?v=DG2QqcHwNdE" -remux -vQ max
```

2. Remux an existing video file:
```sh
cobalt "C:/Users/username/Videos/video.mp4"
```

3. Download multiple videos from links in a text file:
```sh
cobalt "path/to/links.txt"
```

4. Download a video and open it immediately:
```sh
cobalt "https://youtube.com/watch?v=DG2QqcHwNdE" -o
```

5. Download a video and show it in File Explorer/Finder:
```sh
cobalt "https://youtube.com/watch?v=DG2QqcHwNdE" -s
```

6. Specify quality, format, and download location:
```sh
cobalt "https://youtube.com/watch?v=DG2QqcHwNdE" -vQ 1080 -aF mp3 --audioBitrate 320 -fp "C:/Downloads"
```

Use `cobalt -h` to see all available options.

## Managing Instances

pybalt can work with multiple cobalt instances, including your own local instance:

1. List configured instances:
```sh
cobalt -li
```

2. Add a new instance:
```sh
cobalt -ai "https://example-instance.com" "optional-api-key"
```

3. Remove an instance:
```sh
cobalt -ri 1
```

## Local Instance Management

Run your own cobalt instance with Docker:

1. Set up a local instance:
```sh
cobalt -ls
```

2. Start/stop your local instance:
```sh
cobalt -lstart
cobalt -lstop
```

3. Check local instance status:
```sh
cobalt -lstatus
```

# 💻 Python Module Integration

pybalt can be easily integrated into your Python projects:

## Basic Download

```python
from pybalt import download
from asyncio import run

async def main():
    # Simple download with default settings
    file_path = await download("https://youtube.com/watch?v=DG2QqcHwNdE")
    print(f"Downloaded to: {file_path}")
    
    # Download with custom parameters
    file_path = await download(
        "https://youtube.com/watch?v=DG2QqcHwNdE",
        videoQuality="1080",
        audioFormat="mp3",
        audioBitrate="320",
        filenameStyle="pretty",
        remux=True
    )
    print(f"Downloaded to: {file_path}")

run(main())
```

## Advanced Usage with InstanceManager

```python
from pybalt.core.wrapper import InstanceManager
from asyncio import run

async def main():
    # Create an instance manager
    manager = InstanceManager(debug=True)
    
    # Get a list of available instances
    instances = await manager.get_instances()
    print(f"Found {len(instances)} available instances")
    
    # Download a file using the first available instance
    file_path = await manager.download(
        url="https://youtube.com/watch?v=DG2QqcHwNdE",
        videoQuality="1080",
        remux=True
    )
    print(f"Downloaded to: {file_path}")
    
    # Bulk download multiple URLs
    urls = [
        "https://youtube.com/watch?v=DG2QqcHwNdE",
        "https://youtube.com/watch?v=anotherVideo"
    ]
    
    # Download multiple files concurrently
    async for path in manager.download_generator(urls=urls, remux=True):
        print(f"Downloaded: {path}")

run(main())
```

## Track Download Progress

```python
from pybalt import download
from asyncio import run

async def main():
    # Define a status callback function
    async def status_callback(downloaded_size, total_size, download_speed, eta, **kwargs):
        percent = (downloaded_size / total_size * 100) if total_size > 0 else 0
        print(f"Downloaded: {downloaded_size / 1024 / 1024:.2f}MB / "
              f"{total_size / 1024 / 1024:.2f}MB ({percent:.1f}%) at "
              f"{download_speed / 1024 / 1024:.2f}MB/s, ETA: {eta:.0f}s")
    
    # Define a completion callback
    async def done_callback(file_path, downloaded_size, time_passed, **kwargs):
        print(f"Download completed in {time_passed:.2f}s")
        print(f"File saved to: {file_path}")
    
    # Download with progress tracking
    file_path = await download(
        "https://youtube.com/watch?v=DG2QqcHwNdE",
        status_callback=status_callback,
        done_callback=done_callback
    )

run(main())
```

## Using Status Parent

```python
from pybalt import download
from asyncio import run, create_task

class StatusParent:
    def __init__(self):
        self.downloaded_size = 0
        self.total_size = 0
        self.download_speed = 0
        self.eta = 0
        self.completed = False
        self.file_path = None

async def main():
    # Create status parent object to track progress
    status = StatusParent()
    
    # Start download as a background task
    task = create_task(download(
        "https://youtube.com/watch?v=DG2QqcHwNdE",
        status_parent=status
    ))
    
    # Monitor progress while download is running
    while not task.done():
        if status.total_size > 0:
            percent = status.downloaded_size / status.total_size * 100
            print(f"Progress: {percent:.1f}% - Speed: {status.download_speed / 1024 / 1024:.2f}MB/s")
        await run(sleep(1))
    
    # Get the result
    file_path = await task
    print(f"Downloaded to: {file_path}")

run(main())
```

# ⚙️ Configuration System

pybalt features a comprehensive configuration system for customizing behavior:

## Command-line Configuration Interface

Open the interactive configuration interface:

```sh
cobalt -c
```

Get a specific configuration value:

```sh
cobalt -gc "network" "timeout"
```

Set a configuration value:

```sh
cobalt -sc "network" "timeout" "30"
```

## Configuration File Locations

- **Windows**: `%APPDATA%\pybalt\settings.ini`
- **macOS**: `~/Library/Application Support/pybalt/settings.ini`
- **Linux**: `~/.config/pybalt/settings.ini`

## Main Configuration Sections

- **general**: General settings like user agent and debug mode
- **network**: Connection settings like timeouts, proxies, and retries
- **instances**: Cobalt instance settings
- **user_instances**: User-defined cobalt instances
- **paths**: Download paths and file locations
- **local**: Local instance configuration
- **ffmpeg**: Remuxing settings
- **display**: UI/progress display settings

# 📦 Environment Variables

You can configure pybalt with environment variables:

```
PYBALT_CONFIG_DIR=path/to/config/dir        # Custom config directory
PYBALT_CONFIG_PATH=path/to/settings.ini     # Custom config file path

# Section-specific settings
PYBALT_GENERAL_DEBUG=True                   # Enable debug mode
PYBALT_GENERAL_USER_AGENT=custom-agent      # Custom user agent

PYBALT_NETWORK_TIMEOUT=30                   # Network timeout
PYBALT_NETWORK_USE_SYSTEM_PROXY=True        # Use system proxy
PYBALT_NETWORK_PROXY=http://my-proxy:8080   # Custom proxy

PYBALT_PATHS_DEFAULT_DOWNLOADS_DIR=/path    # Custom download directory

PYBALT_LOCAL_LOCAL_INSTANCE_PORT=9000       # Local instance port
```

You can also set variables in a `.env` file in your project directory.

# 🛠️ Local Instance

pybalt can set up and manage a local cobalt instance using Docker:

## Setting Up a Local Instance

```sh
cobalt -ls
```

This interactive wizard will guide you through:
- Setting a port for your instance
- Configuring API key authentication (optional)
- Setting duration limits
- Configuring proxy settings
- Setting up cookies for authenticated services

## Managing Your Local Instance

Start your local instance:

```sh
cobalt -lstart
```

Stop your local instance:

```sh
cobalt -lstop
```

Check the status:

```sh
cobalt -lstatus
```

Restart your instance:

```sh
cobalt -lrestart
```

# 🌐 API Server

pybalt includes a built-in API server that allows you to interact with multiple cobalt instances through a single HTTP request. It also provides a web UI for easy downloading.

## Starting the API Server

Start the API server in detached mode:

```sh
cobalt --api-start
```

Specify a custom port (default is 8009):

```sh
cobalt --api-port 8080 --api-start
```

## Managing the API Server

Check if the API server is running:

```sh
cobalt --api-status
```

Stop the running API server:

```sh
cobalt --api-stop
```

## API Endpoints

The API server exposes the following endpoints:

- **GET `/`**: Returns information about the API server, including version and instance count
- **POST `/`**: Accepts a JSON payload with a URL and parameters to download content and returns a JSON response with download information
- **GET `/ui`**: Serves a web-based user interface for downloading content

## Web UI

The API server includes a comprehensive web UI that allows you to:

- Download videos from various platforms through a user-friendly interface
- Configure advanced settings such as video quality, audio format, and file naming
- Track the download progress
- Ignore specific instances that might be causing issues
- Copy direct download links

Access the web UI at `http://localhost:8009/ui` (or your custom port).

## API Usage Examples

### Example API Request:

```bash
curl -X POST "http://localhost:8009/" \
     -H "Content-Type: application/json" \
     -d '{"url": "https://www.youtube.com/watch?v=DG2QqcHwNdE", "videoQuality": "1080", "audioFormat": "mp3"}'
```

### Example API Response:

```json
{
  "status": "tunnel",
  "url": "http://download-link.mp4",
  "instance_info": {
    "url": "https://instance-url.com",
  },
}
```

# 👥 Used by

pybalt is used by the following projects:

- [download.nichind.dev](https://download.nichind.dev) - Website for downloading media files from various platforms

# 👥 Contributors

[![Contributors](https://contrib.rocks/image?repo=nichind/pybalt)](https://github.com/nichind/pybalt/graphs/contributors)

# 🌟 That's it!

I spent too much time on this project... please consider leaving a :star: if you like it!

[![Star History Chart](https://api.star-history.com/svg?repos=nichind/pybalt&type=Date)](https://github.com/nichind/pybalt)