From 505d1b7fe8d37fba85de99760a77130c25ebf581 Mon Sep 17 00:00:00 2001 From: P3n3tr4t0r Date: Tue, 24 Jun 2025 20:30:43 +0200 Subject: [PATCH] Add rpm installer for Linux --- LICENSE | 21 +++++++++ README.md | 6 ++- corsair_lcd_tool.desktop | 8 ++++ corsair_lcd_tool.py | 86 ++++++++++++++---------------------- install.sh | 2 +- requirements.txt | 2 - rpm/corsair_lcd_tool_v2.spec | 63 ++++++++++++++++++++++++++ 7 files changed, 131 insertions(+), 57 deletions(-) create mode 100644 LICENSE create mode 100644 corsair_lcd_tool.desktop create mode 100644 rpm/corsair_lcd_tool_v2.spec diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d9a7a33 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 shutdown4life + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 5bbd6b0..cda1e56 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,12 @@ This is a fork of [corsair_lcd_tool](https://github.com/UDPSendToFailed/corsair_ - Low resources usage compared to iCUE. # Planned Features -- .rpm installer - Overlay text - Implement temperatures +# TODO: +- fix tray icon with .rpm + # Usage - Install [Python](https://www.python.org/downloads/ "Python") 3.6 or newer. - Clone the repo or download as ZIP and extract it to a new folder. @@ -28,7 +30,7 @@ It might work on Windows but to get sure use the original [corsair_lcd_tool by U # WHY Because Corsair decided to do nothing for Linux users. -If I have some time I might also integrate RGB Controllers in another repo! +If I have some time I might also integrate RGB Controllers in another repo with a fork of this! # Thanks to - [UDPSendToFailed](https://github.com/UDPSendToFailed "UDPSendToFailed") for the work. The main functionality is all in [corsair_lcd_tool](https://github.com/UDPSendToFailed/corsair_lcd_tool "corsair_lcd_tool") diff --git a/corsair_lcd_tool.desktop b/corsair_lcd_tool.desktop new file mode 100644 index 0000000..590dbe1 --- /dev/null +++ b/corsair_lcd_tool.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Name=Corsair LCD Tool v2 +Comment=Manage Corsair LCD screens +Exec=corsair-lcd-tool +Icon=corsair-lcd-tool +Terminal=false +Type=Application +Categories=Utility;System; \ No newline at end of file diff --git a/corsair_lcd_tool.py b/corsair_lcd_tool.py index 53779be..fa3dbb6 100644 --- a/corsair_lcd_tool.py +++ b/corsair_lcd_tool.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 import logging, os, platform, sys, cv2, numpy as np, yaml, usb.core, errno from dataclasses import dataclass from PyQt6.QtCore import Qt, QTimer, QPointF, pyqtSignal, QThread, pyqtSlot, QRectF @@ -5,10 +6,13 @@ from PyQt6.QtGui import QPixmap, QPainter, QMovie, QIcon, QTransform, QImage, QA from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton, QFileDialog, QSlider, QWidget, QGraphicsScene, \ QGraphicsView, QGraphicsPixmapItem, QSystemTrayIcon, QMenu, QStyleFactory, QGraphicsItem, QCheckBox -if platform.system() == 'Windows': - import winshell -elif platform.system() == 'Linux': - import subprocess +match platform.system(): + case 'Windows': + import winshell + case 'Linux': + pass + case _: + raise RuntimeError("Unsupported platform. This script is designed for Windows or Linux.") # Set up logging logging.basicConfig(level=logging.DEBUG) @@ -89,7 +93,11 @@ class UpdateDeviceThread(QThread): device.set_configuration() except usb.core.USBError as e: if e.errno == errno.EACCES: - raise PermissionError("[Access denied] Please set appropriate udev rules (Linux) or use administrator rights (Windows).") + match platform.system(): + case 'Windows': + raise PermissionError("[Access denied] Please use administrator rights.") + case 'Linux': + raise PermissionError("[Access denied] Please set appropriate udev rules.") elif e.errno == errno.EBUSY: raise RuntimeError("[Device busy] Device is blocked by another process or the kernel.") else: @@ -177,7 +185,9 @@ class MainWindow(QMainWindow): self.pixmap_item.setPos(QPointF(0, 0)) self.tray_icon = QSystemTrayIcon(self) - self.tray_icon.setIcon(QIcon('icon.ico')) + script_dir = os.path.dirname(os.path.realpath(__file__)) + icon_path = os.path.join(script_dir, 'corsair-lcd-tool.png') + self.tray_icon.setIcon(QIcon(icon_path)) self.window_state_handler = WindowStateHandler(self) @@ -193,7 +203,8 @@ class MainWindow(QMainWindow): self.container = QWidget(self) self.container.setGeometry(60, 20, 480, 480) - self.container.setStyleSheet("border: 0px") + # black background so the empty space is not visible on the LCD + self.container.setStyleSheet("background-color: #000000; border: 0px") self.scene = QGraphicsScene(self.container) self.view = NoScrollGraphicsView(self.scene, self.container) @@ -219,16 +230,14 @@ class MainWindow(QMainWindow): if platform.system() == "Windows": self.startup_folder = winshell.startup() - self.shortcut_path = os.path.join(self.startup_folder, 'corsair_lcd_tool.lnk') - else: - pass self.python_path = sys.executable - self.startup_checkbox = QCheckBox("Run at startup", self) - self.startup_checkbox.setGeometry(60, 580, 120, 30) - self.startup_checkbox.clicked.connect(self.update_startup) + if platform.system() == "Windows": + self.startup_checkbox = QCheckBox("Run at startup", self) + self.startup_checkbox.setGeometry(60, 580, 120, 30) + self.startup_checkbox.clicked.connect(self.update_startup) self.slider = QSlider(Qt.Orientation.Horizontal, self) self.slider.setGeometry(60, 510, 480, 20) @@ -250,7 +259,7 @@ class MainWindow(QMainWindow): self.tray_icon.setContextMenu(self.tray_menu) - self.setWindowIcon(QIcon('icon.ico')) + self.setWindowIcon(QIcon(icon_path)) self.movie = None logging.debug("MainWindow initialized") @@ -284,10 +293,11 @@ class MainWindow(QMainWindow): self.save_state_handler = SaveStateHandler(self) self.save_state_handler.load_image_state() - if not self.startup_checkbox.isChecked(): - self.show() - else: - QTimer.singleShot(5, self.window_state_handler.minimize_window) + if platform.system() == "Windows": + if not self.startup_checkbox.isChecked(): + self.show() + else: + QTimer.singleShot(5, self.window_state_handler.minimize_window) logging.debug("UI Initialized") def update_startup(self): @@ -308,36 +318,6 @@ class MainWindow(QMainWindow): if os.path.exists(self.shortcut_path): os.remove(self.shortcut_path) logging.debug("Shortcut removed.") - elif platform.system() == "Linux": - service_name = os.path.basename(self.script_path).replace(".py", ".service") - service_path = os.path.join(os.path.expanduser("~"), ".config/systemd/user", service_name) - - service_content = f"""[Unit] - Description=Corsair LCD Tool - - [Service] - ExecStart={self.python_path} {self.script_path} - Restart=on-failure - - [Install] - WantedBy=default.target - """ - - os.makedirs(os.path.dirname(service_path), exist_ok=True) - - if state: - with open(service_path, 'w') as f: - f.write(service_content) - - subprocess.run(["systemctl", "--user", "daemon-reload"], check=True) - subprocess.run(["systemctl", "--user", "enable", service_name], check=True) - logging.debug("Systemd user service created and enabled.") - else: - if os.path.exists(service_path): - os.remove(service_path) - subprocess.run(["systemctl", "--user", "daemon-reload"], check=True) - subprocess.run(["systemctl", "--user", "disable", service_name], check=True) - logging.debug("Systemd user service removed.") def open_image(self): logging.debug("Entering open_image function") @@ -354,7 +334,7 @@ class MainWindow(QMainWindow): pixmap.fill(Qt.GlobalColor.transparent) painter = QPainter(pixmap) painter.setRenderHint(QPainter.RenderHint.Antialiasing) - painter.setBrush(QColor(0, 0, 0, 50)) + painter.setBrush(QColor(0, 0, 0, 150)) painter.setPen(Qt.PenStyle.NoPen) painter.drawRect(0, 0, size, size) painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_Clear) @@ -473,7 +453,8 @@ class SaveStateHandler: self.main.slider.setValue(state.get('last_slider_value')) self.main.view.horizontalScrollBar().setValue(state.get('last_scrollbar_pos')[0]) self.main.view.verticalScrollBar().setValue(state.get('last_scrollbar_pos')[1]) - self.main.startup_checkbox.setChecked(state.get('startup_checkbox_state', False)) + if platform.system() == "Windows": + self.main.startup_checkbox.setChecked(state.get('startup_checkbox_state', False)) logging.debug(f"Loaded state: {state}") else: logging.warning( @@ -504,9 +485,10 @@ class SaveStateHandler: 'last_scene_rect': [self.main.scene.sceneRect().x(), self.main.scene.sceneRect().y(), self.main.scene.sceneRect().width(), self.main.scene.sceneRect().height()], 'last_scrollbar_pos': [self.main.view.horizontalScrollBar().value(), - self.main.view.verticalScrollBar().value()], - 'startup_checkbox_state': self.main.startup_checkbox.isChecked() + self.main.view.verticalScrollBar().value()] } + if sys.platform.startswith("win"): + state['startup_checkbox_state'] = self.main.startup_checkbox.isChecked() with open('state.yaml', 'w') as file: yaml.dump(state, file) logging.debug(f"Saved state to disk: {state}") diff --git a/install.sh b/install.sh index 80b2965..657b80c 100644 --- a/install.sh +++ b/install.sh @@ -10,4 +10,4 @@ sudo cp udev/99-corsair.rules /etc/udev/rules.d/ sudo udevadm control --reload-rules sudo udevadm trigger -echo "✅ Done! Please replug the USB device now." \ No newline at end of file +echo "✅ Done!" \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 967c387..a41b542 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,5 @@ -hidapi numpy opencv-python -openrgb-python PyQt6 pyyaml winshell diff --git a/rpm/corsair_lcd_tool_v2.spec b/rpm/corsair_lcd_tool_v2.spec new file mode 100644 index 0000000..989d783 --- /dev/null +++ b/rpm/corsair_lcd_tool_v2.spec @@ -0,0 +1,63 @@ +Name: corsair_lcd_tool_v2 +Version: 1.0.0 +Release: 1%{?dist} +Summary: Tool for managing Corsair LCDs via Python + +License: MIT +URL: https://github.com/shutdown4life/corsair_lcd_tool_v2 +Source0: %{name}-%{version}.tar.gz + +BuildArch: noarch +BuildRequires: python3-devel +Requires: python3 +Requires: python3-numpy +Requires: python3-opencv +Requires: python3-PyQt6 +Requires: python3-PyYAML +Requires: python3-pyusb + +%description +A Python-based tool to manage Corsair LCD screens. This package includes an installer script and a setup script that runs automatically upon installation. + +%prep +%setup -q + +%build +# No build step is required for plain Python and shell scripts + +%install +rm -rf %{buildroot} +mkdir -p %{buildroot}/usr/share/%{name} +cp -a install.sh corsair_lcd_tool.py %{buildroot}/usr/share/%{name}/ +chmod +x %{buildroot}/usr/share/%{name}/install.sh +chmod +x %{buildroot}/usr/share/%{name}/corsair_lcd_tool.py +cp corsair-lcd-tool.png %{buildroot}/usr/share/%{name}/corsair-lcd-tool.png + +mkdir -p %{buildroot}/usr/share/applications +cp corsair_lcd_tool.desktop %{buildroot}/usr/share/applications/ + +mkdir -p %{buildroot}/usr/bin +ln -sr %{buildroot}/usr/share/%{name}/install.sh %{buildroot}/usr/bin/%{name}-install +ln -sr %{buildroot}/usr/share/%{name}/corsair_lcd_tool.py %{buildroot}/usr/bin/corsair-lcd-tool + +mkdir -p %{buildroot}/usr/share/icons/hicolor/48x48/apps +cp corsair-lcd-tool.png %{buildroot}/usr/share/icons/hicolor/48x48/apps/corsair-lcd-tool.png + +%files +%license LICENSE +%doc README.md +/usr/share/%{name}/install.sh +/usr/share/%{name}/corsair_lcd_tool.py +/usr/share/%{name}/corsair-lcd-tool.png +/usr/bin/%{name}-install +/usr/bin/corsair-lcd-tool +/usr/share/applications/corsair_lcd_tool.desktop +/usr/share/icons/hicolor/48x48/apps/corsair-lcd-tool.png + +%post +echo "Running install.sh to set up udev rules..." > /tmp/corsair_lcd_tool_post.log +/bin/bash /usr/share/%{name}/install.sh >> /tmp/corsair_lcd_tool_post.log 2>&1 || echo "install.sh failed" >> /tmp/corsair_lcd_tool_post.log + +%changelog +* Thu Jun 19 2025 ShUtDoWn discord @shutdown4life - 1.0.0-1 +- Initial RPM release with automatic post-install script \ No newline at end of file