mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 13:40:27 +02:00
Added a download tracker that displays informative messages
This commit is contained in:
+34
-5
@@ -12,6 +12,7 @@ import soundfile as sf
|
||||
from utils import clean_text, create_process
|
||||
from constants import PROGRAM_NAME, LANGUAGE_DESCRIPTIONS, SAMPLE_VOICE_TEXTS
|
||||
from voice_formulas import get_new_voice
|
||||
import hf_tracker
|
||||
import static_ffmpeg
|
||||
import threading # for efficient waiting
|
||||
import subprocess
|
||||
@@ -161,6 +162,7 @@ class ConversionThread(QThread):
|
||||
f"\nVoice: {self.voice}\nLanguage: {self.lang_code}\nSpeed: {self.speed}\nGPU: {self.use_gpu}\nFile: {self.file_name}\nSubtitle mode: {self.subtitle_mode}\nOutput format: {self.output_format}\nSave option: {self.save_option}\n"
|
||||
)
|
||||
try:
|
||||
hf_tracker.set_log_callback(lambda msg: self.log_updated.emit(msg))
|
||||
# Show configuration
|
||||
self.log_updated.emit("Configuration:")
|
||||
# Use display_path for logs if available, otherwise use the actual file name
|
||||
@@ -1003,6 +1005,7 @@ class PlayAudioThread(QThread):
|
||||
def __init__(self, wav_path, parent=None):
|
||||
super().__init__(parent)
|
||||
self.wav_path = wav_path
|
||||
self.is_canceled = False
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
@@ -1012,11 +1015,37 @@ class PlayAudioThread(QThread):
|
||||
pygame.mixer.init()
|
||||
pygame.mixer.music.load(self.wav_path)
|
||||
pygame.mixer.music.play()
|
||||
# Wait until playback is finished
|
||||
while pygame.mixer.music.get_busy():
|
||||
# Wait until playback is finished or canceled
|
||||
while pygame.mixer.music.get_busy() and not self.is_canceled:
|
||||
_time.sleep(0.2)
|
||||
pygame.mixer.music.unload()
|
||||
pygame.mixer.quit() # Quit the mixer
|
||||
|
||||
# Make sure to clean up regardless of how we exited the loop
|
||||
try:
|
||||
pygame.mixer.music.stop()
|
||||
pygame.mixer.music.unload()
|
||||
pygame.mixer.quit() # Quit the mixer
|
||||
except Exception:
|
||||
# Ignore any errors during cleanup
|
||||
pass
|
||||
|
||||
self.finished.emit()
|
||||
except Exception as e:
|
||||
self.error.emit(f"Audio playback error: {str(e)}")
|
||||
# Handle initialization errors separately to give better error messages
|
||||
if "mixer not initialized" in str(e):
|
||||
self.error.emit("Audio playback error: The audio system was not properly initialized")
|
||||
else:
|
||||
self.error.emit(f"Audio playback error: {str(e)}")
|
||||
|
||||
def stop(self):
|
||||
"""Safely stop playback"""
|
||||
self.is_canceled = True
|
||||
# Try to stop pygame if it's running, but catch all exceptions
|
||||
try:
|
||||
import pygame
|
||||
if pygame.mixer.get_init():
|
||||
if pygame.mixer.music.get_busy():
|
||||
pygame.mixer.music.stop()
|
||||
pygame.mixer.music.unload()
|
||||
except Exception:
|
||||
# Ignore all errors when stopping since mixer might not be initialized
|
||||
pass
|
||||
|
||||
+21
-8
@@ -4,6 +4,7 @@ import tempfile
|
||||
import platform
|
||||
import base64
|
||||
import re
|
||||
import hf_tracker
|
||||
import hashlib # Added for cache path generation
|
||||
from PyQt5.QtWidgets import (
|
||||
QApplication,
|
||||
@@ -80,6 +81,13 @@ if platform.system() == "Windows":
|
||||
import ctypes
|
||||
|
||||
|
||||
class ShowWarningSignalEmitter(QObject): # New class to handle signal emission
|
||||
show_warning_signal = pyqtSignal(str, str)
|
||||
|
||||
def emit(self, title, message):
|
||||
self.show_warning_signal.emit(title, message)
|
||||
|
||||
|
||||
class ThreadSafeLogSignal(QObject):
|
||||
log_signal = pyqtSignal(object)
|
||||
|
||||
@@ -533,6 +541,11 @@ class abogen(QWidget):
|
||||
self.log_signal = ThreadSafeLogSignal()
|
||||
self.log_signal.log_signal.connect(self._update_log_main_thread)
|
||||
|
||||
# Create warning signal emitter
|
||||
self.warning_signal_emitter = ShowWarningSignalEmitter()
|
||||
self.warning_signal_emitter.show_warning_signal.connect(self.show_model_download_warning)
|
||||
hf_tracker.set_show_warning_signal_emitter(self.warning_signal_emitter)
|
||||
|
||||
# Set application icon
|
||||
icon_path = get_resource_path("abogen.assets", "icon.ico")
|
||||
if icon_path:
|
||||
@@ -584,6 +597,9 @@ class abogen(QWidget):
|
||||
if self.check_updates:
|
||||
QTimer.singleShot(1000, self.check_for_updates_startup)
|
||||
|
||||
# Set hf_tracker callbacks
|
||||
hf_tracker.set_log_callback(self.update_log)
|
||||
|
||||
def initUI(self):
|
||||
self.setWindowTitle(f"{PROGRAM_NAME} v{VERSION}")
|
||||
screen = QApplication.primaryScreen().geometry()
|
||||
@@ -1571,14 +1587,8 @@ class abogen(QWidget):
|
||||
if self.preview_playing:
|
||||
try:
|
||||
if self.play_audio_thread and self.play_audio_thread.isRunning():
|
||||
# Attempt to stop pygame mixer if it's in use by PlayAudioThread
|
||||
# This is a bit indirect, ideally PlayAudioThread would have a stop method
|
||||
import pygame
|
||||
if pygame.mixer.get_init() and pygame.mixer.music.get_busy():
|
||||
pygame.mixer.music.stop()
|
||||
pygame.mixer.music.unload() # Ensure it's unloaded
|
||||
pygame.mixer.quit() # Quit the mixer
|
||||
self.play_audio_thread.quit() # Ask thread to finish
|
||||
# Call the stop method on PlayAudioThread to safely handle stopping
|
||||
self.play_audio_thread.stop()
|
||||
self.play_audio_thread.wait(500) # Wait a bit
|
||||
except Exception as e:
|
||||
print(f"Error stopping preview audio: {e}")
|
||||
@@ -2428,3 +2438,6 @@ Categories=AudioVideo;Audio;Utility;
|
||||
self.config["separate_chapters_format"] = fmt
|
||||
save_config(self.config)
|
||||
|
||||
def show_model_download_warning(self, title, message):
|
||||
QMessageBox.information(self, title, message)
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
log_callback = None
|
||||
show_warning_signal_emitter = None # Renamed for clarity
|
||||
|
||||
def set_log_callback(cb):
|
||||
global log_callback
|
||||
log_callback = cb
|
||||
|
||||
def set_show_warning_signal_emitter(emitter): # Renamed for clarity
|
||||
global show_warning_signal_emitter
|
||||
show_warning_signal_emitter = emitter
|
||||
|
||||
from huggingface_hub import hf_hub_download
|
||||
|
||||
def tracked_hf_hub_download(*args, **kwargs):
|
||||
try:
|
||||
local_kwargs = dict(kwargs)
|
||||
local_kwargs["local_files_only"] = True
|
||||
hf_hub_download(*args, **local_kwargs)
|
||||
except Exception:
|
||||
repo_id = kwargs.get("repo_id", "<unknown repo>")
|
||||
filename = kwargs.get("filename", "<unknown file>")
|
||||
if filename.endswith(".pth"):
|
||||
msg = f"\nDownloading model '{filename}' from Hugging Face ({repo_id}). This may take a while. Please wait..."
|
||||
if show_warning_signal_emitter: # Check if the emitter is set
|
||||
show_warning_signal_emitter.emit("Downloading Model", f"Downloading model '{filename}' from Hugging Face repository '{repo_id}'. This may take a while, please wait.")
|
||||
else:
|
||||
msg = f"\nDownloading '{filename}' from Hugging Face ({repo_id}). Please wait..."
|
||||
if log_callback:
|
||||
print(msg, flush=True)
|
||||
log_callback(msg)
|
||||
else:
|
||||
print(msg, flush=True)
|
||||
return hf_hub_download(*args, **kwargs)
|
||||
|
||||
import huggingface_hub
|
||||
huggingface_hub.hf_hub_download = tracked_hf_hub_download
|
||||
Reference in New Issue
Block a user