File size: 5,367 Bytes
f725879
76bc4e4
 
f725879
4a5a3f2
 
76bc4e4
 
 
f725879
 
 
 
76bc4e4
67e0627
 
 
 
 
 
 
 
 
 
 
76bc4e4
 
 
 
 
 
 
 
 
 
 
 
f725879
76bc4e4
 
 
 
 
 
 
 
 
 
 
 
 
bf1a231
76bc4e4
 
 
 
 
 
 
f725879
 
 
 
bf1a231
76bc4e4
bf1a231
f725879
bf1a231
 
 
 
f725879
bf1a231
 
76bc4e4
 
 
bf1a231
f725879
76bc4e4
f725879
 
 
76bc4e4
 
 
 
 
4a5a3f2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fb55b5a
 
76bc4e4
f725879
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
from flask import Flask, request, jsonify
from yt_dlp import YoutubeDL
import os
import uuid
import threading
import hashlib

app = Flask(__name__)

# 存储下载文件的临时目录
DOWNLOAD_DIR = 'downloads'
if not os.path.exists(DOWNLOAD_DIR):
    os.makedirs(DOWNLOAD_DIR)

from flask import send_from_directory

@app.route('/downloads/<path:path>')
def serve_downloads(path):
    return send_from_directory(DOWNLOAD_DIR, path)


@app.route('/')
def root():
    return jsonify({'message': 'This is an API service. Please use the appropriate endpoints.'}), 404

@app.route('/get-info', methods=['POST'])
def get_info():
    data = request.json
    url = data.get('url')

    if not url:
        return jsonify({'error': 'URL is required'}), 400

    try:
        ydl_opts = {
            'cookiefile': 'www.youtube.com_cookies.txt'
        }

        with YoutubeDL(ydl_opts) as ydl:
            info = ydl.extract_info(url, download=False)
            return jsonify({
                'title': info['title'],
                'thumbnail': info.get('thumbnail'),
                'duration': info.get('duration'),
                'channel': info.get('channel')
            })

    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/download', methods=['POST'])
def download_audio():
    data = request.json
    url = data.get('url')

    if not url:
        return jsonify({'error': 'URL is required'}), 400

    try:
        # 生成唯一的文件名
        unique_id = str(uuid.uuid4())
        file_name = os.path.join(DOWNLOAD_DIR, f'{unique_id}.mp3')

        # Set up yt-dlp options to download only audio
        ydl_opts = {
            'format': 'bestaudio/best',  # Download the best available audio
            'outtmpl': file_name.rsplit('.', 1)[0] + '.%(ext)s',  # Output filename format
            'cookiefile': 'www.youtube.com_cookies.txt',  # Use cookies file if needed
            'postprocessors': [{
                'key': 'FFmpegExtractAudio',  # Extract audio with FFmpeg
                'preferredcodec': 'mp3',  # Convert to MP3
                'preferredquality': '128',  # Set audio quality
            }],
            'noplaylist': True,  # Avoid downloading entire playlists
        }

        with YoutubeDL(ydl_opts) as ydl:
            # Extract video info and download the audio
            ydl.extract_info(url, download=True)

        # 返回可下载的地址
        download_url = f'{request.host_url}{DOWNLOAD_DIR}/{os.path.basename(file_name)}'
        return jsonify({'download_url': download_url})

    except Exception as e:
        return jsonify({'error': str(e)}), 500


 

# In-memory cache for downloaded videos  
download_cache = {}  # url_hash -> file_path  
download_status = {}  # download_id -> status  

def get_url_hash(url):  
    """Generate a hash of the URL for caching"""  
    return hashlib.md5(url.encode()).hexdigest()  

def download_in_background(url, file_name, download_id, url_hash):  
    try:  
        ydl_opts = {  
            'format': 'bestaudio/best',  
            'outtmpl': file_name.rsplit('.', 1)[0] + '.%(ext)s',  
            'cookiefile': 'www.youtube.com_cookies.txt',  
            'postprocessors': [{  
                'key': 'FFmpegExtractAudio',  
                'preferredcodec': 'mp3',  
                'preferredquality': '320',  
            }],  
            'noplaylist': True,  
        }  
        
        with YoutubeDL(ydl_opts) as ydl:  
            ydl.extract_info(url, download=True)  
        
        # Update cache and status  
        actual_file = f"{file_name.rsplit('.', 1)[0]}.mp3"  
        download_cache[url_hash] = actual_file  
        download_status[download_id] = {  
            'status': 'completed',  
            'download_url': f'{request.host_url}{DOWNLOAD_DIR}/{os.path.basename(actual_file)}'  
        }  
    except Exception as e:  
        download_status[download_id] = {  
            'status': 'error',  
            'error': str(e)  
        }  

@app.route('/audio', methods=['POST'])  
def download_high_audio():  
    data = request.json  
    url = data.get('url')  
    
    if not url:  
        return jsonify({'error': 'URL is required'}), 400  
    
    # Check cache first  
    url_hash = get_url_hash(url)  
    cached_file = download_cache.get(url_hash)  
    
    if cached_file and os.path.exists(cached_file):  
        # Return cached file immediately  
        return jsonify({  
            'status': 'completed',  
            'download_url': f'{request.host_url}{DOWNLOAD_DIR}/{os.path.basename(cached_file)}'  
        })  
    
    # Start new download  
    download_id = str(uuid.uuid4())  
    file_name = os.path.join(DOWNLOAD_DIR, f'{download_id}.mp3')  
    
    download_status[download_id] = {'status': 'processing'}  
    thread = Thread(target=download_in_background, args=(url, file_name, download_id, url_hash))  
    thread.daemon = True  
    thread.start()  
    
    return jsonify({  
        'download_id': download_id,  
        'status': 'processing'  
    })  

@app.route('/audio/status/<download_id>', methods=['GET'])  
def check_download_status(download_id):  
    status = download_status.get(download_id, {'status': 'not_found'})  
    return jsonify(status)


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=7860, debug=True)