Update v1.1
This commit is contained in:
+50
-7
@@ -1,12 +1,13 @@
|
|||||||
import sys
|
import sys
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
|
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
|
||||||
QHBoxLayout, QLabel, QLineEdit, QPushButton,
|
QHBoxLayout, QLabel, QLineEdit, QPushButton,
|
||||||
QProgressBar, QFileDialog, QCheckBox, QRadioButton,
|
QProgressBar, QFileDialog, QCheckBox, QRadioButton,
|
||||||
QGroupBox)
|
QGroupBox)
|
||||||
from PyQt6.QtCore import QThread, pyqtSignal, Qt, QSettings
|
from PyQt6.QtCore import QThread, pyqtSignal, Qt, QSettings, QTimer
|
||||||
from PyQt6.QtGui import QIcon, QPixmap, QCursor
|
from PyQt6.QtGui import QIcon, QPixmap, QCursor
|
||||||
from GetMetadata import get_metadata
|
from GetMetadata import get_metadata
|
||||||
from LucidaDownloader import TrackDownloader
|
from LucidaDownloader import TrackDownloader
|
||||||
@@ -28,10 +29,11 @@ class MetadataFetcher(QThread):
|
|||||||
finished = pyqtSignal(dict)
|
finished = pyqtSignal(dict)
|
||||||
error = pyqtSignal(str)
|
error = pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, url, headless=True):
|
def __init__(self, url, headless=True, use_fallback=False):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.url = url
|
self.url = url
|
||||||
self.headless_mode = headless
|
self.headless_mode = headless
|
||||||
|
self.use_fallback = use_fallback
|
||||||
self.max_retries = 3
|
self.max_retries = 3
|
||||||
|
|
||||||
def extract_track_id(self, url):
|
def extract_track_id(self, url):
|
||||||
@@ -45,7 +47,8 @@ class MetadataFetcher(QThread):
|
|||||||
|
|
||||||
for attempt in range(self.max_retries):
|
for attempt in range(self.max_retries):
|
||||||
try:
|
try:
|
||||||
lucida_url = f"https://lucida.to/?url=https%3A%2F%2Fopen.spotify.com%2Ftrack%2F{track_id}&country=auto&to=tidal"
|
platform = "amazon" if self.use_fallback else "tidal"
|
||||||
|
lucida_url = f"https://lucida.to/?url=https%3A%2F%2Fopen.spotify.com%2Ftrack%2F{track_id}&country=auto&to={platform}"
|
||||||
browser = await zd.start(headless=self.headless_mode)
|
browser = await zd.start(headless=self.headless_mode)
|
||||||
try:
|
try:
|
||||||
page = await browser.get(lucida_url)
|
page = await browser.get(lucida_url)
|
||||||
@@ -82,6 +85,7 @@ class MetadataFetcher(QThread):
|
|||||||
|
|
||||||
class DownloaderWorker(QThread):
|
class DownloaderWorker(QThread):
|
||||||
progress = pyqtSignal(int)
|
progress = pyqtSignal(int)
|
||||||
|
status = pyqtSignal(str)
|
||||||
finished = pyqtSignal(str)
|
finished = pyqtSignal(str)
|
||||||
error = pyqtSignal(str)
|
error = pyqtSignal(str)
|
||||||
|
|
||||||
@@ -91,10 +95,35 @@ class DownloaderWorker(QThread):
|
|||||||
self.output_dir = output_dir
|
self.output_dir = output_dir
|
||||||
self.filename_format = filename_format
|
self.filename_format = filename_format
|
||||||
self.downloader = TrackDownloader()
|
self.downloader = TrackDownloader()
|
||||||
|
self.last_update_time = 0
|
||||||
|
self.last_downloaded_size = 0
|
||||||
|
|
||||||
|
def format_size(self, size_bytes):
|
||||||
|
return f"{size_bytes / (1024 * 1024):.2f}MB"
|
||||||
|
|
||||||
|
def format_speed(self, speed_bytes):
|
||||||
|
return f"{speed_bytes * 8 / (1024 * 1024):.2f}Mbps"
|
||||||
|
|
||||||
|
def progress_callback(self, downloaded_size, total_size):
|
||||||
|
current_time = time.time()
|
||||||
|
if current_time - self.last_update_time >= 0.5: # Update every 0.5 seconds
|
||||||
|
progress = int((downloaded_size / total_size) * 100) if total_size > 0 else 0
|
||||||
|
self.progress.emit(progress)
|
||||||
|
|
||||||
|
# Calculate speed
|
||||||
|
time_diff = current_time - self.last_update_time
|
||||||
|
if time_diff > 0:
|
||||||
|
speed = (downloaded_size - self.last_downloaded_size) / time_diff
|
||||||
|
status = f"Downloading... {self.format_size(downloaded_size)}/{self.format_size(total_size)} | {self.format_speed(speed)}"
|
||||||
|
self.status.emit(status)
|
||||||
|
|
||||||
|
self.last_update_time = current_time
|
||||||
|
self.last_downloaded_size = downloaded_size
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
try:
|
try:
|
||||||
self.downloader.set_progress_callback(self.progress.emit)
|
self.status.emit("Preparing...")
|
||||||
|
self.downloader.set_progress_callback(self.progress_callback)
|
||||||
self.downloader.set_filename_format(self.filename_format)
|
self.downloader.set_filename_format(self.filename_format)
|
||||||
self.progress.emit(0)
|
self.progress.emit(0)
|
||||||
downloaded_file = self.downloader.download(self.metadata, self.output_dir)
|
downloaded_file = self.downloader.download(self.metadata, self.output_dir)
|
||||||
@@ -128,9 +157,11 @@ class SpotifyFlacGUI(QMainWindow):
|
|||||||
|
|
||||||
def load_settings(self):
|
def load_settings(self):
|
||||||
headless = self.settings.value('headless', True, type=bool)
|
headless = self.settings.value('headless', True, type=bool)
|
||||||
|
fallback = self.settings.value('fallback', False, type=bool)
|
||||||
format_type = self.settings.value('format', 'title_artist')
|
format_type = self.settings.value('format', 'title_artist')
|
||||||
output_dir = self.settings.value('output_dir', self.default_music_dir)
|
output_dir = self.settings.value('output_dir', self.default_music_dir)
|
||||||
self.headless_checkbox.setChecked(headless)
|
self.headless_checkbox.setChecked(headless)
|
||||||
|
self.fallback_checkbox.setChecked(fallback)
|
||||||
self.format_title_artist.setChecked(format_type == 'title_artist')
|
self.format_title_artist.setChecked(format_type == 'title_artist')
|
||||||
self.format_artist_title.setChecked(format_type == 'artist_title')
|
self.format_artist_title.setChecked(format_type == 'artist_title')
|
||||||
self.dir_input.setText(output_dir)
|
self.dir_input.setText(output_dir)
|
||||||
@@ -138,6 +169,8 @@ class SpotifyFlacGUI(QMainWindow):
|
|||||||
def setup_settings_persistence(self):
|
def setup_settings_persistence(self):
|
||||||
self.headless_checkbox.stateChanged.connect(
|
self.headless_checkbox.stateChanged.connect(
|
||||||
lambda x: self.settings.setValue('headless', bool(x)))
|
lambda x: self.settings.setValue('headless', bool(x)))
|
||||||
|
self.fallback_checkbox.stateChanged.connect(
|
||||||
|
lambda x: self.settings.setValue('fallback', bool(x)))
|
||||||
self.format_title_artist.toggled.connect(
|
self.format_title_artist.toggled.connect(
|
||||||
lambda x: self.settings.setValue('format', 'title_artist' if x else 'artist_title'))
|
lambda x: self.settings.setValue('format', 'title_artist' if x else 'artist_title'))
|
||||||
self.dir_input.textChanged.connect(
|
self.dir_input.textChanged.connect(
|
||||||
@@ -197,6 +230,11 @@ class SpotifyFlacGUI(QMainWindow):
|
|||||||
self.headless_checkbox.setChecked(True)
|
self.headless_checkbox.setChecked(True)
|
||||||
settings_container_layout.addWidget(self.headless_checkbox)
|
settings_container_layout.addWidget(self.headless_checkbox)
|
||||||
|
|
||||||
|
self.fallback_checkbox = QCheckBox("Fallback")
|
||||||
|
self.fallback_checkbox.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
|
||||||
|
self.fallback_checkbox.setChecked(False)
|
||||||
|
settings_container_layout.addWidget(self.fallback_checkbox)
|
||||||
|
|
||||||
format_widget = QWidget()
|
format_widget = QWidget()
|
||||||
format_layout = QHBoxLayout(format_widget)
|
format_layout = QHBoxLayout(format_widget)
|
||||||
format_layout.setContentsMargins(0, 0, 0, 0)
|
format_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
@@ -323,7 +361,8 @@ class SpotifyFlacGUI(QMainWindow):
|
|||||||
self.fetch_button.setEnabled(False)
|
self.fetch_button.setEnabled(False)
|
||||||
self.status_label.setText("Fetching track information...")
|
self.status_label.setText("Fetching track information...")
|
||||||
headless = self.headless_checkbox.isChecked()
|
headless = self.headless_checkbox.isChecked()
|
||||||
self.fetcher = MetadataFetcher(url, headless=headless)
|
use_fallback = self.fallback_checkbox.isChecked()
|
||||||
|
self.fetcher = MetadataFetcher(url, headless=headless, use_fallback=use_fallback)
|
||||||
self.fetcher.finished.connect(self.handle_track_info)
|
self.fetcher.finished.connect(self.handle_track_info)
|
||||||
self.fetcher.error.connect(self.handle_fetch_error)
|
self.fetcher.error.connect(self.handle_fetch_error)
|
||||||
self.fetcher.start()
|
self.fetcher.start()
|
||||||
@@ -415,7 +454,7 @@ class SpotifyFlacGUI(QMainWindow):
|
|||||||
self.cancel_button.hide()
|
self.cancel_button.hide()
|
||||||
self.progress_bar.show()
|
self.progress_bar.show()
|
||||||
self.progress_bar.setValue(0)
|
self.progress_bar.setValue(0)
|
||||||
self.status_label.setText("Downloading...")
|
self.status_label.setText("Preparing...")
|
||||||
|
|
||||||
format_type = 'artist_title' if self.format_artist_title.isChecked() else 'title_artist'
|
format_type = 'artist_title' if self.format_artist_title.isChecked() else 'title_artist'
|
||||||
self.worker = DownloaderWorker(
|
self.worker = DownloaderWorker(
|
||||||
@@ -425,10 +464,14 @@ class SpotifyFlacGUI(QMainWindow):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.worker.progress.connect(self.update_progress)
|
self.worker.progress.connect(self.update_progress)
|
||||||
|
self.worker.status.connect(self.update_status)
|
||||||
self.worker.finished.connect(self.download_finished)
|
self.worker.finished.connect(self.download_finished)
|
||||||
self.worker.error.connect(self.download_error)
|
self.worker.error.connect(self.download_error)
|
||||||
self.worker.start()
|
self.worker.start()
|
||||||
|
|
||||||
|
def update_status(self, status):
|
||||||
|
self.status_label.setText(status)
|
||||||
|
|
||||||
def update_progress(self, value):
|
def update_progress(self, value):
|
||||||
self.progress_bar.setValue(value)
|
self.progress_bar.setValue(value)
|
||||||
|
|
||||||
@@ -457,4 +500,4 @@ def main():
|
|||||||
sys.exit(app.exec())
|
sys.exit(app.exec())
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
Reference in New Issue
Block a user