Update Kapitanbooru Uploader to version 0.9.0 with significant changes
All checks were successful
Gitea/kapitanbooru-uploader/pipeline/head This commit looks good

- Updated version number in pyproject.toml and messages.po files.
- Added new translations and updated existing ones in messages.po for better localization.
- Implemented core functionality in Core.py, including image processing, tagging, and upload logic.
- Enhanced the autotagging feature to support multiple image formats (PNG, JPEG, WebP, AVIF, GIF).
- Improved error handling and logging for file operations and network requests.
- Added functionality to check for uploaded files and manage tag updates for existing posts.
- Introduced threading for background processing to improve application responsiveness.
This commit is contained in:
2025-06-26 17:22:34 +02:00
parent 0987fbbed0
commit 67df3ea793
6 changed files with 1463 additions and 1123 deletions

View File

@@ -0,0 +1,744 @@
import glob
import hashlib
import os
import threading
from typing import Any, Callable, Tuple
import concurrent.futures
from packaging.version import parse as parse_version
import queue
import time
import networkx as nx
import requests
from PIL import Image
import wdtagger as wdt
from .I18N import _
from .TagsRepo import TagsRepo
from .settings import Settings
from .common import login, get_auth_token
from .ProgressFile import ProgressFile
from .tag_processing import (
TAG_FIXES,
extract_parameters,
parse_parameters,
process_tag,
extract_artist_from_filename,
)
from .tagger_cache import TaggerCache
class Core:
"""
Core functionality for Kapitanbooru Uploader.
Handles image processing, tagging, and upload logic.
"""
def __init__(self, settings: Settings, gui_mode: bool = True):
self.version = "0.9.0"
self.acknowledged_version = parse_version(self.version)
self.settings = settings
self.tags_repo = TagsRepo(settings)
# Dodatkowe ustawienia dla Taggera
self.tagger_name = "wdtagger"
self.tagger_version = (
"1.0" # możesz ustawić wersję dynamicznie, jeśli to możliwe
)
self.tagger_cache = TaggerCache(
self.settings, self.tagger_name, self.tagger_version
)
self.gui_mode = gui_mode
self.main_thread_queue = queue.Queue()
self.after_events = []
self.implication_graph = self.load_implication_graph()
self.missing_tags = set() # Track tags not in the graph
self.check_uploaded_files_stop_event = threading.Event()
self.check_uploaded_files_thread: threading.Thread | None = None
self.process_tagger_queue_stop_event = threading.Event()
self.process_tagger_queue_thread: threading.Thread | None = None
self.check_uploaded_files_callback = None
self.update_status_bar_callback = None
self.process_tagger_for_image_callback = None
self.upload_file_success_callback: Callable[[str], Any] | None = None
self.upload_file_completed_callback: Callable | None = None
self.folder_path = ""
self.image_files = []
self.image_files_md5 = []
self.current_index = None
self.image_cache = None
self.tagger_thread_idx = 0
self.tagger = wdt.Tagger()
# Liczniki statusu
self.total_files = 0
self.tagger_processed = set()
self.upload_verified = 0
self.uploaded_count = 0
# Oryginalny obraz (do skalowania)
self.current_image_original = None
self.current_parameters = ""
# Mapa ratingów: wyświetlana nazwa -> wartość wysyłana
self.rating_map = {
"General": "g",
"Sensitive": "s",
"Questionable": "q",
"Explicit": "e",
"Unrated": "",
}
# Słowniki przechowujące stany tagów (dla PNG i Taggera)
self.png_tags_states = {}
self.tagger_tags_states = {}
# Nowy słownik przechowujący informację, czy dany plik (ścieżka) został już uploadowany
self.uploaded = {} # key: file path, value: True/False
def schedule_in_main_thread(self, func, delay_ms=0):
"""Schedule a function to run in the main thread"""
if self.gui_mode:
# In GUI mode, use the after mechanism
self.after_events.append((time.time() + delay_ms / 1000, func))
else:
# In non-GUI mode, add to queue for immediate execution
self.main_thread_queue.put(func)
def process_main_thread_queue(self):
"""Process pending main thread tasks"""
if self.gui_mode:
# Process scheduled events
now = time.time()
new_events = []
for schedule_time, func in self.after_events:
if now >= schedule_time:
try:
func()
except Exception as e:
print(f"Error in scheduled task: {e}")
else:
new_events.append((schedule_time, func))
self.after_events = new_events
else:
# Process all queued tasks in non-GUI mode
while not self.main_thread_queue.empty():
try:
func = self.main_thread_queue.get_nowait()
func()
except queue.Empty:
break
except Exception as e:
print(f"Error in main thread task: {e}")
def load_implication_graph(self) -> nx.DiGraph:
G = nx.DiGraph()
conn = self.tags_repo.get_conn()
cursor = conn.cursor()
# Step 1: Add all tags from the 'tags' table
cursor.execute(
"""
SELECT
CASE category
WHEN 1 THEN 'artist:' || name
WHEN 3 THEN 'copyright:' || name
WHEN 4 THEN 'character:' || name
WHEN 5 THEN 'meta:' || name
ELSE name
END AS prefixed_name
FROM tags
"""
)
db_tags = {row[0] for row in cursor.fetchall()}
G.add_nodes_from(db_tags)
# Step 2: Add nodes from implications (antecedents/consequents not in 'tags' table)
cursor.execute("SELECT antecedent, consequent FROM tag_closure")
edge_tags = set()
for ant, cons in cursor.fetchall():
edge_tags.add(ant)
edge_tags.add(cons)
G.add_nodes_from(edge_tags - db_tags) # Add tags only in implications
# Step 3: Add edges
cursor.execute("SELECT antecedent, consequent FROM tag_closure")
G.add_edges_from(cursor.fetchall())
conn.close()
return G
def compute_final_tags_and_rating_for_file(
self, file_path, update_status_callback, manual_tags=set()
) -> Tuple[str, str]:
"""
Oblicza finalną listę tagów dla danego pliku oraz rating.
Łączy tagi z:
- pliku (PNG): parsowane przez parse_parameters,
- Taggera (wynik z cache lub wyliczony na bieżąco),
- ustawień (default tags),
- manualnych tagów (z pola manual_tags_entry),
oraz dodaje tag "meta:auto_upload".
Zwraca finalny ciąg tagów oraz rating.
"""
# Pobierz tagi z pliku
try:
img = Image.open(file_path)
parameters = extract_parameters(img, file_path)
artist_tag = extract_artist_from_filename(file_path)
png_tags = set(
[
x
for x in parse_parameters(parameters, self.tags_repo).split()
if process_tag(x, self.tags_repo)[1]
is not None # Ignoruj nieistniejące tagi
]
)
if artist_tag:
png_tags.add("artist:" + artist_tag.replace(" ", "_").replace("\\", ""))
img.close()
except Exception as e:
print(_("Błąd przy otwieraniu pliku"), file_path, ":", e)
png_tags = set()
# Pobierz tagi z Taggera sprawdzając cache
result = self.get_tagger_results(file_path, update_status_callback)
tagger_tags = set()
rating = "Unrated"
tagger_tags.update(
(
TAG_FIXES[tag] if tag in TAG_FIXES else tag
for tag in result.general_tag_data.keys()
)
) # Zamień nieprawidłowe tagi na poprawne
for t in result.character_tags:
full_tag = "character:" + t.replace(" ", "_").replace("\\", "")
# Zamień nieprawidłowe tagi na poprawne
if full_tag in TAG_FIXES:
full_tag = TAG_FIXES[full_tag]
tagger_tags.add(full_tag)
rating = self.map_tagger_rating(result)
# Pobierz tagi z ustawień i manualne
default_tags = set(self.settings.default_tags.split())
# Finalna lista: suma wszystkich tagów
final_tags = default_tags.union(png_tags).union(tagger_tags).union(manual_tags)
final_tags.add("meta:auto_upload")
return " ".join(sorted(final_tags)), rating
def get_tagger_results(self, file_path, callback) -> wdt.Result:
md5 = self.image_files_md5[file_path]
cached = self.tagger_cache[md5]
if cached:
self.tagger_processed.add(md5)
return cached["result"]
try:
with Image.open(file_path) as img:
result = self.tagger.tag(img)
self.tagger_cache[md5] = result
self.tagger_processed.add(md5)
callback()
print(_("Tagger przetworzył:"), f"{file_path}")
return result
except Exception as e:
print(_("Błąd Taggera dla"), file_path, ":", e)
def map_tagger_rating(self, result: wdt.Result) -> str:
"""
Mapuje rating z Taggera na wartość używaną w Kapitanbooru.
"""
if result.rating == "general":
new_rating = "General"
elif result.rating == "sensitive":
new_rating = "Sensitive"
elif result.rating == "questionable":
new_rating = "Questionable"
elif result.rating == "explicit":
new_rating = "Explicit"
else:
new_rating = "Unrated"
return new_rating
def load_images(self):
"""
Ładuje pliki PNG, JPEG, WebP, AVIF i GIF z wybranego folderu.
"""
extensions = ("*.png", "*.jpg", "*.jpeg", "*.webp", "*.avif", "*.gif")
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.image_files_md5 = {
file: md5
for file, md5 in zip(
self.image_files, self.compute_md5_parallel(self.image_files)
)
}
self.tagger_processed.clear()
for md5 in self.image_files_md5.values():
if self.tagger_cache[md5]:
self.tagger_processed.add(md5)
self.uploaded.clear()
self.upload_verified = 0
self.uploaded_count = 0
for file in self.image_files:
self.uploaded[file] = False
if self.image_files:
self.post_load_processing()
def compute_md5(self, file_path, chunk_size=8192):
"""Compute MD5 for a single file."""
hash_md5 = hashlib.md5()
try:
with open(file_path, "rb") as f:
for chunk in iter(lambda: f.read(chunk_size), b""):
hash_md5.update(chunk)
except Exception as e:
print(_("Error computing MD5:"), e)
return ""
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 post_load_processing(self):
"""
Po załadowaniu plików, sprawdza czy są jakieś pliki do uploadu oraz przetwarza Taggerem pliki.
"""
self.join_check_uploaded_files_thread()
self.check_uploaded_files_thread = threading.Thread(
target=self.check_uploaded_files
)
self.check_uploaded_files_thread.start()
self.join_process_tagger_queue_thread()
self.process_tagger_queue_thread = threading.Thread(
target=self.process_tagger_queue
)
self.process_tagger_queue_thread.start()
def wait_for_completion(self):
"""Wait for background threads to finish (non-GUI mode)"""
# Join the checking thread if running
if (
self.check_uploaded_files_thread
and self.check_uploaded_files_thread.is_alive()
):
self.check_uploaded_files_stop_event.set()
self.check_uploaded_files_thread.join()
# Join the tagger processing thread if running
if (
self.process_tagger_queue_thread
and self.process_tagger_queue_thread.is_alive()
):
self.process_tagger_queue_stop_event.set()
self.process_tagger_queue_thread.join()
# Process any remaining main thread tasks
self.process_main_thread_queue()
def join_check_uploaded_files_thread(self):
if self.check_uploaded_files_thread is not None:
self.check_uploaded_files_stop_event.set()
self.check_uploaded_files_thread.join()
self.check_uploaded_files_thread = None
self.check_uploaded_files_stop_event = threading.Event()
def join_process_tagger_queue_thread(self):
if self.process_tagger_queue_thread is not None:
self.process_tagger_queue_stop_event.set()
self.process_tagger_queue_thread.join()
self.process_tagger_queue_thread = None
self.process_tagger_queue_stop_event = threading.Event()
def process_tagger_for_image(self, file_path):
"""Przetwarza obrazek przy użyciu Taggera i zapisuje wynik do cache."""
result = self.get_tagger_results(file_path)
if self.process_tagger_for_image_callback:
self.process_tagger_for_image_callback(file_path, result.rating)
def process_tagger_queue(self):
"""Przetwarza wszystkie obrazki w tle (pomijając aktualnie wybrany)."""
for file_path in self.image_files:
if self.process_tagger_queue_stop_event.is_set():
break
# Jeśli obrazek jest aktualnie wybrany, pomijamy on będzie przetwarzany w foreground
if (
self.current_index is not None
and file_path == self.image_files[self.current_index]
):
continue
self.process_tagger_for_image(file_path)
self.schedule_in_main_thread(self.join_process_tagger_queue_thread, 100)
def check_uploaded_files(self):
"""
Dla każdego obrazu oblicza MD5, grupuje je w paczki (do 100 skrótów),
wysyła zapytanie do endpointa 'posts.json' dla każdej paczki,
a następnie na podstawie odpowiedzi ustawia w self.uploaded post id dla uploadowanych plików.
"""
file_md5_list = [
(idx, file, self.image_files_md5[file])
for idx, file in enumerate(self.image_files)
]
batch_size = 100
for i in range(0, len(file_md5_list), batch_size):
if self.check_uploaded_files_stop_event.is_set():
break
batch = file_md5_list[i : i + batch_size]
batch_md5 = [item[2] for item in batch]
md5_param = ",".join(batch_md5)
url = self.settings.base_url.rstrip("/") + "/posts.json"
try:
response = requests.get(url, params={"md5": md5_param})
root = response.json()
found = {}
for elem in root:
if self.check_uploaded_files_stop_event.is_set():
break
post_md5 = elem.get("md5", "").lower()
post_id = elem.get("id")
if post_md5 and post_id:
found[post_md5] = post_id
for idx, file_path, md5 in batch:
if self.check_uploaded_files_stop_event.is_set():
break
self.upload_verified += 1 # Każdy plik w batchu jest zweryfikowany
if md5.lower() in found:
self.uploaded[file_path] = found[md5.lower()]
self.uploaded_count += 1
if self.check_uploaded_files_callback:
self.check_uploaded_files_callback(idx)
else:
self.uploaded[file_path] = False
if self.update_status_bar_callback:
self.update_status_bar_callback()
except Exception as e:
print(_("Błąd podczas sprawdzania paczki uploadu:"), e)
self.schedule_in_main_thread(self.join_check_uploaded_files_thread, 100)
def autotag_files(self, file_paths):
"""
Autotaguje pliki przy użyciu Taggera i wysyła je na serwer.
"""
for file_path in file_paths:
if not os.path.isfile(file_path):
print(_("Plik nie istnieje:"), file_path)
continue
try:
tags, rating = self.compute_final_tags_and_rating_for_file(
file_path, lambda: None
)
print(_("Tagi dla pliku"), file_path, ":", tags, "Rating:", rating)
self.upload_file(
file_path,
final_tags=tags,
final_rating=rating,
progress_queue=None,
cancel_event=None,
)
except Exception as e:
print(_("Błąd podczas autotagowania pliku"), file_path, ":", e)
def autotag_dir(self, dir):
"""
Autotaguje wszystkie pliki w katalogu przy użyciu Taggera i wysyła je na serwer.
"""
if not os.path.isdir(dir):
print(_("Podana ścieżka nie jest katalogiem:"), dir)
return
self.folder_path = dir
self.load_images()
self.check_uploaded_files_thread.join()
self.process_tagger_queue_thread.join()
files_to_upload = [x for x in self.image_files if not self.uploaded[x]]
if not files_to_upload:
print(_("Brak obrazów do przetworzenia w katalogu:"), dir)
return
self.autotag_files(files_to_upload)
def upload_file(
self,
file_path,
final_tags=None,
final_rating=None,
progress_queue: queue.Queue | None = None,
cancel_event: threading.Event | None = None,
info_callback: Callable[[str], Any] | None = None,
warning_callback: Callable[[str], Any] | None = None,
error_callback: Callable[[str], Any] | None = None,
):
base_file_name = os.path.basename(file_path)
if progress_queue:
progress_queue.put(("mode", "determinate"))
progress_queue.put(("max", 100))
progress_queue.put(
(
"label",
_("Wysyłam plik {base_file_name}...").format(
base_file_name=base_file_name
),
)
)
url = self.settings.base_url.rstrip("/") + "/api/danbooru/add_post"
tags = final_tags
fields = {
"login": self.settings.username,
"password": self.settings.password,
"tags": tags,
"source": "",
}
rating_value = self.rating_map.get(final_rating, "")
if rating_value:
fields["rating"] = rating_value
try:
total_size = os.path.getsize(file_path)
def progress_callback(bytes_read, total_size):
if progress_queue:
percentage = int(bytes_read / total_size * 100)
progress_queue.put(("progress", percentage))
with open(file_path, "rb") as f:
wrapped_file = ProgressFile(
f, progress_callback, total_size, cancel_event
)
files = {"file": (base_file_name, wrapped_file, "image/png")}
response = requests.post(url, data=fields, files=files)
if progress_queue:
progress_queue.put(("progress", 100))
show_warn = False
post_url = None
if response.status_code in (200, 201):
message = _("Wysyłanie zakończone powodzeniem!")
post_url = response.headers.get("X-Danbooru-Location", None)
elif response.status_code == 409:
message = _(
"Wysyłanie zakończone błędem.\nStatus: {status_code}\nTreść: {text}"
).format(
status_code=response.status_code,
text=response.headers.get("X-Danbooru-Errors", ""),
)
post_url = response.headers.get("X-Danbooru-Location", None)
show_warn = True
else:
message = _(
"Wysyłanie zakończone błędem.\nStatus: {status_code}\nTreść: {text}"
).format(status_code=response.status_code, text=response.text)
show_warn = True
# Aktualizacja wyglądu listy musimy użyć domyślnych argumentów w lambdzie, aby zachować bieżący indeks
if show_warn:
if not final_tags:
if warning_callback:
warning_callback(message)
else:
print("[WARN]", _("Wysyłanie"), message)
else:
if not final_tags:
if info_callback:
info_callback(message)
else:
print("[INFO]", _("Wysyłanie"), message)
if self.upload_file_success_callback:
self.upload_file_success_callback(file_path)
if post_url:
post_id = post_url.split("/")[-1]
self.uploaded[file_path] = post_id
self.uploaded_count += 1
self.after(0, self.update_status_bar)
except Exception as e:
if error_callback:
error_callback(str(e))
else:
print("[ERROR]", _("Błąd wysyłania pliku"), file_path, ":", e)
finally:
if self.upload_file_completed_callback:
self.upload_file_completed_callback()
def upload_all_files(
self,
progress_queue: queue.Queue = None,
cancel_event: threading.Event = None,
secondary_progress_queue: queue.Queue = None,
update_status_callback=None,
manual_tags: set = set(),
info_callback: Callable[[str], Any] | None = None,
warning_callback: Callable[[str], Any] | None = None,
error_callback: Callable[[str], Any] | None = None,
):
files_to_upload = [x for x in self.image_files if not self.uploaded[x]]
files_count = len(files_to_upload)
if progress_queue:
progress_queue.put(("mode", "determinate"))
progress_queue.put(("max", 100))
file_idx = 0
for file_path in files_to_upload:
if progress_queue:
progress_queue.put(("progress", file_idx * 100 / files_count))
progress_queue.put(
("label", f"Wysyłam plik {file_idx+1}/{files_count}...")
)
if cancel_event is not None and cancel_event.is_set():
if progress_queue:
progress_queue.put(("label", _("Anulowano operację!")))
return
if not self.uploaded.get(file_path, False):
final_tags, final_rating = self.compute_final_tags_and_rating_for_file(
file_path,
update_status_callback, # lambda: self.after(0, self.update_status_bar)
manual_tags, # set(self.manual_tags_manager.manual_tags)
)
print(
_(
"Wysyłanie {file_path} z tagami: {final_tags} i ratingiem: {final_rating}"
).format(
file_path=file_path,
final_tags=final_tags,
final_rating=final_rating,
)
)
self.upload_file(
file_path,
final_tags=final_tags,
final_rating=final_rating,
progress_queue=secondary_progress_queue,
cancel_event=cancel_event,
info_callback=info_callback,
warning_callback=warning_callback,
error_callback=error_callback,
)
file_idx += 1
if progress_queue:
progress_queue.put(("label", _("Przesłano pliki!")))
progress_queue.put(("progress", 100))
def edit_file(
self,
file_path,
final_tags=None,
final_rating=None,
progress_queue=None,
cancel_event=None,
info_callback: Callable[[str], Any] | None = None,
error_callback: Callable[[str], Any] | None = None,
):
"""
Update tags and rating for an existing post without uploading the file.
"""
base_file_name = os.path.basename(file_path)
post_id = self.uploaded.get(file_path)
if not post_id:
if error_callback:
error_callback(_("Post nie został znaleziony dla tego pliku"))
else:
print(
"[ERROR]",
_("Post nie został znaleziony dla tego pliku"),
file_path,
)
return
if progress_queue:
progress_queue.put(("mode", "determinate"))
progress_queue.put(("max", 100))
progress_queue.put(
(
"label",
_("Aktualizuję tagi dla {base_file_name}...").format(
base_file_name=base_file_name
),
)
)
try:
# Check for cancellation before starting the operation.
if cancel_event is not None and cancel_event.is_set():
if progress_queue:
progress_queue.put(("label", _("Operacja anulowana")))
return
# Get authentication session and token
session = login(self.settings)
auth_token = get_auth_token(session, self.settings)
# Check cancellation after login if needed.
if cancel_event is not None and cancel_event.is_set():
if progress_queue:
progress_queue.put(("label", _("Operacja anulowana")))
return
# Prepare tags and rating
tags = final_tags
rating_value = self.rating_map.get(final_rating, "?")
# Prepare API request
url = self.settings.base_url.rstrip("/") + "/post/set"
payload = {
"auth_token": auth_token,
"image_id": post_id,
"title": base_file_name,
"owner": self.settings.username,
"tags": tags,
"source": "",
"rating": rating_value,
}
if progress_queue:
progress_queue.put(("progress", 50))
# Check for cancellation before sending the update request.
if cancel_event is not None and cancel_event.is_set():
if progress_queue:
progress_queue.put(("label", _("Operacja anulowana")))
return
# Send update request
response = session.post(url, data=payload, allow_redirects=False)
# Handle 302 redirect as success case
if response.status_code == 302:
if progress_queue:
progress_queue.put(("progress", 100))
message = _("Tagi zostały zaktualizowane!")
if not final_tags: # Only show success if not bulk operation
if info_callback:
info_callback(message)
else:
print("[INFO]", _("Sukces edycji"), message)
# Update UI state
if self.upload_file_completed_callback:
self.upload_file_completed_callback()
return
# Handle other status codes
error_msg = _("Błąd podczas aktualizacji tagów\nStatus: {code}").format(
code=response.status_code
)
if response.text:
error_msg += f"\n{_('Treść:')} {response.text}"
if error_callback:
error_callback(error_msg)
else:
print("[ERROR]", _("Błąd edycji"), error_msg)
except Exception as e:
if error_callback:
error_callback(str(e))
else:
print("[ERROR]", _("Krytyczny błąd edycji"), file_path, ":", e)
finally:
if progress_queue:
progress_queue.put(("progress", 100))

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,43 @@
"""kapitanbooru_uploader.__main__: executed """kapitanbooru_uploader.__main__: executed
when kapitanbooru_uploader directory is called as script.""" when kapitanbooru_uploader directory is called as script."""
from .Core import Core
from .settings import Settings
from .ImageBrowser import ImageBrowser from .ImageBrowser import ImageBrowser
import argparse
def main(): def main():
app = ImageBrowser() parser = argparse.ArgumentParser(
app.mainloop() prog="kapitanbooru-uploader", description="KapitanBooru Uploader"
)
group = parser.add_mutually_exclusive_group()
# Add arguments to the group
group.add_argument(
"--autotag-files",
nargs="+",
metavar="PATH",
help="Specify one or more files to process",
)
group.add_argument(
"--autotag-dir", metavar="PATH", help="Specify a directory to process"
)
args = parser.parse_args()
# Determine which function to call
if args.autotag_files:
core = Core(Settings(), gui_mode=False)
core.autotag_files(args.autotag_files)
core.wait_for_completion() # Wait for threads to finish
elif args.autotag_dir:
core = Core(Settings(), gui_mode=False)
core.autotag_dir(args.autotag_dir)
core.wait_for_completion() # Wait for threads to finish
else:
app = ImageBrowser()
app.mainloop()
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -1,8 +1,8 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Kapitanbooru Uploader 0.8.3\n" "Project-Id-Version: Kapitanbooru Uploader 0.9.0\n"
"Report-Msgid-Bugs-To: kapitan@mlesniak.pl\n" "Report-Msgid-Bugs-To: kapitan@mlesniak.pl\n"
"POT-Creation-Date: 2025-06-25 23:49+0200\n" "POT-Creation-Date: 2025-06-26 17:07+0200\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,273 +43,56 @@ 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:138 #: Core.py:204
#, python-brace-format
msgid "Update check failed: {error}"
msgstr "Update check failed: {error}"
#: ImageBrowser.py:140
#, python-brace-format
msgid "Malformed pyproject.toml: {error}"
msgstr "Malformed pyproject.toml: {error}"
#: ImageBrowser.py:143
#, python-brace-format
msgid "Unexpected error during update check: {error}"
msgstr "Unexpected error during update check: {error}"
#: ImageBrowser.py:150
msgid "Update Available"
msgstr "Update Available"
#: ImageBrowser.py:152
#, python-brace-format
msgid ""
"A new version {new_version} is available!\n"
"You have version {current_version}.\n"
"\n"
"Update using: {update_command}"
msgstr ""
"A new version {new_version} is available!\n"
"You have version {current_version}.\n"
"\n"
"Update using: {update_command}"
#: ImageBrowser.py:266
msgid "Błąd przy otwieraniu pliku" msgid "Błąd przy otwieraniu pliku"
msgstr "Error opening file" msgstr "Error opening file"
#: ImageBrowser.py:308 #: Core.py:245
msgid "Tagger przetworzył:" msgid "Tagger przetworzył:"
msgstr "Tagger processed:" msgstr "Tagger processed:"
#: ImageBrowser.py:311 #: Core.py:248
msgid "Błąd Taggera dla" msgid "Błąd Taggera dla"
msgstr "Tagger error for" msgstr "Tagger error for"
#: ImageBrowser.py:337 #: Core.py:303
msgid "Otwórz folder"
msgstr "Open folder"
#: ImageBrowser.py:340 ImageBrowser.py:629 ImageBrowser.py:856
#: ImageBrowser.py:864
msgid "Wyślij"
msgstr "Send"
#: ImageBrowser.py:343 ImageBrowser.py:849
msgid "Wyślij wszystko"
msgstr "Send all"
#: ImageBrowser.py:347 ImageBrowser.py:850 ImageBrowser.py:856
msgid "Podmień tagi"
msgstr "Replace tags"
#: ImageBrowser.py:350 ImageBrowser.py:851
msgid "Otwórz post"
msgstr "Open post"
#: ImageBrowser.py:353
msgid "Zakończ"
msgstr "Finish"
#: ImageBrowser.py:355
msgid "Plik"
msgstr "File"
#: ImageBrowser.py:359 ImageBrowser.py:458
msgid "Ustawienia"
msgstr "Settings"
#: ImageBrowser.py:362
msgid "Wyczyść cache Taggera"
msgstr "Clear Tagger cache"
#: ImageBrowser.py:365
msgid "Zregeneruj bazę tagów"
msgstr "Regenerate tag database"
#: ImageBrowser.py:367
msgid "Opcje"
msgstr "Options"
#: ImageBrowser.py:370
msgid "About"
msgstr "About"
#: ImageBrowser.py:371
msgid "Help"
msgstr "Help"
#: ImageBrowser.py:376
msgid "About Kapitanbooru Uploader"
msgstr "About Kapitanbooru Uploader"
#: ImageBrowser.py:393
#, python-brace-format
msgid "A new version {new_version} is available!"
msgstr "A new version {new_version} is available!"
#: ImageBrowser.py:400
#, python-brace-format
msgid "Current version: {version}"
msgstr "Current version: {version}"
#: ImageBrowser.py:402
msgid "A GUI application for uploading images to KapitanBooru."
msgstr "A GUI application for uploading images to KapitanBooru."
#: ImageBrowser.py:403
msgid "Features include image upload, tag management, automatic"
msgstr "Features include image upload, tag management, automatic"
#: ImageBrowser.py:404
msgid "tagging with wdtagger, and cache management."
msgstr "tagging with wdtagger, and cache management."
#: ImageBrowser.py:406
msgid "Authors:"
msgstr "Authors:"
#: ImageBrowser.py:409
msgid "License: MIT License"
msgstr "License: MIT License"
#: ImageBrowser.py:422
msgid "Repository:"
msgstr "Repository:"
#: ImageBrowser.py:431
msgid "Website:"
msgstr "Website:"
#: ImageBrowser.py:442
msgid "Close"
msgstr "Close"
#: ImageBrowser.py:450 ImageBrowser.py:453
msgid "Cache"
msgstr "Cache"
#: ImageBrowser.py:450
msgid "Cache Taggera zostało wyczyszczone."
msgstr "Tagger cache has been cleared."
#: ImageBrowser.py:453
msgid "Błąd przy czyszczeniu cache:"
msgstr "Error clearing cache:"
#: ImageBrowser.py:463
msgid "Login:"
msgstr "Login:"
#: ImageBrowser.py:469
msgid "Hasło:"
msgstr "Password:"
#: ImageBrowser.py:475
msgid "Base URL:"
msgstr "Base URL:"
#: ImageBrowser.py:481
msgid "Default Tags:"
msgstr "Default Tags:"
#: ImageBrowser.py:487
msgid "Browser:"
msgstr "Browser:"
#: ImageBrowser.py:501
msgid "Language:"
msgstr "Language:"
#: ImageBrowser.py:533
msgid "Zapisz"
msgstr "Save"
#: ImageBrowser.py:575
msgid "PNG Tags"
msgstr "PNG Tags"
#: ImageBrowser.py:587
msgid "Tagger Tags"
msgstr "Tagger Tags"
#: ImageBrowser.py:601
msgid "Manual Tags"
msgstr "Manual Tags"
#: ImageBrowser.py:609
msgid "Final Tags"
msgstr "Final Tags"
#: ImageBrowser.py:634
msgid "Wyświetl"
msgstr "Display"
#: ImageBrowser.py:651
msgid "Przetworzono tagi:"
msgstr "Processed tags:"
#: ImageBrowser.py:651 ImageBrowser.py:652 ImageBrowser.py:653
msgid "plików"
msgstr "files"
#: ImageBrowser.py:652
msgid "Zweryfikowano status uploadu:"
msgstr "Upload status verified:"
#: ImageBrowser.py:653
msgid "Zuploadowano:"
msgstr "Uploaded:"
#: ImageBrowser.py:682
msgid "Wybierz folder z obrazkami PNG, JPEG, WebP, AVIF i GIF"
msgstr "Select folder with PNG, JPEG, WebP, AVIF, and GIF images"
#: ImageBrowser.py:724
msgid "Informacja"
msgstr "Information"
#: ImageBrowser.py:725
#, fuzzy
msgid "Brak plików PNG, JPEG, WebP, AVIF lub GIF w wybranym folderze."
msgstr "No PNG files in the selected folder."
#: ImageBrowser.py:808
msgid "Błąd podczas sprawdzania paczki uploadu:"
msgstr "Error while checking upload package:"
#: ImageBrowser.py:884
msgid "Error computing MD5:" msgid "Error computing MD5:"
msgstr "Error computing MD5:" msgstr "Error computing MD5:"
#: ImageBrowser.py:946 #: Core.py:428
msgid "Błąd" msgid "Błąd podczas sprawdzania paczki uploadu:"
msgstr "Error" msgstr "Error while checking upload package:"
#: ImageBrowser.py:946 #: Core.py:437
msgid "Nie można załadować obrazka:" msgid "Plik nie istnieje:"
msgstr "Unable to load image:" msgstr "File does not exist:"
#: ImageBrowser.py:1156 ImageBrowser.py:1166 #: Core.py:443
#, python-brace-format msgid "Tagi dla pliku"
msgid "Warning: Tag '{tag}' not found in implication graph" msgstr "Tags for file"
msgstr "Warning: Tag '{tag}' not found in implication graph"
#: ImageBrowser.py:1396 #: Core.py:452
msgid "Tagger przetwarza..." msgid "Błąd podczas autotagowania pliku"
msgstr "Tagger processing..." msgstr "Error during file autotagowania"
#: ImageBrowser.py:1421 #: Core.py:459
msgid "Podana ścieżka nie jest katalogiem:"
msgstr "Given path is not a directory:"
#: Core.py:467
msgid "Brak obrazów do przetworzenia w katalogu:"
msgstr "No images to process in directory:"
#: Core.py:490
#, 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 "Uploading file {base_file_name}..."
#: ImageBrowser.py:1462 #: Core.py:525
msgid "Wysyłanie zakończone powodzeniem!" msgid "Wysyłanie zakończone powodzeniem!"
msgstr "Upload completed successfully!" msgstr "Upload completed successfully!"
#: ImageBrowser.py:1466 ImageBrowser.py:1475 #: Core.py:529 Core.py:538
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"Wysyłanie zakończone błędem.\n" "Wysyłanie zakończone błędem.\n"
@@ -320,40 +103,52 @@ msgstr ""
"Status: {status_code}\n" "Status: {status_code}\n"
"Content: {text}" "Content: {text}"
#: ImageBrowser.py:1481 ImageBrowser.py:1484 #: Core.py:547 Core.py:553 ImageBrowser.py:654 ImageBrowser.py:657
#: ImageBrowser.py:1177 ImageBrowser.py:1180
msgid "Wysyłanie" msgid "Wysyłanie"
msgstr "Uploading" msgstr "Uploading"
#: ImageBrowser.py:1497 #: Core.py:565
msgid "Błąd wysyłania" msgid "Błąd wysyłania pliku"
msgstr "Upload error" msgstr "Upload error"
#: ImageBrowser.py:1517 #: Core.py:595
msgid "Błąd edycji" msgid "Anulowano operację!"
msgstr "Edit error" msgstr "Operation cancelled!"
#: ImageBrowser.py:1517 #: Core.py:605
#, python-brace-format
msgid ""
"Wysyłanie {file_path} z tagami: {final_tags} i ratingiem: {final_rating}"
msgstr ""
"Uploading {file_path} with tags: {final_tags} and rating: {final_rating}"
#: Core.py:624
msgid "Przesłano pliki!"
msgstr "Files have been uploaded!"
#: Core.py:645 Core.py:649
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:1527 #: Core.py:660
#, 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:1537 ImageBrowser.py:1547 ImageBrowser.py:1578 #: Core.py:670 Core.py:680 Core.py:705
msgid "Operacja anulowana" msgid "Operacja anulowana"
msgstr "Operation cancelled" msgstr "Operation cancelled"
#: ImageBrowser.py:1588 #: Core.py:715
msgid "Tagi zostały zaktualizowane!" msgid "Tagi zostały zaktualizowane!"
msgstr "Tags have been updated!" msgstr "Tags have been updated!"
#: ImageBrowser.py:1590 #: Core.py:720 ImageBrowser.py:719
msgid "Sukces edycji" msgid "Sukces edycji"
msgstr "Edit successful" msgstr "Edit successful"
#: ImageBrowser.py:1596 #: Core.py:727
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"Błąd podczas aktualizacji tagów\n" "Błąd podczas aktualizacji tagów\n"
@@ -362,19 +157,263 @@ msgstr ""
"Error updating tags\n" "Error updating tags\n"
"Status: {code}" "Status: {code}"
#: ImageBrowser.py:1600 #: Core.py:731
msgid "Treść:" msgid "Treść:"
msgstr "Content:" msgstr "Content:"
#: ImageBrowser.py:1604 #: Core.py:735 ImageBrowser.py:716
msgid "Błąd edycji"
msgstr "Edit error"
#: Core.py:741
msgid "Krytyczny błąd edycji" msgid "Krytyczny błąd edycji"
msgstr "Critical edit error" msgstr "Critical edit error"
#: ImageBrowser.py:1616 #: ImageBrowser.py:112
#, python-brace-format
msgid "Update check failed: {error}"
msgstr "Update check failed: {error}"
#: ImageBrowser.py:114
#, python-brace-format
msgid "Malformed pyproject.toml: {error}"
msgstr "Malformed pyproject.toml: {error}"
#: ImageBrowser.py:117
#, python-brace-format
msgid "Unexpected error during update check: {error}"
msgstr "Unexpected error during update check: {error}"
#: ImageBrowser.py:124
msgid "Update Available"
msgstr "Update Available"
#: ImageBrowser.py:126
#, python-brace-format
msgid ""
"A new version {new_version} is available!\n"
"You have version {current_version}.\n"
"\n"
"Update using: {update_command}"
msgstr ""
"A new version {new_version} is available!\n"
"You have version {current_version}.\n"
"\n"
"Update using: {update_command}"
#: ImageBrowser.py:183
msgid "Otwórz folder"
msgstr "Open folder"
#: ImageBrowser.py:186 ImageBrowser.py:484 ImageBrowser.py:601
#: ImageBrowser.py:609
msgid "Wyślij"
msgstr "Upload"
#: ImageBrowser.py:189 ImageBrowser.py:594
msgid "Wyślij wszystko"
msgstr "Upload all"
#: ImageBrowser.py:193 ImageBrowser.py:595 ImageBrowser.py:601
msgid "Podmień tagi"
msgstr "Replace tags"
#: ImageBrowser.py:196 ImageBrowser.py:596
msgid "Otwórz post"
msgstr "Open post"
#: ImageBrowser.py:199
msgid "Zakończ"
msgstr "Finish"
#: ImageBrowser.py:201
msgid "Plik"
msgstr "File"
#: ImageBrowser.py:205 ImageBrowser.py:306
msgid "Ustawienia"
msgstr "Settings"
#: ImageBrowser.py:208
msgid "Wyczyść cache Taggera"
msgstr "Clear Tagger cache"
#: ImageBrowser.py:211
msgid "Zregeneruj bazę tagów"
msgstr "Regenerate tag database"
#: ImageBrowser.py:213
msgid "Opcje"
msgstr "Options"
#: ImageBrowser.py:216
msgid "About"
msgstr "About"
#: ImageBrowser.py:217
msgid "Help"
msgstr "Help"
#: ImageBrowser.py:222
msgid "About Kapitanbooru Uploader"
msgstr "About Kapitanbooru Uploader"
#: ImageBrowser.py:239
#, python-brace-format
msgid "A new version {new_version} is available!"
msgstr "A new version {new_version} is available!"
#: ImageBrowser.py:246
#, python-brace-format
msgid "Current version: {version}"
msgstr "Current version: {version}"
#: ImageBrowser.py:248
msgid "A GUI application for uploading images to KapitanBooru."
msgstr "A GUI application for uploading images to KapitanBooru."
#: ImageBrowser.py:249
msgid "Features include image upload, tag management, automatic"
msgstr "Features include image upload, tag management, automatic"
#: ImageBrowser.py:250
msgid "tagging with wdtagger, and cache management."
msgstr "tagging with wdtagger, and cache management."
#: ImageBrowser.py:252
msgid "Authors:"
msgstr "Authors:"
#: ImageBrowser.py:255
msgid "License: MIT License"
msgstr "License: MIT License"
#: ImageBrowser.py:268
msgid "Repository:"
msgstr "Repository:"
#: ImageBrowser.py:277
msgid "Website:"
msgstr "Website:"
#: ImageBrowser.py:288
msgid "Close"
msgstr "Close"
#: ImageBrowser.py:298 ImageBrowser.py:301
msgid "Cache"
msgstr "Cache"
#: ImageBrowser.py:298
msgid "Cache Taggera zostało wyczyszczone."
msgstr "Tagger cache has been cleared."
#: ImageBrowser.py:301
msgid "Błąd przy czyszczeniu cache:"
msgstr "Error clearing cache:"
#: ImageBrowser.py:311
msgid "Login:"
msgstr "Login:"
#: ImageBrowser.py:317
msgid "Hasło:"
msgstr "Password:"
#: ImageBrowser.py:323
msgid "Base URL:"
msgstr "Base URL:"
#: ImageBrowser.py:329
msgid "Default Tags:"
msgstr "Default Tags:"
#: ImageBrowser.py:335
msgid "Browser:"
msgstr "Browser:"
#: ImageBrowser.py:349
msgid "Language:"
msgstr "Language:"
#: ImageBrowser.py:385
msgid "Zapisz"
msgstr "Save"
#: ImageBrowser.py:427
msgid "PNG Tags"
msgstr "PNG Tags"
#: ImageBrowser.py:439
msgid "Tagger Tags"
msgstr "Tagger Tags"
#: ImageBrowser.py:453
msgid "Manual Tags"
msgstr "Manual Tags"
#: ImageBrowser.py:464
msgid "Final Tags"
msgstr "Final Tags"
#: ImageBrowser.py:489
msgid "Wyświetl"
msgstr "Display"
#: ImageBrowser.py:506
msgid "Przetworzono tagi:"
msgstr "Processed tags:"
#: ImageBrowser.py:506 ImageBrowser.py:507 ImageBrowser.py:508
msgid "plików"
msgstr "files"
#: ImageBrowser.py:507
msgid "Zweryfikowano status uploadu:"
msgstr "Upload status verified:"
#: ImageBrowser.py:508
msgid "Zuploadowano:"
msgstr "Uploaded:"
#: ImageBrowser.py:537
msgid "Wybierz folder z obrazkami PNG, JPEG, WebP, AVIF i GIF"
msgstr "Select folder with PNG, JPEG, WebP, AVIF, and GIF images"
#: ImageBrowser.py:552
msgid "Informacja"
msgstr "Information"
#: ImageBrowser.py:553
msgid "Brak plików PNG, JPEG, WebP, AVIF lub GIF w wybranym folderze."
msgstr "No PNG, JPEG, WebP, AVIF or GIF files in the selected folder."
#: ImageBrowser.py:660 ImageBrowser.py:1183
msgid "Błąd wysyłania"
msgstr "Upload error"
#: ImageBrowser.py:695
msgid "Błąd"
msgstr "Error"
#: ImageBrowser.py:695
msgid "Nie można załadować obrazka:"
msgstr "Unable to load image:"
#: ImageBrowser.py:923 ImageBrowser.py:935
#, python-brace-format
msgid "Warning: Tag '{tag}' not found in implication graph"
msgstr "Warning: Tag '{tag}' not found in implication graph"
#: ImageBrowser.py:1144
msgid "Tagger przetwarza..."
msgstr "Tagger processing..."
#: ImageBrowser.py:1161
msgid "Potwierdzenie" msgid "Potwierdzenie"
msgstr "Confirmation" msgstr "Confirmation"
#: ImageBrowser.py:1618 #: ImageBrowser.py:1163
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"
@@ -384,21 +423,6 @@ 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:1642
msgid "Anulowano operację!"
msgstr "Operation cancelled!"
#: ImageBrowser.py:1650
#, python-brace-format
msgid ""
"Wysyłanie {file_path} z tagami: {final_tags} i ratingiem: {final_rating}"
msgstr ""
"Uploading {file_path} with tags: {final_tags} and rating: {final_rating}"
#: ImageBrowser.py:1666
msgid "Przesłano pliki!"
msgstr "Files have been uploaded!"
#: ProcessingDialog.py:15 #: ProcessingDialog.py:15
msgid "Processing..." msgid "Processing..."
msgstr "Processing..." msgstr "Processing..."

View File

@@ -1,8 +1,8 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Kapitanbooru Uploader 0.8.3\n" "Project-Id-Version: Kapitanbooru Uploader 0.9.0\n"
"Report-Msgid-Bugs-To: kapitan@mlesniak.pl\n" "Report-Msgid-Bugs-To: kapitan@mlesniak.pl\n"
"POT-Creation-Date: 2025-06-25 23:49+0200\n" "POT-Creation-Date: 2025-06-26 17:07+0200\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,26 +45,152 @@ 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:138 #: Core.py:204
msgid "Błąd przy otwieraniu pliku"
msgstr "Błąd przy otwieraniu pliku"
#: Core.py:245
msgid "Tagger przetworzył:"
msgstr "Tagger przetworzył:"
#: Core.py:248
msgid "Błąd Taggera dla"
msgstr "Błąd Taggera dla"
#: Core.py:303
msgid "Error computing MD5:"
msgstr "Błąd przy obliczaniu MD5:"
#: Core.py:428
msgid "Błąd podczas sprawdzania paczki uploadu:"
msgstr "Błąd podczas sprawdzania paczki uploadu:"
#: Core.py:437
msgid "Plik nie istnieje:"
msgstr ""
#: Core.py:443
msgid "Tagi dla pliku"
msgstr ""
#: Core.py:452
msgid "Błąd podczas autotagowania pliku"
msgstr "Błąd podczas autotagowania pliku"
#: Core.py:459
msgid "Podana ścieżka nie jest katalogiem:"
msgstr ""
#: Core.py:467
msgid "Brak obrazów do przetworzenia w katalogu:"
msgstr ""
#: Core.py:490
#, python-brace-format
msgid "Wysyłam plik {base_file_name}..."
msgstr "Wysyłam plik {base_file_name}..."
#: Core.py:525
msgid "Wysyłanie zakończone powodzeniem!"
msgstr "Wysyłanie zakończone powodzeniem!"
#: Core.py:529 Core.py:538
#, python-brace-format
msgid ""
"Wysyłanie zakończone błędem.\n"
"Status: {status_code}\n"
"Treść: {text}"
msgstr ""
"Wysyłanie zakończone błędem.\n"
"Status: {status_code}\n"
"Treść: {text}"
#: Core.py:547 Core.py:553 ImageBrowser.py:654 ImageBrowser.py:657
#: ImageBrowser.py:1177 ImageBrowser.py:1180
msgid "Wysyłanie"
msgstr "Wysyłanie"
#: Core.py:565
msgid "Błąd wysyłania pliku"
msgstr "Błąd wysyłania pliku"
#: Core.py:595
msgid "Anulowano operację!"
msgstr "Operacja anulowana!"
#: Core.py:605
#, python-brace-format
msgid ""
"Wysyłanie {file_path} z tagami: {final_tags} i ratingiem: {final_rating}"
msgstr ""
"Wysyłanie {file_path} z tagami: {final_tags} i ratingiem: {final_rating}"
#: Core.py:624
msgid "Przesłano pliki!"
msgstr "Pliki zostały przesłane!"
#: Core.py:645 Core.py:649
msgid "Post nie został znaleziony dla tego pliku"
msgstr "Post nie został znaleziony dla tego pliku"
#: Core.py:660
#, python-brace-format
msgid "Aktualizuję tagi dla {base_file_name}..."
msgstr "Aktualizuję tagi dla {base_file_name}..."
#: Core.py:670 Core.py:680 Core.py:705
msgid "Operacja anulowana"
msgstr "Operacja anulowana"
#: Core.py:715
msgid "Tagi zostały zaktualizowane!"
msgstr "Tagi zostały zaktualizowane!"
#: Core.py:720 ImageBrowser.py:719
msgid "Sukces edycji"
msgstr "Sukces edycji"
#: Core.py:727
#, python-brace-format
msgid ""
"Błąd podczas aktualizacji tagów\n"
"Status: {code}"
msgstr ""
"Błąd podczas aktualizacji tagów\n"
"Status: {code}"
#: Core.py:731
msgid "Treść:"
msgstr "Treść:"
#: Core.py:735 ImageBrowser.py:716
msgid "Błąd edycji"
msgstr "Błąd edycji"
#: Core.py:741
msgid "Krytyczny błąd edycji"
msgstr "Krytyczny błąd edycji"
#: ImageBrowser.py:112
#, 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:140 #: ImageBrowser.py:114
#, 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:143 #: ImageBrowser.py:117
#, 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:150 #: ImageBrowser.py:124
msgid "Update Available" msgid "Update Available"
msgstr "Aktualizacja dostępna" msgstr "Aktualizacja dostępna"
#: ImageBrowser.py:152 #: ImageBrowser.py:126
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"A new version {new_version} is available!\n" "A new version {new_version} is available!\n"
@@ -77,307 +203,219 @@ msgstr ""
"\n" "\n"
"Aktualizuj za pomocą: {update_command}" "Aktualizuj za pomocą: {update_command}"
#: ImageBrowser.py:266 #: ImageBrowser.py:183
msgid "Błąd przy otwieraniu pliku"
msgstr "Błąd przy otwieraniu pliku"
#: ImageBrowser.py:308
msgid "Tagger przetworzył:"
msgstr "Tagger przetworzył:"
#: ImageBrowser.py:311
msgid "Błąd Taggera dla"
msgstr "Błąd Taggera dla"
#: ImageBrowser.py:337
msgid "Otwórz folder" msgid "Otwórz folder"
msgstr "Otwórz folder" msgstr "Otwórz folder"
#: ImageBrowser.py:340 ImageBrowser.py:629 ImageBrowser.py:856 #: ImageBrowser.py:186 ImageBrowser.py:484 ImageBrowser.py:601
#: ImageBrowser.py:864 #: ImageBrowser.py:609
msgid "Wyślij" msgid "Wyślij"
msgstr "Wyślij" msgstr "Wyślij"
#: ImageBrowser.py:343 ImageBrowser.py:849 #: ImageBrowser.py:189 ImageBrowser.py:594
msgid "Wyślij wszystko" msgid "Wyślij wszystko"
msgstr "Wyślij wszystko" msgstr "Wyślij wszystko"
#: ImageBrowser.py:347 ImageBrowser.py:850 ImageBrowser.py:856 #: ImageBrowser.py:193 ImageBrowser.py:595 ImageBrowser.py:601
msgid "Podmień tagi" msgid "Podmień tagi"
msgstr "Podmień tagi" msgstr "Podmień tagi"
#: ImageBrowser.py:350 ImageBrowser.py:851 #: ImageBrowser.py:196 ImageBrowser.py:596
msgid "Otwórz post" msgid "Otwórz post"
msgstr "Otwórz post" msgstr "Otwórz post"
#: ImageBrowser.py:353 #: ImageBrowser.py:199
msgid "Zakończ" msgid "Zakończ"
msgstr "Zakończ" msgstr "Zakończ"
#: ImageBrowser.py:355 #: ImageBrowser.py:201
msgid "Plik" msgid "Plik"
msgstr "Plik" msgstr "Plik"
#: ImageBrowser.py:359 ImageBrowser.py:458 #: ImageBrowser.py:205 ImageBrowser.py:306
msgid "Ustawienia" msgid "Ustawienia"
msgstr "Ustawienia" msgstr "Ustawienia"
#: ImageBrowser.py:362 #: ImageBrowser.py:208
msgid "Wyczyść cache Taggera" msgid "Wyczyść cache Taggera"
msgstr "Wyczyść cache Taggera" msgstr "Wyczyść cache Taggera"
#: ImageBrowser.py:365 #: ImageBrowser.py:211
msgid "Zregeneruj bazę tagów" msgid "Zregeneruj bazę tagów"
msgstr "Zregeneruj bazę tagów" msgstr "Zregeneruj bazę tagów"
#: ImageBrowser.py:367 #: ImageBrowser.py:213
msgid "Opcje" msgid "Opcje"
msgstr "Opcje" msgstr "Opcje"
#: ImageBrowser.py:370 #: ImageBrowser.py:216
msgid "About" msgid "About"
msgstr "O programie" msgstr "O programie"
#: ImageBrowser.py:371 #: ImageBrowser.py:217
msgid "Help" msgid "Help"
msgstr "Pomoc" msgstr "Pomoc"
#: ImageBrowser.py:376 #: ImageBrowser.py:222
msgid "About Kapitanbooru Uploader" msgid "About Kapitanbooru Uploader"
msgstr "O programie Kapitanbooru Uploader" msgstr "O programie Kapitanbooru Uploader"
#: ImageBrowser.py:393 #: ImageBrowser.py:239
#, 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:400 #: ImageBrowser.py:246
#, python-brace-format #, python-brace-format
msgid "Current version: {version}" msgid "Current version: {version}"
msgstr "Obecna wersja: {version}" msgstr "Obecna wersja: {version}"
#: ImageBrowser.py:402 #: ImageBrowser.py:248
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:403 #: ImageBrowser.py:249
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:404 #: ImageBrowser.py:250
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:406 #: ImageBrowser.py:252
msgid "Authors:" msgid "Authors:"
msgstr "Autorzy:" msgstr "Autorzy:"
#: ImageBrowser.py:409 #: ImageBrowser.py:255
msgid "License: MIT License" msgid "License: MIT License"
msgstr "Licencja: MIT License" msgstr "Licencja: MIT License"
#: ImageBrowser.py:422 #: ImageBrowser.py:268
msgid "Repository:" msgid "Repository:"
msgstr "Repozytorium:" msgstr "Repozytorium:"
#: ImageBrowser.py:431 #: ImageBrowser.py:277
msgid "Website:" msgid "Website:"
msgstr "Strona internetowa:" msgstr "Strona internetowa:"
#: ImageBrowser.py:442 #: ImageBrowser.py:288
msgid "Close" msgid "Close"
msgstr "Zamknij" msgstr "Zamknij"
#: ImageBrowser.py:450 ImageBrowser.py:453 #: ImageBrowser.py:298 ImageBrowser.py:301
msgid "Cache" msgid "Cache"
msgstr "Cache" msgstr "Cache"
#: ImageBrowser.py:450 #: ImageBrowser.py:298
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:453 #: ImageBrowser.py:301
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:463 #: ImageBrowser.py:311
msgid "Login:" msgid "Login:"
msgstr "Login:" msgstr "Login:"
#: ImageBrowser.py:469 #: ImageBrowser.py:317
msgid "Hasło:" msgid "Hasło:"
msgstr "Hasło:" msgstr "Hasło:"
#: ImageBrowser.py:475 #: ImageBrowser.py:323
msgid "Base URL:" msgid "Base URL:"
msgstr "Base URL:" msgstr "Base URL:"
#: ImageBrowser.py:481 #: ImageBrowser.py:329
msgid "Default Tags:" msgid "Default Tags:"
msgstr "Domyślne tagi:" msgstr "Domyślne tagi:"
#: ImageBrowser.py:487 #: ImageBrowser.py:335
msgid "Browser:" msgid "Browser:"
msgstr "Przeglądarka:" msgstr "Przeglądarka:"
#: ImageBrowser.py:501 #: ImageBrowser.py:349
msgid "Language:" msgid "Language:"
msgstr "Język:" msgstr "Język:"
#: ImageBrowser.py:533 #: ImageBrowser.py:385
msgid "Zapisz" msgid "Zapisz"
msgstr "Zapisz" msgstr "Zapisz"
#: ImageBrowser.py:575 #: ImageBrowser.py:427
msgid "PNG Tags" msgid "PNG Tags"
msgstr "Tagi PNG" msgstr "Tagi PNG"
#: ImageBrowser.py:587 #: ImageBrowser.py:439
msgid "Tagger Tags" msgid "Tagger Tags"
msgstr "Tagi Taggera" msgstr "Tagi Taggera"
#: ImageBrowser.py:601 #: ImageBrowser.py:453
msgid "Manual Tags" msgid "Manual Tags"
msgstr "Tagi ręczne" msgstr "Tagi ręczne"
#: ImageBrowser.py:609 #: ImageBrowser.py:464
msgid "Final Tags" msgid "Final Tags"
msgstr "Ostateczne tagi" msgstr "Ostateczne tagi"
#: ImageBrowser.py:634 #: ImageBrowser.py:489
msgid "Wyświetl" msgid "Wyświetl"
msgstr "Wyświetl" msgstr "Wyświetl"
#: ImageBrowser.py:651 #: ImageBrowser.py:506
msgid "Przetworzono tagi:" msgid "Przetworzono tagi:"
msgstr "Przetworzono tagi:" msgstr "Przetworzono tagi:"
#: ImageBrowser.py:651 ImageBrowser.py:652 ImageBrowser.py:653 #: ImageBrowser.py:506 ImageBrowser.py:507 ImageBrowser.py:508
msgid "plików" msgid "plików"
msgstr "plików" msgstr "plików"
#: ImageBrowser.py:652 #: ImageBrowser.py:507
msgid "Zweryfikowano status uploadu:" msgid "Zweryfikowano status uploadu:"
msgstr "Zweryfikowano status uploadu:" msgstr "Zweryfikowano status uploadu:"
#: ImageBrowser.py:653 #: ImageBrowser.py:508
msgid "Zuploadowano:" msgid "Zuploadowano:"
msgstr "Zuploadowano:" msgstr "Zuploadowano:"
#: ImageBrowser.py:682 #: ImageBrowser.py:537
#, fuzzy
msgid "Wybierz folder z obrazkami PNG, JPEG, WebP, AVIF i GIF" msgid "Wybierz folder z obrazkami PNG, JPEG, WebP, AVIF i GIF"
msgstr "Wybierz folder z obrazami PNG" msgstr "Wybierz folder z obrazkami PNG, JPEG, WebP, AVIF i GIF"
#: ImageBrowser.py:724 #: ImageBrowser.py:552
msgid "Informacja" msgid "Informacja"
msgstr "Informacja" msgstr "Informacja"
#: ImageBrowser.py:725 #: ImageBrowser.py:553
#, fuzzy
msgid "Brak plików PNG, JPEG, WebP, AVIF lub GIF w wybranym folderze." 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, JPEG, WebP, AVIF lub GIF w wybranym folderze."
#: ImageBrowser.py:808 #: ImageBrowser.py:660 ImageBrowser.py:1183
msgid "Błąd podczas sprawdzania paczki uploadu:" msgid "Błąd wysyłania"
msgstr "Błąd podczas sprawdzania paczki uploadu:" msgstr "Błąd wysyłania"
#: ImageBrowser.py:884 #: ImageBrowser.py:695
msgid "Error computing MD5:"
msgstr "Błąd przy obliczaniu MD5:"
#: ImageBrowser.py:946
msgid "Błąd" msgid "Błąd"
msgstr "Błąd" msgstr "Błąd"
#: ImageBrowser.py:946 #: ImageBrowser.py:695
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:1156 ImageBrowser.py:1166 #: ImageBrowser.py:923 ImageBrowser.py:935
#, 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:1396 #: ImageBrowser.py:1144
msgid "Tagger przetwarza..." msgid "Tagger przetwarza..."
msgstr "Tagger przetwarza..." msgstr "Tagger przetwarza..."
#: ImageBrowser.py:1421 #: ImageBrowser.py:1161
#, python-brace-format
msgid "Wysyłam plik {base_file_name}..."
msgstr "Wysyłam plik {base_file_name}..."
#: ImageBrowser.py:1462
msgid "Wysyłanie zakończone powodzeniem!"
msgstr "Wysyłanie zakończone powodzeniem!"
#: ImageBrowser.py:1466 ImageBrowser.py:1475
#, python-brace-format
msgid ""
"Wysyłanie zakończone błędem.\n"
"Status: {status_code}\n"
"Treść: {text}"
msgstr ""
"Wysyłanie zakończone błędem.\n"
"Status: {status_code}\n"
"Treść: {text}"
#: ImageBrowser.py:1481 ImageBrowser.py:1484
msgid "Wysyłanie"
msgstr "Wysyłanie"
#: ImageBrowser.py:1497
msgid "Błąd wysyłania"
msgstr "Błąd wysyłania"
#: ImageBrowser.py:1517
msgid "Błąd edycji"
msgstr "Błąd edycji"
#: ImageBrowser.py:1517
msgid "Post nie został znaleziony dla tego pliku"
msgstr "Post nie został znaleziony dla tego pliku"
#: ImageBrowser.py:1527
#, python-brace-format
msgid "Aktualizuję tagi dla {base_file_name}..."
msgstr "Aktualizuję tagi dla {base_file_name}..."
#: ImageBrowser.py:1537 ImageBrowser.py:1547 ImageBrowser.py:1578
msgid "Operacja anulowana"
msgstr "Operacja anulowana"
#: ImageBrowser.py:1588
msgid "Tagi zostały zaktualizowane!"
msgstr "Tagi zostały zaktualizowane!"
#: ImageBrowser.py:1590
msgid "Sukces edycji"
msgstr "Sukces edycji"
#: ImageBrowser.py:1596
#, python-brace-format
msgid ""
"Błąd podczas aktualizacji tagów\n"
"Status: {code}"
msgstr ""
"Błąd podczas aktualizacji tagów\n"
"Status: {code}"
#: ImageBrowser.py:1600
msgid "Treść:"
msgstr "Treść:"
#: ImageBrowser.py:1604
msgid "Krytyczny błąd edycji"
msgstr "Krytyczny błąd edycji"
#: ImageBrowser.py:1616
msgid "Potwierdzenie" msgid "Potwierdzenie"
msgstr "Potwierdzenie" msgstr "Potwierdzenie"
#: ImageBrowser.py:1618 #: ImageBrowser.py:1163
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"
@@ -387,21 +425,6 @@ 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:1642
msgid "Anulowano operację!"
msgstr "Operacja anulowana!"
#: ImageBrowser.py:1650
#, python-brace-format
msgid ""
"Wysyłanie {file_path} z tagami: {final_tags} i ratingiem: {final_rating}"
msgstr ""
"Wysyłanie {file_path} z tagami: {final_tags} i ratingiem: {final_rating}"
#: ImageBrowser.py:1666
msgid "Przesłano pliki!"
msgstr "Pliki zostały przesłane!"
#: ProcessingDialog.py:15 #: ProcessingDialog.py:15
msgid "Processing..." msgid "Processing..."
msgstr "Przetwarzanie..." msgstr "Przetwarzanie..."
@@ -435,9 +458,8 @@ 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:208 #: tag_processing.py:208
#, fuzzy
msgid "Nie można sparsować parametrów." msgid "Nie można sparsować parametrów."
msgstr "Nie można załadować obrazka:" msgstr "Nie można sparsować parametrów."
#: tag_processing.py:295 #: tag_processing.py:295
msgid "Błąd podczas odczytu tag_aliases:" msgid "Błąd podczas odczytu tag_aliases:"

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "kapitanbooru-uploader" name = "kapitanbooru-uploader"
version = "0.8.3" version = "0.9.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 = [