from flask import Flask, request, jsonify, send_from_directory, send_file import subprocess import json import os import threading import uuid import re app = Flask(__name__) BASE_DIR = os.path.dirname(os.path.abspath(__file__)) DOWNLOAD_DIR = os.path.join(BASE_DIR, 'downloads') os.makedirs(DOWNLOAD_DIR, exist_ok=True) download_status = {} @app.route('/') def index(): return send_from_directory(BASE_DIR, 'deepu_downloader.html') @app.route('/formats', methods=['POST']) def get_formats(): data = request.json url = data.get('url', '').strip() if not url: return jsonify({'error': 'URL do bhai!'}), 400 try: result = subprocess.run( ['yt-dlp', '-J', '--no-playlist', url], capture_output=True, text=True, timeout=30 ) if result.returncode != 0: return jsonify({'error': 'URL sahi nahi hai ya video private hai'}), 400 info = json.loads(result.stdout) formats = [] seen = set() for f in info.get('formats', []): fid = f.get('format_id', '') height = f.get('height') acodec = f.get('acodec', 'none') vcodec = f.get('vcodec', 'none') ext = f.get('ext', '') filesize = f.get('filesize') or f.get('filesize_approx') or 0 if vcodec != 'none' and height: ftype = 'video' label = f'{height}p' elif acodec != 'none' and vcodec == 'none': ftype = 'audio' abr = f.get('abr', 0) label = f'Audio {int(abr)}kbps' if abr else 'Audio' elif vcodec != 'none' and acodec != 'none': ftype = 'both' label = f'{height}p (V+A)' if height else 'Video+Audio' else: continue key = f'{label}-{ext}-{ftype}' if key in seen: continue seen.add(key) size_str = '' if filesize: mb = filesize / (1024*1024) size_str = f'{mb:.1f} MB' formats.append({ 'id': fid, 'label': label, 'ext': ext, 'type': ftype, 'size': size_str, 'height': height or 0 }) formats.sort(key=lambda x: (x['height'] or 0), reverse=True) return jsonify({ 'title': info.get('title', 'Unknown'), 'thumbnail': info.get('thumbnail', ''), 'duration': info.get('duration_string', ''), 'formats': formats }) except subprocess.TimeoutExpired: return jsonify({'error': 'Timeout ho gaya, dobara try karo'}), 500 except Exception as e: return jsonify({'error': str(e)}), 500 @app.route('/download', methods=['POST']) def start_download(): data = request.json url = data.get('url', '').strip() format_id = data.get('format_id', 'bestvideo+bestaudio') mode = data.get('mode', 'normal') dl_id = str(uuid.uuid4())[:8] download_status[dl_id] = {'status': 'starting', 'progress': 0, 'speed': '', 'log': [], 'filename': ''} # Speed boost flags SPEED_FLAGS = [ '--concurrent-fragments', '8', '--buffer-size', '16K', '--http-chunk-size', '10M', ] def run_download(): try: if mode == 'live': cmd = ['yt-dlp', '--live-from-start', '-f', 'best'] + SPEED_FLAGS + \ ['-o', os.path.join(DOWNLOAD_DIR, '%(title)s.%(ext)s'), url] elif mode == 'audio': cmd = ['yt-dlp', '-x', '--audio-format', 'mp3'] + SPEED_FLAGS + \ ['-o', os.path.join(DOWNLOAD_DIR, '%(title)s.%(ext)s'), url] else: if format_id in ['best', 'bestvideo+bestaudio']: fmt = 'bestvideo+bestaudio/best' else: fmt = f'{format_id}+140/best' cmd = ['yt-dlp', '-f', fmt, '--merge-output-format', 'mp4'] + SPEED_FLAGS + \ ['-o', os.path.join(DOWNLOAD_DIR, '%(title)s.%(ext)s'), url] process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1 ) download_status[dl_id]['status'] = 'downloading' for line in process.stdout: line = line.strip() if not line: continue download_status[dl_id]['log'].append(line) pct_match = re.search(r'(\d+\.\d+)%', line) speed_match = re.search(r'at\s+([\d.]+\s*\w+/s)', line) dest_match = re.search(r'Destination:\s+(.+)', line) merge_match = re.search(r'Merging formats into "(.+)"', line) if pct_match: download_status[dl_id]['progress'] = float(pct_match.group(1)) if speed_match: download_status[dl_id]['speed'] = speed_match.group(1) if dest_match: download_status[dl_id]['filename'] = os.path.basename(dest_match.group(1).strip()) if merge_match: download_status[dl_id]['filename'] = os.path.basename(merge_match.group(1).strip()) process.wait() if process.returncode == 0: download_status[dl_id]['status'] = 'done' download_status[dl_id]['progress'] = 100 files = os.listdir(DOWNLOAD_DIR) if files: latest = max([os.path.join(DOWNLOAD_DIR, f) for f in files], key=os.path.getmtime) download_status[dl_id]['filename'] = os.path.basename(latest) else: download_status[dl_id]['status'] = 'error' except Exception as e: download_status[dl_id]['status'] = 'error' download_status[dl_id]['log'].append(str(e)) t = threading.Thread(target=run_download) t.daemon = True t.start() return jsonify({'dl_id': dl_id}) @app.route('/progress/') def get_progress(dl_id): return jsonify(download_status.get(dl_id, {'status': 'not found'})) @app.route('/get-file/') def get_file(filename): try: filepath = os.path.join(DOWNLOAD_DIR, filename) if not os.path.exists(filepath): return jsonify({'error': 'File nahi mili'}), 404 return send_file(filepath, as_attachment=True, download_name=filename) except Exception as e: return jsonify({'error': str(e)}), 500 @app.route('/files') def list_files(): files = [] for f in os.listdir(DOWNLOAD_DIR): fp = os.path.join(DOWNLOAD_DIR, f) size = os.path.getsize(fp) files.append({'name': f, 'size': f'{size/(1024*1024):.1f} MB'}) files.sort(key=lambda x: os.path.getmtime(os.path.join(DOWNLOAD_DIR, x['name'])), reverse=True) return jsonify(files) @app.route('/delete-file', methods=['POST']) def delete_file(): data = request.json filename = data.get('filename', '') filepath = os.path.join(DOWNLOAD_DIR, filename) if os.path.exists(filepath): os.remove(filepath) return jsonify({'success': True}) return jsonify({'error': 'File nahi mili'}), 404 if __name__ == "__main__": port = int(os.environ.get("PORT", 7860)) app.run(host="0.0.0.0", port=port)