File size: 5,962 Bytes
ab583e0 2e90f5d ab583e0 6e234dd ab583e0 38551f3 ab583e0 2e90f5d ab583e0 941eff1 ab583e0 0d4a981 ab583e0 |
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 170 171 172 173 174 175 176 177 |
from pathlib import Path
import subprocess
from re import compile, findall, sub
from time import sleep
from typing import Literal
from urllib.parse import quote_plus
import uuid
import threading
from flask import Flask, render_template, request, jsonify, send_file
from httpx import Client
from yt_dlp import YoutubeDL
def extract_youtube_id(url: str) -> list[str] | str | None:
youtube_regex = r'(https?://)?(www\.)?(youtube|youtu|youtube-nocookie)\.(com|be)/(watch\?v=|embed/|v/|.+\?v=|shorts/)?([^&=%\?]{11})'
youtube_url_format = compile(youtube_regex)
urls = findall(youtube_url_format, url)
if len(urls) > 0:
return urls[0][-1]
else:
return None
def download_yt_audio_ytdlp(youtube_id: str) -> Path:
ydl_opts = {
'format': 'bestaudio/best',
'outtmpl': '%(title)s.%(ext)s',
}
with YoutubeDL(ydl_opts) as ydl:
info_dict = ydl.extract_info(f'https://www.youtube.com/watch?v={youtube_id}', download=True)
file_name = Path(ydl.prepare_filename(info_dict))
print('yt_dlp ok')
return file_name
def download_yt_audio_api(youtube_id: str) -> Path:
encoded_youtube_url = quote_plus(f'https://www.youtube.com/watch?v={youtube_id}')
api_response_url = f'https://ab.cococococ.com/ajax/download.php?copyright=0&format=webm&url={encoded_youtube_url}&api=dfcb6d76f2f6a9894gjkege8a4ab232222'
with Client(verify=False, timeout=90, follow_redirects=True) as client:
response = client.get(api_response_url)
response.raise_for_status()
data = response.json()
file_name = sub(r'[^A-Za-zА-Яа-я_]', '', data['info']['title'].replace(' ', '_'))
video_id = data.get('id')
if not video_id:
raise ValueError("ошибка на стороне апи!")
progress_url = f'https://p.oceansaver.in/ajax/progress.php?id={video_id}'
while True:
response = client.get(progress_url)
response.raise_for_status()
data = response.json()
download_url = data.get('download_url')
if download_url:
break
sleep(1)
response = client.get(download_url)
response.raise_for_status()
path = Path('./')
file_name = path / f'{file_name}.webm'
with open(file_name, 'wb') as f:
f.write(response.content)
print('===========================================')
print(' API API APIAPI API API API API API API')
print('===========================================')
return file_name
def download_yt_audio(youtube_id: str) -> Path | None:
try:
return download_yt_audio_ytdlp(youtube_id)
except Exception as e:
print(e)
return download_yt_audio_api(youtube_id)
def audio_to_wav(input_file: Path) -> Path | None:
# if not input_file or not input_file.is_file():
# return None
wav_file = f'{input_file.stem}.wav'
ffmpeg_command = ["./ffmpeg", "-i", input_file, "-ac", "1", wav_file]
subprocess.run(ffmpeg_command, check=True)
input_file.unlink(missing_ok=True)
return Path(wav_file)
def wav_to_opus(wav_file: Path, del_input: bool = True) -> Path:
# if not wav_file or not wav_file.is_file():
# raise ValueError('входной файл для кодирования не был получен!')
opus_file = f'{wav_file.stem}.opus'
opusenc_command = [
"./opusenc",
"--bitrate", "18",
"--vbr",
"--speech",
"--comp", "10",
"--framesize", "60",
"--downmix-mono",
wav_file, opus_file
]
subprocess.run(opusenc_command, check=True)
if del_input:
wav_file.unlink(missing_ok=True)
return Path(opus_file)
def wav_to_usac(wav_file: Path, del_input: bool = True) -> Path:
# if not wav_file or not wav_file.is_file():
# raise ValueError('входной файл для кодирования не был получен!')
exhale_file = f'{wav_file.stem}.m4a'
exhale_command = ["./exhale", "0", wav_file, exhale_file]
subprocess.run(exhale_command, check=True)
if del_input:
wav_file.unlink(missing_ok=True)
return Path(exhale_file)
def download_and_encode(youtube_url: str, codec: Literal['opus', 'usac', 'both'] = 'both') -> list[Path]:
temp_wav = audio_to_wav(download_yt_audio(extract_youtube_id(youtube_url)))
if codec == 'opus':
return [wav_to_opus(temp_wav)]
elif codec == 'usac':
return [wav_to_usac(temp_wav)]
else:
return [wav_to_opus(temp_wav, del_input=False), wav_to_usac(temp_wav)]
app = Flask(__name__)
tasks = {}
@app.route('/')
def index():
return render_template('index.html')
@app.route('/download', methods=['POST'])
def download():
youtube_url = request.form['youtube_url']
codec = request.form['codec']
task_id = str(uuid.uuid4())
def process_task():
tasks[task_id] = {'status': 'скачивание с ютуба...'}
audio_file = download_yt_audio(extract_youtube_id(youtube_url))
tasks[task_id]['status'] = 'предварительная конвертация...'
wav_file = audio_to_wav(audio_file)
tasks[task_id]['status'] = 'сжатие...'
encoded_files = download_and_encode(youtube_url, codec)
tasks[task_id]['status'] = 'готово'
tasks[task_id]['files'] = [str(f) for f in encoded_files]
threading.Thread(target=process_task).start()
return jsonify({'task_id': task_id})
@app.route('/download_status/<task_id>')
def download_status(task_id):
task = tasks.get(task_id)
if task:
return jsonify(task)
else:
return jsonify({'error': 'Task not found'}), 404
@app.route('/play/<path:filename>')
def play(filename):
return send_file(filename, as_attachment=True)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=7860)
|