Télécharger votre première vidéo
Soumettez une URL vidéo, interrogez le résultat du job asynchrone et sauvegardez le fichier localement — tutoriel complet de bout en bout avec HuntAPI.
Vue d'ensemble
HuntAPI utilise un modèle de job asynchrone : vous soumettez une URL, recevez un job_id, puis interrogez jusqu'à ce que la vidéo soit prête. Ce guide parcourt les trois étapes et télécharge le fichier final sur disque.
Prérequis
- Une clé API HuntAPI — obtenez-en une sur app.huntapi.com
- Installez les dépendances pour votre langage :
pip install requestsAucune dépendance supplémentaire — utilise l'API native fetch (Node 18+).
Extension curl activée (par défaut).
Aucune dépendance supplémentaire — utilise net/http (Go 1.18+).
Aucune dépendance supplémentaire — utilise java.net.http (Java 11+).
Aucune dépendance supplémentaire — utilise System.Net.Http (.NET 6+).
# Cargo.toml
[dependencies]
reqwest = { version = "0.12", features = ["json", "stream"] }
tokio = { version = "1", features = ["full"] }
serde_json = "1"Étapes
Soumettre le job de téléchargement
Appelez GET /v1/video/download avec le paramètre url. La réponse renvoie immédiatement un job_id.
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 soumis : {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 soumis : ${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 soumis : {$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 soumis :", 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 soumis : " + 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 soumis : {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 soumis : {}", job_id);Interroger jusqu'à ce que la vidéo soit prête
Vérifiez GET /v1/job/{job_id} toutes les quelques secondes. Quand status devient "done", le champ download_url contient l'URL du fichier.
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" Statut : {status}")
if status == "done":
return result
if status == "error":
raise RuntimeError(f"Job échoué : {result.get('error')}")
time.sleep(poll_interval)
raise TimeoutError("Le job n'a pas terminé dans le délai imparti.")
result = wait_for_job(job_id)
download_url = result["download_url"]
print(f"Prêt ! URL de téléchargement : {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(` Statut : ${result.status}`);
if (result.status === "done") return result;
if (result.status === "error") throw new Error(`Job échoué : ${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(`Prêt ! URL de téléchargement : ${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 " Statut : {$status}\n";
if ($status === "done") return $result;
if ($status === "error") throw new RuntimeException("Job échoué : " . ($result["error"] ?? ""));
sleep($pollSec);
}
throw new RuntimeException("Timeout");
}
$result = waitForJob($apiKey, $jobId);
$downloadUrl = $result["download_url"];
echo "Prêt ! URL de téléchargement : {$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(" Statut :", status)
if status == "done" { return result, nil }
if status == "error" { return nil, fmt.Errorf("job échoué : %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("Prêt ! URL de téléchargement :", 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(" Statut : " + status);
if ("done".equals(status)) return result;
if ("error".equals(status)) throw new RuntimeException("Job échoué : " + 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("Prêt ! URL de téléchargement : " + 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($" Statut : {status}");
if (status == "done") return result;
if (status == "error") throw new Exception($"Job échoué : {result.GetProperty("error")}");
await Task.Delay(5000);
}
throw new TimeoutException("Le job n'a pas terminé dans le délai imparti.");
}
var result = await WaitForJob(client, jobId);
var downloadUrl = result.GetProperty("download_url").GetString()!;
Console.WriteLine($"Prêt ! URL de téléchargement : {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!(" Statut : {}", status);
if status == "done" { return result; }
if status == "error" { panic!("Job échoué : {}", 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!("Prêt ! URL de téléchargement : {}", download_url);Télécharger le fichier vidéo sur disque
Diffusez le fichier depuis download_url et sauvegardez-le localement.
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"Sauvegardé dans {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("Sauvegardé dans 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 "Sauvegardé dans 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("Sauvegardé dans 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("Sauvegardé dans video.mp4");using var fileStream = File.Create("video.mp4");
using var download = await new HttpClient().GetStreamAsync(downloadUrl);
await download.CopyToAsync(fileStream);
Console.WriteLine("Sauvegardé dans 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!("Sauvegardé dans video.mp4");Vous pouvez passer quality: "best", "1080p", "720p" ou "audio" dans la requête initiale pour contrôler le format de sortie avant la soumission du job.