Update Kapitanbooru Uploader to version 0.9.0 with significant changes
All checks were successful
Gitea/kapitanbooru-uploader/pipeline/head This commit looks good
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:
744
kapitanbooru_uploader/Core.py
Normal file
744
kapitanbooru_uploader/Core.py
Normal 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
@@ -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__":
|
||||
|
@@ -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..."
|
||||
|
@@ -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:"
|
||||
|
@@ -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 = [
|
||||
|
Reference in New Issue
Block a user