Ytddownload / app.py
Opera8's picture
Update app.py
ba4bea1 verified
import os
import time
import uuid
import threading
from flask import Flask, request, jsonify, send_file, render_template_string
from flask_cors import CORS
import yt_dlp
app = Flask(__name__)
CORS(app)
DOWNLOAD_FOLDER = 'downloads'
os.makedirs(DOWNLOAD_FOLDER, exist_ok=True)
# ==========================================
# سیستم پاکسازی خودکار فایل‌های قدیمی
# ==========================================
def cleanup_old_files():
"""این تابع هر یک ساعت اجرا می‌شود و فایل‌های قدیمی‌تر از 1 ساعت را پاک می‌کند تا حافظه پر نشود"""
while True:
try:
current_time = time.time()
for filename in os.listdir(DOWNLOAD_FOLDER):
file_path = os.path.join(DOWNLOAD_FOLDER, filename)
if os.path.isfile(file_path):
# اگر فایل قدیمی‌تر از 3600 ثانیه (1 ساعت) بود، حذف شود
if current_time - os.path.getctime(file_path) > 3600:
os.remove(file_path)
except Exception as e:
print(f"Cleanup error: {e}")
time.sleep(3600)
# راه‌اندازی نخ پاکسازی در پس‌زمینه
cleanup_thread = threading.Thread(target=cleanup_old_files, daemon=True)
cleanup_thread.start()
# ==========================================
# رابط کاربری ساده برای تست (رابط وب)
# ==========================================
HTML_TEMPLATE = """
<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>دانلودر اختصاصی ویدیو</title>
<style>
body { font-family: Tahoma, Arial, sans-serif; background-color: #f3f4f6; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }
.container { background: #fff; padding: 30px; border-radius: 12px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); max-width: 500px; width: 100%; text-align: center; }
input { width: 90%; padding: 12px; margin: 15px 0; border: 1px solid #ccc; border-radius: 8px; font-size: 16px; direction: ltr; }
button { background: #3b82f6; color: white; border: none; padding: 12px 24px; font-size: 16px; border-radius: 8px; cursor: pointer; transition: 0.3s; width: 100%; font-weight: bold; }
button:hover { background: #2563eb; }
button:disabled { background: #9ca3af; cursor: not-allowed; }
#status { margin-top: 15px; font-size: 14px; color: #4b5563; }
.video-container { margin-top: 20px; display: none; }
video { width: 100%; border-radius: 8px; }
.dl-btn { background: #10b981; margin-top: 10px; display: inline-block; text-decoration: none; padding: 10px 20px; color: white; border-radius: 8px; }
.dl-btn:hover { background: #059669; }
</style>
</head>
<body>
<div class="container">
<h2>📥 دانلودر ویدیو (YouTube / Instagram)</h2>
<p>لینک ویدیو را در کادر زیر قرار دهید:</p>
<input type="text" id="urlInput" placeholder="https://www.youtube.com/watch?v=...">
<button id="downloadBtn" onclick="startDownload()">دریافت ویدیو</button>
<div id="status"></div>
<div class="video-container" id="videoContainer">
<video id="videoPlayer" controls></video>
<br>
<a id="downloadLink" class="dl-btn" href="#" download>ذخیره ویدیو در دستگاه</a>
</div>
</div>
<script>
async function startDownload() {
const url = document.getElementById('urlInput').value;
const btn = document.getElementById('downloadBtn');
const status = document.getElementById('status');
const videoContainer = document.getElementById('videoContainer');
const videoPlayer = document.getElementById('videoPlayer');
const downloadLink = document.getElementById('downloadLink');
if (!url) return alert('لطفا لینک را وارد کنید');
btn.disabled = true;
status.innerHTML = "⏳ در حال استخراج و دانلود ویدیو از سرور اصلی... لطفاً صبور باشید.";
videoContainer.style.display = 'none';
try {
const response = await fetch('/api/download', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ url: url })
});
if (!response.ok) {
const data = await response.json();
throw new Error(data.error || 'خطا در دانلود ویدیو');
}
// دریافت فایل به صورت Blob
const blob = await response.blob();
const videoUrl = URL.createObjectURL(blob);
videoPlayer.src = videoUrl;
downloadLink.href = videoUrl;
downloadLink.download = "video.mp4";
status.innerHTML = "✅ ویدیو با موفقیت دریافت شد!";
videoContainer.style.display = 'block';
} catch (error) {
status.innerHTML = "❌ خطا: " + error.message;
} finally {
btn.disabled = false;
}
}
</script>
</body>
</html>
"""
@app.route('/')
def index():
return render_template_string(HTML_TEMPLATE)
# ==========================================
# API دانلود ویدیو
# ==========================================
@app.route('/api/download', methods=['POST'])
def download_video():
data = request.get_json()
if not data or 'url' not in data:
return jsonify({'error': 'URL is required'}), 400
url = data['url']
# شناسه یکتا برای فایل خروجی
file_id = str(uuid.uuid4())
output_template = os.path.join(DOWNLOAD_FOLDER, f"{file_id}.%(ext)s")
# تنظیمات yt-dlp همراه با سیستم بای‌پس یوتیوب
ydl_opts = {
'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best',
'outtmpl': output_template,
'quiet': True,
'no_warnings': True,
'merge_output_format': 'mp4',
# 1. آدرس فایل کوکی که باید در کنار app.py آپلود شود
'cookiefile': 'cookies.txt',
# 2. تغییر کلاینت به موبایل/وب برای کاهش حساسیت ربات‌های یوتیوب
'extractor_args': {'youtube': {'player_client': ['android', 'web']}},
}
try:
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
# استخراج اطلاعات و دانلود
info_dict = ydl.extract_info(url, download=True)
downloaded_ext = info_dict.get('ext', 'mp4')
final_filename = f"{file_id}.{downloaded_ext}"
if not os.path.exists(os.path.join(DOWNLOAD_FOLDER, final_filename)):
final_filename = f"{file_id}.mp4"
final_path = os.path.join(DOWNLOAD_FOLDER, final_filename)
if os.path.exists(final_path):
return send_file(final_path, as_attachment=True, download_name=f"video_{int(time.time())}.mp4")
else:
return jsonify({'error': 'فایل پس از دانلود یافت نشد.'}), 500
except Exception as e:
error_msg = str(e)
if "Sign in to confirm" in error_msg or "Private video" in error_msg:
return jsonify({'error': 'آی‌پی سرور مسدود شده است. لطفا مطمئن شوید فایل cookies.txt را در روت پروژه آپلود کرده‌اید.'}), 403
return jsonify({'error': f'خطا در دانلود: {error_msg}'}), 500
if __name__ == '__main__':
port = int(os.environ.get('PORT', 7860))
app.run(host='0.0.0.0', port=port)