generated from LouisMazin/PythonApplicationTemplate
nice
This commit is contained in:
parent
9cbe5d4de0
commit
7b29ea57b7
@ -141,33 +141,41 @@ class AudioDownloadWorker(QThread):
|
|||||||
if track_album:
|
if track_album:
|
||||||
tags.add(TALB(encoding=3, text=track_album))
|
tags.add(TALB(encoding=3, text=track_album))
|
||||||
|
|
||||||
tags.delall("APIC")
|
|
||||||
if track_cover:
|
|
||||||
cover_file = Path(track_cover)
|
|
||||||
if cover_file.exists() and cover_file.is_file():
|
|
||||||
mime_type = "image/jpeg"
|
|
||||||
cover_data = None
|
|
||||||
if cover_file.suffix.lower() in (".png", ".webp"):
|
|
||||||
try:
|
|
||||||
from PIL import Image
|
|
||||||
import io
|
|
||||||
img = Image.open(cover_file)
|
|
||||||
buf = io.BytesIO()
|
|
||||||
img.convert("RGB").save(buf, format="JPEG")
|
|
||||||
cover_data = buf.getvalue()
|
|
||||||
mime_type = "image/jpeg"
|
|
||||||
except Exception:
|
|
||||||
with open(cover_file, "rb") as stream:
|
|
||||||
cover_data = stream.read()
|
|
||||||
mime_type = "image/png" if cover_file.suffix.lower() == ".png" else "image/webp"
|
|
||||||
else:
|
|
||||||
with open(cover_file, "rb") as stream:
|
|
||||||
cover_data = stream.read()
|
|
||||||
if cover_data:
|
|
||||||
tags.add(APIC(encoding=3, mime=mime_type, type=3, desc="Cover", data=cover_data))
|
|
||||||
|
|
||||||
tags.save(str(file_path), v2_version=4)
|
tags.save(str(file_path), v2_version=4)
|
||||||
|
|
||||||
|
# Use only eyeD3 for cover art (Windows Explorer compatibility)
|
||||||
|
if track_cover:
|
||||||
|
try:
|
||||||
|
import eyed3
|
||||||
|
from PIL import Image
|
||||||
|
import io
|
||||||
|
audiofile = eyed3.load(str(file_path))
|
||||||
|
if audiofile is not None:
|
||||||
|
if audiofile.tag is None:
|
||||||
|
audiofile.initTag()
|
||||||
|
cover_file = Path(track_cover)
|
||||||
|
if cover_file.exists() and cover_file.is_file():
|
||||||
|
# Always convert to JPEG and resize to 999x999
|
||||||
|
try:
|
||||||
|
img = Image.open(cover_file)
|
||||||
|
img = img.convert("RGB")
|
||||||
|
img = img.resize((999, 999), Image.LANCZOS)
|
||||||
|
buf = io.BytesIO()
|
||||||
|
img.save(buf, format="JPEG")
|
||||||
|
image_data = buf.getvalue()
|
||||||
|
mime_type = "image/jpeg"
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[eyeD3] Failed to process image: {e}")
|
||||||
|
image_data = cover_file.read_bytes()
|
||||||
|
mime_type = "image/jpeg"
|
||||||
|
audiofile.tag.images.set(3, image_data, mime_type, u"Cover")
|
||||||
|
# Force ID3v2.3
|
||||||
|
audiofile.tag.version = (2, 3, 0)
|
||||||
|
audiofile.tag.save(version=(2, 3, 0))
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[eyeD3] Failed to embed cover: {e}")
|
||||||
|
|
||||||
renamed_file = self._rename_output_file(file_path, track_title or fallback_title, track_artist)
|
renamed_file = self._rename_output_file(file_path, track_title or fallback_title, track_artist)
|
||||||
if renamed_file is not None:
|
if renamed_file is not None:
|
||||||
self.progress_text.emit(renamed_file.stem)
|
self.progress_text.emit(renamed_file.stem)
|
||||||
@ -441,84 +449,10 @@ class DownloadManager(QObject):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
track = self.track_list[index]
|
track = self.track_list[index]
|
||||||
clean_mp3_title = mp3_title.strip() or track.get("title", "")
|
track["mp3_title"] = mp3_title.strip()
|
||||||
clean_artist = artist.strip()
|
track["artist"] = artist.strip()
|
||||||
clean_album = album.strip()
|
track["album"] = album.strip()
|
||||||
clean_cover = cover_path.strip()
|
track["cover_path"] = cover_path.strip()
|
||||||
|
|
||||||
# Update in-memory metadata
|
|
||||||
track["mp3_title"] = clean_mp3_title
|
|
||||||
track["artist"] = clean_artist
|
|
||||||
track["album"] = clean_album
|
|
||||||
track["cover_path"] = clean_cover
|
|
||||||
|
|
||||||
# Try to find the file path (assume output dir is known, search for file)
|
|
||||||
# Use the current filename or try to reconstruct it
|
|
||||||
output_dir = self.settings_manager.get_config("output_dir")
|
|
||||||
if not output_dir:
|
|
||||||
output_dir = "."
|
|
||||||
output_dir = Path(output_dir)
|
|
||||||
# Try to find the file by matching artist/title or fallback to most recent
|
|
||||||
found_file = None
|
|
||||||
for f in output_dir.glob("*.mp3"):
|
|
||||||
# Try to match by old artist/title
|
|
||||||
if f.stem == f"{track.get('artist', '')} - {track.get('mp3_title', '')}":
|
|
||||||
found_file = f
|
|
||||||
break
|
|
||||||
if not found_file:
|
|
||||||
# fallback: most recent
|
|
||||||
mp3_files = sorted(output_dir.glob("*.mp3"), key=lambda file_path: file_path.stat().st_mtime, reverse=True)
|
|
||||||
if mp3_files:
|
|
||||||
found_file = mp3_files[0]
|
|
||||||
|
|
||||||
if found_file and found_file.exists():
|
|
||||||
# Update ID3 tags
|
|
||||||
try:
|
|
||||||
id3_delete(str(found_file))
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
tags = ID3()
|
|
||||||
tags.delall("TIT2")
|
|
||||||
tags.add(TIT2(encoding=3, text=clean_mp3_title or track.get("title", "")))
|
|
||||||
tags.delall("TPE1")
|
|
||||||
if clean_artist:
|
|
||||||
tags.add(TPE1(encoding=3, text=clean_artist))
|
|
||||||
tags.delall("TALB")
|
|
||||||
if clean_album:
|
|
||||||
tags.add(TALB(encoding=3, text=clean_album))
|
|
||||||
tags.delall("APIC")
|
|
||||||
if clean_cover:
|
|
||||||
cover_file = Path(clean_cover)
|
|
||||||
if cover_file.exists() and cover_file.is_file():
|
|
||||||
mime_type = "image/jpeg"
|
|
||||||
if cover_file.suffix.lower() == ".png":
|
|
||||||
mime_type = "image/png"
|
|
||||||
elif cover_file.suffix.lower() == ".webp":
|
|
||||||
mime_type = "image/webp"
|
|
||||||
with open(cover_file, "rb") as stream:
|
|
||||||
cover_data = stream.read()
|
|
||||||
if cover_data:
|
|
||||||
tags.add(APIC(encoding=3, mime=mime_type, type=3, desc="Cover", data=cover_data))
|
|
||||||
tags.save(str(found_file), v2_version=4)
|
|
||||||
|
|
||||||
# Always rename file to 'artist - title.mp3'
|
|
||||||
safe_title = self._sanitize_filename_part(clean_mp3_title)
|
|
||||||
safe_artist = self._sanitize_filename_part(clean_artist)
|
|
||||||
if safe_artist and safe_title:
|
|
||||||
base_name = f"{safe_artist} - {safe_title}"
|
|
||||||
else:
|
|
||||||
base_name = safe_title or self._sanitize_filename_part(found_file.stem)
|
|
||||||
target_path = found_file.with_name(f"{base_name}{found_file.suffix}")
|
|
||||||
if target_path != found_file:
|
|
||||||
counter = 2
|
|
||||||
while target_path.exists():
|
|
||||||
target_path = found_file.with_name(f"{base_name} ({counter}){found_file.suffix}")
|
|
||||||
counter += 1
|
|
||||||
try:
|
|
||||||
found_file.rename(target_path)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
self.list_changed.emit(self.get_tracks())
|
self.list_changed.emit(self.get_tracks())
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"app_name": "Application",
|
"app_name": "Youtube MP3 Downloader",
|
||||||
"app_os": "Windows",
|
"app_os": "Windows",
|
||||||
"app_version": "1.0.0",
|
"app_version": "1.0.0",
|
||||||
"architecture": "x64",
|
"architecture": "x64",
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 8.4 KiB |
85
main.py
85
main.py
@ -24,82 +24,95 @@ def preload_application(progress_callback, splash=None):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
main_manager = MainManager.get_instance()
|
main_manager = MainManager.get_instance()
|
||||||
|
|
||||||
language_manager = main_manager.get_language_manager()
|
language_manager = main_manager.get_language_manager()
|
||||||
update_manager = main_manager.get_update_manager()
|
update_manager = main_manager.get_update_manager()
|
||||||
license_manager = main_manager.get_license_manager()
|
license_manager = main_manager.get_license_manager()
|
||||||
settings_manager = main_manager.get_settings_manager()
|
settings_manager = main_manager.get_settings_manager()
|
||||||
|
|
||||||
# Vérifier la licence uniquement si le système est activé
|
# Vérifier la licence uniquement si le système est activé
|
||||||
if settings_manager.get_config("enable_licensing"):
|
if settings_manager.get_config("enable_licensing"):
|
||||||
progress_callback(language_manager.get_text("verifying_license"))
|
progress_callback(language_manager.get_text("verifying_license"))
|
||||||
license_manager.verify_license()
|
license_manager.verify_license()
|
||||||
|
|
||||||
progress_callback(language_manager.get_text("checking_updates"))
|
progress_callback(language_manager.get_text("checking_updates"))
|
||||||
|
|
||||||
if update_manager.check_for_update(splash, splash):
|
if update_manager.check_for_update(splash, splash):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
progress_callback(language_manager.get_text("initializing"))
|
progress_callback(language_manager.get_text("initializing"))
|
||||||
|
|
||||||
preloaded_window = MainWindow()
|
preloaded_window = MainWindow()
|
||||||
|
|
||||||
progress_callback(language_manager.get_text("loading_complete"))
|
progress_callback(language_manager.get_text("loading_complete"))
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
print(f"Error during preload: {e}")
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
global preloaded_window
|
global preloaded_window
|
||||||
|
try:
|
||||||
|
QApplication.setAttribute(Qt.ApplicationAttribute.AA_ShareOpenGLContexts, True)
|
||||||
|
except Exception:
|
||||||
|
return 0
|
||||||
|
|
||||||
QApplication.setAttribute(Qt.ApplicationAttribute.AA_ShareOpenGLContexts, True)
|
try:
|
||||||
|
main_manager: MainManager = MainManager.get_instance()
|
||||||
main_manager: MainManager = MainManager.get_instance()
|
|
||||||
theme_manager = main_manager.get_theme_manager()
|
theme_manager = main_manager.get_theme_manager()
|
||||||
settings_manager = main_manager.get_settings_manager()
|
settings_manager = main_manager.get_settings_manager()
|
||||||
|
except Exception:
|
||||||
|
return 0
|
||||||
|
|
||||||
app: QApplication = QApplication(sys.argv)
|
try:
|
||||||
app.setStyleSheet(theme_manager.get_sheet())
|
app: QApplication = QApplication(sys.argv)
|
||||||
app.setApplicationName(settings_manager.get_config("app_name"))
|
except Exception:
|
||||||
app.setWindowIcon(QIcon(paths.get_asset_path("icon")))
|
return 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
app.setStyleSheet(theme_manager.get_sheet())
|
||||||
|
app.setApplicationName(settings_manager.get_config("app_name"))
|
||||||
|
app.setWindowIcon(QIcon(paths.get_asset_path("icon")))
|
||||||
|
except Exception:
|
||||||
|
return 0
|
||||||
|
|
||||||
splash_image_path = paths.get_asset_path(settings_manager.get_config("splash_image"))
|
splash_image_path = paths.get_asset_path(settings_manager.get_config("splash_image"))
|
||||||
use_splash = splash_image_path and paths.Path(splash_image_path).exists()
|
use_splash = splash_image_path and paths.Path(splash_image_path).exists()
|
||||||
|
|
||||||
if use_splash:
|
if use_splash:
|
||||||
splash = SplashScreen(preload_function=lambda callback: preload_application(callback, splash))
|
try:
|
||||||
splash.show_splash()
|
splash = SplashScreen(preload_function=lambda callback: preload_application(callback, splash))
|
||||||
|
splash.show_splash()
|
||||||
|
except Exception as e:
|
||||||
|
return 0
|
||||||
|
|
||||||
def on_splash_finished(success):
|
def on_splash_finished(success):
|
||||||
global preloaded_window
|
global preloaded_window
|
||||||
if not success:
|
if not success:
|
||||||
app.quit()
|
app.quit()
|
||||||
return
|
return
|
||||||
|
try:
|
||||||
if preloaded_window:
|
if preloaded_window:
|
||||||
preloaded_window.show()
|
preloaded_window.show()
|
||||||
else:
|
else:
|
||||||
window = MainWindow()
|
window = MainWindow()
|
||||||
window.show()
|
window.show()
|
||||||
|
except Exception:
|
||||||
|
app.quit()
|
||||||
|
|
||||||
splash.finished.connect(on_splash_finished)
|
splash.finished.connect(on_splash_finished)
|
||||||
|
return app.exec()
|
||||||
else:
|
else:
|
||||||
|
|
||||||
def dummy_progress(text):
|
def dummy_progress(text):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
success = preload_application(dummy_progress)
|
success = preload_application(dummy_progress)
|
||||||
if not success:
|
if not success:
|
||||||
return 0
|
return 0
|
||||||
|
try:
|
||||||
window = preloaded_window if preloaded_window else MainWindow()
|
window = preloaded_window if preloaded_window else MainWindow()
|
||||||
window.show()
|
window.show()
|
||||||
|
except Exception:
|
||||||
|
return 0
|
||||||
|
return app.exec()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
try:
|
sys.exit(main())
|
||||||
sys.exit(main())
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
sys.exit(0)
|
|
||||||
@ -4,4 +4,5 @@ pyinstaller
|
|||||||
python-dotenv
|
python-dotenv
|
||||||
requests
|
requests
|
||||||
yt-dlp
|
yt-dlp
|
||||||
mutagen
|
mutagen
|
||||||
|
pillow
|
||||||
Loading…
x
Reference in New Issue
Block a user