Skip to content

Uploading an NZB Using the API

You can streamline NZB uploads by leveraging the NZBs.in API instead of using the web interface. Below are the details and instructions for automating this process using Python, cURL, or a Bash wrapper.

1. Parameters

Mandatory

  • category:: anime, apps, books, movies, music, tv-shows, xxx.
  • nzb:
    • Type: File
    • Format: .nzb
    • Maximum Size: 20MB

Optional

  • name:
    If not provided, the API defaults to the file name of the NZB as the release name. To ensure proper parsing and accurate metadata, name your NZB files correctly or explicitly provide a relevant release name.

  • screenshots:

    • Type: A list of URLs or a comma-separated string pointing to image files.
    • Accepted Formats: .jpg, .png
    • Purpose: Provide visual previews or context for the NZB content.
    • Quantity: Up to 10 URLs can be included.
    • Order: Screenshots are processed in the sequence provided.
  • mediainfo:

    • Type: A .txt file containing Mediainfo's text output.
    • Maximum Size: 2MB
    • Requirement: Ensure the file matches Mediainfo's standard text output format.
  • nfo:

    • Type: A plain text file.
    • Maximum Size: 2MB
    • Format: ASCII/text.
    • Purpose: Provide additional metadata or release details.

2. Python Example

The following Python function demonstrates how to upload an NZB file using the API:

python
import os
import requests
import argparse

# Configuration
API_URL = "https://v2.nzbs.in/api/v1/nzb/upload"  # Base API URL
API_TOKEN = "YOUR_API_TOKEN"                      # Replace with your actual API token

def upload_nzb_v2(*, nzb_file, category, release_name=None, screenshots=None, mediainfo=None, nfo=None):
    """
    Upload an NZB file to NZBs.in using their API.
    """
    try:
        # Check if the NZB file exists
        if not os.path.isfile(nzb_file):
            print(f"NZB file not found: {nzb_file}")
            return False

        # Determine the release name if not provided
        if not release_name:
            release_name = os.path.splitext(os.path.basename(nzb_file))[0]

        # Prepare the request payload
        files = {
            "nzb": open(nzb_file, 'rb')
        }
        data = {
            "category": category,
            "name": release_name,
        }

        # Add optional files
        if mediainfo and os.path.isfile(mediainfo):
            files["mediainfo"] = open(mediainfo, 'rb')
        if nfo and os.path.isfile(nfo):
            files["nfo"] = open(nfo, 'rb')

        # Add optional screenshots
        if screenshots:
            if isinstance(screenshots, list):
                data["screenshots[]"] = ",".join(screenshots)
            else:
                data["screenshots[]"] = screenshots

        # Send the request to the NZBs.in API
        response = requests.post(
            url=API_URL,
            headers={
                "Authorization": f"Bearer {API_TOKEN}",
                "Accept": "application/json",
            },
            files=files,
            data=data,
        )

        # Parse the response
        response_data = response.json()
        if response_data.get('success'):
            print("Upload successful:", response_data['success'])
            return True
        else:
            print("Upload failed:", response_data)
            return False
    except Exception as e:
        print(f"An error occurred: {e}")
        return False

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Upload an NZB file using the NZBs.in API.")
    parser.add_argument("--nzb", required=True, help="Path to the NZB file")
    parser.add_argument("--category", required=True, help="Category of the NZB (e.g., movies, tv-shows)")
    parser.add_argument("--name", help="Optional release name")
    parser.add_argument("--screenshots", help="Optional comma-separated list of screenshot URLs")
    parser.add_argument("--mediainfo", help="Optional path to the Mediainfo file")
    parser.add_argument("--nfo", help="Optional path to the NFO file")

    args = parser.parse_args()

    upload_nzb_v2(
        nzb_file=args.nzb,
        category=args.category,
        release_name=args.name,
        screenshots=args.screenshots.split(",") if args.screenshots else None,
        mediainfo=args.mediainfo,
        nfo=args.nfo,
    )

1. Basic upload:

bash
python upload_nzb.py --nzb /path/to/file.nzb --category movies

2. Upload with Optional Parameters:

bash
python upload_nzb.py --nzb /path/to/file.nzb \
                     --category tv-shows \
                     --name "My Custom Release" \
                     --screenshots "https://screenshot1.jpg,https://screenshot2.png" \
                     --mediainfo /path/to/mediainfo.txt \
                     --nfo /path/to/nfo.txt

3. cURL Example

Use the following cURL command to upload an NZB file via the API:

bash
curl -X POST "https://v2.nzbs.in/api/v1/nzb/upload" \
     -H "Authorization: Bearer YOUR_API_TOKEN" \
     -H "Accept: application/json" \
     -F "nzb=@path/to/your/file.nzb" \
     -F "name=my_release_name" \
     -F "category=movies" \
     -F "screenshots[]=https://screenshot_1.jpg,https://screenshot_2.png" \
     -F "mediainfo=@/path/to/your/file.txt" \
     -F "nfo=@/path/to/your/file.txt"

4. Bash Wrapper Example

bash
#!/bin/bash

# Configuration
API_URL="https://v2.nzbs.in/api/v1/nzb/upload"  # Base API URL
API_TOKEN="YOUR_API_TOKEN"                      # Replace with your actual API token

# Function to upload NZB files via NZBs.in API
upload_nzb() {
  local NZB_FILE=""
  local CATEGORY=""
  local NAME=""
  local SCREENSHOTS=""
  local MEDIAINFO=""
  local NFO=""

  # Parse named parameters
  for ARG in "$@"; do
    case $ARG in
      --nzb=*)
        NZB_FILE="${ARG#*=}"
        shift
        ;;
      --category=*)
        CATEGORY="${ARG#*=}"
        shift
        ;;
      --name=*)
        NAME="${ARG#*=}"
        shift
        ;;
      --screenshots=*)
        SCREENSHOTS="${ARG#*=}"
        shift
        ;;
      --mediainfo=*)
        MEDIAINFO="${ARG#*=}"
        shift
        ;;
      --nfo=*)
        NFO="${ARG#*=}"
        shift
        ;;
      *)
        echo "Unknown argument: $ARG"
        return 1
        ;;
    esac
  done

  # Validate mandatory parameters
  if [ -z "$NZB_FILE" ] || [ -z "$CATEGORY" ]; then
    echo "Error: --nzb and --category are required parameters."
    return 1
  fi

  if [ ! -f "$NZB_FILE" ]; then
    echo "NZB file not found: $NZB_FILE"
    return 1
  fi

  # Use the file name as the release name if NAME is not provided
  if [ -z "$NAME" ]; then
    NAME=$(basename "$NZB_FILE" .nzb)
  fi

  RESPONSE=$(curl -X POST "$API_URL" \
    -H "Authorization: Bearer $API_TOKEN" \
    -H "Accept: application/json" \
    -F "nzb=@${NZB_FILE}" \
    -F "name=${NAME}" \
    -F "category=${CATEGORY}" \
    -F "screenshots[]=${SCREENSHOTS}" \
    -F "mediainfo=@${MEDIAINFO}" \
    -F "nfo=@${NFO}" 2>/dev/null)

  if [[ $RESPONSE == *"\"success\":"* ]]; then
    echo "Upload successful!"
  else
    echo "Upload failed: $RESPONSE"
  fi
}

Example usage:

bash
./upload_nzb.sh --nzb="/path/to/file.nzb" --category="movies" --name="my_release_name" --screenshots="https://screenshot1.jpg,https://screenshot2.png" --mediainfo="/path/to/mediainfo.txt" --nfo="/path/to/nfo.txt"
  • Save the script as upload_nzb.sh.
  • Make it executable: chmod +x upload_nzb.sh

Notes

  1. Uploads are not counted towards your API limits: You can upload files without worrying about exceeding your general API usage quota.
  2. Processing Time: After uploading, it may take a few minutes for the NZB to appear due to processing. There is no need to worry or re-upload.
  3. Error Handling: Add proper error handling in your scripts to account for network issues or invalid responses.
  4. Rate Limiting: To avoid overwhelming the API or triggering abuse protection mechanisms, implement a delay between consecutive uploads. For example, you can add a time.sleep(2) in Python or use the sleep command in Bash between upload requests.

>>Not Y3K Compliant<<