Bump version to 0.8.0 and add support for all image formats
All checks were successful
Gitea/kapitanbooru-uploader/pipeline/head This commit looks good

This commit is contained in:
Michał Leśniak 2025-03-27 21:11:36 +01:00
parent dcd8e0824f
commit b1b8ed237e
6 changed files with 450 additions and 360 deletions

View File

@ -1,148 +1,38 @@
import glob import glob
import hashlib import hashlib
import inspect
import os import os
import queue import queue
import threading import threading
import tkinter as tk import tkinter as tk
from tkinter import filedialog, messagebox, ttk from tkinter import filedialog, messagebox, ttk
from typing import Dict, Tuple, Optional from typing import Dict, Tuple, Optional
import concurrent.futures
from packaging.version import parse as parse_version from packaging.version import parse as parse_version
import itertools import itertools
import networkx as nx import networkx as nx
import requests import requests
from PIL import Image, ImageTk, PngImagePlugin from PIL import Image, ImageTk
import wdtagger as wdt import wdtagger as wdt
import tomli import tomli
from .ProcessingDialog import ProcessingDialog
from .I18N import _ from .I18N import _
from .ProgressFile import ProgressFile from .ProgressFile import ProgressFile
from .TagsRepo import TagsRepo from .TagsRepo import TagsRepo
from .autocomplete import TagManager from .autocomplete import TagManager
from .common import get_auth_token, login, open_tag_wiki_url, open_webbrowser from .common import get_auth_token, login, open_tag_wiki_url, open_webbrowser
from .settings import Settings from .settings import Settings
from .tag_processing import TAG_FIXES, parse_parameters, process_tag from .tag_processing import TAG_FIXES, extract_parameters, parse_parameters, process_tag
from .tagger_cache import TaggerCache from .tagger_cache import TaggerCache
class ProcessingDialog:
def __init__(self, root, target_function, *args):
self.root = root
self.top = tk.Toplevel(root)
self.top.title(_("Processing..."))
self.top.geometry("300x150")
self.top.protocol("WM_DELETE_WINDOW", self.on_close)
self.label = tk.Label(self.top, text=_("Processing, please wait..."))
self.label.pack(pady=10)
# Start with indeterminate progress bar
self.progress = ttk.Progressbar(self.top, mode="indeterminate")
self.progress.pack(pady=10, fill="x")
self.progress.start(10)
sig = inspect.signature(target_function)
if "secondary_progress_queue" in sig.parameters:
self.sub_progress = ttk.Progressbar(self.top, mode="indeterminate")
self.sub_progress.pack(pady=10, fill="x")
self.sub_progress.start(10)
# Setup communication queue and periodic checker
self.queue = queue.Queue()
self.sub_queue = queue.Queue()
self.running = True
self.cancel_event = threading.Event() # Cancellation flag
self.thread = threading.Thread(
target=self.run_task, args=(target_function, *args)
)
self.thread.start()
self.top.after(100, self.process_queue)
def process_queue(self):
"""Process messages from the background thread"""
while self.running:
try:
msg = self.queue.get_nowait()
if msg[0] == "mode":
self.progress.config(mode=msg[1])
if msg[1] == "determinate":
self.progress["value"] = 0
self.progress.stop()
elif msg[1] == "indeterminate":
self.progress["value"] = 0
self.progress.start()
elif msg[0] == "max":
self.progress["maximum"] = msg[1]
elif msg[0] == "progress":
self.progress["value"] = msg[1]
elif msg[0] == "label":
self.label.config(text=msg[1])
self.top.update_idletasks()
except queue.Empty:
break
try:
msg = self.sub_queue.get_nowait()
if msg[0] == "mode":
self.sub_progress.config(mode=msg[1])
if msg[1] == "determinate":
self.sub_progress["value"] = 0
self.sub_progress.stop()
elif msg[1] == "indeterminate":
self.sub_progress["value"] = 0
self.sub_progress.start()
elif msg[0] == "max":
self.sub_progress["maximum"] = msg[1]
elif msg[0] == "progress":
self.sub_progress["value"] = msg[1]
self.top.update_idletasks()
except queue.Empty:
break
if self.running:
self.top.after(100, self.process_queue)
def run_task(self, target_function, *args):
"""Execute target function with progress queue if supported"""
try:
sig = inspect.signature(target_function)
kwargs = {}
if "progress_queue" in sig.parameters:
kwargs["progress_queue"] = self.queue
if "secondary_progress_queue" in sig.parameters:
kwargs["secondary_progress_queue"] = self.sub_queue
if "cancel_event" in sig.parameters:
kwargs["cancel_event"] = self.cancel_event
target_function(*args, **kwargs)
finally:
self.close_dialog()
def close_dialog(self):
"""Safely close the dialog"""
if self.running:
self.running = False
self.progress.stop()
self.top.after(0, self.top.destroy)
self.root.after(100, self.thread.join)
def on_close(self):
"""Handle manual window closure"""
self.running = False
self.cancel_event.set() # Notify target function that cancellation is requested
self.top.destroy()
class ImageBrowser(tk.Tk): class ImageBrowser(tk.Tk):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.title("Kapitanbooru Uploader") self.title("Kapitanbooru Uploader")
self.geometry("900x600") self.geometry("900x600")
self.version = "0.7.0" self.version = "0.8.0"
self.acknowledged_version = parse_version(self.version) self.acknowledged_version = parse_version(self.version)
self.settings = Settings() self.settings = Settings()
@ -359,9 +249,7 @@ class ImageBrowser(tk.Tk):
# Pobierz tagi z pliku # Pobierz tagi z pliku
try: try:
img = Image.open(file_path) img = Image.open(file_path)
parameters = "" parameters = extract_parameters(img, file_path)
if isinstance(img, PngImagePlugin.PngImageFile):
parameters = img.info.get("parameters", "")
png_tags = set( png_tags = set(
[ [
x x
@ -785,27 +673,37 @@ class ImageBrowser(tk.Tk):
def select_folder(self): def select_folder(self):
""" """
Otwiera okno dialogowe wyboru folderu z obrazkami Otwiera okno dialogowe wyboru folderu z obrazkami
i wczytuje pliki PNG z wybranego folderu. i wczytuje pliki PNG, JPEG, WebP, AVIF i GIF z wybranego folderu.
""" """
folder = filedialog.askdirectory(title=_("Wybierz folder z obrazkami PNG")) folder = filedialog.askdirectory(
title=_("Wybierz folder z obrazkami PNG, JPEG, WebP, AVIF i GIF")
)
if folder: if folder:
self.folder_path = folder self.folder_path = folder
self.load_images() self.load_images()
def load_images(self): def load_images(self):
""" """
Ładuje pliki PNG z wybranego folderu. Ładuje pliki PNG, JPEG, WebP, AVIF i GIF z wybranego folderu.
""" """
pattern = os.path.join(self.folder_path, "*.png") extensions = ("*.png", "*.jpg", "*.jpeg", "*.webp", "*.avif", "*.gif")
self.image_files = sorted(glob.glob(pattern)) self.image_files = sorted(
file
for ext in extensions
for file in glob.glob(os.path.join(self.folder_path, ext), recursive=True)
)
self.total_files = len(self.image_files) self.total_files = len(self.image_files)
self.image_files_md5 = { self.image_files_md5 = {
file: self.compute_md5(file) for file in self.image_files file: md5
for file, md5 in zip(
self.image_files, self.compute_md5_parallel(self.image_files)
)
} }
self.tagger_processed.clear() self.tagger_processed.clear()
for md5 in self.image_files_md5.values(): for md5 in self.image_files_md5.values():
if self.tagger_cache[md5]: if self.tagger_cache[md5]:
self.tagger_processed.add(md5) self.tagger_processed.add(md5)
# Clear the entire listbox to prepare for reloading new items
self.listbox.delete(0, tk.END) self.listbox.delete(0, tk.END)
self.uploaded.clear() self.uploaded.clear()
self.upload_verified = 0 self.upload_verified = 0
@ -820,7 +718,8 @@ class ImageBrowser(tk.Tk):
self.post_load_processing() self.post_load_processing()
else: else:
messagebox.showinfo( messagebox.showinfo(
_("Informacja"), _("Brak plików PNG w wybranym folderze.") _("Informacja"),
_("Brak plików PNG, JPEG, WebP, AVIF lub GIF w wybranym folderze."),
) )
def post_load_processing(self): def post_load_processing(self):
@ -972,17 +871,22 @@ class ImageBrowser(tk.Tk):
open_webbrowser(url, self.settings) open_webbrowser(url, self.settings)
def compute_md5(self, file_path, chunk_size=8192): def compute_md5(self, file_path, chunk_size=8192):
"""Oblicza MD5 dla danego pliku.""" """Compute MD5 for a single file."""
hash_md5 = hashlib.md5() hash_md5 = hashlib.md5()
try: try:
with open(file_path, "rb") as f: with open(file_path, "rb") as f:
for chunk in iter(lambda: f.read(chunk_size), b""): for chunk in iter(lambda: f.read(chunk_size), b""):
hash_md5.update(chunk) hash_md5.update(chunk)
except Exception as e: except Exception as e:
print(_("Błąd przy obliczaniu MD5:"), e) print(_("Error computing MD5:"), e)
return "" return ""
return hash_md5.hexdigest() return hash_md5.hexdigest()
def compute_md5_parallel(self, file_paths):
"""Compute MD5 for multiple files in parallel."""
with concurrent.futures.ThreadPoolExecutor() as executor:
return list(executor.map(self.compute_md5, file_paths))
def on_listbox_select(self, event): def on_listbox_select(self, event):
""" """
Wywoływane po wybraniu pliku z listy. Wywoływane po wybraniu pliku z listy.
@ -1019,9 +923,7 @@ class ImageBrowser(tk.Tk):
file_path = self.image_files[index] file_path = self.image_files[index]
try: try:
img = Image.open(file_path) img = Image.open(file_path)
parameters = "" parameters = extract_parameters(img, file_path)
if isinstance(img, PngImagePlugin.PngImageFile):
parameters = img.info.get("parameters", "")
self.current_image_original = img.copy() self.current_image_original = img.copy()
self.current_parameters = parameters self.current_parameters = parameters
self.update_display_image() self.update_display_image()

View File

@ -0,0 +1,119 @@
from .I18N import _
import inspect
import queue
import threading
import tkinter as tk
from tkinter import ttk
class ProcessingDialog:
def __init__(self, root, target_function, *args):
self.root = root
self.top = tk.Toplevel(root)
self.top.title(_("Processing..."))
self.top.geometry("300x150")
self.top.protocol("WM_DELETE_WINDOW", self.on_close)
self.label = tk.Label(self.top, text=_("Processing, please wait..."))
self.label.pack(pady=10)
# Start with indeterminate progress bar
self.progress = ttk.Progressbar(self.top, mode="indeterminate")
self.progress.pack(pady=10, fill="x")
self.progress.start(10)
sig = inspect.signature(target_function)
if "secondary_progress_queue" in sig.parameters:
self.sub_progress = ttk.Progressbar(self.top, mode="indeterminate")
self.sub_progress.pack(pady=10, fill="x")
self.sub_progress.start(10)
# Setup communication queue and periodic checker
self.queue = queue.Queue()
self.sub_queue = queue.Queue()
self.running = True
self.cancel_event = threading.Event() # Cancellation flag
self.thread = threading.Thread(
target=self.run_task, args=(target_function, *args)
)
self.thread.start()
self.top.after(100, self.process_queue)
def process_queue(self):
"""Process messages from the background thread"""
while self.running:
try:
msg = self.queue.get_nowait()
if msg[0] == "mode":
self.progress.config(mode=msg[1])
if msg[1] == "determinate":
self.progress["value"] = 0
self.progress.stop()
elif msg[1] == "indeterminate":
self.progress["value"] = 0
self.progress.start()
elif msg[0] == "max":
self.progress["maximum"] = msg[1]
elif msg[0] == "progress":
self.progress["value"] = msg[1]
elif msg[0] == "label":
self.label.config(text=msg[1])
self.top.update_idletasks()
except queue.Empty:
break
try:
msg = self.sub_queue.get_nowait()
if msg[0] == "mode":
self.sub_progress.config(mode=msg[1])
if msg[1] == "determinate":
self.sub_progress["value"] = 0
self.sub_progress.stop()
elif msg[1] == "indeterminate":
self.sub_progress["value"] = 0
self.sub_progress.start()
elif msg[0] == "max":
self.sub_progress["maximum"] = msg[1]
elif msg[0] == "progress":
self.sub_progress["value"] = msg[1]
self.top.update_idletasks()
except queue.Empty:
break
if self.running:
self.top.after(100, self.process_queue)
def run_task(self, target_function, *args):
"""Execute target function with progress queue if supported"""
try:
sig = inspect.signature(target_function)
kwargs = {}
if "progress_queue" in sig.parameters:
kwargs["progress_queue"] = self.queue
if "secondary_progress_queue" in sig.parameters:
kwargs["secondary_progress_queue"] = self.sub_queue
if "cancel_event" in sig.parameters:
kwargs["cancel_event"] = self.cancel_event
target_function(*args, **kwargs)
finally:
self.close_dialog()
def close_dialog(self):
"""Safely close the dialog"""
if self.running:
self.running = False
self.progress.stop()
self.top.after(0, self.top.destroy)
self.root.after(100, self.thread.join)
def on_close(self):
"""Handle manual window closure"""
self.running = False
self.cancel_event.set() # Notify target function that cancellation is requested
self.top.destroy()

View File

@ -1,8 +1,8 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Kapitanbooru Uploader 0.7.0\n" "Project-Id-Version: Kapitanbooru Uploader 0.8.0\n"
"Report-Msgid-Bugs-To: kapitan@mlesniak.pl\n" "Report-Msgid-Bugs-To: kapitan@mlesniak.pl\n"
"POT-Creation-Date: 2025-03-16 01:22+0100\n" "POT-Creation-Date: 2025-03-27 20:47+0100\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
@ -43,34 +43,26 @@ msgstr "Found auth_token:"
msgid "auth_token not found in the HTML page." msgid "auth_token not found in the HTML page."
msgstr "auth_token not found in the HTML page." msgstr "auth_token not found in the HTML page."
#: ImageBrowser.py:33 #: ImageBrowser.py:138
msgid "Processing..."
msgstr "Processing..."
#: ImageBrowser.py:37
msgid "Processing, please wait..."
msgstr "Processing, please wait..."
#: ImageBrowser.py:248
#, python-brace-format #, python-brace-format
msgid "Update check failed: {error}" msgid "Update check failed: {error}"
msgstr "Update check failed: {error}" msgstr "Update check failed: {error}"
#: ImageBrowser.py:250 #: ImageBrowser.py:140
#, python-brace-format #, python-brace-format
msgid "Malformed pyproject.toml: {error}" msgid "Malformed pyproject.toml: {error}"
msgstr "Malformed pyproject.toml: {error}" msgstr "Malformed pyproject.toml: {error}"
#: ImageBrowser.py:253 #: ImageBrowser.py:143
#, python-brace-format #, python-brace-format
msgid "Unexpected error during update check: {error}" msgid "Unexpected error during update check: {error}"
msgstr "Unexpected error during update check: {error}" msgstr "Unexpected error during update check: {error}"
#: ImageBrowser.py:260 #: ImageBrowser.py:150
msgid "Update Available" msgid "Update Available"
msgstr "Update Available" msgstr "Update Available"
#: ImageBrowser.py:262 #: ImageBrowser.py:152
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"A new version {new_version} is available!\n" "A new version {new_version} is available!\n"
@ -83,240 +75,241 @@ msgstr ""
"\n" "\n"
"Update using: {update_command}" "Update using: {update_command}"
#: ImageBrowser.py:375 #: ImageBrowser.py:263
msgid "Błąd przy otwieraniu pliku" msgid "Błąd przy otwieraniu pliku"
msgstr "Error opening file" msgstr "Error opening file"
#: ImageBrowser.py:417 #: ImageBrowser.py:305
msgid "Tagger przetworzył:" msgid "Tagger przetworzył:"
msgstr "Tagger processed:" msgstr "Tagger processed:"
#: ImageBrowser.py:420 #: ImageBrowser.py:308
msgid "Błąd Taggera dla" msgid "Błąd Taggera dla"
msgstr "Tagger error for" msgstr "Tagger error for"
#: ImageBrowser.py:446 #: ImageBrowser.py:334
msgid "Otwórz folder" msgid "Otwórz folder"
msgstr "Open folder" msgstr "Open folder"
#: ImageBrowser.py:449 ImageBrowser.py:738 ImageBrowser.py:954 #: ImageBrowser.py:337 ImageBrowser.py:626 ImageBrowser.py:853
#: ImageBrowser.py:962 #: ImageBrowser.py:861
msgid "Wyślij" msgid "Wyślij"
msgstr "Send" msgstr "Send"
#: ImageBrowser.py:452 ImageBrowser.py:947 #: ImageBrowser.py:340 ImageBrowser.py:846
msgid "Wyślij wszystko" msgid "Wyślij wszystko"
msgstr "Send all" msgstr "Send all"
#: ImageBrowser.py:456 ImageBrowser.py:948 ImageBrowser.py:954 #: ImageBrowser.py:344 ImageBrowser.py:847 ImageBrowser.py:853
msgid "Podmień tagi" msgid "Podmień tagi"
msgstr "Replace tags" msgstr "Replace tags"
#: ImageBrowser.py:459 ImageBrowser.py:949 #: ImageBrowser.py:347 ImageBrowser.py:848
msgid "Otwórz post" msgid "Otwórz post"
msgstr "Open post" msgstr "Open post"
#: ImageBrowser.py:462 #: ImageBrowser.py:350
msgid "Zakończ" msgid "Zakończ"
msgstr "Finish" msgstr "Finish"
#: ImageBrowser.py:464 #: ImageBrowser.py:352
msgid "Plik" msgid "Plik"
msgstr "File" msgstr "File"
#: ImageBrowser.py:468 ImageBrowser.py:567 #: ImageBrowser.py:356 ImageBrowser.py:455
msgid "Ustawienia" msgid "Ustawienia"
msgstr "Settings" msgstr "Settings"
#: ImageBrowser.py:471 #: ImageBrowser.py:359
msgid "Wyczyść cache Taggera" msgid "Wyczyść cache Taggera"
msgstr "Clear Tagger cache" msgstr "Clear Tagger cache"
#: ImageBrowser.py:474 #: ImageBrowser.py:362
msgid "Zregeneruj bazę tagów" msgid "Zregeneruj bazę tagów"
msgstr "Regenerate tag database" msgstr "Regenerate tag database"
#: ImageBrowser.py:476 #: ImageBrowser.py:364
msgid "Opcje" msgid "Opcje"
msgstr "Options" msgstr "Options"
#: ImageBrowser.py:479 #: ImageBrowser.py:367
msgid "About" msgid "About"
msgstr "About" msgstr "About"
#: ImageBrowser.py:480 #: ImageBrowser.py:368
msgid "Help" msgid "Help"
msgstr "Help" msgstr "Help"
#: ImageBrowser.py:485 #: ImageBrowser.py:373
msgid "About Kapitanbooru Uploader" msgid "About Kapitanbooru Uploader"
msgstr "About Kapitanbooru Uploader" msgstr "About Kapitanbooru Uploader"
#: ImageBrowser.py:502 #: ImageBrowser.py:390
#, python-brace-format #, python-brace-format
msgid "A new version {new_version} is available!" msgid "A new version {new_version} is available!"
msgstr "A new version {new_version} is available!" msgstr "A new version {new_version} is available!"
#: ImageBrowser.py:509 #: ImageBrowser.py:397
#, python-brace-format #, python-brace-format
msgid "Current version: {version}" msgid "Current version: {version}"
msgstr "Current version: {version}" msgstr "Current version: {version}"
#: ImageBrowser.py:511 #: ImageBrowser.py:399
msgid "A GUI application for uploading images to KapitanBooru." msgid "A GUI application for uploading images to KapitanBooru."
msgstr "A GUI application for uploading images to KapitanBooru." msgstr "A GUI application for uploading images to KapitanBooru."
#: ImageBrowser.py:512 #: ImageBrowser.py:400
msgid "Features include image upload, tag management, automatic" msgid "Features include image upload, tag management, automatic"
msgstr "Features include image upload, tag management, automatic" msgstr "Features include image upload, tag management, automatic"
#: ImageBrowser.py:513 #: ImageBrowser.py:401
msgid "tagging with wdtagger, and cache management." msgid "tagging with wdtagger, and cache management."
msgstr "tagging with wdtagger, and cache management." msgstr "tagging with wdtagger, and cache management."
#: ImageBrowser.py:515 #: ImageBrowser.py:403
msgid "Authors:" msgid "Authors:"
msgstr "Authors:" msgstr "Authors:"
#: ImageBrowser.py:518 #: ImageBrowser.py:406
msgid "License: MIT License" msgid "License: MIT License"
msgstr "License: MIT License" msgstr "License: MIT License"
#: ImageBrowser.py:531 #: ImageBrowser.py:419
msgid "Repository:" msgid "Repository:"
msgstr "Repository:" msgstr "Repository:"
#: ImageBrowser.py:540 #: ImageBrowser.py:428
msgid "Website:" msgid "Website:"
msgstr "Website:" msgstr "Website:"
#: ImageBrowser.py:551 #: ImageBrowser.py:439
msgid "Close" msgid "Close"
msgstr "Close" msgstr "Close"
#: ImageBrowser.py:559 ImageBrowser.py:562 #: ImageBrowser.py:447 ImageBrowser.py:450
msgid "Cache" msgid "Cache"
msgstr "Cache" msgstr "Cache"
#: ImageBrowser.py:559 #: ImageBrowser.py:447
msgid "Cache Taggera zostało wyczyszczone." msgid "Cache Taggera zostało wyczyszczone."
msgstr "Tagger cache has been cleared." msgstr "Tagger cache has been cleared."
#: ImageBrowser.py:562 #: ImageBrowser.py:450
msgid "Błąd przy czyszczeniu cache:" msgid "Błąd przy czyszczeniu cache:"
msgstr "Error clearing cache:" msgstr "Error clearing cache:"
#: ImageBrowser.py:572 #: ImageBrowser.py:460
msgid "Login:" msgid "Login:"
msgstr "Login:" msgstr "Login:"
#: ImageBrowser.py:578 #: ImageBrowser.py:466
msgid "Hasło:" msgid "Hasło:"
msgstr "Password:" msgstr "Password:"
#: ImageBrowser.py:584 #: ImageBrowser.py:472
msgid "Base URL:" msgid "Base URL:"
msgstr "Base URL:" msgstr "Base URL:"
#: ImageBrowser.py:590 #: ImageBrowser.py:478
msgid "Default Tags:" msgid "Default Tags:"
msgstr "Default Tags:" msgstr "Default Tags:"
#: ImageBrowser.py:596 #: ImageBrowser.py:484
msgid "Browser:" msgid "Browser:"
msgstr "Browser:" msgstr "Browser:"
#: ImageBrowser.py:610 #: ImageBrowser.py:498
msgid "Language:" msgid "Language:"
msgstr "Language:" msgstr "Language:"
#: ImageBrowser.py:642 #: ImageBrowser.py:530
msgid "Zapisz" msgid "Zapisz"
msgstr "Save" msgstr "Save"
#: ImageBrowser.py:684 #: ImageBrowser.py:572
msgid "PNG Tags" msgid "PNG Tags"
msgstr "PNG Tags" msgstr "PNG Tags"
#: ImageBrowser.py:696 #: ImageBrowser.py:584
msgid "Tagger Tags" msgid "Tagger Tags"
msgstr "Tagger Tags" msgstr "Tagger Tags"
#: ImageBrowser.py:710 #: ImageBrowser.py:598
msgid "Manual Tags" msgid "Manual Tags"
msgstr "Manual Tags" msgstr "Manual Tags"
#: ImageBrowser.py:718 #: ImageBrowser.py:606
msgid "Final Tags" msgid "Final Tags"
msgstr "Final Tags" msgstr "Final Tags"
#: ImageBrowser.py:743 #: ImageBrowser.py:631
msgid "Wyświetl" msgid "Wyświetl"
msgstr "Display" msgstr "Display"
#: ImageBrowser.py:760 #: ImageBrowser.py:648
msgid "Przetworzono tagi:" msgid "Przetworzono tagi:"
msgstr "Processed tags:" msgstr "Processed tags:"
#: ImageBrowser.py:760 ImageBrowser.py:761 ImageBrowser.py:762 #: ImageBrowser.py:648 ImageBrowser.py:649 ImageBrowser.py:650
msgid "plików" msgid "plików"
msgstr "files" msgstr "files"
#: ImageBrowser.py:761 #: ImageBrowser.py:649
msgid "Zweryfikowano status uploadu:" msgid "Zweryfikowano status uploadu:"
msgstr "Upload status verified:" msgstr "Upload status verified:"
#: ImageBrowser.py:762 #: ImageBrowser.py:650
msgid "Zuploadowano:" msgid "Zuploadowano:"
msgstr "Uploaded:" msgstr "Uploaded:"
#: ImageBrowser.py:790 #: ImageBrowser.py:679
msgid "Wybierz folder z obrazkami PNG" msgid "Wybierz folder z obrazkami PNG, JPEG, WebP, AVIF i GIF"
msgstr "Select folder with PNG images" msgstr "Select folder with PNG, JPEG, WebP, AVIF, and GIF images"
#: ImageBrowser.py:823 #: ImageBrowser.py:721
msgid "Informacja" msgid "Informacja"
msgstr "Information" msgstr "Information"
#: ImageBrowser.py:823 #: ImageBrowser.py:722
msgid "Brak plików PNG w wybranym folderze." #, fuzzy
msgid "Brak plików PNG, JPEG, WebP, AVIF lub GIF w wybranym folderze."
msgstr "No PNG files in the selected folder." msgstr "No PNG files in the selected folder."
#: ImageBrowser.py:906 #: ImageBrowser.py:805
msgid "Błąd podczas sprawdzania paczki uploadu:" msgid "Błąd podczas sprawdzania paczki uploadu:"
msgstr "Error while checking upload package:" msgstr "Error while checking upload package:"
#: ImageBrowser.py:982 #: ImageBrowser.py:881
msgid "Błąd przy obliczaniu MD5:" #: ImageBrowser.py:881
msgstr "Error calculating MD5:" msgid "Error computing MD5:"
msgstr "Error computing MD5:"
#: ImageBrowser.py:1038 #: ImageBrowser.py:940
msgid "Błąd" msgid "Błąd"
msgstr "Error" msgstr "Error"
#: ImageBrowser.py:1038 #: ImageBrowser.py:940
msgid "Nie można załadować obrazka:" msgid "Nie można załadować obrazka:"
msgstr "Unable to load image:" msgstr "Unable to load image:"
#: ImageBrowser.py:1248 ImageBrowser.py:1258 #: ImageBrowser.py:1150 ImageBrowser.py:1160
#, python-brace-format #, python-brace-format
msgid "Warning: Tag '{tag}' not found in implication graph" msgid "Warning: Tag '{tag}' not found in implication graph"
msgstr "Warning: Tag '{tag}' not found in implication graph" msgstr "Warning: Tag '{tag}' not found in implication graph"
#: ImageBrowser.py:1488 #: ImageBrowser.py:1390
msgid "Tagger przetwarza..." msgid "Tagger przetwarza..."
msgstr "Tagger processing..." msgstr "Tagger processing..."
#: ImageBrowser.py:1513 #: ImageBrowser.py:1415
#, python-brace-format #, python-brace-format
msgid "Wysyłam plik {base_file_name}..." msgid "Wysyłam plik {base_file_name}..."
msgstr "Sending file {base_file_name}..." msgstr "Sending file {base_file_name}..."
#: ImageBrowser.py:1554 #: ImageBrowser.py:1456
msgid "Wysyłanie zakończone powodzeniem!" msgid "Wysyłanie zakończone powodzeniem!"
msgstr "Upload completed successfully!" msgstr "Upload completed successfully!"
#: ImageBrowser.py:1558 ImageBrowser.py:1567 #: ImageBrowser.py:1460 ImageBrowser.py:1469
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"Wysyłanie zakończone błędem.\n" "Wysyłanie zakończone błędem.\n"
@ -327,40 +320,40 @@ msgstr ""
"Status: {status_code}\n" "Status: {status_code}\n"
"Content: {text}" "Content: {text}"
#: ImageBrowser.py:1573 ImageBrowser.py:1576 #: ImageBrowser.py:1475 ImageBrowser.py:1478
msgid "Wysyłanie" msgid "Wysyłanie"
msgstr "Uploading" msgstr "Uploading"
#: ImageBrowser.py:1589 #: ImageBrowser.py:1491
msgid "Błąd wysyłania" msgid "Błąd wysyłania"
msgstr "Upload error" msgstr "Upload error"
#: ImageBrowser.py:1609 #: ImageBrowser.py:1511
msgid "Błąd edycji" msgid "Błąd edycji"
msgstr "Edit error" msgstr "Edit error"
#: ImageBrowser.py:1609 #: ImageBrowser.py:1511
msgid "Post nie został znaleziony dla tego pliku" msgid "Post nie został znaleziony dla tego pliku"
msgstr "Post not found for this file" msgstr "Post not found for this file"
#: ImageBrowser.py:1619 #: ImageBrowser.py:1521
#, python-brace-format #, python-brace-format
msgid "Aktualizuję tagi dla {base_file_name}..." msgid "Aktualizuję tagi dla {base_file_name}..."
msgstr "Updating tags for {base_file_name}..." msgstr "Updating tags for {base_file_name}..."
#: ImageBrowser.py:1629 ImageBrowser.py:1639 ImageBrowser.py:1670 #: ImageBrowser.py:1531 ImageBrowser.py:1541 ImageBrowser.py:1572
msgid "Operacja anulowana" msgid "Operacja anulowana"
msgstr "Operation cancelled" msgstr "Operation cancelled"
#: ImageBrowser.py:1680 #: ImageBrowser.py:1582
msgid "Tagi zostały zaktualizowane!" msgid "Tagi zostały zaktualizowane!"
msgstr "Tags have been updated!" msgstr "Tags have been updated!"
#: ImageBrowser.py:1682 #: ImageBrowser.py:1584
msgid "Sukces edycji" msgid "Sukces edycji"
msgstr "Edit successful" msgstr "Edit successful"
#: ImageBrowser.py:1688 #: ImageBrowser.py:1590
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"Błąd podczas aktualizacji tagów\n" "Błąd podczas aktualizacji tagów\n"
@ -369,19 +362,19 @@ msgstr ""
"Error updating tags\n" "Error updating tags\n"
"Status: {code}" "Status: {code}"
#: ImageBrowser.py:1692 #: ImageBrowser.py:1594
msgid "Treść:" msgid "Treść:"
msgstr "Content:" msgstr "Content:"
#: ImageBrowser.py:1696 #: ImageBrowser.py:1598
msgid "Krytyczny błąd edycji" msgid "Krytyczny błąd edycji"
msgstr "Critical edit error" msgstr "Critical edit error"
#: ImageBrowser.py:1708 #: ImageBrowser.py:1610
msgid "Potwierdzenie" msgid "Potwierdzenie"
msgstr "Confirmation" msgstr "Confirmation"
#: ImageBrowser.py:1710 #: ImageBrowser.py:1612
msgid "" msgid ""
"Czy na pewno chcesz wrzucić wszystkie niewrzucone pliki?\n" "Czy na pewno chcesz wrzucić wszystkie niewrzucone pliki?\n"
"Każdy z nich zostanie oznaczony tagiem 'meta:auto_upload'.\n" "Każdy z nich zostanie oznaczony tagiem 'meta:auto_upload'.\n"
@ -391,21 +384,29 @@ msgstr ""
"Each will be tagged with 'meta:auto_upload'.\n" "Each will be tagged with 'meta:auto_upload'.\n"
"Make sure the tags are correct!" "Make sure the tags are correct!"
#: ImageBrowser.py:1734 #: ImageBrowser.py:1636
msgid "Anulowano operację!" msgid "Anulowano operację!"
msgstr "Operation cancelled!" msgstr "Operation cancelled!"
#: ImageBrowser.py:1742 #: ImageBrowser.py:1644
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"Wysyłanie {file_path} z tagami: {final_tags} i ratingiem: {final_rating}" "Wysyłanie {file_path} z tagami: {final_tags} i ratingiem: {final_rating}"
msgstr "" msgstr ""
"Uploading {file_path} with tags: {final_tags} and rating: {final_rating}" "Uploading {file_path} with tags: {final_tags} and rating: {final_rating}"
#: ImageBrowser.py:1758 #: ImageBrowser.py:1660
msgid "Przesłano pliki!" msgid "Przesłano pliki!"
msgstr "Files have been uploaded!" msgstr "Files have been uploaded!"
#: ProcessingDialog.py:15
msgid "Processing..."
msgstr "Processing..."
#: ProcessingDialog.py:19
msgid "Processing, please wait..."
msgstr "Processing, please wait..."
#: ProgressFile.py:16 #: ProgressFile.py:16
msgid "Upload cancelled by user." msgid "Upload cancelled by user."
msgstr "Upload cancelled by user." msgstr "Upload cancelled by user."
@ -426,15 +427,19 @@ msgstr "Error fetching character tags:"
msgid "Błąd przy pobieraniu tagów copyright:" msgid "Błąd przy pobieraniu tagów copyright:"
msgstr "Error fetching copyright tags:" msgstr "Error fetching copyright tags:"
#: tag_processing.py:48 #: tag_processing.py:49
msgid "Błąd przy pobieraniu tagów artystów:" msgid "Błąd przy pobieraniu tagów artystów:"
msgstr "Error fetching artist tags:" msgstr "Error fetching artist tags:"
#: tag_processing.py:200 #: tag_processing.py:164
#: tag_processing.py:164
msgid "Nie można sparsować parametrów."
msgstr "Unable to parse parameters."
#: tag_processing.py:249
msgid "Błąd podczas odczytu tag_aliases:" msgid "Błąd podczas odczytu tag_aliases:"
msgstr "Error reading tag aliases:" msgstr "Error reading tag aliases:"
#: tag_processing.py:216 #: tag_processing.py:265
msgid "Błąd podczas odczytu tags:" msgid "Błąd podczas odczytu tags:"
msgstr "Error reading tags:" msgstr "Error reading tags:"
@ -490,52 +495,55 @@ msgstr "Tag processing cancelled."
msgid "Pobrano {count} tagów..." msgid "Pobrano {count} tagów..."
msgstr "Fetched {count} tags..." msgstr "Fetched {count} tags..."
#: TagsRepo.py:271 #: TagsRepo.py:301
msgid "Anulowano pobieranie aliasów tagów." msgid "Anulowano pobieranie aliasów tagów."
msgstr "Tag alias fetching cancelled." msgstr "Tag alias fetching cancelled."
#: TagsRepo.py:280 #: TagsRepo.py:310
#, python-brace-format #, python-brace-format
msgid "Pobieranie aliasów tagów (od ID {last_id})..." msgid "Pobieranie aliasów tagów (od ID {last_id})..."
msgstr "Fetching tag aliases (from ID {last_id})..." msgstr "Fetching tag aliases (from ID {last_id})..."
#: TagsRepo.py:297 #: TagsRepo.py:327
#, python-brace-format #, python-brace-format
msgid "Błąd przy pobieraniu aliasów tagów od ID {last_id}: HTTP {code}" msgid "Błąd przy pobieraniu aliasów tagów od ID {last_id}: HTTP {code}"
msgstr "Error fetching tag aliases from ID {last_id}: HTTP {code}" msgstr "Error fetching tag aliases from ID {last_id}: HTTP {code}"
#: TagsRepo.py:312 #: TagsRepo.py:342
msgid "Anulowano przetwarzanie aliasów tagów." msgid "Anulowano przetwarzanie aliasów tagów."
msgstr "Tag alias processing cancelled." msgstr "Tag alias processing cancelled."
#: TagsRepo.py:334 #: TagsRepo.py:364
#, python-brace-format #, python-brace-format
msgid "Pobrano {count} aliasów tagów..." msgid "Pobrano {count} aliasów tagów..."
msgstr "Fetched {count} tag aliases..." msgstr "Fetched {count} tag aliases..."
#: TagsRepo.py:375 #: TagsRepo.py:405
msgid "Anulowano pobieranie implikacji tagów." msgid "Anulowano pobieranie implikacji tagów."
msgstr "Tag implication fetching cancelled." msgstr "Tag implication fetching cancelled."
#: TagsRepo.py:384 #: TagsRepo.py:414
#, python-brace-format #, python-brace-format
msgid "Pobieranie implikacji tagów (od ID {last_id})..." msgid "Pobieranie implikacji tagów (od ID {last_id})..."
msgstr "Fetching tag implications (from ID {last_id})..." msgstr "Fetching tag implications (from ID {last_id})..."
#: TagsRepo.py:398 #: TagsRepo.py:428
#, python-brace-format #, python-brace-format
msgid "Błąd przy pobieraniu implikacji tagów od ID {last_id}: HTTP {code}" msgid "Błąd przy pobieraniu implikacji tagów od ID {last_id}: HTTP {code}"
msgstr "Error fetching tag implications from ID {last_id}: HTTP {code}" msgstr "Error fetching tag implications from ID {last_id}: HTTP {code}"
#: TagsRepo.py:413 #: TagsRepo.py:443
msgid "Anulowano przetwarzanie implikacji tagów." msgid "Anulowano przetwarzanie implikacji tagów."
msgstr "Tag implication processing cancelled." msgstr "Tag implication processing cancelled."
#: TagsRepo.py:460 #: TagsRepo.py:490
#, python-brace-format #, python-brace-format
msgid "Pobrano implikacje dla {count} tagów..." msgid "Pobrano implikacje dla {count} tagów..."
msgstr "Fetched implications for {count} tags..." msgstr "Fetched implications for {count} tags..."
#: TagsRepo.py:487 #: TagsRepo.py:517
msgid "Regeneracja bazy zakończona." msgid "Regeneracja bazy zakończona."
msgstr "Database regeneration complete." msgstr "Database regeneration complete."
#~ msgid "Błąd przy obliczaniu MD5:"
#~ msgstr "Error calculating MD5:"

View File

@ -1,8 +1,8 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Kapitanbooru Uploader 0.7.0\n" "Project-Id-Version: Kapitanbooru Uploader 0.8.0\n"
"Report-Msgid-Bugs-To: kapitan@mlesniak.pl\n" "Report-Msgid-Bugs-To: kapitan@mlesniak.pl\n"
"POT-Creation-Date: 2025-03-16 01:22+0100\n" "POT-Creation-Date: 2025-03-27 20:47+0100\n"
"Language: pl\n" "Language: pl\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
@ -45,34 +45,26 @@ msgstr "Znaleziono auth_token:"
msgid "auth_token not found in the HTML page." msgid "auth_token not found in the HTML page."
msgstr "Nie znaleziono auth_token w stronie HTML." msgstr "Nie znaleziono auth_token w stronie HTML."
#: ImageBrowser.py:33 #: ImageBrowser.py:138
msgid "Processing..."
msgstr "Przetwarzanie..."
#: ImageBrowser.py:37
msgid "Processing, please wait..."
msgstr "Przetwarzanie, proszę czekać..."
#: ImageBrowser.py:248
#, python-brace-format #, python-brace-format
msgid "Update check failed: {error}" msgid "Update check failed: {error}"
msgstr "Sprawdzenie aktualizacji nie powiodło się: {error}" msgstr "Sprawdzenie aktualizacji nie powiodło się: {error}"
#: ImageBrowser.py:250 #: ImageBrowser.py:140
#, python-brace-format #, python-brace-format
msgid "Malformed pyproject.toml: {error}" msgid "Malformed pyproject.toml: {error}"
msgstr "Nieprawidłowy plik pyproject.toml: {error}" msgstr "Nieprawidłowy plik pyproject.toml: {error}"
#: ImageBrowser.py:253 #: ImageBrowser.py:143
#, python-brace-format #, python-brace-format
msgid "Unexpected error during update check: {error}" msgid "Unexpected error during update check: {error}"
msgstr "Nieoczekiwany błąd podczas sprawdzania aktualizacji: {error}" msgstr "Nieoczekiwany błąd podczas sprawdzania aktualizacji: {error}"
#: ImageBrowser.py:260 #: ImageBrowser.py:150
msgid "Update Available" msgid "Update Available"
msgstr "Aktualizacja dostępna" msgstr "Aktualizacja dostępna"
#: ImageBrowser.py:262 #: ImageBrowser.py:152
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"A new version {new_version} is available!\n" "A new version {new_version} is available!\n"
@ -85,240 +77,242 @@ msgstr ""
"\n" "\n"
"Aktualizuj za pomocą: {update_command}" "Aktualizuj za pomocą: {update_command}"
#: ImageBrowser.py:375 #: ImageBrowser.py:263
msgid "Błąd przy otwieraniu pliku" msgid "Błąd przy otwieraniu pliku"
msgstr "Błąd przy otwieraniu pliku" msgstr "Błąd przy otwieraniu pliku"
#: ImageBrowser.py:417 #: ImageBrowser.py:305
msgid "Tagger przetworzył:" msgid "Tagger przetworzył:"
msgstr "Tagger przetworzył:" msgstr "Tagger przetworzył:"
#: ImageBrowser.py:420 #: ImageBrowser.py:308
msgid "Błąd Taggera dla" msgid "Błąd Taggera dla"
msgstr "Błąd Taggera dla" msgstr "Błąd Taggera dla"
#: ImageBrowser.py:446 #: ImageBrowser.py:334
msgid "Otwórz folder" msgid "Otwórz folder"
msgstr "Otwórz folder" msgstr "Otwórz folder"
#: ImageBrowser.py:449 ImageBrowser.py:738 ImageBrowser.py:954 #: ImageBrowser.py:337 ImageBrowser.py:626 ImageBrowser.py:853
#: ImageBrowser.py:962 #: ImageBrowser.py:861
msgid "Wyślij" msgid "Wyślij"
msgstr "Wyślij" msgstr "Wyślij"
#: ImageBrowser.py:452 ImageBrowser.py:947 #: ImageBrowser.py:340 ImageBrowser.py:846
msgid "Wyślij wszystko" msgid "Wyślij wszystko"
msgstr "Wyślij wszystko" msgstr "Wyślij wszystko"
#: ImageBrowser.py:456 ImageBrowser.py:948 ImageBrowser.py:954 #: ImageBrowser.py:344 ImageBrowser.py:847 ImageBrowser.py:853
msgid "Podmień tagi" msgid "Podmień tagi"
msgstr "Podmień tagi" msgstr "Podmień tagi"
#: ImageBrowser.py:459 ImageBrowser.py:949 #: ImageBrowser.py:347 ImageBrowser.py:848
msgid "Otwórz post" msgid "Otwórz post"
msgstr "Otwórz post" msgstr "Otwórz post"
#: ImageBrowser.py:462 #: ImageBrowser.py:350
msgid "Zakończ" msgid "Zakończ"
msgstr "Zakończ" msgstr "Zakończ"
#: ImageBrowser.py:464 #: ImageBrowser.py:352
msgid "Plik" msgid "Plik"
msgstr "Plik" msgstr "Plik"
#: ImageBrowser.py:468 ImageBrowser.py:567 #: ImageBrowser.py:356 ImageBrowser.py:455
msgid "Ustawienia" msgid "Ustawienia"
msgstr "Ustawienia" msgstr "Ustawienia"
#: ImageBrowser.py:471 #: ImageBrowser.py:359
msgid "Wyczyść cache Taggera" msgid "Wyczyść cache Taggera"
msgstr "Wyczyść cache Taggera" msgstr "Wyczyść cache Taggera"
#: ImageBrowser.py:474 #: ImageBrowser.py:362
msgid "Zregeneruj bazę tagów" msgid "Zregeneruj bazę tagów"
msgstr "Zregeneruj bazę tagów" msgstr "Zregeneruj bazę tagów"
#: ImageBrowser.py:476 #: ImageBrowser.py:364
msgid "Opcje" msgid "Opcje"
msgstr "Opcje" msgstr "Opcje"
#: ImageBrowser.py:479 #: ImageBrowser.py:367
msgid "About" msgid "About"
msgstr "O programie" msgstr "O programie"
#: ImageBrowser.py:480 #: ImageBrowser.py:368
msgid "Help" msgid "Help"
msgstr "Pomoc" msgstr "Pomoc"
#: ImageBrowser.py:485 #: ImageBrowser.py:373
msgid "About Kapitanbooru Uploader" msgid "About Kapitanbooru Uploader"
msgstr "O programie Kapitanbooru Uploader" msgstr "O programie Kapitanbooru Uploader"
#: ImageBrowser.py:502 #: ImageBrowser.py:390
#, python-brace-format #, python-brace-format
msgid "A new version {new_version} is available!" msgid "A new version {new_version} is available!"
msgstr "Dostępna jest nowa wersja {new_version}!" msgstr "Dostępna jest nowa wersja {new_version}!"
#: ImageBrowser.py:509 #: ImageBrowser.py:397
#, python-brace-format #, python-brace-format
msgid "Current version: {version}" msgid "Current version: {version}"
msgstr "Obecna wersja: {version}" msgstr "Obecna wersja: {version}"
#: ImageBrowser.py:511 #: ImageBrowser.py:399
msgid "A GUI application for uploading images to KapitanBooru." msgid "A GUI application for uploading images to KapitanBooru."
msgstr "Aplikacja GUI do przesyłania obrazów do KapitanBooru." msgstr "Aplikacja GUI do przesyłania obrazów do KapitanBooru."
#: ImageBrowser.py:512 #: ImageBrowser.py:400
msgid "Features include image upload, tag management, automatic" msgid "Features include image upload, tag management, automatic"
msgstr "Funkcje obejmują przesyłanie obrazów, zarządzanie tagami, automatyczne" msgstr "Funkcje obejmują przesyłanie obrazów, zarządzanie tagami, automatyczne"
#: ImageBrowser.py:513 #: ImageBrowser.py:401
msgid "tagging with wdtagger, and cache management." msgid "tagging with wdtagger, and cache management."
msgstr "tagowanie za pomocą wdtagger oraz zarządzanie cache." msgstr "tagowanie za pomocą wdtagger oraz zarządzanie cache."
#: ImageBrowser.py:515 #: ImageBrowser.py:403
msgid "Authors:" msgid "Authors:"
msgstr "Autorzy:" msgstr "Autorzy:"
#: ImageBrowser.py:518 #: ImageBrowser.py:406
msgid "License: MIT License" msgid "License: MIT License"
msgstr "Licencja: MIT License" msgstr "Licencja: MIT License"
#: ImageBrowser.py:531 #: ImageBrowser.py:419
msgid "Repository:" msgid "Repository:"
msgstr "Repozytorium:" msgstr "Repozytorium:"
#: ImageBrowser.py:540 #: ImageBrowser.py:428
msgid "Website:" msgid "Website:"
msgstr "Strona internetowa:" msgstr "Strona internetowa:"
#: ImageBrowser.py:551 #: ImageBrowser.py:439
msgid "Close" msgid "Close"
msgstr "Zamknij" msgstr "Zamknij"
#: ImageBrowser.py:559 ImageBrowser.py:562 #: ImageBrowser.py:447 ImageBrowser.py:450
msgid "Cache" msgid "Cache"
msgstr "Cache" msgstr "Cache"
#: ImageBrowser.py:559 #: ImageBrowser.py:447
msgid "Cache Taggera zostało wyczyszczone." msgid "Cache Taggera zostało wyczyszczone."
msgstr "Cache Taggera zostało wyczyszczone." msgstr "Cache Taggera zostało wyczyszczone."
#: ImageBrowser.py:562 #: ImageBrowser.py:450
msgid "Błąd przy czyszczeniu cache:" msgid "Błąd przy czyszczeniu cache:"
msgstr "Błąd przy czyszczeniu cache:" msgstr "Błąd przy czyszczeniu cache:"
#: ImageBrowser.py:572 #: ImageBrowser.py:460
msgid "Login:" msgid "Login:"
msgstr "Login:" msgstr "Login:"
#: ImageBrowser.py:578 #: ImageBrowser.py:466
msgid "Hasło:" msgid "Hasło:"
msgstr "Hasło:" msgstr "Hasło:"
#: ImageBrowser.py:584 #: ImageBrowser.py:472
msgid "Base URL:" msgid "Base URL:"
msgstr "Base URL:" msgstr "Base URL:"
#: ImageBrowser.py:590 #: ImageBrowser.py:478
msgid "Default Tags:" msgid "Default Tags:"
msgstr "Domyślne tagi:" msgstr "Domyślne tagi:"
#: ImageBrowser.py:596 #: ImageBrowser.py:484
msgid "Browser:" msgid "Browser:"
msgstr "Przeglądarka:" msgstr "Przeglądarka:"
#: ImageBrowser.py:610 #: ImageBrowser.py:498
msgid "Language:" msgid "Language:"
msgstr "Język:" msgstr "Język:"
#: ImageBrowser.py:642 #: ImageBrowser.py:530
msgid "Zapisz" msgid "Zapisz"
msgstr "Zapisz" msgstr "Zapisz"
#: ImageBrowser.py:684 #: ImageBrowser.py:572
msgid "PNG Tags" msgid "PNG Tags"
msgstr "Tagi PNG" msgstr "Tagi PNG"
#: ImageBrowser.py:696 #: ImageBrowser.py:584
msgid "Tagger Tags" msgid "Tagger Tags"
msgstr "Tagi Taggera" msgstr "Tagi Taggera"
#: ImageBrowser.py:710 #: ImageBrowser.py:598
msgid "Manual Tags" msgid "Manual Tags"
msgstr "Tagi ręczne" msgstr "Tagi ręczne"
#: ImageBrowser.py:718 #: ImageBrowser.py:606
msgid "Final Tags" msgid "Final Tags"
msgstr "Ostateczne tagi" msgstr "Ostateczne tagi"
#: ImageBrowser.py:743 #: ImageBrowser.py:631
msgid "Wyświetl" msgid "Wyświetl"
msgstr "Wyświetl" msgstr "Wyświetl"
#: ImageBrowser.py:760 #: ImageBrowser.py:648
msgid "Przetworzono tagi:" msgid "Przetworzono tagi:"
msgstr "Przetworzono tagi:" msgstr "Przetworzono tagi:"
#: ImageBrowser.py:760 ImageBrowser.py:761 ImageBrowser.py:762 #: ImageBrowser.py:648 ImageBrowser.py:649 ImageBrowser.py:650
msgid "plików" msgid "plików"
msgstr "plików" msgstr "plików"
#: ImageBrowser.py:761 #: ImageBrowser.py:649
msgid "Zweryfikowano status uploadu:" msgid "Zweryfikowano status uploadu:"
msgstr "Zweryfikowano status uploadu:" msgstr "Zweryfikowano status uploadu:"
#: ImageBrowser.py:762 #: ImageBrowser.py:650
msgid "Zuploadowano:" msgid "Zuploadowano:"
msgstr "Zuploadowano:" msgstr "Zuploadowano:"
#: ImageBrowser.py:790 #: ImageBrowser.py:679
msgid "Wybierz folder z obrazkami PNG" #, fuzzy
msgid "Wybierz folder z obrazkami PNG, JPEG, WebP, AVIF i GIF"
msgstr "Wybierz folder z obrazami PNG" msgstr "Wybierz folder z obrazami PNG"
#: ImageBrowser.py:823 #: ImageBrowser.py:721
msgid "Informacja" msgid "Informacja"
msgstr "Informacja" msgstr "Informacja"
#: ImageBrowser.py:823 #: ImageBrowser.py:722
msgid "Brak plików PNG w wybranym folderze." #, fuzzy
msgid "Brak plików PNG, JPEG, WebP, AVIF lub GIF w wybranym folderze."
msgstr "Brak plików PNG w wybranym folderze." msgstr "Brak plików PNG w wybranym folderze."
#: ImageBrowser.py:906 #: ImageBrowser.py:805
msgid "Błąd podczas sprawdzania paczki uploadu:" msgid "Błąd podczas sprawdzania paczki uploadu:"
msgstr "Błąd podczas sprawdzania paczki uploadu:" msgstr "Błąd podczas sprawdzania paczki uploadu:"
#: ImageBrowser.py:982 #: ImageBrowser.py:881
msgid "Błąd przy obliczaniu MD5:" msgid "Error computing MD5:"
msgstr "Błąd przy obliczaniu MD5:" msgstr "Błąd przy obliczaniu MD5:"
#: ImageBrowser.py:1038 #: ImageBrowser.py:940
msgid "Błąd" msgid "Błąd"
msgstr "Błąd" msgstr "Błąd"
#: ImageBrowser.py:1038 #: ImageBrowser.py:940
msgid "Nie można załadować obrazka:" msgid "Nie można załadować obrazka:"
msgstr "Nie można załadować obrazka:" msgstr "Nie można załadować obrazka:"
#: ImageBrowser.py:1248 ImageBrowser.py:1258 #: ImageBrowser.py:1150 ImageBrowser.py:1160
#, python-brace-format #, python-brace-format
msgid "Warning: Tag '{tag}' not found in implication graph" msgid "Warning: Tag '{tag}' not found in implication graph"
msgstr "Ostrzeżenie: Tag '{tag}' nie został znaleziony w grafie implikacji" msgstr "Ostrzeżenie: Tag '{tag}' nie został znaleziony w grafie implikacji"
#: ImageBrowser.py:1488 #: ImageBrowser.py:1390
msgid "Tagger przetwarza..." msgid "Tagger przetwarza..."
msgstr "Tagger przetwarza..." msgstr "Tagger przetwarza..."
#: ImageBrowser.py:1513 #: ImageBrowser.py:1415
#, python-brace-format #, python-brace-format
msgid "Wysyłam plik {base_file_name}..." msgid "Wysyłam plik {base_file_name}..."
msgstr "Wysyłam plik {base_file_name}..." msgstr "Wysyłam plik {base_file_name}..."
#: ImageBrowser.py:1554 #: ImageBrowser.py:1456
msgid "Wysyłanie zakończone powodzeniem!" msgid "Wysyłanie zakończone powodzeniem!"
msgstr "Wysyłanie zakończone powodzeniem!" msgstr "Wysyłanie zakończone powodzeniem!"
#: ImageBrowser.py:1558 ImageBrowser.py:1567 #: ImageBrowser.py:1460 ImageBrowser.py:1469
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"Wysyłanie zakończone błędem.\n" "Wysyłanie zakończone błędem.\n"
@ -329,40 +323,40 @@ msgstr ""
"Status: {status_code}\n" "Status: {status_code}\n"
"Treść: {text}" "Treść: {text}"
#: ImageBrowser.py:1573 ImageBrowser.py:1576 #: ImageBrowser.py:1475 ImageBrowser.py:1478
msgid "Wysyłanie" msgid "Wysyłanie"
msgstr "Wysyłanie" msgstr "Wysyłanie"
#: ImageBrowser.py:1589 #: ImageBrowser.py:1491
msgid "Błąd wysyłania" msgid "Błąd wysyłania"
msgstr "Błąd wysyłania" msgstr "Błąd wysyłania"
#: ImageBrowser.py:1609 #: ImageBrowser.py:1511
msgid "Błąd edycji" msgid "Błąd edycji"
msgstr "Błąd edycji" msgstr "Błąd edycji"
#: ImageBrowser.py:1609 #: ImageBrowser.py:1511
msgid "Post nie został znaleziony dla tego pliku" msgid "Post nie został znaleziony dla tego pliku"
msgstr "Post nie został znaleziony dla tego pliku" msgstr "Post nie został znaleziony dla tego pliku"
#: ImageBrowser.py:1619 #: ImageBrowser.py:1521
#, python-brace-format #, python-brace-format
msgid "Aktualizuję tagi dla {base_file_name}..." msgid "Aktualizuję tagi dla {base_file_name}..."
msgstr "Aktualizuję tagi dla {base_file_name}..." msgstr "Aktualizuję tagi dla {base_file_name}..."
#: ImageBrowser.py:1629 ImageBrowser.py:1639 ImageBrowser.py:1670 #: ImageBrowser.py:1531 ImageBrowser.py:1541 ImageBrowser.py:1572
msgid "Operacja anulowana" msgid "Operacja anulowana"
msgstr "Operacja anulowana" msgstr "Operacja anulowana"
#: ImageBrowser.py:1680 #: ImageBrowser.py:1582
msgid "Tagi zostały zaktualizowane!" msgid "Tagi zostały zaktualizowane!"
msgstr "Tagi zostały zaktualizowane!" msgstr "Tagi zostały zaktualizowane!"
#: ImageBrowser.py:1682 #: ImageBrowser.py:1584
msgid "Sukces edycji" msgid "Sukces edycji"
msgstr "Sukces edycji" msgstr "Sukces edycji"
#: ImageBrowser.py:1688 #: ImageBrowser.py:1590
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"Błąd podczas aktualizacji tagów\n" "Błąd podczas aktualizacji tagów\n"
@ -371,19 +365,19 @@ msgstr ""
"Błąd podczas aktualizacji tagów\n" "Błąd podczas aktualizacji tagów\n"
"Status: {code}" "Status: {code}"
#: ImageBrowser.py:1692 #: ImageBrowser.py:1594
msgid "Treść:" msgid "Treść:"
msgstr "Treść:" msgstr "Treść:"
#: ImageBrowser.py:1696 #: ImageBrowser.py:1598
msgid "Krytyczny błąd edycji" msgid "Krytyczny błąd edycji"
msgstr "Krytyczny błąd edycji" msgstr "Krytyczny błąd edycji"
#: ImageBrowser.py:1708 #: ImageBrowser.py:1610
msgid "Potwierdzenie" msgid "Potwierdzenie"
msgstr "Potwierdzenie" msgstr "Potwierdzenie"
#: ImageBrowser.py:1710 #: ImageBrowser.py:1612
msgid "" msgid ""
"Czy na pewno chcesz wrzucić wszystkie niewrzucone pliki?\n" "Czy na pewno chcesz wrzucić wszystkie niewrzucone pliki?\n"
"Każdy z nich zostanie oznaczony tagiem 'meta:auto_upload'.\n" "Każdy z nich zostanie oznaczony tagiem 'meta:auto_upload'.\n"
@ -393,21 +387,29 @@ msgstr ""
"Każdy z nich zostanie oznaczony tagiem 'meta:auto_upload'.\n" "Każdy z nich zostanie oznaczony tagiem 'meta:auto_upload'.\n"
"Upewnij się, że tagi są poprawne!" "Upewnij się, że tagi są poprawne!"
#: ImageBrowser.py:1734 #: ImageBrowser.py:1636
msgid "Anulowano operację!" msgid "Anulowano operację!"
msgstr "Operacja anulowana!" msgstr "Operacja anulowana!"
#: ImageBrowser.py:1742 #: ImageBrowser.py:1644
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"Wysyłanie {file_path} z tagami: {final_tags} i ratingiem: {final_rating}" "Wysyłanie {file_path} z tagami: {final_tags} i ratingiem: {final_rating}"
msgstr "" msgstr ""
"Wysyłanie {file_path} z tagami: {final_tags} i ratingiem: {final_rating}" "Wysyłanie {file_path} z tagami: {final_tags} i ratingiem: {final_rating}"
#: ImageBrowser.py:1758 #: ImageBrowser.py:1660
msgid "Przesłano pliki!" msgid "Przesłano pliki!"
msgstr "Pliki zostały przesłane!" msgstr "Pliki zostały przesłane!"
#: ProcessingDialog.py:15
msgid "Processing..."
msgstr "Przetwarzanie..."
#: ProcessingDialog.py:19
msgid "Processing, please wait..."
msgstr "Przetwarzanie, proszę czekać..."
#: ProgressFile.py:16 #: ProgressFile.py:16
msgid "Upload cancelled by user." msgid "Upload cancelled by user."
msgstr "Przesyłanie anulowane przez użytkownika." msgstr "Przesyłanie anulowane przez użytkownika."
@ -428,15 +430,20 @@ msgstr "Błąd przy pobieraniu tagów postaci:"
msgid "Błąd przy pobieraniu tagów copyright:" msgid "Błąd przy pobieraniu tagów copyright:"
msgstr "Błąd przy pobieraniu tagów copyright:" msgstr "Błąd przy pobieraniu tagów copyright:"
#: tag_processing.py:48 #: tag_processing.py:49
msgid "Błąd przy pobieraniu tagów artystów:" msgid "Błąd przy pobieraniu tagów artystów:"
msgstr "Błąd przy pobieraniu tagów artystów:" msgstr "Błąd przy pobieraniu tagów artystów:"
#: tag_processing.py:200 #: tag_processing.py:164
#, fuzzy
msgid "Nie można sparsować parametrów."
msgstr "Nie można załadować obrazka:"
#: tag_processing.py:249
msgid "Błąd podczas odczytu tag_aliases:" msgid "Błąd podczas odczytu tag_aliases:"
msgstr "Błąd podczas odczytu tag_aliases:" msgstr "Błąd podczas odczytu tag_aliases:"
#: tag_processing.py:216 #: tag_processing.py:265
msgid "Błąd podczas odczytu tags:" msgid "Błąd podczas odczytu tags:"
msgstr "Błąd podczas odczytu tags:" msgstr "Błąd podczas odczytu tags:"
@ -492,52 +499,55 @@ msgstr "Przetwarzanie tagów anulowane."
msgid "Pobrano {count} tagów..." msgid "Pobrano {count} tagów..."
msgstr "Pobrano {count} tagów..." msgstr "Pobrano {count} tagów..."
#: TagsRepo.py:271 #: TagsRepo.py:301
msgid "Anulowano pobieranie aliasów tagów." msgid "Anulowano pobieranie aliasów tagów."
msgstr "Pobieranie aliasów tagów anulowane." msgstr "Pobieranie aliasów tagów anulowane."
#: TagsRepo.py:280 #: TagsRepo.py:310
#, python-brace-format #, python-brace-format
msgid "Pobieranie aliasów tagów (od ID {last_id})..." msgid "Pobieranie aliasów tagów (od ID {last_id})..."
msgstr "Pobieranie aliasów tagów (od ID {last_id})..." msgstr "Pobieranie aliasów tagów (od ID {last_id})..."
#: TagsRepo.py:297 #: TagsRepo.py:327
#, python-brace-format #, python-brace-format
msgid "Błąd przy pobieraniu aliasów tagów od ID {last_id}: HTTP {code}" msgid "Błąd przy pobieraniu aliasów tagów od ID {last_id}: HTTP {code}"
msgstr "Błąd przy pobieraniu aliasów tagów od ID {last_id}: HTTP {code}" msgstr "Błąd przy pobieraniu aliasów tagów od ID {last_id}: HTTP {code}"
#: TagsRepo.py:312 #: TagsRepo.py:342
msgid "Anulowano przetwarzanie aliasów tagów." msgid "Anulowano przetwarzanie aliasów tagów."
msgstr "Przetwarzanie aliasów tagów anulowane." msgstr "Przetwarzanie aliasów tagów anulowane."
#: TagsRepo.py:334 #: TagsRepo.py:364
#, python-brace-format #, python-brace-format
msgid "Pobrano {count} aliasów tagów..." msgid "Pobrano {count} aliasów tagów..."
msgstr "Pobrano {count} aliasów tagów..." msgstr "Pobrano {count} aliasów tagów..."
#: TagsRepo.py:375 #: TagsRepo.py:405
msgid "Anulowano pobieranie implikacji tagów." msgid "Anulowano pobieranie implikacji tagów."
msgstr "Pobieranie implikacji tagów anulowane." msgstr "Pobieranie implikacji tagów anulowane."
#: TagsRepo.py:384 #: TagsRepo.py:414
#, python-brace-format #, python-brace-format
msgid "Pobieranie implikacji tagów (od ID {last_id})..." msgid "Pobieranie implikacji tagów (od ID {last_id})..."
msgstr "Pobieranie implikacji tagów (od ID {last_id})..." msgstr "Pobieranie implikacji tagów (od ID {last_id})..."
#: TagsRepo.py:398 #: TagsRepo.py:428
#, python-brace-format #, python-brace-format
msgid "Błąd przy pobieraniu implikacji tagów od ID {last_id}: HTTP {code}" msgid "Błąd przy pobieraniu implikacji tagów od ID {last_id}: HTTP {code}"
msgstr "Błąd przy pobieraniu implikacji tagów od ID {last_id}: HTTP {code}" msgstr "Błąd przy pobieraniu implikacji tagów od ID {last_id}: HTTP {code}"
#: TagsRepo.py:413 #: TagsRepo.py:443
msgid "Anulowano przetwarzanie implikacji tagów." msgid "Anulowano przetwarzanie implikacji tagów."
msgstr "Przetwarzanie implikacji tagów anulowane." msgstr "Przetwarzanie implikacji tagów anulowane."
#: TagsRepo.py:460 #: TagsRepo.py:490
#, python-brace-format #, python-brace-format
msgid "Pobrano implikacje dla {count} tagów..." msgid "Pobrano implikacje dla {count} tagów..."
msgstr "Pobrano implikacje dla {count} tagów..." msgstr "Pobrano implikacje dla {count} tagów..."
#: TagsRepo.py:487 #: TagsRepo.py:517
msgid "Regeneracja bazy zakończona." msgid "Regeneracja bazy zakończona."
msgstr "Regeneracja bazy zakończona." msgstr "Regeneracja bazy zakończona."
#~ msgid "Błąd przy obliczaniu MD5:"
#~ msgstr "Błąd przy obliczaniu MD5:"

View File

@ -34,6 +34,7 @@ def get_copyright_tags(tags_repo: TagsRepo):
print(_("Błąd przy pobieraniu tagów copyright:"), e) print(_("Błąd przy pobieraniu tagów copyright:"), e)
return set() return set()
@lru_cache(maxsize=1) @lru_cache(maxsize=1)
def get_artist_tags(tags_repo: TagsRepo): def get_artist_tags(tags_repo: TagsRepo):
"""Zwraca zbiór nazw tagów z kategorii Artist (kategoria = 1) z bazy tags.sqlite""" """Zwraca zbiór nazw tagów z kategorii Artist (kategoria = 1) z bazy tags.sqlite"""
@ -50,6 +51,10 @@ def get_artist_tags(tags_repo: TagsRepo):
# Wzorce i ustawienia związane z tagami # Wzorce i ustawienia związane z tagami
PARAMETERS_PATTERN = re.compile(
r"^(?P<prompt>.*?)\s+(?:Negative prompt:\s+(?P<negative_prompt>.*?)\s+)?Steps:\s+(?P<steps>\d+),\s+Sampler:\s+(?P<sampler>.*?),\s+Schedule type:\s+(?P<schedule_type>.*?),\s+CFG scale:\s+(?P<cfg_scale>.*?),\s+Seed:\s+(?P<seed>.*?),\s+Size:\s+(?P<size>.*?),\s+Model hash:\s+(?P<model_hash>.*?),\s+Model:\s+(?P<model>.*?),\s+(?:Denoising strength:\s+(?P<denoising_strength>.*?),\s+)?(?:Clip skip: (?P<clip_skip>.*?),\s+)?(?:Hires CFG Scale:\s+(?P<hires_cfg_scale>.*?),\s+Hires upscale:\s+(?P<hires_upscale>.*?),\s+Hires steps:\s+(?P<hires_steps>.*?),\s+Hires upscaler:\s+(?P<hires_upscaler>.*?),\s+)?Version:\s+(?P<version>.*?)\s*$",
re.DOTALL,
)
COEFFICIENT_PATTERN = re.compile(r"^.*?(:\d+|\d+\.\d+)$") COEFFICIENT_PATTERN = re.compile(r"^.*?(:\d+|\d+\.\d+)$")
UNESCAPED_PATTERN = re.compile(r"(?<!\\)[\(\)\[\]]+") UNESCAPED_PATTERN = re.compile(r"(?<!\\)[\(\)\[\]]+")
SLASH_PATTERN = re.compile(r"\\+(?=[\(\)](?!\^))") SLASH_PATTERN = re.compile(r"\\+(?=[\(\)](?!\^))")
@ -107,16 +112,62 @@ MULTI_TAG_FIXES = {
} }
def parse_parameters(param_str, tags_repo: TagsRepo): from PIL import Image, PngImagePlugin
def extract_parameters(img: Image, file_path: str) -> str:
"""Funkcja do ekstrakcji parametrów z pliku graficznego.
Obsługuje PNG, JPEG, WebP, AVIF i GIF.
"""
parameters = ""
lower_path = file_path.lower()
# For PNG: use the custom "parameters" field.
if isinstance(img, PngImagePlugin.PngImageFile):
parameters = img.info.get("parameters", "")
# For JPEG, WebP, and AVIF: extract EXIF UserComment (EXIF tag 37510).
elif lower_path.endswith((".jpg", ".jpeg", ".webp", ".avif")):
exif_data = img.getexif()
user_comment = exif_data.get(37510)
if user_comment:
# UserComment might be stored as bytes; decode to string.
if isinstance(user_comment, bytes):
try:
parameters = user_comment.decode("utf-8", errors="replace")
except Exception:
parameters = str(user_comment)
else:
parameters = str(user_comment)
# For GIF: extract the GIF comment.
elif lower_path.endswith(".gif"):
comment = img.info.get("comment")
if comment:
if isinstance(comment, bytes):
try:
parameters = comment.decode("utf-8", errors="replace")
except Exception:
parameters = str(comment)
else:
parameters = str(comment)
return parameters
def parse_parameters(param_str):
""" """
Funkcja do parsowania zawartości pola 'parameters' z pliku PNG. Funkcja do parsowania zawartości pola 'parameters' z pliku PNG.
""" """
tags = ( match = PARAMETERS_PATTERN.match(param_str)
param_str.split("\nNegative", 1)[0] if not match:
.removesuffix(",") print(_("Nie można sparsować parametrów."))
.replace("\n", " ") return ""
.split(",") tags = match.group("prompt").removesuffix(",").replace("\n", " ").split(",")
)
if "pony" in match.group("model"):
tags = [tag.strip() for tag in tags if not tag.strip().startswith("score_")]
tags = tags[1:]
tags = set([WHITESPACE_PATTERN.sub("_", param.strip()) for param in tags]) tags = set([WHITESPACE_PATTERN.sub("_", param.strip()) for param in tags])
tags = set( tags = set(
[ [
@ -141,9 +192,9 @@ def parse_parameters(param_str, tags_repo: TagsRepo):
# Usuń tagi tekstowe # Usuń tagi tekstowe
tags = {tag for tag in tags if not tag.startswith("text:")} tags = {tag for tag in tags if not tag.startswith("text:")}
# Pobierz tagi z bazy # Pobierz tagi z bazy
character_tags = get_character_tags(tags_repo) character_tags = get_character_tags()
copyright_tags = get_copyright_tags(tags_repo) copyright_tags = get_copyright_tags()
artist_tags = get_artist_tags(tags_repo) artist_tags = get_artist_tags()
# Dla tagów należących do kategorii Character # Dla tagów należących do kategorii Character
for tag in list(tags): # iterujemy po kopii zbioru for tag in list(tags): # iterujemy po kopii zbioru

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "kapitanbooru-uploader" name = "kapitanbooru-uploader"
version = "0.7.0" version = "0.8.0"
description = "A GUI application for uploading images to KapitanBooru" description = "A GUI application for uploading images to KapitanBooru"
authors = [{ name = "Michał Leśniak", email = "kapitan@mlesniak.pl" }] authors = [{ name = "Michał Leśniak", email = "kapitan@mlesniak.pl" }]
dependencies = [ dependencies = [