diff options
Diffstat (limited to 'SoundboardUpdater.py')
| -rw-r--r-- | SoundboardUpdater.py | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/SoundboardUpdater.py b/SoundboardUpdater.py new file mode 100644 index 0000000..51674b6 --- /dev/null +++ b/SoundboardUpdater.py @@ -0,0 +1,176 @@ +# Soundboard Engine - customizable soundboard +# Copyright (C) 2026 Vidhu Kant Sharma <vidhukant@vidhukant.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +import shutil +import sys +import zipfile +from pathlib import Path + +import requests +from PySide6.QtCore import Qt, QThread, Signal +from PySide6.QtWidgets import QLabel, QPushButton, QVBoxLayout, QWidget + +from Soundboard import Soundboard + + +class SoundboardUpdaterWindow(QWidget): + start_soundboard = Signal() + + def __init__(self, soundboard: Soundboard): + super().__init__() + + self.soundboard = soundboard + + if soundboard.update_url.strip() != "": + self.worker = SoundboardUpdaterWorker(self.soundboard) + self.worker.start() + self.init_ui() + else: + self.start_soundboard.emit() + + def init_ui(self): + self.setWindowTitle("Soundboard Updater") + self.setFixedSize(300, 180) + + self.layout = QVBoxLayout(self) + self.status_label = QLabel("Updater coming soon") + self.layout.addWidget(self.status_label) + + self.btn_layout = QVBoxLayout() + + self.continue_btn = QPushButton("Continue Without Updating") + self.continue_btn.clicked.connect(self._start_soundboard) + self.btn_layout.addWidget(self.continue_btn) + + self.layout.addLayout(self.btn_layout) + + self.worker.no_update_found.connect(self._start_soundboard) + self.worker.update_found.connect(self._on_update_found) + self.worker.extracting.connect( + lambda: self.status_label.setText("Extracting update...") + ) + self.worker.extracting.connect( + lambda: self.status_label.setText("Copying files...") + ) + self.worker.update_completed.connect(self._on_update_completed) + + def _on_update_found(self, size): + self.status_label.setText(f"Update found ({size})") + + self.update_btn = QPushButton("Download Update") + self.update_btn.clicked.connect(self._on_download_update) + + self.btn_layout.addWidget(self.update_btn) + + def _on_download_update(self): + self.update_btn.setEnabled(False) + self.continue_btn.setEnabled(False) + self.status_label.setText("Downloading update...") + self.worker.start() + + def _on_update_completed(self): + self.status_label.setText("Update completed! Please restart soundboard") + self.update_btn.setVisible(False) + self.continue_btn.setVisible(False) + + def _start_soundboard(self): + self.start_soundboard.emit() + self.deleteLater() + + +class SoundboardUpdaterWorker(QThread): + update_found = Signal(str) + no_update_found = Signal() + extracting = Signal() + copying = Signal() + update_completed = Signal() + + def __init__(self, soundboard: Soundboard): + super().__init__() + + self.soundboard = soundboard + self.mode = "CHECKING_UPDATE" + + def run(self): + if self.mode == "CHECKING_UPDATE": + self._check_for_update() + else: + self._download_and_extract() + + def _check_for_update(self): + try: + res = requests.get(self.soundboard.update_url + "SOUNDBOARD_VERSION") + remote_version = res.text.strip() + + self.download_url = self.soundboard.update_url + remote_version + ".zip" + + if remote_version != self.soundboard.soundboard_version: + head = requests.head(self.download_url, timeout=5) + update_size = self.format_size( + int(head.headers.get("content-length", 0)) + ) + self.mode = "FOUND_UPDATE" + self.update_found.emit(update_size) + else: + self.no_update_found.emit() + except Exception as e: + print(e) + sys.exit(1) + + def _download_and_extract(self): + download_path = Path("temp_update.zip") + if download_path.exists(): + download_path.unlink() + + try: + res = requests.get(self.download_url) + + with open(download_path, "wb") as f: + f.write(res.content) + + self.extracting.emit() + + with zipfile.ZipFile(download_path, "r") as zip_ref: + zip_ref.extractall(Path.cwd()) + + if download_path.exists(): + download_path.unlink() + + self.copying.emit() + + extracted_path = Path("temp_update") + + shutil.copy2( + extracted_path / "soundboard.json", self.soundboard.soundboard_path + ) + + shutil.rmtree(Path.cwd() / "assets") + shutil.copytree(extracted_path / "assets", Path.cwd() / "assets") + + if extracted_path.exists(): + shutil.rmtree(extracted_path) + + self.update_completed.emit() + except Exception as e: + print(e) + sys.exit(1) + + def format_size(self, bytes_size): + if bytes_size >= 1024 * 1024: + return f"{bytes_size / (1024 * 1024):.1f} MB" + elif bytes_size >= 1024: + return f"{bytes_size / 1024:.1f} KB" + return f"{bytes_size} B" |