diff --git a/client/server_sync.py b/client/server_sync.py index 4d3f218..ebaa056 100644 --- a/client/server_sync.py +++ b/client/server_sync.py @@ -19,7 +19,10 @@ class ServerSyncClient: font_source: str = "None", websafe_font: Optional[str] = None, google_font: Optional[str] = None, - custom_font_file: Optional[str] = None): + custom_font_file: Optional[str] = None, + user_color: str = "#4CAF50", + text_color: str = "#FFFFFF", + background_color: str = "#000000B3"): """ Initialize server sync client. @@ -33,6 +36,9 @@ class ServerSyncClient: websafe_font: Web-safe font name (e.g., "Arial", "Times New Roman") google_font: Google Font name (e.g., "Roboto", "Open Sans") custom_font_file: Path to a custom font file for this speaker + user_color: User name color (hex format) + text_color: Text color (hex format) + background_color: Background color (hex format with optional alpha) """ self.url = url self.room = room @@ -43,6 +49,9 @@ class ServerSyncClient: self.websafe_font = websafe_font self.google_font = google_font self.custom_font_file = custom_font_file + self.user_color = user_color + self.text_color = text_color + self.background_color = background_color # Font info to send with transcriptions self.font_family: Optional[str] = None @@ -303,7 +312,11 @@ class ServerSyncClient: 'user_name': self.user_name, 'text': trans_data['text'], 'timestamp': trans_data['timestamp'], - 'is_preview': trans_data.get('is_preview', False) + 'is_preview': trans_data.get('is_preview', False), + # Always include user's color settings + 'user_color': self.user_color, + 'text_color': self.text_color, + 'background_color': self.background_color } # Add font info if user has a custom font configured diff --git a/config/default_config.yaml b/config/default_config.yaml index 12f20b4..66ede0d 100644 --- a/config/default_config.yaml +++ b/config/default_config.yaml @@ -59,6 +59,10 @@ display: font_size: 12 theme: "dark" fade_after_seconds: 10 # Time before transcriptions fade out (0 = never fade) + # Color settings (used for both local display and server sync) + user_color: "#4CAF50" # User's name color (default green) + text_color: "#FFFFFF" # Text/font color (default white) + background_color: "#000000B3" # Background color with alpha (default semi-transparent black) web_server: port: 8080 diff --git a/gui/main_window_qt.py b/gui/main_window_qt.py index 60bfda7..e43701d 100644 --- a/gui/main_window_qt.py +++ b/gui/main_window_qt.py @@ -373,6 +373,11 @@ class MainWindow(QMainWindow): websafe_font = self.config.get('display.websafe_font', 'Arial') google_font = self.config.get('display.google_font', 'Roboto') + # Color settings + user_color = self.config.get('display.user_color', '#4CAF50') + text_color = self.config.get('display.text_color', '#FFFFFF') + background_color = self.config.get('display.background_color', '#000000B3') + # Try up to 5 ports if the default is in use ports_to_try = [port] + [port + i for i in range(1, 5)] server_started = False @@ -390,7 +395,10 @@ class MainWindow(QMainWindow): fonts_dir=fonts_dir, font_source=font_source, websafe_font=websafe_font, - google_font=google_font + google_font=google_font, + user_color=user_color, + text_color=text_color, + background_color=background_color ) self.web_server_thread = WebServerThread(self.web_server) self.web_server_thread.start() @@ -643,6 +651,10 @@ class MainWindow(QMainWindow): self.web_server.font_source = self.config.get('display.font_source', 'System Font') self.web_server.websafe_font = self.config.get('display.websafe_font', 'Arial') self.web_server.google_font = self.config.get('display.google_font', 'Roboto') + # Update color settings + self.web_server.user_color = self.config.get('display.user_color', '#4CAF50') + self.web_server.text_color = self.config.get('display.text_color', '#FFFFFF') + self.web_server.background_color = self.config.get('display.background_color', '#000000B3') # Update sync link visibility based on server sync settings self._update_sync_link() @@ -728,6 +740,11 @@ class MainWindow(QMainWindow): google_font = self.config.get('display.google_font', '') custom_font_file = self.config.get('display.custom_font_file', '') + # Color settings + user_color = self.config.get('display.user_color', '#4CAF50') + text_color = self.config.get('display.text_color', '#FFFFFF') + background_color = self.config.get('display.background_color', '#000000B3') + if not url: print("Server sync enabled but no URL configured") return @@ -743,7 +760,10 @@ class MainWindow(QMainWindow): font_source=font_source, websafe_font=websafe_font if websafe_font else None, google_font=google_font if google_font else None, - custom_font_file=custom_font_file if custom_font_file else None + custom_font_file=custom_font_file if custom_font_file else None, + user_color=user_color, + text_color=text_color, + background_color=background_color ) self.server_sync_client.start() diff --git a/gui/settings_dialog_qt.py b/gui/settings_dialog_qt.py index 73da05e..0b28bbc 100644 --- a/gui/settings_dialog_qt.py +++ b/gui/settings_dialog_qt.py @@ -4,10 +4,10 @@ from PySide6.QtWidgets import ( QDialog, QVBoxLayout, QHBoxLayout, QFormLayout, QLabel, QLineEdit, QComboBox, QCheckBox, QSlider, QPushButton, QMessageBox, QGroupBox, QScrollArea, QWidget, - QFileDialog + QFileDialog, QColorDialog ) from PySide6.QtCore import Qt -from PySide6.QtGui import QScreen, QFontDatabase +from PySide6.QtGui import QScreen, QFontDatabase, QColor from typing import Callable, List, Tuple @@ -388,6 +388,53 @@ class SettingsDialog(QDialog): ) display_layout.addRow("Fade After (seconds):", self.fade_seconds_input) + # Color settings + color_label = QLabel("Color Settings") + color_label.setStyleSheet("font-weight: bold; margin-top: 10px;") + display_layout.addRow("", color_label) + + # User name color picker + user_color_layout = QHBoxLayout() + self.user_color_button = QPushButton() + self.user_color_button.setFixedSize(100, 30) + self.user_color_button.setCursor(Qt.PointingHandCursor) + self.user_color_button.setToolTip("Click to change user name color") + self.user_color_button.clicked.connect(self._pick_user_color) + user_color_layout.addWidget(self.user_color_button) + self.user_color_hex = QLabel("#4CAF50") + self.user_color_hex.setStyleSheet("font-family: monospace;") + user_color_layout.addWidget(self.user_color_hex) + user_color_layout.addStretch() + display_layout.addRow("User Name Color:", user_color_layout) + + # Text color picker + text_color_layout = QHBoxLayout() + self.text_color_button = QPushButton() + self.text_color_button.setFixedSize(100, 30) + self.text_color_button.setCursor(Qt.PointingHandCursor) + self.text_color_button.setToolTip("Click to change text color") + self.text_color_button.clicked.connect(self._pick_text_color) + text_color_layout.addWidget(self.text_color_button) + self.text_color_hex = QLabel("#FFFFFF") + self.text_color_hex.setStyleSheet("font-family: monospace;") + text_color_layout.addWidget(self.text_color_hex) + text_color_layout.addStretch() + display_layout.addRow("Text Color:", text_color_layout) + + # Background color picker + bg_color_layout = QHBoxLayout() + self.bg_color_button = QPushButton() + self.bg_color_button.setFixedSize(100, 30) + self.bg_color_button.setCursor(Qt.PointingHandCursor) + self.bg_color_button.setToolTip("Click to change background color (with transparency)") + self.bg_color_button.clicked.connect(self._pick_background_color) + bg_color_layout.addWidget(self.bg_color_button) + self.bg_color_hex = QLabel("#000000B3") + self.bg_color_hex.setStyleSheet("font-family: monospace;") + bg_color_layout.addWidget(self.bg_color_hex) + bg_color_layout.addStretch() + display_layout.addRow("Background Color:", bg_color_layout) + display_group.setLayout(display_layout) content_layout.addWidget(display_group) @@ -577,6 +624,64 @@ class SettingsDialog(QDialog): if file_path: self.display_custom_font_input.setText(file_path) + def _update_color_button_style(self, button: QPushButton, color_hex: str): + """Update a color button's background to show the selected color.""" + # Handle colors with alpha (8-char hex) + if len(color_hex) == 9: # #RRGGBBAA + # For display, we just show the color (alpha is visible through the button style) + rgb = color_hex[:7] + alpha_hex = color_hex[7:9] + alpha = int(alpha_hex, 16) / 255 + button.setStyleSheet( + f"background-color: {rgb}; " + f"border: 2px solid #888; " + f"border-radius: 4px; " + f"opacity: {alpha};" + ) + else: + button.setStyleSheet( + f"background-color: {color_hex}; " + f"border: 2px solid #888; " + f"border-radius: 4px;" + ) + + def _pick_user_color(self): + """Open color dialog for user name color.""" + current_color = QColor(self.user_color_hex.text()) + color = QColorDialog.getColor(current_color, self, "Select User Name Color") + if color.isValid(): + hex_color = color.name() + self.user_color_hex.setText(hex_color) + self._update_color_button_style(self.user_color_button, hex_color) + + def _pick_text_color(self): + """Open color dialog for text color.""" + current_color = QColor(self.text_color_hex.text()) + color = QColorDialog.getColor(current_color, self, "Select Text Color") + if color.isValid(): + hex_color = color.name() + self.text_color_hex.setText(hex_color) + self._update_color_button_style(self.text_color_button, hex_color) + + def _pick_background_color(self): + """Open color dialog for background color (with alpha support).""" + current_hex = self.bg_color_hex.text() + current_color = QColor(current_hex[:7] if len(current_hex) > 7 else current_hex) + if len(current_hex) == 9: + current_color.setAlpha(int(current_hex[7:9], 16)) + + color = QColorDialog.getColor( + current_color, + self, + "Select Background Color", + QColorDialog.ShowAlphaChannel + ) + if color.isValid(): + # Include alpha in hex format: #RRGGBBAA + hex_color = f"{color.name()}{color.alpha():02X}" + self.bg_color_hex.setText(hex_color) + self._update_color_button_style(self.bg_color_button, hex_color) + def _load_current_settings(self): """Load current settings from config.""" # User settings @@ -649,6 +754,19 @@ class SettingsDialog(QDialog): self.font_size_input.setText(str(self.config.get('display.font_size', 12))) self.fade_seconds_input.setText(str(self.config.get('display.fade_after_seconds', 10))) + # Color settings + user_color = self.config.get('display.user_color', '#4CAF50') + self.user_color_hex.setText(user_color) + self._update_color_button_style(self.user_color_button, user_color) + + text_color = self.config.get('display.text_color', '#FFFFFF') + self.text_color_hex.setText(text_color) + self._update_color_button_style(self.text_color_button, text_color) + + bg_color = self.config.get('display.background_color', '#000000B3') + self.bg_color_hex.setText(bg_color) + self._update_color_button_style(self.bg_color_button, bg_color) + # Server sync settings self.server_enabled_check.setChecked(self.config.get('server_sync.enabled', False)) self.server_url_input.setText(self.config.get('server_sync.url', '')) @@ -716,6 +834,11 @@ class SettingsDialog(QDialog): fade_seconds = int(self.fade_seconds_input.text()) self.config.set('display.fade_after_seconds', fade_seconds) + # Color settings + self.config.set('display.user_color', self.user_color_hex.text()) + self.config.set('display.text_color', self.text_color_hex.text()) + self.config.set('display.background_color', self.bg_color_hex.text()) + # Server sync settings self.config.set('server_sync.enabled', self.server_enabled_check.isChecked()) self.config.set('server_sync.url', self.server_url_input.text()) diff --git a/server/nodejs/server.js b/server/nodejs/server.js index 2732c50..0b56431 100644 --- a/server/nodejs/server.js +++ b/server/nodejs/server.js @@ -374,13 +374,29 @@ app.get('/', (req, res) => { overflow-x: auto; margin-top: 10px; } + + .button { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + border: none; + padding: 15px 30px; + border-radius: 10px; + cursor: pointer; + font-weight: bold; + transition: transform 0.2s, box-shadow 0.2s; + } + + .button:hover { + transform: translateY(-2px); + box-shadow: 0 5px 20px rgba(102, 126, 234, 0.4); + }
Multi-User Server (Node.js)
+Multi-User Transcription Server
When creating a display URL for OBS, you can customize it with these URL parameters:
+| Parameter | +Description | +Default | +
|---|---|---|
room |
+ Room name (required) | +- | +
fade |
+ Seconds before text fades (0 = never) | +10 | +
timestamps |
+ Show timestamps (true/false) | +true | +
maxlines |
+ Maximum visible lines | +50 | +
fontsize |
+ Font size in pixels | +16 | +
fontsource |
+ Font source: websafe, google, or custom | +websafe | +
websafefont |
+ Web-safe font name (Arial, Courier New, etc.) | +Arial | +
googlefont |
+ Google Font name (Roboto, Open Sans, etc.) | +Roboto | +
+ Note: Per-user colors and fonts set in the desktop app will override these defaults. + Each user can customize their name color, text color, and background color in Settings. +