This commit is contained in:
2026-08-11 23:05:38 +02:00
parent da16a66d41
commit 1d5e5d7a4b

108
gui.py
View File

@@ -23,13 +23,41 @@ def normalize_file_path(path_str: str) -> str:
else:
path_str = urllib.parse.unquote(path_str[7:])
return os.path.abspath(path_str)
def copy_to_clipboard(text: str):
if not text:
return
try:
cb = QApplication.clipboard()
if cb:
cb.setText(text, QClipboard.Mode.Clipboard)
cb.setText(text, QClipboard.Mode.Selection)
except Exception as e:
print(f"Qt clipboard error: {e}")
# Fallback to system CLI clipboard utilities for Wayland/X11 persistence
if shutil.which("wl-copy"):
try:
subprocess.run(["wl-copy", text], check=False)
except Exception as e:
print(f"wl-copy error: {e}")
elif shutil.which("xclip"):
try:
subprocess.run(["xclip", "-selection", "clipboard"], input=text.encode("utf-8"), check=False)
except Exception as e:
print(f"xclip error: {e}")
elif shutil.which("xsel"):
try:
subprocess.run(["xsel", "--clipboard", "--input"], input=text.encode("utf-8"), check=False)
except Exception as e:
print(f"xsel error: {e}")
from PySide6.QtCore import Qt, QThread, QObject, Signal, QUrl, QFile, QIODevice, QTimer, QMimeData
from PySide6.QtGui import QIcon, QAction, QPixmap, QPainter, QColor, QFont, QPen, QImage, QDesktopServices, QDrag
from PySide6.QtGui import QIcon, QAction, QPixmap, QPainter, QColor, QFont, QPen, QImage, QDesktopServices, QDrag, QClipboard
from PySide6.QtNetwork import QNetworkAccessManager, QNetworkRequest, QHttpMultiPart, QHttpPart, QNetworkReply, QLocalServer, QLocalSocket
from PySide6.QtWidgets import (
QApplication, QSystemTrayIcon, QMenu, QDialog, QVBoxLayout, QHBoxLayout,
QLabel, QLineEdit, QComboBox, QCheckBox, QPushButton, QGroupBox,
QFormLayout, QMessageBox, QFileDialog, QSlider, QScrollArea, QFrame, QGridLayout, QWidget
QFormLayout, QMessageBox, QFileDialog, QSlider, QScrollArea, QFrame, QGridLayout, QWidget, QSizePolicy
)
# Configuration paths
@@ -70,7 +98,8 @@ DEFAULT_CONFIG = {
"enable_notifications": True,
"show_progress_dialog": True,
"autostart": False,
"icon_theme": "dark"
"icon_theme": "dark",
"clipboard_url_type": "post"
}
def load_config():
@@ -353,7 +382,17 @@ class SettingsDialog(QDialog):
theme_layout.addWidget(self.cb_icon_theme)
theme_layout.addStretch()
behavior_layout.addLayout(theme_layout)
# Copied Link Format Selection
url_type_layout = QHBoxLayout()
url_type_label = QLabel("Copied Link Format:")
self.cb_url_type = QComboBox()
self.cb_url_type.addItems(["Post Page URL (e.g. /v/123)", "Direct File URL (e.g. /files/123.png)"])
url_type_layout.addWidget(url_type_label)
url_type_layout.addWidget(self.cb_url_type)
url_type_layout.addStretch()
behavior_layout.addLayout(url_type_layout)
main_layout.addWidget(grp_behavior)
# Section 4: Sound Notification
@@ -442,6 +481,9 @@ class SettingsDialog(QDialog):
icon_theme = config.get("icon_theme", "dark").lower()
self.cb_icon_theme.setCurrentIndex(1 if icon_theme == "light" else 0)
url_type = config.get("clipboard_url_type", "post").lower()
self.cb_url_type.setCurrentIndex(1 if url_type == "direct" else 0)
self.chk_sound.setChecked(config.get("play_success_sound", False))
self.txt_sound_path.setText(config.get("success_audio_path", ""))
@@ -520,6 +562,7 @@ class SettingsDialog(QDialog):
"show_progress_dialog": self.chk_progress.isChecked(),
"autostart": self.chk_autostart.isChecked(),
"icon_theme": "light" if self.cb_icon_theme.currentIndex() == 1 else "dark",
"clipboard_url_type": "direct" if self.cb_url_type.currentIndex() == 1 else "post",
"play_success_sound": self.chk_sound.isChecked(),
"success_audio_path": self.txt_sound_path.text().strip(),
"success_audio_volume": self.slider_volume.value()
@@ -575,7 +618,9 @@ class GalleryCard(QFrame):
self.item = item
self.on_delete = on_delete
self.setFrameShape(QFrame.StyledPanel)
self.setFixedHeight(195)
self.setFixedHeight(190)
self.setMinimumWidth(160)
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
self.setStyleSheet("""
GalleryCard {
background-color: #1e1e24;
@@ -595,7 +640,8 @@ class GalleryCard(QFrame):
# Thumbnail with Drag & Drop support
file_path = item.get("file_path", "")
self.thumb_label = DraggableImageLabel(file_path)
self.thumb_label.setFixedSize(160, 100)
self.thumb_label.setFixedHeight(95)
self.thumb_label.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
self.thumb_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.thumb_label.setCursor(Qt.CursorShape.OpenHandCursor)
self.thumb_label.setToolTip("Click & Drag to drop file into other apps")
@@ -664,7 +710,7 @@ class GalleryCard(QFrame):
def on_copy_link(self):
url = self.item.get("url", "")
if url:
QApplication.clipboard().setText(url)
copy_to_clipboard(url)
def on_open_url(self):
url = self.item.get("url", "")
@@ -715,25 +761,42 @@ class GalleryWindow(QDialog):
# Scroll Area for Gallery Cards
self.scroll_area = QScrollArea()
self.scroll_area.setWidgetResizable(True)
self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
self.scroll_area.setStyleSheet("QScrollArea { border: 1px solid #333340; background: #141418; border-radius: 6px; }")
self.scroll_content = QWidget()
self.grid_layout = QGridLayout(self.scroll_content)
self.grid_layout.setContentsMargins(12, 12, 12, 12)
self.grid_layout.setSpacing(12)
self.grid_layout.setAlignment(Qt.AlignmentFlag.AlignTop)
self.grid_layout.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignLeft)
self.scroll_area.setWidget(self.scroll_content)
main_layout.addWidget(self.scroll_area)
self.current_cols = 0
self.load_items()
def get_column_count(self):
w = self.scroll_area.viewport().width()
if w <= 0:
w = self.width() - 40
card_min_w = 160
spacing = 12
margin_padding = 40
cols = max(1, (w - margin_padding + spacing) // (card_min_w + spacing))
return cols
def load_items(self):
while self.grid_layout.count():
child = self.grid_layout.takeAt(0)
if child.widget():
child.widget().deleteLater()
# Reset column stretches
for c in range(20):
self.grid_layout.setColumnStretch(c, 0)
history = load_history()
query = self.txt_search.text().strip().lower()
if query:
@@ -746,13 +809,24 @@ class GalleryWindow(QDialog):
self.grid_layout.addWidget(lbl_empty, 0, 0)
return
cols = 4
cols = self.get_column_count()
self.current_cols = cols
for c in range(cols):
self.grid_layout.setColumnStretch(c, 1)
for idx, item in enumerate(history):
card = GalleryCard(item, on_delete=self.delete_item)
row = idx // cols
col = idx % cols
self.grid_layout.addWidget(card, row, col)
def resizeEvent(self, event):
super().resizeEvent(event)
cols = self.get_column_count()
if cols != getattr(self, "current_cols", 0):
self.load_items()
def delete_item(self, item):
history = load_history()
history = [h for h in history if h.get("url") != item.get("url")]
@@ -1240,9 +1314,19 @@ class SystemTrayApp(QObject):
try:
res = json.loads(response_text)
if res.get("success") and res.get("url"):
item_url = res.get("url")
QApplication.clipboard().setText(item_url)
if res.get("success") and (res.get("url") or res.get("file_url") or res.get("direct_url") or res.get("target_url") or res.get("file")):
config = get_env_config()
url_type = config.get("clipboard_url_type", "post").lower()
post_url = res.get("url") or res.get("post_url") or ""
direct_url = res.get("file_url") or res.get("direct_url") or res.get("target_url") or res.get("file") or ""
if url_type == "direct" and direct_url:
item_url = direct_url
else:
item_url = post_url or direct_url or res.get("url", "")
copy_to_clipboard(item_url)
# Add to history gallery
thumb = generate_thumbnail(file_path)