made installer and fixed releated bug fixes
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -4,4 +4,4 @@
|
||||
/build
|
||||
__pycache__/
|
||||
*.iss
|
||||
*.spec
|
||||
UFF-Search.spec
|
||||
17
README.md
17
README.md
@@ -2,10 +2,6 @@
|
||||
|
||||
# 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.
|
||||
|
||||
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:**
|
||||
```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
|
||||
|
||||
(texts are only in german)
|
||||
1. Start the application.
|
||||
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).
|
||||
@@ -94,6 +96,7 @@ This command will create a single executable file in the `dist` folder.
|
||||
* `openpyxl` for `.xlsx` files.
|
||||
* `python-pptx` for `.pptx` files.
|
||||
* **Index Location:** The search index database (`uff_index.db`) is stored in `%LOCALAPPDATA%\UFF_Search` on Windows.
|
||||
* **Size:** (ca. 400-600 MB)
|
||||
|
||||
## 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")
|
||||
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 ---
|
||||
class Logger(object):
|
||||
def __init__(self):
|
||||
# "w" überschreibt bei jedem Start. Nutze "a" für anhängen (append).
|
||||
self.terminal = sys.stdout # Optional: Falls du es AUCH im Terminal sehen willst
|
||||
self.terminal = sys.stdout
|
||||
self.log = open(LOG_FILE, "w", encoding="utf-8")
|
||||
|
||||
def write(self, message):
|
||||
# Optional: ins Terminal schreiben (auskommentieren, wenn du nur Logfile willst)
|
||||
# self.terminal.write(message)
|
||||
|
||||
|
||||
self.log.write(message)
|
||||
self.log.flush()
|
||||
|
||||
def flush(self):
|
||||
# self.terminal.flush()
|
||||
self.log.flush()
|
||||
|
||||
# --- 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
|
||||
|
||||
# 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
|
||||
|
||||
@@ -19,15 +19,14 @@ if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
app.setFont(QFont("Segoe UI", 10))
|
||||
|
||||
# 1. ICON SETZEN (Für die ganze App)
|
||||
# Wenn assets/icon.png existiert, wird es genutzt.
|
||||
if os.path.exists("assets/icon.png"):
|
||||
app_icon = QIcon("assets/icon.png")
|
||||
icon_path = resource_path("assets/uff_icon.jpeg") # <--- HIER
|
||||
if os.path.exists(icon_path):
|
||||
app_icon = QIcon(icon_path)
|
||||
app.setWindowIcon(app_icon)
|
||||
|
||||
# 2. SPLASH SCREEN ERSTELLEN
|
||||
splash_pix = QPixmap("assets/uff_banner.jpeg")
|
||||
# Falls kein Bild da ist, nehmen wir ein leeres (damit es nicht crasht)
|
||||
# SPLASH LADEN (Mit resource_path)
|
||||
banner_path = resource_path("assets/uff_banner.jpeg")
|
||||
splash_pix = QPixmap(banner_path)
|
||||
if splash_pix.isNull():
|
||||
splash_pix = QPixmap(600, 400)
|
||||
splash_pix.fill(Qt.GlobalColor.white)
|
||||
@@ -35,8 +34,6 @@ if __name__ == "__main__":
|
||||
splash = ModernSplashScreen(splash_pix)
|
||||
splash.show()
|
||||
|
||||
# 3. LADEN SIMULIEREN & STARTEN
|
||||
# Wir nutzen einen kleinen Trick, um den Start visuell zu "begleiten"
|
||||
|
||||
splash.set_progress(10, "Lade Konfiguration...")
|
||||
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
|
||||
)
|
||||
7
ui.py
7
ui.py
@@ -1,6 +1,6 @@
|
||||
# ui.py
|
||||
import os
|
||||
from PyQt6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
||||
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
||||
QLineEdit, QPushButton, QLabel, QFileDialog,
|
||||
QProgressBar, QMessageBox, QListWidget, QListWidgetItem,
|
||||
QSplitter, QFrame, QScrollArea, QStyle, QGraphicsDropShadowEffect,
|
||||
@@ -133,10 +133,7 @@ class UffWindow(QMainWindow):
|
||||
self.db = DatabaseHandler()
|
||||
self.initUI()
|
||||
|
||||
# NEU: Icon setzen
|
||||
if os.path.exists("assets/uff_icon.jpeg"):
|
||||
self.setWindowIcon(QIcon("assets/uff_icon.jpeg"))
|
||||
|
||||
|
||||
self.load_saved_folders()
|
||||
|
||||
def initUI(self):
|
||||
|
||||
Reference in New Issue
Block a user