Skip to main content

A standalone Python video downloader toolkit for public platform media and direct streams.

Project description

Bentu Downloader

Bentu Downloader ist eine eigenstaendige Python-Bibliothek und ein Terminal-Programm zum Herunterladen von oeffentlich erreichbaren Videos, direkten Videodateien und einfachen Videostreams.

Das Paket kann auf PyPI veroeffentlicht und danach so installiert werden:

python -m pip install bentu-downloader

Im Python-Code wird es so importiert:

import bentu_downloader

Python erlaubt keine Bindestriche in import-Namen. Deshalb heisst das PyPI-Paket bentu-downloader, aber der Import heisst bentu_downloader.

Features

  • Python-Bibliothek fuer eigene Programme
  • Terminal-Befehl bentu
  • Download von direkten .mp4, .webm, .mov, .m4v-Links
  • Download von direkten Audio-Dateien wie .mp3, .m4a, .aac, .ogg
  • Download von einfachen unverschluesselten .m3u8-Streams
  • HTML-Seiten nach sichtbaren Media-Links durchsuchen
  • Schutz gegen kaputte Downloads: HTML wird nicht als MP4 gespeichert
  • SSL-Unterstuetzung mit normalem Python-SSL und optional certifi
  • Keine benoetigten Drittanbieter-Bibliotheken fuer den Bentu-Kern
  • Open-Source-tauglich mit MIT-Lizenz

Wichtiger Hinweis

Bentu braucht keine andere Downloader-Bibliothek fuer direkte Media-Links und einfache Streams.

Plattformseiten wie YouTube, Instagram oder TikTok sind aber oft zuerst normale HTML-Webseiten. Wenn die Webseite keinen oeffentlichen direkten Media-Link bereitstellt, speichert Bentu keine falsche .mp4, sondern bricht mit einer klaren Fehlermeldung ab.

Bentu umgeht keine Logins, Captchas, Paywalls, DRM, private APIs, geschuetzte Signaturen oder andere Zugriffsschutz-Systeme.

Installation

Von PyPI:

python -m pip install bentu-downloader

Update:

python -m pip install -U bentu-downloader

Aus diesem Repository lokal:

python -m pip install -e .

Schnellstart In Python

import bentu_downloader

result = bentu_downloader.download(
    "https://example.com/video.mp4",
    output="downloads/video.mp4",
)

print("Gespeichert:", result.path)

Mit automatischem Dateinamen:

import bentu_downloader

result = bentu_downloader.download(
    "https://example.com/video.mp4",
    output="downloads/%(title)s.%(ext)s",
)

print(result.path)

Informationen auslesen:

import bentu_downloader

info = bentu_downloader.extract_info("https://example.com/video.mp4")

print(info.title)
print(info.formats)

Terminal Nutzung

Download:

bentu "https://example.com/video.mp4"

Als MP4 speichern:

bentu "https://example.com/video.mp4" -o "downloads/video.mp4"

Mit Titel und Endung:

bentu "https://example.com/video.mp4" -o "downloads/%(title)s.%(ext)s"

Infos anzeigen:

bentu "https://example.com/video.mp4" --print-info

Formate anzeigen:

bentu "https://example.com/video.mp4" --list-formats

Alle Optionen:

bentu --help

YouTube, Instagram Und TikTok Beispiel

Im Ordner examples/social_downloader.py liegt ein aufgeraeumtes Beispielprogramm. Es ist aus dem funktionierenden Testcode entstanden und zeigt ein Menue fuer:

  • YouTube Download
  • Instagram Download
  • TikTok Download

Dieses Beispiel nutzt optional btch-downloader, um fuer diese Plattformen direkte Media-URLs zu bekommen. Bentu selbst bleibt weiterhin eigenstaendig und hat keine Pflicht-Abhaengigkeiten.

Optionale Beispiel-Abhaengigkeiten installieren:

python -m pip install -r examples/requirements-social.txt

Beispiel starten:

python examples/social_downloader.py

Dann erscheint:

Social Downloader
=================
1 YouTube Download
2 Instagram Download
3 TikTok Download

Danach Zahl eingeben, Link einfuegen und Enter druecken. Dateien werden im Ordner downloads/ gespeichert.

Kompakter Code Fuer Eigene Social-Downloader

Dieser Code zeigt das Prinzip aus dem Beispiel: Plattform-API fragen, Media-URL finden, Datei speichern.

from __future__ import annotations

import asyncio
from pathlib import Path
from urllib.parse import unquote, urlparse
from urllib.request import Request, urlopen


DOWNLOAD_DIR = Path("downloads")


async def fetch_platform_info(platform: str, url: str):
    import btch_downloader

    fn_name = {
        "youtube": "youtube",
        "instagram": "igdl",
        "tiktok": "ttdl",
    }[platform]

    result = getattr(btch_downloader, fn_name)(url)
    if hasattr(result, "__await__"):
        result = await result
    return result


def extract_media_urls(platform: str, result) -> list[str]:
    urls: list[str] = []

    if platform == "youtube" and isinstance(result, dict):
        for key in ("mp4", "mp3"):
            value = result.get(key)
            if isinstance(value, str) and value.startswith(("http://", "https://")):
                urls.append(value)

    elif platform == "tiktok" and isinstance(result, dict):
        for key in ("video", "audio"):
            value = result.get(key)
            if isinstance(value, str) and value.startswith(("http://", "https://")):
                urls.append(value)

    elif platform == "instagram":
        if isinstance(result, list):
            for item in result:
                if isinstance(item, dict):
                    value = item.get("url")
                    if isinstance(value, str) and value.startswith(("http://", "https://")):
                        urls.append(value)
        elif isinstance(result, dict):
            value = result.get("url")
            if isinstance(value, str) and value.startswith(("http://", "https://")):
                urls.append(value)

    return list(dict.fromkeys(urls))


def sanitize_filename(value: str) -> str:
    cleaned = "".join("_" if char in '\\/:*?"<>|\n\r\t' else char for char in value)
    cleaned = " ".join(cleaned.split()).strip(". ")
    return cleaned[:120] or "download"


def build_target_path(title: str, media_url: str, index: int) -> Path:
    parsed = urlparse(media_url)
    suffix = Path(unquote(parsed.path)).suffix.lower()
    if not suffix or len(suffix) > 8:
        suffix = ".mp4"

    safe_title = sanitize_filename(title)
    if index > 1:
        safe_title = f"{safe_title}_{index}"
    return DOWNLOAD_DIR / f"{safe_title}{suffix}"


def download_file(media_url: str, target: Path) -> int:
    request = Request(media_url, headers={"User-Agent": "Mozilla/5.0"})
    target.parent.mkdir(parents=True, exist_ok=True)

    bytes_written = 0
    with urlopen(request, timeout=60.0) as response, target.open("wb") as output:
        while True:
            chunk = response.read(1024 * 256)
            if not chunk:
                break
            output.write(chunk)
            bytes_written += len(chunk)
    return bytes_written


def extract_title(platform: str, result) -> str:
    if isinstance(result, dict):
        title = result.get("title")
        if isinstance(title, str) and title.strip():
            return title.strip()
    return f"{platform}_download"


def download_platform_video(platform: str, url: str) -> None:
    DOWNLOAD_DIR.mkdir(parents=True, exist_ok=True)
    result = asyncio.run(fetch_platform_info(platform, url))
    media_urls = extract_media_urls(platform, result)

    if not media_urls:
        raise RuntimeError("Keine direkte Media-URL gefunden.")

    title = extract_title(platform, result)
    for index, media_url in enumerate(media_urls, start=1):
        target = build_target_path(title, media_url, index)
        bytes_written = download_file(media_url, target)
        print(f"Fertig: {target} ({bytes_written} Bytes)")


if __name__ == "__main__":
    download_platform_video("youtube", "https://www.youtube.com/watch?v=VIDEO_ID")

Fuer das komplette Menue-Programm nutze examples/social_downloader.py.

Bentu Als Fallback Verwenden

Wenn du schon eine URL hast, kannst du Bentu direkt verwenden:

import bentu_downloader

result = bentu_downloader.download(
    "https://example.com/video.mp4",
    output="downloads/%(title)s.%(ext)s",
    overwrite=True,
)

print(result.path)

Fehler: HTML Statt Video

Wenn diese Meldung erscheint:

The server returned HTML, not a media file.

dann hat der Server eine Webseite geliefert, keine echte Media-Datei. Bentu speichert diese Webseite nicht als MP4, weil die Datei sonst kaputt waere.

Moegliche Loesungen:

  • direkten .mp4-, .webm- oder .m3u8-Link verwenden
  • bentu URL --print-info ausfuehren
  • bei Seiten mit Referer-Schutz --add-header "Referer:https://example.com/" nutzen
  • fuer Plattformen mit eigener Datenstruktur einen Provider oder ein Social-Beispiel wie oben verwenden

SSL Hinweis

Bentu nutzt automatisch den normalen Python-SSL-Kontext. Wenn certifi installiert ist, nutzt Bentu automatisch dessen Zertifikate.

python -m pip install certifi

Projektstruktur

.
├── LICENSE
├── README.md
├── pyproject.toml
├── examples/
│   ├── requirements-social.txt
│   └── social_downloader.py
├── scripts/
│   └── bump_version.py
├── src/
│   ├── bentu/
│   └── bentu_downloader/
└── tests/

Tests

python -m unittest discover -s tests

Paket Bauen

Jeder PyPI-Upload braucht eine neue Versionsnummer. Eine Version, die schon bei PyPI liegt, kann nicht noch einmal hochgeladen werden.

Version erhoehen:

python scripts/bump_version.py 0.1.5

Alte Build-Dateien loeschen:

rm -rf dist build

Bauen:

python -m pip install build
python -m build

Hochladen:

python -m pip install twine
python -m twine upload dist/*

GitHub Veroeffentlichung

  1. Repository auf GitHub erstellen.
  2. Platzhalter in pyproject.toml ersetzen:
Homepage = "https://github.com/YOUR_USERNAME/bentu-downloader"
Repository = "https://github.com/YOUR_USERNAME/bentu-downloader"
Issues = "https://github.com/YOUR_USERNAME/bentu-downloader/issues"
  1. Dateien committen:
git add .
git commit -m "Initial open source release"
git branch -M main
git remote add origin https://github.com/YOUR_USERNAME/bentu-downloader.git
git push -u origin main

Lizenz

Dieses Projekt steht unter der MIT-Lizenz. Siehe LICENSE.

Rechtlicher Hinweis

Lade nur Inhalte herunter, fuer die du die Rechte oder eine Erlaubnis hast. Bentu ist fuer legale Downloads, eigene Inhalte, erlaubte Medien, direkte Media-Links und oeffentliche Streams gedacht.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bentu_downloader-0.1.4.tar.gz (24.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bentu_downloader-0.1.4-py3-none-any.whl (22.5 kB view details)

Uploaded Python 3

File details

Details for the file bentu_downloader-0.1.4.tar.gz.

File metadata

  • Download URL: bentu_downloader-0.1.4.tar.gz
  • Upload date:
  • Size: 24.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for bentu_downloader-0.1.4.tar.gz
Algorithm Hash digest
SHA256 64909fda8d9e8bb4c2ff74387fa7687f3238f11e258ea4b73304ee7ab6ac091f
MD5 46bdd2aa692c54e18cddc11354a29bcd
BLAKE2b-256 cbe78b721f70e4d7499fe2ec796642300b9d9c9c5423f7b3028f9cfa6c99a2a2

See more details on using hashes here.

File details

Details for the file bentu_downloader-0.1.4-py3-none-any.whl.

File metadata

File hashes

Hashes for bentu_downloader-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 8e9bbac95b3d9cd01e98460607bf9ae864f8183a3c704af899f20c88d75ccd56
MD5 7f3d30963b5aca0f6f6ee48d710477b5
BLAKE2b-256 e74623cf7320e79a9defb16601db9b90e231ce36ea4dabc62238ab56c0afbb55

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page