made installer and fixed releated bug fixes
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -4,4 +4,4 @@
|
|||||||
/build
|
/build
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.iss
|
*.iss
|
||||||
*.spec
|
UFF-Search.spec
|
||||||
17
README.md
17
README.md
@@ -2,10 +2,6 @@
|
|||||||
|
|
||||||
# UFF Search - Unsorted Folder Full-Text Search
|
# UFF Search - Unsorted Folder Full-Text Search
|
||||||
|
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
UFF Search is a powerful desktop application for Windows that allows you to perform fast, intelligent, and fuzzy full-text searches on your local files, including searching inside ZIP archives.
|
UFF Search is a powerful desktop application for Windows that allows you to perform fast, intelligent, and fuzzy full-text searches on your local files, including searching inside ZIP archives.
|
||||||
|
|
||||||
It builds a local search index for the folders you specify, allowing you to quickly find documents based on their meaning (semantic search) and specific keywords, even with typos in your search query.
|
It builds a local search index for the folders you specify, allowing you to quickly find documents based on their meaning (semantic search) and specific keywords, even with typos in your search query.
|
||||||
@@ -68,12 +64,18 @@ To create a standalone executable from the source code, you can use `pyinstaller
|
|||||||
|
|
||||||
2. **Build the executable:**
|
2. **Build the executable:**
|
||||||
```bash
|
```bash
|
||||||
pyinstaller --name "UFF_Search" --windowed --onefile --icon="favicon.ico" --add-data "assets;assets" main.py
|
pyinstaller --noconfirm --onedir --windowed --add-data "assets;assets" --icon "assets/favicon.ico" main.py
|
||||||
```
|
```
|
||||||
This command will create a single executable file in the `dist` folder.
|
Or:
|
||||||
|
```bash
|
||||||
|
pyinstaller main.spec
|
||||||
|
```
|
||||||
|
|
||||||
|
Both of these commands will create a single executable file in the `dist` folder. It may take some time to build.
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
(texts are only in german)
|
||||||
1. Start the application.
|
1. Start the application.
|
||||||
2. Click **" + Hinzufügen"** (Add) to select a folder you want to index. The application will start scanning it immediately.
|
2. Click **" + Hinzufügen"** (Add) to select a folder you want to index. The application will start scanning it immediately.
|
||||||
3. Once indexing is complete, type your search query into the search bar and press Enter or click **"Suchen"** (Search).
|
3. Once indexing is complete, type your search query into the search bar and press Enter or click **"Suchen"** (Search).
|
||||||
@@ -94,6 +96,7 @@ This command will create a single executable file in the `dist` folder.
|
|||||||
* `openpyxl` for `.xlsx` files.
|
* `openpyxl` for `.xlsx` files.
|
||||||
* `python-pptx` for `.pptx` files.
|
* `python-pptx` for `.pptx` files.
|
||||||
* **Index Location:** The search index database (`uff_index.db`) is stored in `%LOCALAPPDATA%\UFF_Search` on Windows.
|
* **Index Location:** The search index database (`uff_index.db`) is stored in `%LOCALAPPDATA%\UFF_Search` on Windows.
|
||||||
|
* **Size:** (ca. 400-600 MB)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
20
config.py
20
config.py
@@ -15,22 +15,32 @@ if not os.path.exists(APP_DATA_DIR):
|
|||||||
DB_NAME = os.path.join(APP_DATA_DIR, "uff_index.db")
|
DB_NAME = os.path.join(APP_DATA_DIR, "uff_index.db")
|
||||||
LOG_FILE = os.path.join(APP_DATA_DIR, "uff.log")
|
LOG_FILE = os.path.join(APP_DATA_DIR, "uff.log")
|
||||||
|
|
||||||
|
def resource_path(relative_path):
|
||||||
|
"""
|
||||||
|
Holt den absoluten Pfad zu Ressourcen.
|
||||||
|
Funktioniert für Dev-Modus UND für PyInstaller EXE (_MEIPASS).
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# PyInstaller erstellt temporären Ordner _MEIPASS
|
||||||
|
base_path = sys._MEIPASS
|
||||||
|
except Exception:
|
||||||
|
base_path = os.path.abspath(".")
|
||||||
|
|
||||||
|
return os.path.join(base_path, relative_path)
|
||||||
|
|
||||||
# --- LOGGING KLASSE ---
|
# --- LOGGING KLASSE ---
|
||||||
class Logger(object):
|
class Logger(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# "w" überschreibt bei jedem Start. Nutze "a" für anhängen (append).
|
self.terminal = sys.stdout
|
||||||
self.terminal = sys.stdout # Optional: Falls du es AUCH im Terminal sehen willst
|
|
||||||
self.log = open(LOG_FILE, "w", encoding="utf-8")
|
self.log = open(LOG_FILE, "w", encoding="utf-8")
|
||||||
|
|
||||||
def write(self, message):
|
def write(self, message):
|
||||||
# Optional: ins Terminal schreiben (auskommentieren, wenn du nur Logfile willst)
|
|
||||||
# self.terminal.write(message)
|
|
||||||
|
|
||||||
self.log.write(message)
|
self.log.write(message)
|
||||||
self.log.flush()
|
self.log.flush()
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
# self.terminal.flush()
|
|
||||||
self.log.flush()
|
self.log.flush()
|
||||||
|
|
||||||
# --- AKTIVIERUNG DES LOGGERS ---
|
# --- AKTIVIERUNG DES LOGGERS ---
|
||||||
|
|||||||
17
main.py
17
main.py
@@ -7,7 +7,7 @@ from PyQt6.QtGui import QPixmap, QFont, QIcon
|
|||||||
from PyQt6.QtCore import qInstallMessageHandler, QTimer, Qt
|
from PyQt6.QtCore import qInstallMessageHandler, QTimer, Qt
|
||||||
|
|
||||||
# Config zuerst!
|
# Config zuerst!
|
||||||
from config import qt_message_handler, LOG_FILE
|
from config import qt_message_handler, LOG_FILE, resource_path
|
||||||
|
|
||||||
from ui import UffWindow, ModernSplashScreen, ModelLoaderThread
|
from ui import UffWindow, ModernSplashScreen, ModelLoaderThread
|
||||||
|
|
||||||
@@ -19,15 +19,14 @@ if __name__ == "__main__":
|
|||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
app.setFont(QFont("Segoe UI", 10))
|
app.setFont(QFont("Segoe UI", 10))
|
||||||
|
|
||||||
# 1. ICON SETZEN (Für die ganze App)
|
icon_path = resource_path("assets/uff_icon.jpeg") # <--- HIER
|
||||||
# Wenn assets/icon.png existiert, wird es genutzt.
|
if os.path.exists(icon_path):
|
||||||
if os.path.exists("assets/icon.png"):
|
app_icon = QIcon(icon_path)
|
||||||
app_icon = QIcon("assets/icon.png")
|
|
||||||
app.setWindowIcon(app_icon)
|
app.setWindowIcon(app_icon)
|
||||||
|
|
||||||
# 2. SPLASH SCREEN ERSTELLEN
|
# SPLASH LADEN (Mit resource_path)
|
||||||
splash_pix = QPixmap("assets/uff_banner.jpeg")
|
banner_path = resource_path("assets/uff_banner.jpeg")
|
||||||
# Falls kein Bild da ist, nehmen wir ein leeres (damit es nicht crasht)
|
splash_pix = QPixmap(banner_path)
|
||||||
if splash_pix.isNull():
|
if splash_pix.isNull():
|
||||||
splash_pix = QPixmap(600, 400)
|
splash_pix = QPixmap(600, 400)
|
||||||
splash_pix.fill(Qt.GlobalColor.white)
|
splash_pix.fill(Qt.GlobalColor.white)
|
||||||
@@ -35,8 +34,6 @@ if __name__ == "__main__":
|
|||||||
splash = ModernSplashScreen(splash_pix)
|
splash = ModernSplashScreen(splash_pix)
|
||||||
splash.show()
|
splash.show()
|
||||||
|
|
||||||
# 3. LADEN SIMULIEREN & STARTEN
|
|
||||||
# Wir nutzen einen kleinen Trick, um den Start visuell zu "begleiten"
|
|
||||||
|
|
||||||
splash.set_progress(10, "Lade Konfiguration...")
|
splash.set_progress(10, "Lade Konfiguration...")
|
||||||
app.processEvents()
|
app.processEvents()
|
||||||
|
|||||||
72
main.spec
Normal file
72
main.spec
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# -*- mode: python ; coding: utf-8 -*-
|
||||||
|
from PyInstaller.utils.hooks import collect_all
|
||||||
|
|
||||||
|
# --- 1. SPEZIELLE BIBLIOTHEKEN SAMMELN ---
|
||||||
|
# sentence_transformers und rapidfuzz sind komplex, wir holen alles automatisch
|
||||||
|
datas = [('assets', 'assets')]
|
||||||
|
binaries = []
|
||||||
|
hiddenimports = [
|
||||||
|
'docx',
|
||||||
|
'openpyxl',
|
||||||
|
'pptx',
|
||||||
|
'pdfplumber',
|
||||||
|
'rapidfuzz',
|
||||||
|
'sentence_transformers',
|
||||||
|
'numpy'
|
||||||
|
]
|
||||||
|
|
||||||
|
# Sammle alle Daten für die KI-Bibliothek (verhindert Import-Fehler)
|
||||||
|
tmp_ret = collect_all('sentence_transformers')
|
||||||
|
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||||
|
|
||||||
|
# Sammle rapidfuzz sicherheitshalber auch komplett
|
||||||
|
tmp_ret = collect_all('rapidfuzz')
|
||||||
|
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||||
|
|
||||||
|
|
||||||
|
# --- 2. ANALYSE ---
|
||||||
|
a = Analysis(
|
||||||
|
['main.py'],
|
||||||
|
pathex=[],
|
||||||
|
binaries=binaries,
|
||||||
|
datas=datas,
|
||||||
|
hiddenimports=hiddenimports,
|
||||||
|
hookspath=[],
|
||||||
|
hooksconfig={},
|
||||||
|
runtime_hooks=[],
|
||||||
|
excludes=[],
|
||||||
|
noarchive=False,
|
||||||
|
optimize=0,
|
||||||
|
)
|
||||||
|
pyz = PYZ(a.pure)
|
||||||
|
|
||||||
|
# --- 3. EXE ERSTELLEN ---
|
||||||
|
exe = EXE(
|
||||||
|
pyz,
|
||||||
|
a.scripts,
|
||||||
|
[],
|
||||||
|
exclude_binaries=True,
|
||||||
|
name='UFF_Search', # Name der Datei (UFF_Search.exe)
|
||||||
|
debug=False,
|
||||||
|
bootloader_ignore_signals=False,
|
||||||
|
strip=False,
|
||||||
|
upx=True,
|
||||||
|
console=False,
|
||||||
|
disable_windowed_traceback=False,
|
||||||
|
argv_emulation=False,
|
||||||
|
target_arch=None,
|
||||||
|
codesign_identity=None,
|
||||||
|
entitlements_file=None,
|
||||||
|
icon='assets\\favicon.ico', # Pfad zum Icon
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- 4. ORDNER ZUSAMMENSTELLEN ---
|
||||||
|
coll = COLLECT(
|
||||||
|
exe,
|
||||||
|
a.binaries,
|
||||||
|
a.datas,
|
||||||
|
strip=False,
|
||||||
|
upx=True,
|
||||||
|
upx_exclude=[],
|
||||||
|
name='UFF_Search', # Name des Ordners
|
||||||
|
)
|
||||||
5
ui.py
5
ui.py
@@ -1,6 +1,6 @@
|
|||||||
# ui.py
|
# ui.py
|
||||||
import os
|
import os
|
||||||
from PyQt6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
||||||
QLineEdit, QPushButton, QLabel, QFileDialog,
|
QLineEdit, QPushButton, QLabel, QFileDialog,
|
||||||
QProgressBar, QMessageBox, QListWidget, QListWidgetItem,
|
QProgressBar, QMessageBox, QListWidget, QListWidgetItem,
|
||||||
QSplitter, QFrame, QScrollArea, QStyle, QGraphicsDropShadowEffect,
|
QSplitter, QFrame, QScrollArea, QStyle, QGraphicsDropShadowEffect,
|
||||||
@@ -133,9 +133,6 @@ class UffWindow(QMainWindow):
|
|||||||
self.db = DatabaseHandler()
|
self.db = DatabaseHandler()
|
||||||
self.initUI()
|
self.initUI()
|
||||||
|
|
||||||
# NEU: Icon setzen
|
|
||||||
if os.path.exists("assets/uff_icon.jpeg"):
|
|
||||||
self.setWindowIcon(QIcon("assets/uff_icon.jpeg"))
|
|
||||||
|
|
||||||
self.load_saved_folders()
|
self.load_saved_folders()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user