ChartQuery

Erstes Video herunterladen

Senden Sie eine Video-URL, fragen Sie das asynchrone Job-Ergebnis ab und speichern Sie die Datei lokal — vollständige End-to-End-Anleitung mit dem HuntAPI Video-Downloader.

Übersicht

HuntAPI verwendet ein asynchrones Job-Modell: Sie senden eine URL, erhalten eine job_id und fragen dann ab, bis das Video fertig ist. Dieses Playbook führt durch alle drei Schritte und lädt die fertige Datei auf die Festplatte.

Voraussetzungen

  • Einen HuntAPI-Schlüssel — erhalten Sie einen auf app.huntapi.com
  • Installieren Sie die Abhängigkeiten für Ihre Sprache:
pip install requests

Keine zusätzlichen Abhängigkeiten — verwendet die native fetch-API (Node 18+).

curl-Erweiterung aktiviert (standardmäßig).

Keine zusätzlichen Abhängigkeiten — verwendet net/http (Go 1.18+).

Keine zusätzlichen Abhängigkeiten — verwendet java.net.http (Java 11+).

Keine zusätzlichen Abhängigkeiten — verwendet System.Net.Http (.NET 6+).

# Cargo.toml
[dependencies]
reqwest = { version = "0.12", features = ["json", "stream"] }
tokio = { version = "1", features = ["full"] }
serde_json = "1"

Schritte

Download-Job einreichen

Rufen Sie GET /v1/video/download mit dem Parameter url auf. Die Antwort gibt sofort eine job_id zurück.

import requests

API_KEY   = "YOUR_API_KEY"
VIDEO_URL = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

response = requests.get(
    "https://api.huntapi.com/v1/video/download",
    headers={"x-api-key": API_KEY},
    params={"url": VIDEO_URL, "quality": "best"},
)
data   = response.json()
job_id = data["job_id"]
print(f"Job eingereicht: {job_id}")
const API_KEY   = "YOUR_API_KEY";
const VIDEO_URL = "https://www.youtube.com/watch?v=dQw4w9WgXcQ";

const params   = new URLSearchParams({ url: VIDEO_URL, quality: "best" });
const response = await fetch(`https://api.huntapi.com/v1/video/download?${params}`, {
  headers: { "x-api-key": API_KEY },
});
const data  = await response.json();
const jobId = data.job_id;
console.log(`Job eingereicht: ${jobId}`);
<?php
$apiKey   = "YOUR_API_KEY";
$videoUrl = "https://www.youtube.com/watch?v=dQw4w9WgXcQ";

$params = http_build_query(["url" => $videoUrl, "quality" => "best"]);
$ch     = curl_init("https://api.huntapi.com/v1/video/download?{$params}");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-api-key: {$apiKey}"]);
$data  = json_decode(curl_exec($ch), true);
curl_close($ch);
$jobId = $data["job_id"];
echo "Job eingereicht: {$jobId}\n";
package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "net/url"
)

const APIKey   = "YOUR_API_KEY"
const VideoURL = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

func main() {
    params := url.Values{"url": {VideoURL}, "quality": {"best"}}
    req, _ := http.NewRequest("GET", "https://api.huntapi.com/v1/video/download?"+params.Encode(), nil)
    req.Header.Set("x-api-key", APIKey)

    resp, _ := http.DefaultClient.Do(req)
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)

    var data map[string]any
    json.Unmarshal(body, &data)
    jobID := data["job_id"].(string)
    fmt.Println("Job eingereicht:", jobID)
}
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.*;
import java.nio.charset.StandardCharsets;
import org.json.*;

var apiKey   = "YOUR_API_KEY";
var videoUrl = URLEncoder.encode("https://www.youtube.com/watch?v=dQw4w9WgXcQ", StandardCharsets.UTF_8);
var url      = "https://api.huntapi.com/v1/video/download?url=" + videoUrl + "&quality=best";

var client  = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder().uri(URI.create(url))
    .header("x-api-key", apiKey).GET().build();

var response = client.send(request, HttpResponse.BodyHandlers.ofString());
var jobId    = new JSONObject(response.body()).getString("job_id");
System.out.println("Job eingereicht: " + jobId);
using System.Net.Http;
using System.Text.Json;

var apiKey   = "YOUR_API_KEY";
var videoUrl = Uri.EscapeDataString("https://www.youtube.com/watch?v=dQw4w9WgXcQ");

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", apiKey);

var body  = await client.GetStringAsync($"https://api.huntapi.com/v1/video/download?url={videoUrl}&quality=best");
var jobId = JsonDocument.Parse(body).RootElement.GetProperty("job_id").GetString()!;
Console.WriteLine($"Job eingereicht: {jobId}");
use reqwest::Client;
use serde_json::Value;

let client   = Client::new();
let api_key  = "YOUR_API_KEY";
let video_url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ";

let data = client.get("https://api.huntapi.com/v1/video/download")
    .header("x-api-key", api_key)
    .query(&[("url", video_url), ("quality", "best")])
    .send().await?.json::<Value>().await?;

let job_id = data["job_id"].as_str().unwrap();
println!("Job eingereicht: {}", job_id);

Auf das fertige Video warten (Polling)

Überprüfen Sie GET /v1/job/{job_id} alle paar Sekunden. Wenn status zu "done" wird, enthält das Feld download_url die Datei-URL.

import time

def wait_for_job(job_id: str, poll_interval: int = 5, timeout: int = 300) -> dict:
    start = time.time()
    while time.time() - start < timeout:
        r      = requests.get(f"https://api.huntapi.com/v1/job/{job_id}",
            headers={"x-api-key": API_KEY})
        result = r.json()
        status = result.get("status")
        print(f"  Status: {status}")

        if status == "done":
            return result
        if status == "error":
            raise RuntimeError(f"Job fehlgeschlagen: {result.get('error')}")
        time.sleep(poll_interval)

    raise TimeoutError("Job wurde nicht innerhalb des Timeout abgeschlossen.")

result       = wait_for_job(job_id)
download_url = result["download_url"]
print(f"Bereit! Download-URL: {download_url}")
async function waitForJob(jobId: string, pollMs = 5000, timeoutMs = 300_000) {
  const deadline = Date.now() + timeoutMs;

  while (Date.now() < deadline) {
    const res    = await fetch(`https://api.huntapi.com/v1/job/${jobId}`, {
      headers: { "x-api-key": API_KEY },
    });
    const result = await res.json();
    console.log(`  Status: ${result.status}`);

    if (result.status === "done")  return result;
    if (result.status === "error") throw new Error(`Job fehlgeschlagen: ${result.error}`);
    await new Promise(r => setTimeout(r, pollMs));
  }
  throw new Error("Timeout");
}

const result      = await waitForJob(jobId);
const downloadUrl = result.download_url;
console.log(`Bereit! Download-URL: ${downloadUrl}`);
function waitForJob(string $apiKey, string $jobId, int $pollSec = 5, int $timeoutSec = 300): array {
    $start = time();
    while (time() - $start < $timeoutSec) {
        $ch = curl_init("https://api.huntapi.com/v1/job/{$jobId}");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-api-key: {$apiKey}"]);
        $result = json_decode(curl_exec($ch), true);
        curl_close($ch);

        $status = $result["status"] ?? "";
        echo "  Status: {$status}\n";
        if ($status === "done")  return $result;
        if ($status === "error") throw new RuntimeException("Job fehlgeschlagen: " . ($result["error"] ?? ""));
        sleep($pollSec);
    }
    throw new RuntimeException("Timeout");
}

$result      = waitForJob($apiKey, $jobId);
$downloadUrl = $result["download_url"];
echo "Bereit! Download-URL: {$downloadUrl}\n";
import "time"

func waitForJob(apiKey, jobID string) (map[string]any, error) {
    deadline := time.Now().Add(5 * time.Minute)
    for time.Now().Before(deadline) {
        req, _ := http.NewRequest("GET", "https://api.huntapi.com/v1/job/"+jobID, nil)
        req.Header.Set("x-api-key", apiKey)
        resp, _ := http.DefaultClient.Do(req)
        body, _ := io.ReadAll(resp.Body)
        resp.Body.Close()

        var result map[string]any
        json.Unmarshal(body, &result)
        status := result["status"].(string)
        fmt.Println("  Status:", status)

        if status == "done"  { return result, nil }
        if status == "error" { return nil, fmt.Errorf("Job fehlgeschlagen: %v", result["error"]) }
        time.Sleep(5 * time.Second)
    }
    return nil, fmt.Errorf("Timeout")
}

result, err := waitForJob(APIKey, jobID)
if err != nil { panic(err) }
downloadURL := result["download_url"].(string)
fmt.Println("Bereit! Download-URL:", downloadURL)
import java.time.*;

static JSONObject waitForJob(HttpClient client, String apiKey, String jobId) throws Exception {
    var deadline = Instant.now().plusSeconds(300);
    while (Instant.now().isBefore(deadline)) {
        var req  = HttpRequest.newBuilder()
            .uri(URI.create("https://api.huntapi.com/v1/job/" + jobId))
            .header("x-api-key", apiKey).GET().build();
        var resp   = client.send(req, HttpResponse.BodyHandlers.ofString());
        var result = new JSONObject(resp.body());
        var status = result.getString("status");
        System.out.println("  Status: " + status);

        if ("done".equals(status))  return result;
        if ("error".equals(status)) throw new RuntimeException("Job fehlgeschlagen: " + result.optString("error"));
        Thread.sleep(5000);
    }
    throw new RuntimeException("Timeout");
}

var result      = waitForJob(client, apiKey, jobId);
var downloadUrl = result.getString("download_url");
System.out.println("Bereit! Download-URL: " + downloadUrl);
async Task<JsonElement> WaitForJob(HttpClient client, string jobId)
{
    var deadline = DateTime.UtcNow.AddMinutes(5);
    while (DateTime.UtcNow < deadline)
    {
        var body   = await client.GetStringAsync($"https://api.huntapi.com/v1/job/{jobId}");
        var result = JsonDocument.Parse(body).RootElement;
        var status = result.GetProperty("status").GetString();
        Console.WriteLine($"  Status: {status}");

        if (status == "done")  return result;
        if (status == "error") throw new Exception($"Job fehlgeschlagen: {result.GetProperty("error")}");
        await Task.Delay(5000);
    }
    throw new TimeoutException("Job nicht rechtzeitig abgeschlossen.");
}

var result      = await WaitForJob(client, jobId);
var downloadUrl = result.GetProperty("download_url").GetString()!;
Console.WriteLine($"Bereit! Download-URL: {downloadUrl}");
use tokio::time::{sleep, Duration};
use std::time::Instant;

async fn wait_for_job(client: &Client, api_key: &str, job_id: &str) -> Value {
    let deadline = Instant::now() + Duration::from_secs(300);
    loop {
        assert!(Instant::now() < deadline, "Timeout");
        let result = client.get(format!("https://api.huntapi.com/v1/job/{}", job_id))
            .header("x-api-key", api_key)
            .send().await.unwrap().json::<Value>().await.unwrap();
        let status = result["status"].as_str().unwrap_or("");
        println!("  Status: {}", status);
        if status == "done"  { return result; }
        if status == "error" { panic!("Job fehlgeschlagen: {}", result["error"]); }
        sleep(Duration::from_secs(5)).await;
    }
}

let result       = wait_for_job(&client, api_key, job_id).await;
let download_url = result["download_url"].as_str().unwrap();
println!("Bereit! Download-URL: {}", download_url);

Videodatei auf die Festplatte herunterladen

Streamen Sie die Datei von der download_url und speichern Sie sie lokal.

filename = "video.mp4"

with requests.get(download_url, stream=True) as r:
    r.raise_for_status()
    with open(filename, "wb") as f:
        for chunk in r.iter_content(chunk_size=8192):
            f.write(chunk)

print(f"Gespeichert als {filename}")
import { createWriteStream } from "fs";
import { Readable } from "stream";

const fileResponse = await fetch(downloadUrl);
const writer       = createWriteStream("video.mp4");
Readable.fromWeb(fileResponse.body as any).pipe(writer);
await new Promise((resolve, reject) => { writer.on("finish", resolve); writer.on("error", reject); });
console.log("Gespeichert als video.mp4");
$fp = fopen("video.mp4", "wb");
$ch = curl_init($downloadUrl);
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_exec($ch);
curl_close($ch);
fclose($fp);
echo "Gespeichert als video.mp4\n";
import "os"

resp, _ := http.Get(downloadURL)
defer resp.Body.Close()
file, _ := os.Create("video.mp4")
defer file.Close()
io.Copy(file, resp.Body)
fmt.Println("Gespeichert als video.mp4")
import java.nio.file.*;
import java.net.URL;

var in   = new URL(downloadUrl).openStream();
Files.copy(in, Path.of("video.mp4"), StandardCopyOption.REPLACE_EXISTING);
System.out.println("Gespeichert als video.mp4");
using var fileStream = File.Create("video.mp4");
using var download   = await new HttpClient().GetStreamAsync(downloadUrl);
await download.CopyToAsync(fileStream);
Console.WriteLine("Gespeichert als video.mp4");
use std::io::Write;
use std::fs::File;

let bytes = reqwest::get(download_url).await?.bytes().await?;
let mut file = File::create("video.mp4").unwrap();
file.write_all(&bytes).unwrap();
println!("Gespeichert als video.mp4");

Sie können quality: "best", "1080p", "720p" oder "audio" in der Anfrage übergeben, um das Ausgabeformat zu steuern, bevor der Job eingereicht wird.

Auf dieser Seite