From 01d598684cecfaa7066d1c69b39de22c988ea56b Mon Sep 17 00:00:00 2001 From: Nell Date: Mon, 26 May 2025 00:31:51 +0200 Subject: [PATCH] =?UTF-8?q?d=C3=A9sactivation=20async?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/download.py | 125 +++++++++++++++++++++++------------------ src/logs.py | 2 +- windows/main_window.py | 13 ----- 3 files changed, 70 insertions(+), 70 deletions(-) diff --git a/src/download.py b/src/download.py index a3ba058..169bd29 100644 --- a/src/download.py +++ b/src/download.py @@ -1,5 +1,3 @@ -import threading - from PySide6.QtCore import QObject, Signal, QTimer, QUrl, Slot, QThread from PySide6.QtNetwork import QNetworkCookie, QNetworkAccessManager, QNetworkRequest, QNetworkReply, QNetworkCookieJar @@ -36,7 +34,6 @@ class DownloadManager(QObject): self.files: dict[str, FileType] = self.conf.get_value("files", {}) self.tasks: dict[FileType, DownloaderWorker] = {} self.task_stats: dict[str, FileStatsType] = {} - self.waiter = threading.Event() self.cookies = {} # slots @@ -56,21 +53,25 @@ class DownloadManager(QObject): self.status = {} self.update_status() - def loop_queue(self): - self.logger.info("Démarrage de la boucle de téléchargement") - while not self.stop: - available_worker = next((worker for worker in self.worker_pool if worker.available), None) - file = next((file for file in self.files.values() if not file.downloaded and file not in self.tasks), None) - # wait if pause is true - if not available_worker or not file or self.pause: - self.logger.info("loop queue paused, waiting for tasks to finish...") - self.waiter.clear() - self.waiter.wait() - self.logger.info("loop queue resumed") - else: - self.logger.info(f"Assignation du fichier {file.id} à un worker disponible") - self.tasks[file] = available_worker - available_worker.start_download(file) + self.queue_timer = QTimer(self) + self.queue_timer.timeout.connect(self.process_queue) + self.queue_timer.start(1) + + def process_queue(self): + if self.pause: + return + + available_worker = next((worker for worker in self.worker_pool if worker.available), None) + file = next((file for file in self.files.values() if not file.downloaded and file not in self.tasks), None) + if available_worker and file: + self.logger.info(f"Assignation du fichier {file.id} à un worker disponible") + self.tasks[file] = available_worker + available_worker.start_download(file) + else: + self.queue_timer.stop() + if all(file.downloaded for file in self.files.values()): + self.logger.info("Tous les fichiers ont été téléchargés") + self.set_pause(True) self.logger.info("Arrêt de la boucle de téléchargement") @@ -82,11 +83,11 @@ class DownloadManager(QObject): self.logger.info(f"État de pause modifié à: {value}") if self.pause: self.logger.info("Arrêt de tous les téléchargements actifs") - for worker in self.tasks.values(): + for worker in self.tasks.copy().values(): worker.stop_download() else: self.logger.info("Reprise des téléchargements") - self.waiter.set() + self.queue_timer.start(1) QTimer.singleShot(100, self.update_status) def task_ended(self, file): @@ -99,7 +100,7 @@ class DownloadManager(QObject): self.task_stats.pop(file.id) self.logger.debug("Notification du waiter pour traiter le prochain fichier") - self.waiter.set() + self.queue_timer.start(1) self.files_updated.emit(self.files) @@ -151,6 +152,7 @@ class DownloadManager(QObject): "downloader_stats": {key: dl_stat.to_dict() for key, dl_stat in self.task_stats.items()} } if self.status != new_status: + print(new_status["downloader_stats"]) self.status = new_status self.status_updated.emit(self.status) self.logger.debug(f"Mise à jour du statut: {len(self.files)} fichiers, {new_status['downloaded_files']} téléchargés, Vitesse: {new_status['speed']/1024:.2f} Ko/s") @@ -184,12 +186,13 @@ class DownloaderWorker(QObject): self.logger = logging.getLogger('DownloaderWorker') self.logger.info("Initialisation d'un nouveau worker de téléchargement") - self.dl_thread = QThread() - self.dl_thread.start() + self.dl_thread = QThread(self) + + self.manager = QNetworkAccessManager(self) + self.manager.moveToThread(self.dl_thread) if not self.manager.cookieJar(): self.manager.setCookieJar(QNetworkCookieJar()) - # self.manager.moveToThread(self.dl_thread) self.manager.finished.connect(self._on_finished) self.available = True @@ -198,8 +201,10 @@ class DownloaderWorker(QObject): self.file: Optional[FileType] = None self.stats: Optional[FileStatsType] = None - self.last_update_time = time.monotonic() - self.last_downloaded_size = 0 + self.last_update_time = 0 + self.accumulated_bytes = 0 + + self.dl_thread.start() self.logger.debug("Worker de téléchargement initialisé et prêt") @Slot(FileType) @@ -214,6 +219,7 @@ class DownloaderWorker(QObject): # construction des stats + vérification si le téléchargement est déjà terminé self.file = file self.stats = FileStatsType() + self.stats.total_size = file.total_size self.stats.downloaded_size = file.size_downloaded if self.stats.downloaded_size >= file.total_size: self.logger.info(f"Le fichier {file.id} est déjà téléchargé") @@ -243,29 +249,35 @@ class DownloaderWorker(QObject): self.logger.debug(f"Fichier ouvert en mode {mode}: {file.target}") self.last_update_time = time.monotonic() - self.last_downloaded_size = self.stats.downloaded_size + self.accumulated_bytes = 0 def _on_data_ready(self): - chunk = self.reply.readAll() - self.file_io.write(chunk.data()) + chunk_size = 0 + while self.reply.bytesAvailable(): + chunk = self.reply.read(64 * 1024) + self.file_io.write(chunk.data()) + chunk_size += chunk.size() - # stats calculation - chunk_size = chunk.size() self.stats.downloaded_size += chunk_size - current_time = time.monotonic() - elapsed_time = max(current_time - self.last_update_time, 0.001) - current_speed = chunk_size / elapsed_time - if self.file.speed > 0: - self.file.speed = round(0.7 * current_speed + 0.3 * self.file.speed) - else: - self.file.speed = round(current_speed) + self.accumulated_bytes += chunk_size + now = time.monotonic() + elapsed = now - self.last_update_time - self.last_update_time = current_time - self.last_downloaded_size = chunk_size - self.logger.debug(f"Données reçues: {chunk_size} octets, vitesse: {self.file.speed/1024:.2f} Ko/s") + if elapsed >= 1.0: + # EMA lissage court terme (optionnel : 0.7 nouveau / 0.3 ancien) + new_speed = self.accumulated_bytes / elapsed + if self.stats.speed > 0: + self.stats.speed = round(0.7 * new_speed + 0.3 * self.stats.speed) + else: + self.stats.speed = round(new_speed) + + self.accumulated_bytes = 0 + self.last_update_time = now + # self.logger.info(f"Données reçues: {chunk_size} octets, vitesse: {self.stats.speed/1024:.2f} Ko/s") def _on_progress(self, bytes_received, bytes_total): - self.logger.debug(f"Progression du téléchargement pour {self.file.id}: {bytes_received}/{bytes_total} octets ({(bytes_received/max(bytes_total, 1))*100:.1f}%)") + pass + # self.logger.debug(f"Progression du téléchargement pour {self.file.id}: {bytes_received}/{bytes_total} octets ({(bytes_received/max(bytes_total, 1))*100:.1f}%)") def _on_finished(self, reply: QNetworkReply): if not self.file: @@ -280,8 +292,9 @@ class DownloaderWorker(QObject): self.logger.error(f"Échec du téléchargement pour {self.file.id}: {error_msg}") self.file.error = error_msg - self.clear() self.download_manager.task_ended(self.file) + self.clear() + def stop_download(self): if self.file: @@ -301,17 +314,18 @@ class DownloaderWorker(QObject): if not self.reply.isFinished(): self.logger.debug("Annulation de la requête réseau") self.reply.abort() - self.reply.deleteLater() - self.reply = None + if self.reply: + self.reply.deleteLater() + self.reply = None self.logger.debug("Requête réseau nettoyée") - if self.stats: - self.stats = None - self.logger.debug("Statistiques réinitialisées") - - if self.file: - self.file = None - self.logger.debug("Référence au fichier supprimée") + # if self.stats: + # self.stats = None + # self.logger.debug("Statistiques réinitialisées") + # + # if self.file: + # self.file = None + # self.logger.debug("Référence au fichier supprimée") self.available = True self.logger.debug("Worker marqué comme disponible") @@ -330,9 +344,8 @@ class DownloaderWorker(QObject): self.reply.abort() self.reply.deleteLater() self.manager.deleteLater() - self.logger.debug("Arrêt du thread de téléchargement") + self.dl_thread.quit() - if not self.dl_thread.wait(3000): - self.logger.warning("Le thread ne s'est pas arrêté proprement, terminaison forcée") - self.dl_thread.terminate() + self.dl_thread.wait() + self.logger.debug("Arrêt du thread de téléchargement") self.logger.info("Worker fermé") \ No newline at end of file diff --git a/src/logs.py b/src/logs.py index ab0f6c3..eb92f8f 100644 --- a/src/logs.py +++ b/src/logs.py @@ -20,7 +20,7 @@ def configure_logging(debug_mode=False): formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler = logging.StreamHandler(sys.stdout) - handler.setLevel(logging.DEBUG) + handler.setLevel(logging.INFO) handler.setFormatter(formatter) root.addHandler(handler) diff --git a/windows/main_window.py b/windows/main_window.py index 372371d..b77effa 100644 --- a/windows/main_window.py +++ b/windows/main_window.py @@ -46,18 +46,8 @@ class MainWindow(QMainWindow): self.site_window.on_cookie_added.connect(self.download_manager.add_cookie) self.logger.debug("Signaux connectés") - # initialisation du gestionnaire de téléchargement - self.dm_loop = None - QTimer.singleShot(0, self.setup_tasks) - self.logger.info("Fenêtre principale initialisée avec succès") - def setup_tasks(self): - # Lancer les tâches une fois que l'application est prête - self.logger.debug("Configuration des tâches") - self.dm_loop = threading.Thread(target=self.download_manager.loop_queue, daemon=True) - self.dm_loop.start() - self.logger.debug("File d'attente de téléchargement démarrée") def handle_files(self, file_paths): """ @@ -95,10 +85,7 @@ class MainWindow(QMainWindow): def closeEvent(self, event, /): self.download_manager.pause = True self.download_manager.stop = True - self.download_manager.waiter.set() self.download_manager.close_thread_workers() - self.dm_loop.join(timeout=1) - event.accept()