Video-Clipper / app.py
Gresekxnol's picture
Update app.py
fe14511 verified
Raw
History Blame Contribute Delete
4.44 kB
import gradio as gr
import requests
import subprocess
import os
import uuid
import re
# Fungsi untuk mengekstrak ID Video (misal: I0RkuBBi0a8) dari URL lengkap
def extract_video_id(url):
pattern = r"(?:v=|\/)([0-9A-Za-z_-]{11}).*"
match = re.search(pattern, url)
return match.group(1) if match else None
def get_direct_url(youtube_url):
video_id = extract_video_id(youtube_url)
if not video_id:
return None, "Format URL YouTube tidak valid."
# Menggunakan beberapa instance Piped API sebagai Proxy Load Balancer
api_urls = [
f"https://pipedapi.kavin.rocks/streams/{video_id}",
f"https://pipedapi.adminforge.de/streams/{video_id}",
f"https://api.piped.projectsegfau.lt/streams/{video_id}"
]
for api_url in api_urls:
try:
response = requests.get(api_url, timeout=15)
if response.status_code == 200:
data = response.json()
streams = data.get("videoStreams", [])
# Cari stream yang berisi gabungan video+audio (progressive)
# Piped menandai stream tanpa audio sebagai videoOnly: true
progressive_streams = [s for s in streams if not s.get("videoOnly", True)]
if progressive_streams:
# Ambil kualitas yang tersedia (biasanya sudah dibungkus proxy Piped)
return progressive_streams[0]["url"], f"Sukses via {api_url.split('/')[2]}"
except Exception:
# Jika server Piped ini mati/timeout, abaikan dan coba server berikutnya
continue
return None, "Semua server proxy Piped sedang sibuk atau gagal merespons."
def clip_youtube(url, start_time, end_time):
# 1. Dapatkan Direct Link dari Piped
direct_url, extract_status = get_direct_url(url)
if not direct_url:
return None, f"Gagal membobol link. Detail: {extract_status}"
# 2. Persiapan File
output_filename = f"clip_{uuid.uuid4().hex[:8]}.mp4"
start_sec = parse_time(start_time)
end_sec = parse_time(end_time)
duration = end_sec - start_sec
if duration <= 0:
return None, "Waktu selesai harus lebih besar dari waktu mulai!"
# 3. Eksekusi FFmpeg langsung dari URL Streaming Proxy
cmd = [
"ffmpeg",
"-ss", str(start_sec),
"-i", direct_url,
"-t", str(duration),
"-c:v", "libx264",
"-preset", "veryfast",
"-c:a", "aac",
"-y", output_filename
]
try:
subprocess.run(cmd, check=True, capture_output=True)
if os.path.exists(output_filename):
return output_filename, "Berhasil! Klip siap diputar dan diunduh."
else:
return None, "Terjadi kesalahan saat memotong video di server."
except subprocess.CalledProcessError as e:
return None, f"Error FFmpeg: {e.stderr.decode('utf-8')}"
# Helper function
def parse_time(time_str):
try:
parts = time_str.split(':')
if len(parts) == 2:
return int(parts[0]) * 60 + int(parts[1])
elif len(parts) == 3:
return int(parts[0]) * 3600 + int(parts[1]) * 60 + int(parts[2])
return int(time_str)
except:
return 0
# UI Gradio
with gr.Blocks(title="YouTube Piped Clipper") as app:
gr.Markdown("## ✂️ YouTube Clipper (Proxy Version)")
gr.Markdown("Mengekstrak dan memotong video menggunakan jaringan proxy *open-source* (Piped) untuk menghindari blokir infrastruktur YouTube.")
with gr.Row():
with gr.Column():
url_input = gr.Textbox(label="URL YouTube", placeholder="https://www.youtube.com/watch?v=...")
start_input = gr.Textbox(label="Waktu Mulai (MM:SS)", placeholder="01:30")
end_input = gr.Textbox(label="Waktu Selesai (MM:SS)", placeholder="02:00")
submit_btn = gr.Button("✂️ Potong Video", variant="primary")
with gr.Column():
video_output = gr.Video(label="Hasil Klip")
status_output = gr.Textbox(label="Status Sistem", interactive=False)
submit_btn.click(
fn=clip_youtube,
inputs=[url_input, start_input, end_input],
outputs=[video_output, status_output]
)
app.queue(max_size=5).launch()