Skip to content

LorenBll/YoutubeDownloader

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

YoutubeDownloader

A production-ready REST API service that downloads single YouTube videos as MP4 or MP3, with asynchronous job tracking and batch support.

Table of Contents

Features

  • MP4 (video) and MP3 (audio) support
  • Batch request support via videos array
  • YouTube URL validation (youtube.com/youtu.be only)
  • Playlist URLs rejected (single videos only)
  • Permission and disk space error handling
  • In-memory task retention with automatic cleanup worker
  • Uses pytubefix first, falls back to pytube
  • Auto-startup configuration for Windows, Linux, and macOS
  • Asynchronous task processing with non-blocking API responses

Architecture

The service uses a simple but effective architecture:

  1. Flask Web Server: Handles HTTP requests and responses
  2. Background Workers: Separate threads process downloads asynchronously
  3. In-Memory Storage: Tasks are stored in a thread-safe dictionary
  4. Cleanup Worker: Daemon thread removes old completed/failed downloads
  5. Configuration-Driven: All settings loaded from JSON file
┌─────────────┐
│   Client    │
└──────┬──────┘
       │ HTTP Request
       ▼
┌──────────────────────┐
│   Flask Routes       │
│  - POST /api/download│
│  - GET /api/download/id │
│  - GET /api/health   │
└──────┬───────────────┘
       │
       ▼
┌──────────────────────┐
│  Task Queue          │
│  (In-Memory Dict)    │
└──────┬───────────────┘
       │
       ▼
┌──────────────────────┐
│  Worker Threads      │
│  - Download videos   │
│  - Update status     │
└──────────────────────┘

Project Structure

YoutubeDownloader/
├─ src/
│  └─ main.py                       # Main Flask application
├─ scripts/
│  ├─ run.bat                       # Windows run script
│  ├─ run.sh                        # Unix run script
│  ├─ setup.bat                     # Windows setup script
│  └─ setup.sh                      # Unix setup script
├─ deployment/
│  ├─ startup-windows.vbs           # Windows auto-startup wrapper
│  ├─ service.service               # Linux systemd service file
│  └─ com.service.plist             # macOS launchd configuration
├─ resources/
│  └─ configuration.json            # Service configuration
├─ requirements.txt                 # Python dependencies
├─ LICENSE
└─ README.md

Installation

Prerequisites

  • Python 3.10 or newer
  • Windows, macOS, or Linux

Quick start

  1. Clone the repository:

    git clone https://github.com/LorenBll/youtube-downloader.git
    cd youtube-downloader
  2. Make the run script executable (macOS/Linux only):

    chmod +x scripts/run.sh
  3. Run the application:

    • Windows:
      scripts\run.bat
    • macOS/Linux:
      ./scripts/run.sh

By default, the service starts in the background. To see real-time output and debug information, use the --verbose flag:

  • Windows:
    scripts\run.bat --verbose
  • macOS/Linux:
    ./scripts/run.sh --verbose

The run scripts create a virtual environment and install dependencies on first run.

Manual execution

If you prefer to manage the environment yourself:

  1. Create and activate a virtual environment:

    python -m venv .venv
    # Windows
    .venv\Scripts\activate
    # macOS/Linux
    source .venv/bin/activate
  2. Install dependencies:

    pip install -r requirements.txt
  3. Run the API:

    python src/main.py

The API binds to 127.0.0.1:49153 by default.

Configuration

Configuration is loaded from resources/configuration.json. It supports three modes:

  • private: Local-only service with no authentication
  • unprivate: Requires API keys for protected endpoints
  • public: No authentication and intended for LAN access

Example structure:

{
   "defaultMode": "private",
   "private": {"ip": "127.0.0.1", "port": 49153},
   "unprivate": {"ip": "127.0.0.1", "port": 49153, "keylist": ["your-key"]},
   "public": {"ip": "0.0.0.0", "port": 49153}
}

Optional environment variables:

  • TASK_RETENTION_MINUTES (default 30): How long completed/failed tasks stay in memory
  • TASK_CLEANUP_INTERVAL_SECONDS (default 60): Cleanup worker interval
  • FFMPEG_PATH (optional): Full path to the ffmpeg executable

Run and service modes

Background mode

The run scripts start the service in the background without displaying a terminal window.

  • Background mode (default): Terminal closes after startup
  • Verbose mode: Use --verbose to keep the terminal open

Verify the service is running:

curl http://127.0.0.1:49153/api/health

Auto-startup configuration

Use the files in deployment/ to start the service automatically on boot:

  • Windows: deployment/startup-windows.vbs (place in Startup folder)
  • Linux: deployment/service.service (systemd)
  • macOS: deployment/com.service.plist (launchd)

API reference

Authentication (unprivate mode only)

Provide the API key in the request body or query string:

  • POST requests: include api_key in the JSON body
  • GET requests: add ?api_key=<api-key> to the URL

Example (POST):

{
   "api_key": "your-key",
   "video_link": "https://www.youtube.com/watch?v=...",
   "format": "mp4",
   "quality": "720p",
   "folder": "C:/Downloads",
   "name": "optional-file-name"
}

Example (GET):

GET /api/download/<task_id>?api_key=your-key

POST /api/download

Create a new async download task.

Single-item payload:

{
   "api_key": "your-key",
   "video_link": "https://www.youtube.com/watch?v=...",
   "format": "mp4",
   "quality": "720p",
   "folder": "C:/Downloads",
   "name": "optional-file-name"
}

Batch payload:

{
   "api_key": "your-key",
   "videos": [
      {
         "video_link": "https://www.youtube.com/watch?v=...",
         "format": "mp3",
         "quality": "128kbps",
         "folder": "C:/Downloads"
      }
   ]
}

Response (202):

{
   "task_id": "uuid",
   "status": "queued"
}

Batch response (202):

{
   "task_id": "uuid",
   "status": "queued",
   "video_count": 1
}

Notes:

  • quality is normalized: mp4 expects values like 720p (or digits like 720), mp3 expects 128kbps (or digits like 128).
  • Playlist URLs are rejected.

GET /api/download/<task_id>

Returns task status (queued, in_progress, completed, failed) and result/error payload.

Success response (single item, completed):

{
   "task_id": "uuid",
   "status": "completed",
   "result": {
      "name": "My Video",
      "format": "mp4",
      "requested_quality": "720p",
      "actual_quality": "720p",
      "save_path": "C:/Downloads/My Video.mp4"
   }
}

Success response (batch, completed):

{
   "task_id": "uuid",
   "status": "completed",
   "result": {
      "items": [
         {
            "index": 0,
            "status": "completed",
            "result": {
               "name": "Track",
               "format": "mp3",
               "requested_quality": "128kbps",
               "actual_quality": "128kbps",
               "save_path": "C:/Downloads/Track.mp3"
            }
         }
      ],
      "summary": {
         "total": 1,
         "completed": 1,
         "failed": 0
      }
   }
}

Failed response (failed):

{
   "task_id": "uuid",
   "status": "failed",
   "error": "Invalid API key."
}

GET /api/health

Health report including bind/port, task counts, retention settings, and active YouTube client.

Notes and limitations

  • Playlist URLs are intentionally rejected.
  • MP4 uses progressive streams up to 720p. Higher qualities use separate video/audio streams that are merged with ffmpeg.
  • Task data is in-memory and cleared on process restart.

Install ffmpeg

High-quality MP4 downloads (above 720p) require ffmpeg to merge video and audio streams.

Windows

  1. Download the Release full build from https://www.gyan.dev/ffmpeg/builds/
  2. Extract the zip (for example: C:\ffmpeg)
  3. Add C:\ffmpeg\bin to your PATH
  4. Open a new terminal and run:
    ffmpeg -version

macOS (Homebrew)

brew install ffmpeg
ffmpeg -version

Linux (Ubuntu/Debian)

sudo apt update
sudo apt install ffmpeg
ffmpeg -version

Troubleshooting

"Address already in use"

  • Another process is using the configured port
  • Update resources/configuration.json to use a different port

"Permission denied"

  • On Linux/macOS, ports below 1024 require root privileges
  • Use a port >= 1024 or run with sudo if necessary

"Cannot create or access download folder"

  • The folder does not exist or is not writable
  • Ensure the folder exists and your user account has write access
  • Check available disk space

"Cannot write file"

  • Verify the output folder path is valid and accessible
  • Check disk space; YouTube videos can require large temporary space
  • On Windows, avoid paths over 260 characters

Usage examples

Download a video

curl -X POST http://localhost:49153/api/download \
  -H "Content-Type: application/json" \
YoutubeDownloader/
├── src/
│   └── main.py                     # Main Flask application
├── scripts/
│   ├── run.bat                     # Windows run script
│   ├── run.sh                      # Unix run script
│   ├── setup.bat                   # Windows setup script
│   └── setup.sh                    # Unix setup script
├── deployment/
│   ├── startup-windows.vbs         # Windows auto-startup wrapper
│   ├── service.service             # Linux systemd service file
│   └── com.service.plist           # macOS launchd configuration
├── resources/
│   └── configuration.json          # Service configuration
├── requirements.txt                # Python dependencies
├── LICENSE
├── SECURITY.md
└── README.md
curl -X POST http://localhost:49153/api/download \
  -H "Content-Type: application/json" \
  -d '{
    "videos": [
      {
        "video_link": "https://www.youtube.com/watch?v=VIDEO1",
        "format": "mp4",
        "quality": "720p",
        "folder": "/Users/username/Downloads"
      },
      {
        "video_link": "https://www.youtube.com/watch?v=VIDEO2",
        "format": "mp3",
        "quality": "128kbps",
        "folder": "/Users/username/Downloads"
      }
    ]
  }'

License

The Unlicense - See LICENSE file for details

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Test thoroughly
  5. Submit a pull request

Support

For issues, questions, or contributions:

  • Open an issue on GitHub
  • Check existing issues for solutions
  • Provide detailed information about your environment
  • Include logs from --verbose mode when reporting issues

About

Local Flask API for asynchronous YouTube video downloads (mp4/mp3) with background service support and auto-startup configs. Designed for integration with desktop apps and automation workflows.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Contributors