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
when kapitanbooru_uploader directory is called as script."""
from .Core import Core
from .settings import Settings
from .ImageBrowser import ImageBrowser
import argparse
def main():
app = ImageBrowser()
app.mainloop()
parser = argparse.ArgumentParser(
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__":

View File

@@ -1,8 +1,8 @@
msgid ""
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"
"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-Transfer-Encoding: 8bit\n"
@@ -43,273 +43,56 @@ msgstr "Found auth_token:"
msgid "auth_token not found in the HTML page."
msgstr "auth_token not found in the HTML page."
#: ImageBrowser.py:138
#, 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
#: Core.py:204
msgid "Błąd przy otwieraniu pliku"
msgstr "Error opening file"
#: ImageBrowser.py:308
#: Core.py:245
msgid "Tagger przetworzył:"
msgstr "Tagger processed:"
#: ImageBrowser.py:311
#: Core.py:248
msgid "Błąd Taggera dla"
msgstr "Tagger error for"
#: ImageBrowser.py:337
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
#: Core.py:303
msgid "Error computing MD5:"
msgstr "Error computing MD5:"
#: ImageBrowser.py:946
msgid "Błąd"
msgstr "Error"
#: Core.py:428
msgid "Błąd podczas sprawdzania paczki uploadu:"
msgstr "Error while checking upload package:"
#: ImageBrowser.py:946
msgid "Nie można załadować obrazka:"
msgstr "Unable to load image:"
#: Core.py:437
msgid "Plik nie istnieje:"
msgstr "File does not exist:"
#: ImageBrowser.py:1156 ImageBrowser.py:1166
#, python-brace-format
msgid "Warning: Tag '{tag}' not found in implication graph"
msgstr "Warning: Tag '{tag}' not found in implication graph"
#: Core.py:443
msgid "Tagi dla pliku"
msgstr "Tags for file"
#: ImageBrowser.py:1396
msgid "Tagger przetwarza..."
msgstr "Tagger processing..."
#: Core.py:452
msgid "Błąd podczas autotagowania pliku"
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
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!"
msgstr "Upload completed successfully!"
#: ImageBrowser.py:1466 ImageBrowser.py:1475
#: Core.py:529 Core.py:538
#, python-brace-format
msgid ""
"Wysyłanie zakończone błędem.\n"
@@ -320,40 +103,52 @@ msgstr ""
"Status: {status_code}\n"
"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"
msgstr "Uploading"
#: ImageBrowser.py:1497
msgid "Błąd wysyłania"
#: Core.py:565
msgid "Błąd wysyłania pliku"
msgstr "Upload error"
#: ImageBrowser.py:1517
msgid "Błąd edycji"
msgstr "Edit error"
#: Core.py:595
msgid "Anulowano operację!"
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"
msgstr "Post not found for this file"
#: ImageBrowser.py:1527
#: Core.py:660
#, python-brace-format
msgid "Aktualizuję tagi dla {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"
msgstr "Operation cancelled"
#: ImageBrowser.py:1588
#: Core.py:715
msgid "Tagi zostały zaktualizowane!"
msgstr "Tags have been updated!"
#: ImageBrowser.py:1590
#: Core.py:720 ImageBrowser.py:719
msgid "Sukces edycji"
msgstr "Edit successful"
#: ImageBrowser.py:1596
#: Core.py:727
#, python-brace-format
msgid ""
"Błąd podczas aktualizacji tagów\n"
@@ -362,19 +157,263 @@ msgstr ""
"Error updating tags\n"
"Status: {code}"
#: ImageBrowser.py:1600
#: Core.py:731
msgid "Treść:"
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"
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"
msgstr "Confirmation"
#: ImageBrowser.py:1618
#: ImageBrowser.py:1163
msgid ""
"Czy na pewno chcesz wrzucić wszystkie niewrzucone pliki?\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"
"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
msgid "Processing..."
msgstr "Processing..."

View File

@@ -1,8 +1,8 @@
msgid ""
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"
"POT-Creation-Date: 2025-06-25 23:49+0200\n"
"POT-Creation-Date: 2025-06-26 17:07+0200\n"
"Language: pl\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -45,26 +45,152 @@ msgstr "Znaleziono auth_token:"
msgid "auth_token not found in the HTML page."
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
msgid "Update check failed: {error}"
msgstr "Sprawdzenie aktualizacji nie powiodło się: {error}"
#: ImageBrowser.py:140
#: ImageBrowser.py:114
#, python-brace-format
msgid "Malformed pyproject.toml: {error}"
msgstr "Nieprawidłowy plik pyproject.toml: {error}"
#: ImageBrowser.py:143
#: ImageBrowser.py:117
#, python-brace-format
msgid "Unexpected error during update check: {error}"
msgstr "Nieoczekiwany błąd podczas sprawdzania aktualizacji: {error}"
#: ImageBrowser.py:150
#: ImageBrowser.py:124
msgid "Update Available"
msgstr "Aktualizacja dostępna"
#: ImageBrowser.py:152
#: ImageBrowser.py:126
#, python-brace-format
msgid ""
"A new version {new_version} is available!\n"
@@ -77,307 +203,219 @@ msgstr ""
"\n"
"Aktualizuj za pomocą: {update_command}"
#: ImageBrowser.py:266
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
#: ImageBrowser.py:183
msgid "Otwórz folder"
msgstr "Otwórz folder"
#: ImageBrowser.py:340 ImageBrowser.py:629 ImageBrowser.py:856
#: ImageBrowser.py:864
#: ImageBrowser.py:186 ImageBrowser.py:484 ImageBrowser.py:601
#: ImageBrowser.py:609
msgid "Wyślij"
msgstr "Wyślij"
#: ImageBrowser.py:343 ImageBrowser.py:849
#: ImageBrowser.py:189 ImageBrowser.py:594
msgid "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"
msgstr "Podmień tagi"
#: ImageBrowser.py:350 ImageBrowser.py:851
#: ImageBrowser.py:196 ImageBrowser.py:596
msgid "Otwórz post"
msgstr "Otwórz post"
#: ImageBrowser.py:353
#: ImageBrowser.py:199
msgid "Zakończ"
msgstr "Zakończ"
#: ImageBrowser.py:355
#: ImageBrowser.py:201
msgid "Plik"
msgstr "Plik"
#: ImageBrowser.py:359 ImageBrowser.py:458
#: ImageBrowser.py:205 ImageBrowser.py:306
msgid "Ustawienia"
msgstr "Ustawienia"
#: ImageBrowser.py:362
#: ImageBrowser.py:208
msgid "Wyczyść cache Taggera"
msgstr "Wyczyść cache Taggera"
#: ImageBrowser.py:365
#: ImageBrowser.py:211
msgid "Zregeneruj bazę tagów"
msgstr "Zregeneruj bazę tagów"
#: ImageBrowser.py:367
#: ImageBrowser.py:213
msgid "Opcje"
msgstr "Opcje"
#: ImageBrowser.py:370
#: ImageBrowser.py:216
msgid "About"
msgstr "O programie"
#: ImageBrowser.py:371
#: ImageBrowser.py:217
msgid "Help"
msgstr "Pomoc"
#: ImageBrowser.py:376
#: ImageBrowser.py:222
msgid "About Kapitanbooru Uploader"
msgstr "O programie Kapitanbooru Uploader"
#: ImageBrowser.py:393
#: ImageBrowser.py:239
#, python-brace-format
msgid "A new version {new_version} is available!"
msgstr "Dostępna jest nowa wersja {new_version}!"
#: ImageBrowser.py:400
#: ImageBrowser.py:246
#, python-brace-format
msgid "Current version: {version}"
msgstr "Obecna wersja: {version}"
#: ImageBrowser.py:402
#: ImageBrowser.py:248
msgid "A GUI application for uploading images to 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"
msgstr "Funkcje obejmują przesyłanie obrazów, zarządzanie tagami, automatyczne"
#: ImageBrowser.py:404
#: ImageBrowser.py:250
msgid "tagging with wdtagger, and cache management."
msgstr "tagowanie za pomocą wdtagger oraz zarządzanie cache."
#: ImageBrowser.py:406
#: ImageBrowser.py:252
msgid "Authors:"
msgstr "Autorzy:"
#: ImageBrowser.py:409
#: ImageBrowser.py:255
msgid "License: MIT License"
msgstr "Licencja: MIT License"
#: ImageBrowser.py:422
#: ImageBrowser.py:268
msgid "Repository:"
msgstr "Repozytorium:"
#: ImageBrowser.py:431
#: ImageBrowser.py:277
msgid "Website:"
msgstr "Strona internetowa:"
#: ImageBrowser.py:442
#: ImageBrowser.py:288
msgid "Close"
msgstr "Zamknij"
#: ImageBrowser.py:450 ImageBrowser.py:453
#: ImageBrowser.py:298 ImageBrowser.py:301
msgid "Cache"
msgstr "Cache"
#: ImageBrowser.py:450
#: ImageBrowser.py:298
msgid "Cache Taggera zostało wyczyszczone."
msgstr "Cache Taggera zostało wyczyszczone."
#: ImageBrowser.py:453
#: ImageBrowser.py:301
msgid "Błąd przy czyszczeniu cache:"
msgstr "Błąd przy czyszczeniu cache:"
#: ImageBrowser.py:463
#: ImageBrowser.py:311
msgid "Login:"
msgstr "Login:"
#: ImageBrowser.py:469
#: ImageBrowser.py:317
msgid "Hasło:"
msgstr "Hasło:"
#: ImageBrowser.py:475
#: ImageBrowser.py:323
msgid "Base URL:"
msgstr "Base URL:"
#: ImageBrowser.py:481
#: ImageBrowser.py:329
msgid "Default Tags:"
msgstr "Domyślne tagi:"
#: ImageBrowser.py:487
#: ImageBrowser.py:335
msgid "Browser:"
msgstr "Przeglądarka:"
#: ImageBrowser.py:501
#: ImageBrowser.py:349
msgid "Language:"
msgstr "Język:"
#: ImageBrowser.py:533
#: ImageBrowser.py:385
msgid "Zapisz"
msgstr "Zapisz"
#: ImageBrowser.py:575
#: ImageBrowser.py:427
msgid "PNG Tags"
msgstr "Tagi PNG"
#: ImageBrowser.py:587
#: ImageBrowser.py:439
msgid "Tagger Tags"
msgstr "Tagi Taggera"
#: ImageBrowser.py:601
#: ImageBrowser.py:453
msgid "Manual Tags"
msgstr "Tagi ręczne"
#: ImageBrowser.py:609
#: ImageBrowser.py:464
msgid "Final Tags"
msgstr "Ostateczne tagi"
#: ImageBrowser.py:634
#: ImageBrowser.py:489
msgid "Wyświetl"
msgstr "Wyświetl"
#: ImageBrowser.py:651
#: ImageBrowser.py:506
msgid "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"
msgstr "plików"
#: ImageBrowser.py:652
#: ImageBrowser.py:507
msgid "Zweryfikowano status uploadu:"
msgstr "Zweryfikowano status uploadu:"
#: ImageBrowser.py:653
#: ImageBrowser.py:508
msgid "Zuploadowano:"
msgstr "Zuploadowano:"
#: ImageBrowser.py:682
#, fuzzy
#: ImageBrowser.py:537
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"
msgstr "Informacja"
#: ImageBrowser.py:725
#, fuzzy
#: ImageBrowser.py:553
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
msgid "Błąd podczas sprawdzania paczki uploadu:"
msgstr "Błąd podczas sprawdzania paczki uploadu:"
#: ImageBrowser.py:660 ImageBrowser.py:1183
msgid "Błąd wysyłania"
msgstr "Błąd wysyłania"
#: ImageBrowser.py:884
msgid "Error computing MD5:"
msgstr "Błąd przy obliczaniu MD5:"
#: ImageBrowser.py:946
#: ImageBrowser.py:695
msgid "Błąd"
msgstr "Błąd"
#: ImageBrowser.py:946
#: ImageBrowser.py:695
msgid "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
msgid "Warning: Tag '{tag}' not found in implication graph"
msgstr "Ostrzeżenie: Tag '{tag}' nie został znaleziony w grafie implikacji"
#: ImageBrowser.py:1396
#: ImageBrowser.py:1144
msgid "Tagger przetwarza..."
msgstr "Tagger przetwarza..."
#: ImageBrowser.py:1421
#, 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
#: ImageBrowser.py:1161
msgid "Potwierdzenie"
msgstr "Potwierdzenie"
#: ImageBrowser.py:1618
#: ImageBrowser.py:1163
msgid ""
"Czy na pewno chcesz wrzucić wszystkie niewrzucone pliki?\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"
"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
msgid "Processing..."
msgstr "Przetwarzanie..."
@@ -435,9 +458,8 @@ msgid "Błąd przy pobieraniu tagów artystów:"
msgstr "Błąd przy pobieraniu tagów artystów:"
#: tag_processing.py:208
#, fuzzy
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
msgid "Błąd podczas odczytu tag_aliases:"

View File

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