Есть код который меня полностью устраивает, кроме того что вот совсем непонятно по выставлению уровня децибел и так далее.. нужны прям подсказки или описание. Потому что вот я создал а мне и самому не понятно почему столько дефаулт. Какое оптимальное и наилучшее, какие вообще бывают и чем отличаются чтобы это было конечно в удобном виде и в GUI. Можешь не спешить с ответом для меня главное не скорость ответа, а глубина и качество проработки моего запроса. Мой Мой код точь-в-точь ниже (нужно обязательно сохранить весь функционал и возможности) и прислать уже полностью готовый, целый, комплексный, всесторонний и работоспособный код: import os
import sys
import logging
import threading
import subprocess
import tkinter as tk
from tkinter import filedialog, messagebox, StringVar, ttk
from tkinterdnd2 import DND_FILES, TkinterDnD
import requests
import json
from urllib.parse import urlparse

# Attempt to import necessary libraries
try:
import torchaudio
from demucs.pretrained import get_model as demucs_get_model
from demucs.apply import apply_model as demucs_apply_model
DEMUCS_AVAILABLE = True
except ImportError:
DEMUCS_AVAILABLE = False

try:
import noisereduce as nr
NOISEREDUCE_AVAILABLE = True
except ImportError:
NOISEREDUCE_AVAILABLE = False

from pydub import AudioSegment, effects
import numpy as np # Required for noisereduce

# Logging setup
LOG_FILE = "audio_extraction.log"
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

# Handlers for logging to file and console
file_handler = logging.FileHandler(LOG_FILE)
file_handler.setLevel(logging.DEBUG)
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(logging.INFO)
logger.addHandler(file_handler)
logger.addHandler(console_handler)

# Configuration
CONFIG_FILE = "config.json"

DEFAULT_CONFIG = {
"output_path": "audio",
"audio_format": "flac", # Default format
"use_demucs": False,
"use_noise_reduction": False,
"bitrate": "320k", # Default bitrate
"volume_level": -20.0, # Target volume level
"normalize_audio": True, # Audio normalization
}

# Load configuration
def load_config():
if os.path.exists(CONFIG_FILE):
try:
with open(CONFIG_FILE, "r", encoding='utf-8') as f:
return json.load(f)
except Exception as e:
logger.error(f"Ошибка загрузки конфигурации: {e}")
return DEFAULT_CONFIG.copy()

# Save configuration
def save_config(config):
try:
with open(CONFIG_FILE, "w", encoding='utf-8') as f:
json.dump(config, f, indent=4, ensure_ascii=False)
except Exception as e:
logger.error(f"Ошибка сохранения конфигурации: {e}")

# Placeholder for update checking function
def check_for_updates(current_version):
"""Проверяет наличие обновлений."""
pass # Implement update checking logic if needed

# Validate URL
def is_valid_url(url):
"""Validates if a string is a URL."""
try:
result = urlparse(url)
return all([result.scheme, result.netloc])
except ValueError:
return False

def enhance_audio(audio_path, config):
"""Enhances audio without using Demucs."""
try:
logger.info(f"Улучшение аудио: {audio_path}")
audio = AudioSegment.from_file(audio_path)

# Noise reduction
if config['use_noise_reduction'] and NOISEREDUCE_AVAILABLE:
logger.info("Применение шумоподавления...")
samples = np.array(audio.get_array_of_samples()).astype(np.float32)
sample_rate = audio.frame_rate

reduced_noise = nr.reduce_noise(
y=samples,
sr=sample_rate,
prop_decrease=1.0 # Adjust intensity if needed
)
audio = AudioSegment(
reduced_noise.astype(np.int16).tobytes(),
frame_rate=audio.frame_rate,
sample_width=2,
channels=audio.channels
)
elif config['use_noise_reduction']:
logger.warning("Библиотека для шумоподавления недоступна. Установите 'noisereduce'.")

# Normalization
if config['normalize_audio']:
audio = effects.normalize(audio)

# Adjusting volume
change_in_dBFS = config['volume_level'] - audio.dBFS
audio = audio.apply_gain(change_in_dBFS)

# Saving audio
audio.export(audio_path, format=audio_path.split('.')[-1])
except Exception as e:
logger.error(f"Ошибка улучшения аудио {audio_path}: {e}")

def enhance_audio_with_demucs(audio_path):
"""Uses Demucs model to enhance audio quality."""
if not DEMUCS_AVAILABLE:
logger.error("Demucs не установлен или не может быть импортирован.")
return
try:
logger.info(f"Улучшение аудио с помощью Demucs: {audio_path}")
model = demucs_get_model('demucs_quantized')
waveform, sr = torchaudio.load(audio_path)
sources = demucs_apply_model(model, waveform, device='cpu', split=True, overlap=0.25)
# Combine all sources
enhanced_waveform = sum(sources)
torchaudio.save(audio_path, enhanced_waveform, sr)
except Exception as e:
logger.error(f"Ошибка улучшения аудио с помощью Demucs для {audio_path}: {e}")

def process_audio(audio_path, config):
"""Processes an audio file to enhance its quality."""
if config['use_demucs']:
if DEMUCS_AVAILABLE:
enhance_audio_with_demucs(audio_path)
else:
logger.warning("Demucs недоступен. Будет использовано стандартное улучшение.")
enhance_audio(audio_path, config)
else:
enhance_audio(audio_path, config)

def extract_audio_from_local_file(file_path, output_path, config):
"""Extracts audio from a local video file."""
if not os.path.exists(output_path):
os.makedirs(output_path)

try:
logger.info(f"Извлечение аудио из локального файла: {file_path}")
base_name = os.path.splitext(os.path.basename(file_path))[0]
audio_path = os.path.join(output_path, f'{base_name}.{config["audio_format"]}')
logger.info("Конвертация и улучшение аудио с помощью FFmpeg...")

command = [
'ffmpeg', '-y',
'-i', file_path,
'-vn', # Disable video processing
'-ar', '44100',
'-b:a', config["bitrate"],
audio_path
]
subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)

process_audio(audio_path, config)
logger.info(f'Аудио сохранено: {audio_path}')
return audio_path
except Exception as e:
logger.error(f"Ошибка обработки локального файла: {e}")
return None

def download_audio_with_ytdlp(url, output_path, config):
"""Downloads audio from video using yt-dlp, supports many platforms."""
if not os.path.exists(output_path):
os.makedirs(output_path)

try:
logger.info(f"Загрузка аудио: {url}")
output_template = os.path.join(output_path, '%(title)s.%(ext)s')
command = [
'yt-dlp', '-x', '--audio-format', config["audio_format"],
'--audio-quality', '0', # Best quality
'--output', output_template,
url
]
subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
# Find the downloaded file(s)
downloaded_files = [f for f in os.listdir(output_path) if f.endswith(config["audio_format"])]
for file in downloaded_files:
audio_path = os.path.join(output_path, file)
process_audio(audio_path, config)
logger.info('Аудио успешно загружено и извлечено.')
return True
except subprocess.CalledProcessError as e:
logger.error(f"Ошибка при загрузке аудио: {e}")
return None

def process_video(urls, output_path, config, progress_callback=None):
results = []
total = len(urls)
for idx, url in enumerate(urls):
url = url.strip()
if not url:
continue
try:
if os.path.isfile(url):
result = extract_audio_from_local_file(url, output_path, config)
results.append(result)
elif is_valid_url(url):
result = download_audio_with_ytdlp(url, output_path, config)
results.append(result)
else:
logger.warning(f"Недействительный путь или URL: {url}")
results.append(None)
except Exception as e:
logger.error(f"Ошибка при обработке {url}: {e}")
results.append(None)
if progress_callback:
progress_callback(idx + 1, total)
return results

def show_summary(results):
successful_count = sum(1 for result in results if result is not None)
messagebox.showinfo("Завершено", f"Обработка завершена!\nУспешно обработано: {successful_count}/{len(results)}")

def gui_main():
"""Graphical User Interface."""
config = load_config()

# Mappings for formats and bitrates
AUDIO_FORMAT_OPTIONS = {
'mp3 (Стандартный формат сжатия)': 'mp3',
'wav (Несжатый формат, лучшее качество)': 'wav',
'flac (Сжатый без потерь, для архивирования)': 'flac',
'aac (Современный формат с высоким качеством)': 'aac'
}

BITRATE_OPTIONS = {
'128k (Стандартное качество)': '128k',
'192k (Выше среднего качества)': '192k',
'256k (Высокое качество)': '256k',
'320k (Максимальное качество)': '320k'
}

# Initialize main window
root = TkinterDnD.Tk()
root.title("Извлечение Аудио")

# Style settings
style = ttk.Style(root)
style.theme_use('clam')

frame = ttk.Frame(root, padding=(10, 10))
frame.pack(fill=tk.BOTH, expand=True)

# Video URLs
label_urls = ttk.Label(frame, text="Ссылки на видео (через запятую):")
label_urls.grid(row=0, column=0, sticky='w')

entry_urls = ttk.Entry(frame)
entry_urls.grid(row=1, column=0, pady=5, sticky='we')
create_tooltip(entry_urls, "Введите ссылки с любого поддерживаемого платформы (например, YouTube, Vimeo, Dailymotion и т.д.)")

# Drag and Drop files
label_drag_drop = ttk.Label(frame, text="Перетащите видео файлы сюда:")
label_drag_drop.grid(row=2, column=0, sticky='w')

file_listbox = tk.Listbox(frame, height=5)
file_listbox.grid(row=3, column=0, pady=5, sticky='we')
file_listbox.drop_target_register(DND_FILES)
file_listbox.dnd_bind('<<Drop>>', lambda event: drag_and_drop(event, file_listbox))

scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL, command=file_listbox.yview)
file_listbox['yscrollcommand'] = scrollbar.set
scrollbar.grid(row=3, column=1, sticky='ns')

# Audio format
label_format = ttk.Label(frame, text="Формат аудио:")
label_format.grid(row=4, column=0, sticky='w')

# Set default audio format option
for key, value in AUDIO_FORMAT_OPTIONS.items():
if value == config['audio_format']:
format_default_option = key
break
else:
format_default_option = 'mp3 (Стандартный формат сжатия)'

format_var = tk.StringVar(value=format_default_option)
entry_format = ttk.OptionMenu(frame, format_var, format_default_option, *AUDIO_FORMAT_OPTIONS.keys())
entry_format.grid(row=5, column=0, pady=5, sticky='we')
create_tooltip(entry_format, "Выберите формат аудио файла.")

# Bitrate
label_bitrate = ttk.Label(frame, text="Битрейт:")
label_bitrate.grid(row=6, column=0, sticky='w')

# Set default bitrate option
for key, value in BITRATE_OPTIONS.items():
if value == config['bitrate']:
bitrate_default_option = key
break
else:
bitrate_default_option = '320k (Максимальное качество)'

bitrate_var = tk.StringVar(value=bitrate_default_option)
entry_bitrate = ttk.OptionMenu(frame, bitrate_var, bitrate_default_option, *BITRATE_OPTIONS.keys())
entry_bitrate.grid(row=7, column=0, pady=5, sticky='we')
create_tooltip(entry_bitrate, "Выберите битрейт аудио. Более высокий битрейт означает лучшее качество, но больший размер файла.")

# Target volume level
label_volume = ttk.Label(frame, text="Целевой уровень громкости (дБ):")
label_volume.grid(row=8, column=0, sticky='w')

volume_var = tk.DoubleVar(value=config.get('volume_level', -20.0))
entry_volume = ttk.Scale(frame, from_=-60.0, to=0.0, variable=volume_var, orient='horizontal')
entry_volume.grid(row=9, column=0, pady=5, sticky='we')
create_tooltip(entry_volume, "Установите целевой уровень громкости для нормализации аудио.")

# Normalize audio
normalize_var = tk.BooleanVar(value=config.get('normalize_audio', True))
checkbox_normalize = ttk.Checkbutton(frame, text="Нормализовать аудио", variable=normalize_var)
checkbox_normalize.grid(row=10, column=0, sticky='w')

# Noise reduction
noise_reduction_var = tk.BooleanVar(value=config.get('use_noise_reduction', False))
checkbox_noise_reduction = ttk.Checkbutton(frame, text="Применить шумоподавление", variable=noise_reduction_var)
checkbox_noise_reduction.grid(row=11, column=0, sticky='w')

if not NOISEREDUCE_AVAILABLE:
checkbox_noise_reduction.config(state='disabled')
label_noisereduce_unavailable = ttk.Label(frame, text="Библиотека 'noisereduce' недоступна.", foreground="red")
label_noisereduce_unavailable.grid(row=12, column=0, sticky='w')

# Use Demucs
demucs_var = tk.BooleanVar(value=config['use_demucs'])
checkbox_demucs = ttk.Checkbutton(frame, text="Использовать Demucs для улучшения", variable=demucs_var)
checkbox_demucs.grid(row=13, column=0, sticky='w')

if not DEMUCS_AVAILABLE:
checkbox_demucs.config(state='disabled')
label_demucs_unavailable = ttk.Label(frame, text="Demucs недоступен.", foreground="red")
label_demucs_unavailable.grid(row=14, column=0, sticky='w')

# Progress bar
progress_var = tk.DoubleVar()
progress_bar = ttk.Progressbar(frame, variable=progress_var, maximum=100)
progress_bar.grid(row=15, column=0, pady=10, sticky='we')

# "Start" button
button_start = ttk.Button(frame, text="Начать", command=lambda: start_processing(
entry_urls, file_listbox, config, AUDIO_FORMAT_OPTIONS, BITRATE_OPTIONS,
format_var, bitrate_var, demucs_var, noise_reduction_var, volume_var, normalize_var, root, progress_var
))
button_start.grid(row=16, column=0, pady=10)

# Configure column to fill space
frame.columnconfigure(0, weight=1)

# Hotkeys
root.bind('<Return>', lambda event: start_processing(
entry_urls, file_listbox, config, AUDIO_FORMAT_OPTIONS, BITRATE_OPTIONS,
format_var, bitrate_var, demucs_var, noise_reduction_var, volume_var, normalize_var, root, progress_var
))

root.mainloop()

def create_tooltip(widget, text):
"""Создает всплывающую подсказку для виджета."""
tooltip = tk.Toplevel(widget)
tooltip.withdraw()
tooltip.overrideredirect(True)
label = ttk.Label(tooltip, text=text, background="#ffffe0", relief='solid', borderwidth=1)
label.pack()
def enter(event):
x = widget.winfo_rootx() + 20
y = widget.winfo_rooty() + 20
tooltip.geometry(f"+{x}+{y}")
tooltip.deiconify()
def leave(event):
tooltip.withdraw()
widget.bind('<Enter>', enter)
widget.bind('<Leave>', leave)

def drag_and_drop(event, file_listbox):
files = event.data
files = files.strip("{}") # Remove braces if present
files_list = files.split()
for file in files_list:
file_listbox.insert(tk.END, file)

def start_processing(entry_urls, file_listbox, config, AUDIO_FORMAT_OPTIONS, BITRATE_OPTIONS,
format_var, bitrate_var, demucs_var, noise_reduction_var, volume_var, normalize_var, root, progress_var):
"""Starts processing in a separate thread."""
# Choose output directory in main thread
output_dir = filedialog.askdirectory(title="Выберите папку для сохранения") or config['output_path']

if not output_dir:
messagebox.showwarning("Предупреждение", "Пожалуйста, выберите папку для сохранения.")
return

threading.Thread(target=lambda: processing_task(
entry_urls, file_listbox, config, AUDIO_FORMAT_OPTIONS, BITRATE_OPTIONS,
format_var, bitrate_var, demucs_var, noise_reduction_var, volume_var, normalize_var, root, progress_var, output_dir
)).start()

def processing_task(entry_urls, file_listbox, config, AUDIO_FORMAT_OPTIONS, BITRATE_OPTIONS,
format_var, bitrate_var, demucs_var, noise_reduction_var, volume_var, normalize_var, root, progress_var, output_dir):
try:
urls = list(filter(None, [u.strip() for u in entry_urls.get().split(',')]))
file_paths = file_listbox.get(0, tk.END)
urls.extend(file_paths)

if not urls:
root.after(0, messagebox.showwarning, "Предупреждение", "Пожалуйста, введите ссылки или добавьте файлы для обработки.")
return

audio_format = AUDIO_FORMAT_OPTIONS.get(format_var.get(), 'mp3')
use_demucs = demucs_var.get()
use_noise_reduction = noise_reduction_var.get()
bitrate = BITRATE_OPTIONS.get(bitrate_var.get(), '320k')
target_level = volume_var.get()
normalize_audio = normalize_var.get()

# Update configuration
config['output_path'] = output_dir
config['audio_format'] = audio_format
config['use_demucs'] = use_demucs
config['use_noise_reduction'] = use_noise_reduction
config['bitrate'] = bitrate
config['volume_level'] = target_level
config['normalize_audio'] = normalize_audio
save_config(config)

def progress_callback(current, total):
progress = (current / total) * 100
root.after(0, progress_var.set, progress)

results = process_video(urls, output_dir, config, progress_callback)
root.after(0, show_summary, results)
except Exception as e:
logger.error(f"Произошла ошибка: {e}")
root.after(0, messagebox.showerror, "Ошибка", f"Произошла ошибка во время обработки: {e}")

if name == 'main':
check_for_updates(current_version="1.0.0")
gui_main()