| 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_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/<dl_id>') |
| def get_progress(dl_id): |
| return jsonify(download_status.get(dl_id, {'status': 'not found'})) |
|
|
|
|
| @app.route('/get-file/<path:filename>') |
| 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) |