Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d18f2803ec |
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Python-generated files
|
||||||
|
__pycache__/
|
||||||
|
*.py[oc]
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
wheels/
|
||||||
|
*.egg-info
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
|
.venv
|
||||||
1
.python-version
Normal file
1
.python-version
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3.11
|
||||||
2
compile_ui.sh
Normal file
2
compile_ui.sh
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
pyside6-uic ./src/ui/window.ui -o ./src/ui/window.py
|
||||||
|
echo Done
|
||||||
10
pyproject.toml
Normal file
10
pyproject.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[project]
|
||||||
|
name = "clipboard-link-cleaner"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Add your description here"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.11"
|
||||||
|
dependencies = [
|
||||||
|
"pyperclip>=1.11.0",
|
||||||
|
"pyside6>=6.10.0",
|
||||||
|
]
|
||||||
140
src/main.py
Normal file
140
src/main.py
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
import sys
|
||||||
|
import html
|
||||||
|
import signal
|
||||||
|
from time import sleep
|
||||||
|
from urllib.parse import unquote
|
||||||
|
|
||||||
|
import pyperclip
|
||||||
|
from PySide6.QtWidgets import QApplication
|
||||||
|
from PySide6.QtWidgets import QMainWindow
|
||||||
|
from PySide6.QtWidgets import QSystemTrayIcon
|
||||||
|
from PySide6.QtWidgets import QTextBrowser
|
||||||
|
from PySide6.QtCore import QThread
|
||||||
|
from PySide6.QtCore import Signal
|
||||||
|
from PySide6.QtGui import QIcon
|
||||||
|
from PySide6.QtGui import QTextCharFormat, QColor
|
||||||
|
|
||||||
|
from ui.window import Ui_MainWindow
|
||||||
|
|
||||||
|
|
||||||
|
def highlight_special_chars(text):
|
||||||
|
text = html.escape(text)
|
||||||
|
|
||||||
|
text = text.replace(
|
||||||
|
"?", '<span style="background-color: yellow; color: black;">?</span>'
|
||||||
|
)
|
||||||
|
text = text.replace(
|
||||||
|
"&", '<span style="background-color: yellow; color: black;">&</span>'
|
||||||
|
)
|
||||||
|
|
||||||
|
return text
|
||||||
|
|
||||||
|
def set_text_with_highlight(browser: QTextBrowser, text: str):
|
||||||
|
browser.clear()
|
||||||
|
text = unquote(text)
|
||||||
|
cursor = browser.textCursor()
|
||||||
|
|
||||||
|
highlight_fmt = QTextCharFormat()
|
||||||
|
highlight_fmt.setBackground(QColor("yellow"))
|
||||||
|
highlight_fmt.setForeground(QColor("black"))
|
||||||
|
|
||||||
|
normal_fmt = QTextCharFormat()
|
||||||
|
|
||||||
|
for ch in text:
|
||||||
|
if ch in ("?", "&"):
|
||||||
|
cursor.insertText(ch, highlight_fmt)
|
||||||
|
else:
|
||||||
|
cursor.insertText(ch, normal_fmt)
|
||||||
|
|
||||||
|
class ClipboardWatcher(QThread):
|
||||||
|
clipboard_content = Signal(str)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.clipboard = ""
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
while True:
|
||||||
|
content = pyperclip.paste()
|
||||||
|
if content != self.clipboard:
|
||||||
|
self.clipboard = content
|
||||||
|
self.clipboard_content.emit(content)
|
||||||
|
sleep(.5)
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.terminate()
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
|
||||||
|
class MainWindow(QMainWindow):
|
||||||
|
def __init__(self):
|
||||||
|
super(MainWindow, self).__init__()
|
||||||
|
self.ui = Ui_MainWindow()
|
||||||
|
self.ui.setupUi(self)
|
||||||
|
self.tray = QSystemTrayIcon()
|
||||||
|
self.tray.setIcon(QIcon.fromTheme("edit-copy"))
|
||||||
|
self.tray.setVisible(True)
|
||||||
|
self.clipboard_watcher = ClipboardWatcher()
|
||||||
|
self.clipboard_watcher.clipboard_content.connect(self.on_clipboard)
|
||||||
|
self.clipboard_watcher.start()
|
||||||
|
|
||||||
|
self.ui.button_cleanup.clicked.connect(self.on_cleanup)
|
||||||
|
|
||||||
|
self.notification_duration_seconds = 7
|
||||||
|
self.content = []
|
||||||
|
self.sanitized_link = False
|
||||||
|
|
||||||
|
def on_clipboard(self, content:str):
|
||||||
|
if not content.startswith("http"): return
|
||||||
|
self.cleanup(content)
|
||||||
|
self.ui.textbrowser_list.clear()
|
||||||
|
# self.ui.textbrowser_list.setHtml(highlight_special_chars(content))
|
||||||
|
set_text_with_highlight(browser=self.ui.textbrowser_list, text=self.content[0])
|
||||||
|
|
||||||
|
if len(self.content) == 2:
|
||||||
|
set_text_with_highlight(browser=self.ui.textbrowser_list_removed, text=self.content[1])
|
||||||
|
if self.ui.checkBox_auto_sanitize.isChecked():
|
||||||
|
self.overwrite_clipboard()
|
||||||
|
self.ui.listWidget_history.addItem(unquote(content))
|
||||||
|
|
||||||
|
def overwrite_clipboard(self):
|
||||||
|
pyperclip.copy(self.content[0])
|
||||||
|
self.sanitized_link = True
|
||||||
|
self.tray.showMessage(
|
||||||
|
"CliPy Utility",
|
||||||
|
"Sanitized link",
|
||||||
|
icon=QSystemTrayIcon.Information,
|
||||||
|
msecs=self.notification_duration_seconds * 1000
|
||||||
|
)
|
||||||
|
|
||||||
|
def on_cleanup(self):
|
||||||
|
self.overwrite_clipboard()
|
||||||
|
|
||||||
|
def cleanup(self, text):
|
||||||
|
self.content = text.split("?", 1)
|
||||||
|
|
||||||
|
def closeEvent(self, event) -> None:
|
||||||
|
"""On close event take care to stop all QThreads
|
||||||
|
|
||||||
|
Args:
|
||||||
|
event (_type_): _description_
|
||||||
|
"""
|
||||||
|
self.clipboard_watcher.stop()
|
||||||
|
super().closeEvent(event)
|
||||||
|
|
||||||
|
def handle_sigterm(self, *args) -> None:
|
||||||
|
"""Handle SigInit and SigTerm
|
||||||
|
"""
|
||||||
|
QApplication.quit()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = MainWindow()
|
||||||
|
signal.signal(signal.SIGINT, window.handle_sigterm)
|
||||||
|
signal.signal(signal.SIGTERM, window.handle_sigterm)
|
||||||
|
window.setFixedSize(691,477)
|
||||||
|
window.setWindowIcon(QIcon.fromTheme("edit-copy"))
|
||||||
|
window.setWindowTitle("CliPy Utility")
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
130
src/ui/window.py
Normal file
130
src/ui/window.py
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## Form generated from reading UI file 'window.ui'
|
||||||
|
##
|
||||||
|
## Created by: Qt User Interface Compiler version 6.9.0
|
||||||
|
##
|
||||||
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
|
||||||
|
QMetaObject, QObject, QPoint, QRect,
|
||||||
|
QSize, QTime, QUrl, Qt)
|
||||||
|
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
||||||
|
QFont, QFontDatabase, QGradient, QIcon,
|
||||||
|
QImage, QKeySequence, QLinearGradient, QPainter,
|
||||||
|
QPalette, QPixmap, QRadialGradient, QTransform)
|
||||||
|
from PySide6.QtWidgets import (QApplication, QCheckBox, QFrame, QLabel,
|
||||||
|
QListWidget, QListWidgetItem, QMainWindow, QMenuBar,
|
||||||
|
QPushButton, QSizePolicy, QSpinBox, QStatusBar,
|
||||||
|
QTabWidget, QTextBrowser, QWidget)
|
||||||
|
|
||||||
|
class Ui_MainWindow(object):
|
||||||
|
def setupUi(self, MainWindow):
|
||||||
|
if not MainWindow.objectName():
|
||||||
|
MainWindow.setObjectName(u"MainWindow")
|
||||||
|
MainWindow.resize(691, 506)
|
||||||
|
MainWindow.setAnimated(True)
|
||||||
|
MainWindow.setDocumentMode(False)
|
||||||
|
MainWindow.setTabShape(QTabWidget.TabShape.Rounded)
|
||||||
|
self.centralwidget = QWidget(MainWindow)
|
||||||
|
self.centralwidget.setObjectName(u"centralwidget")
|
||||||
|
self.tabWidget = QTabWidget(self.centralwidget)
|
||||||
|
self.tabWidget.setObjectName(u"tabWidget")
|
||||||
|
self.tabWidget.setGeometry(QRect(0, 0, 691, 461))
|
||||||
|
self.tab_2 = QWidget()
|
||||||
|
self.tab_2.setObjectName(u"tab_2")
|
||||||
|
self.spinBox_max_history = QSpinBox(self.tab_2)
|
||||||
|
self.spinBox_max_history.setObjectName(u"spinBox_max_history")
|
||||||
|
self.spinBox_max_history.setGeometry(QRect(170, 10, 71, 21))
|
||||||
|
self.spinBox_max_history.setMaximum(10000)
|
||||||
|
self.label_max_history = QLabel(self.tab_2)
|
||||||
|
self.label_max_history.setObjectName(u"label_max_history")
|
||||||
|
self.label_max_history.setGeometry(QRect(10, 10, 81, 21))
|
||||||
|
self.checkBox_auto_sanitize = QCheckBox(self.tab_2)
|
||||||
|
self.checkBox_auto_sanitize.setObjectName(u"checkBox_auto_sanitize")
|
||||||
|
self.checkBox_auto_sanitize.setGeometry(QRect(170, 70, 71, 23))
|
||||||
|
self.checkBox_auto_sanitize.setChecked(True)
|
||||||
|
self.label = QLabel(self.tab_2)
|
||||||
|
self.label.setObjectName(u"label")
|
||||||
|
self.label.setGeometry(QRect(10, 40, 121, 18))
|
||||||
|
self.spinBox_notification_duration = QSpinBox(self.tab_2)
|
||||||
|
self.spinBox_notification_duration.setObjectName(u"spinBox_notification_duration")
|
||||||
|
self.spinBox_notification_duration.setGeometry(QRect(170, 40, 71, 21))
|
||||||
|
self.spinBox_notification_duration.setMaximum(10000)
|
||||||
|
self.spinBox_notification_duration.setValue(7)
|
||||||
|
self.label_2 = QLabel(self.tab_2)
|
||||||
|
self.label_2.setObjectName(u"label_2")
|
||||||
|
self.label_2.setGeometry(QRect(10, 70, 131, 18))
|
||||||
|
self.tabWidget.addTab(self.tab_2, "")
|
||||||
|
self.tab = QWidget()
|
||||||
|
self.tab.setObjectName(u"tab")
|
||||||
|
self.textbrowser_list = QTextBrowser(self.tab)
|
||||||
|
self.textbrowser_list.setObjectName(u"textbrowser_list")
|
||||||
|
self.textbrowser_list.setGeometry(QRect(0, 0, 681, 171))
|
||||||
|
self.textbrowser_list.setFrameShape(QFrame.Shape.Box)
|
||||||
|
self.button_cleanup = QPushButton(self.tab)
|
||||||
|
self.button_cleanup.setObjectName(u"button_cleanup")
|
||||||
|
self.button_cleanup.setGeometry(QRect(10, 390, 71, 26))
|
||||||
|
self.textbrowser_list_removed = QTextBrowser(self.tab)
|
||||||
|
self.textbrowser_list_removed.setObjectName(u"textbrowser_list_removed")
|
||||||
|
self.textbrowser_list_removed.setGeometry(QRect(0, 180, 681, 201))
|
||||||
|
self.textbrowser_list_removed.setFrameShape(QFrame.Shape.Box)
|
||||||
|
self.tabWidget.addTab(self.tab, "")
|
||||||
|
self.tab_3 = QWidget()
|
||||||
|
self.tab_3.setObjectName(u"tab_3")
|
||||||
|
self.listWidget_history = QListWidget(self.tab_3)
|
||||||
|
self.listWidget_history.setObjectName(u"listWidget_history")
|
||||||
|
self.listWidget_history.setGeometry(QRect(0, 0, 681, 381))
|
||||||
|
self.listWidget_history.setFrameShape(QFrame.Shape.Box)
|
||||||
|
self.pushButton_clear_history = QPushButton(self.tab_3)
|
||||||
|
self.pushButton_clear_history.setObjectName(u"pushButton_clear_history")
|
||||||
|
self.pushButton_clear_history.setGeometry(QRect(10, 390, 61, 26))
|
||||||
|
self.tabWidget.addTab(self.tab_3, "")
|
||||||
|
MainWindow.setCentralWidget(self.centralwidget)
|
||||||
|
self.menubar = QMenuBar(MainWindow)
|
||||||
|
self.menubar.setObjectName(u"menubar")
|
||||||
|
self.menubar.setGeometry(QRect(0, 0, 691, 23))
|
||||||
|
MainWindow.setMenuBar(self.menubar)
|
||||||
|
self.statusbar = QStatusBar(MainWindow)
|
||||||
|
self.statusbar.setObjectName(u"statusbar")
|
||||||
|
MainWindow.setStatusBar(self.statusbar)
|
||||||
|
|
||||||
|
self.retranslateUi(MainWindow)
|
||||||
|
|
||||||
|
self.tabWidget.setCurrentIndex(0)
|
||||||
|
|
||||||
|
|
||||||
|
QMetaObject.connectSlotsByName(MainWindow)
|
||||||
|
# setupUi
|
||||||
|
|
||||||
|
def retranslateUi(self, MainWindow):
|
||||||
|
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"Py Clipy Utility", None))
|
||||||
|
self.label_max_history.setText(QCoreApplication.translate("MainWindow", u"Max history", None))
|
||||||
|
self.checkBox_auto_sanitize.setText("")
|
||||||
|
self.label.setText(QCoreApplication.translate("MainWindow", u"Notify timeout (s)", None))
|
||||||
|
self.label_2.setText(QCoreApplication.translate("MainWindow", u"Auto-Sanitize links", None))
|
||||||
|
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), QCoreApplication.translate("MainWindow", u"General", None))
|
||||||
|
self.textbrowser_list.setHtml(QCoreApplication.translate("MainWindow", u"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
|
||||||
|
"<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n"
|
||||||
|
"p, li { white-space: pre-wrap; }\n"
|
||||||
|
"hr { height: 1px; border-width: 0; }\n"
|
||||||
|
"li.unchecked::marker { content: \"\\2610\"; }\n"
|
||||||
|
"li.checked::marker { content: \"\\2612\"; }\n"
|
||||||
|
"</style></head><body style=\" font-family:'Cantarell'; font-size:11pt; font-weight:400; font-style:normal;\">\n"
|
||||||
|
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br /></p></body></html>", None))
|
||||||
|
self.button_cleanup.setText(QCoreApplication.translate("MainWindow", u"Sanitize", None))
|
||||||
|
self.textbrowser_list_removed.setHtml(QCoreApplication.translate("MainWindow", u"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
|
||||||
|
"<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n"
|
||||||
|
"p, li { white-space: pre-wrap; }\n"
|
||||||
|
"hr { height: 1px; border-width: 0; }\n"
|
||||||
|
"li.unchecked::marker { content: \"\\2610\"; }\n"
|
||||||
|
"li.checked::marker { content: \"\\2612\"; }\n"
|
||||||
|
"</style></head><body style=\" font-family:'Cantarell'; font-size:11pt; font-weight:400; font-style:normal;\">\n"
|
||||||
|
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br /></p></body></html>", None))
|
||||||
|
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), QCoreApplication.translate("MainWindow", u"URLs", None))
|
||||||
|
self.pushButton_clear_history.setText(QCoreApplication.translate("MainWindow", u"Clear", None))
|
||||||
|
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), QCoreApplication.translate("MainWindow", u"History", None))
|
||||||
|
# retranslateUi
|
||||||
|
|
||||||
238
src/ui/window.ui
Normal file
238
src/ui/window.ui
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>691</width>
|
||||||
|
<height>506</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Py Clipy Utility</string>
|
||||||
|
</property>
|
||||||
|
<property name="animated">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="documentMode">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="tabShape">
|
||||||
|
<enum>QTabWidget::TabShape::Rounded</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>691</width>
|
||||||
|
<height>461</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="tab_2">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>General</string>
|
||||||
|
</attribute>
|
||||||
|
<widget class="QSpinBox" name="spinBox_max_history">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>170</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>21</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>10000</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label_max_history">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>81</width>
|
||||||
|
<height>21</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Max history</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QCheckBox" name="checkBox_auto_sanitize">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>170</x>
|
||||||
|
<y>70</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>23</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>40</y>
|
||||||
|
<width>121</width>
|
||||||
|
<height>18</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Notify timeout (s)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QSpinBox" name="spinBox_notification_duration">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>170</x>
|
||||||
|
<y>40</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>21</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>10000</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>7</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>70</y>
|
||||||
|
<width>131</width>
|
||||||
|
<height>18</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Auto-Sanitize links</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>URLs</string>
|
||||||
|
</attribute>
|
||||||
|
<widget class="QTextBrowser" name="textbrowser_list">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>681</width>
|
||||||
|
<height>171</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::Shape::Box</enum>
|
||||||
|
</property>
|
||||||
|
<property name="html">
|
||||||
|
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
|
<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css">
|
||||||
|
p, li { white-space: pre-wrap; }
|
||||||
|
hr { height: 1px; border-width: 0; }
|
||||||
|
li.unchecked::marker { content: "\2610"; }
|
||||||
|
li.checked::marker { content: "\2612"; }
|
||||||
|
</style></head><body style=" font-family:'Cantarell'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||||
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="button_cleanup">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>390</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>26</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Sanitize</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QTextBrowser" name="textbrowser_list_removed">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>180</y>
|
||||||
|
<width>681</width>
|
||||||
|
<height>201</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::Shape::Box</enum>
|
||||||
|
</property>
|
||||||
|
<property name="html">
|
||||||
|
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
|
<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css">
|
||||||
|
p, li { white-space: pre-wrap; }
|
||||||
|
hr { height: 1px; border-width: 0; }
|
||||||
|
li.unchecked::marker { content: "\2610"; }
|
||||||
|
li.checked::marker { content: "\2612"; }
|
||||||
|
</style></head><body style=" font-family:'Cantarell'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||||
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_3">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>History</string>
|
||||||
|
</attribute>
|
||||||
|
<widget class="QListWidget" name="listWidget_history">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>681</width>
|
||||||
|
<height>381</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::Shape::Box</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pushButton_clear_history">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>390</y>
|
||||||
|
<width>61</width>
|
||||||
|
<height>26</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Clear</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>691</width>
|
||||||
|
<height>23</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
87
uv.lock
generated
Normal file
87
uv.lock
generated
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
version = 1
|
||||||
|
revision = 3
|
||||||
|
requires-python = ">=3.11"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clipboard-link-cleaner"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = { virtual = "." }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "pyperclip" },
|
||||||
|
{ name = "pyside6" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
requires-dist = [
|
||||||
|
{ name = "pyperclip", specifier = ">=1.11.0" },
|
||||||
|
{ name = "pyside6", specifier = ">=6.10.0" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyperclip"
|
||||||
|
version = "1.11.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/e8/52/d87eba7cb129b81563019d1679026e7a112ef76855d6159d24754dbd2a51/pyperclip-1.11.0.tar.gz", hash = "sha256:244035963e4428530d9e3a6101a1ef97209c6825edab1567beac148ccc1db1b6", size = 12185, upload-time = "2025-09-26T14:40:37.245Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl", hash = "sha256:299403e9ff44581cb9ba2ffeed69c7aa96a008622ad0c46cb575ca75b5b84273", size = 11063, upload-time = "2025-09-26T14:40:36.069Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyside6"
|
||||||
|
version = "6.10.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "pyside6-addons" },
|
||||||
|
{ name = "pyside6-essentials" },
|
||||||
|
{ name = "shiboken6" },
|
||||||
|
]
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/56/22/f82cfcd1158be502c5741fe67c3fa853f3c1edbd3ac2c2250769dd9722d1/pyside6-6.10.1-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:d0e70dd0e126d01986f357c2a555722f9462cf8a942bf2ce180baf69f468e516", size = 558169, upload-time = "2025-11-20T10:09:08.79Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/66/eb/54afe242a25d1c33b04ecd8321a549d9efb7b89eef7690eed92e98ba1dc9/pyside6-6.10.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4053bf51ba2c2cb20e1005edd469997976a02cec009f7c46356a0b65c137f1fa", size = 557818, upload-time = "2025-11-20T10:09:10.132Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4d/af/5706b1b33587dc2f3dfa3a5000424befba35e4f2d5889284eebbde37138b/pyside6-6.10.1-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:7d3ca20a40139ca5324a7864f1d91cdf2ff237e11bd16354a42670f2a4eeb13c", size = 558358, upload-time = "2025-11-20T10:09:11.288Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/26/41/3f48d724ecc8e42cea8a8442aa9b5a86d394b85093275990038fd1020039/pyside6-6.10.1-cp39-abi3-win_amd64.whl", hash = "sha256:9f89ff994f774420eaa38cec6422fddd5356611d8481774820befd6f3bb84c9e", size = 564424, upload-time = "2025-11-20T10:09:12.677Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/af/30/395411473b433875a82f6b5fdd0cb28f19a0e345bcaac9fbc039400d7072/pyside6-6.10.1-cp39-abi3-win_arm64.whl", hash = "sha256:9c5c1d94387d1a32a6fae25348097918ef413b87dfa3767c46f737c6d48ae437", size = 548866, upload-time = "2025-11-20T10:09:14.174Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyside6-addons"
|
||||||
|
version = "6.10.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "pyside6-essentials" },
|
||||||
|
{ name = "shiboken6" },
|
||||||
|
]
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2d/f9/b72a2578d7dbef7741bb90b5756b4ef9c99a5b40148ea53ce7f048573fe9/pyside6_addons-6.10.1-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:4d2b82bbf9b861134845803837011e5f9ac7d33661b216805273cf0c6d0f8e82", size = 322639446, upload-time = "2025-11-20T09:54:50.75Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/94/3b/3ed951c570a15570706a89d39bfd4eaaffdf16d5c2dca17e82fc3ec8aaa6/pyside6_addons-6.10.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:330c229b58d30083a7b99ed22e118eb4f4126408429816a4044ccd0438ae81b4", size = 170678293, upload-time = "2025-11-20T09:56:40.991Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/22/77/4c780b204d0bf3323a75c184e349d063e208db44c993f1214aa4745d6f47/pyside6_addons-6.10.1-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:56864b5fecd6924187a2d0f7e98d968ed72b6cc267caa5b294cd7e88fff4e54c", size = 166365011, upload-time = "2025-11-20T09:57:20.261Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/14/58239776499e6b279fa6ca2e0d47209531454b99f6bd2ad7c96f11109416/pyside6_addons-6.10.1-cp39-abi3-win_amd64.whl", hash = "sha256:b6e249d15407dd33d6a2ffabd9dc6d7a8ab8c95d05f16a71dad4d07781c76341", size = 164864664, upload-time = "2025-11-20T09:57:54.815Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e2/cd/1b74108671ba4b1ebb2661330665c4898b089e9c87f7ba69fe2438f3d1b6/pyside6_addons-6.10.1-cp39-abi3-win_arm64.whl", hash = "sha256:0de303c0447326cdc6c8be5ab066ef581e2d0baf22560c9362d41b8304fdf2db", size = 34191225, upload-time = "2025-11-20T09:58:04.184Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyside6-essentials"
|
||||||
|
version = "6.10.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "shiboken6" },
|
||||||
|
]
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/b0/c43209fecef79912e9b1c70a1b5172b1edf76caebcc885c58c60a09613b0/pyside6_essentials-6.10.1-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:cd224aff3bb26ff1fca32c050e1c4d0bd9f951a96219d40d5f3d0128485b0bbe", size = 105461499, upload-time = "2025-11-20T09:59:23.733Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/8e/b69ba7fa0c701f3f4136b50460441697ec49ee6ea35c229eb2a5ee4b5952/pyside6_essentials-6.10.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:e9ccbfb58c03911a0bce1f2198605b02d4b5ca6276bfc0cbcf7c6f6393ffb856", size = 76764617, upload-time = "2025-11-20T09:59:38.831Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bd/83/569d27f4b6c6b9377150fe1a3745d64d02614021bea233636bc936a23423/pyside6_essentials-6.10.1-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:ec8617c9b143b0c19ba1cc5a7e98c538e4143795480cb152aee47802c18dc5d2", size = 75850373, upload-time = "2025-11-20T09:59:56.082Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1e/64/a8df6333de8ccbf3a320e1346ca30d0f314840aff5e3db9b4b66bf38e26c/pyside6_essentials-6.10.1-cp39-abi3-win_amd64.whl", hash = "sha256:9555a48e8f0acf63fc6a23c250808db841b28a66ed6ad89ee0e4df7628752674", size = 74491180, upload-time = "2025-11-20T10:00:11.215Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/67/da/65cc6c6a870d4ea908c59b2f0f9e2cf3bfc6c0710ebf278ed72f69865e4e/pyside6_essentials-6.10.1-cp39-abi3-win_arm64.whl", hash = "sha256:4d1d248644f1778f8ddae5da714ca0f5a150a5e6f602af2765a7d21b876da05c", size = 55190458, upload-time = "2025-11-20T10:00:26.226Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shiboken6"
|
||||||
|
version = "6.10.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6f/8b/e5db743d505ceea3efc4cd9634a3bee22a3e2bf6e07cefd28c9b9edabcc6/shiboken6-6.10.1-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:9f2990f5b61b0b68ecadcd896ab4441f2cb097eef7797ecc40584107d9850d71", size = 478483, upload-time = "2025-11-20T10:08:52.411Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/56/ba/b50c1a44b3c4643f482afbf1a0ea58f393827307100389ce29404f9ad3b0/shiboken6-6.10.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f4221a52dfb81f24a0d20cc4f8981cb6edd810d5a9fb28287ce10d342573a0e4", size = 271993, upload-time = "2025-11-20T10:08:54.093Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/16/b8/939c24ebd662b0aa5c945443d0973145b3fb7079f0196274ef7bb4b98f73/shiboken6-6.10.1-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:c095b00f4d6bf578c0b2464bb4e264b351a99345374478570f69e2e679a2a1d0", size = 268691, upload-time = "2025-11-20T10:08:55.639Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cf/a6/8c65ee0fa5e172ebcca03246b1bc3bd96cdaf1d60537316648536b7072a5/shiboken6-6.10.1-cp39-abi3-win_amd64.whl", hash = "sha256:c1601d3cda1fa32779b141663873741b54e797cb0328458d7466281f117b0a4e", size = 1234704, upload-time = "2025-11-20T10:08:57.417Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7b/6a/c0fea2f2ac7d9d96618c98156500683a4d1f93fea0e8c5a2bc39913d7ef1/shiboken6-6.10.1-cp39-abi3-win_arm64.whl", hash = "sha256:5cf800917008587b551005a45add2d485cca66f5f7ecd5b320e9954e40448cc9", size = 1795567, upload-time = "2025-11-20T10:08:59.184Z" },
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user