diff --git a/app/api/admin.py b/app/api/admin.py
index 54f7845..702b097 100644
--- a/app/api/admin.py
+++ b/app/api/admin.py
@@ -30,7 +30,7 @@ router = APIRouter(
def _raw_to_thumb(raw: dict, kind: SourceKind) -> str | None:
"""Wyciąga thumbnail URL z external_records.raw dla danego źródła.
TPDB ma `image`/`poster`/`background.large`. StashDB raw nie zawiera image
- (osobny query do StashDB potrzebny — tu zwracamy None)."""
+ (osobny query do StashDB potrzebny, tu zwracamy None)."""
if kind == SourceKind.tpdb:
for k in ("image", "poster"):
v = raw.get(k)
@@ -42,7 +42,7 @@ def _raw_to_thumb(raw: dict, kind: SourceKind) -> str | None:
if isinstance(v, str) and v.startswith("http"):
return v
elif kind == SourceKind.stashdb:
- # StashDB scene response includes images via separate query — nie trzymamy
+ # StashDB scene response includes images via separate query, nie trzymamy
# tego w raw obecnie. TODO: dorzucić mirror do `paths.screenshot` przy ingest.
paths = raw.get("paths")
if isinstance(paths, dict):
@@ -142,7 +142,7 @@ def list_candidates(
# Pre-fetch po jednym statycznym i animowanym thumbnailu per scenę (mobile queue
# używa statycznego do listy + animowanego po hold-to-preview). Wybieramy najpierw
- # napotkany niepusty URL — kolejność rzędów playback_sources nie jest gwarantowana,
+ # napotkany niepusty URL, kolejność rzędów playback_sources nie jest gwarantowana,
# ale dla triage to wystarcza.
thumbs: dict[uuid.UUID, str] = {}
animated_thumbs: dict[uuid.UUID, str] = {}
@@ -292,7 +292,7 @@ def _fmt_bytes(b: int) -> str:
def bandwidth_stats() -> BandwidthStats:
"""Per-CDN VPS proxy bytes-out + Hetzner traffic stats.
- Critical dla public release — pokazuje gdzie VPS bandwidth wycieka. Pozwala
+ Critical dla public release, pokazuje gdzie VPS bandwidth wycieka. Pozwala
spotted Mixdrop / bandwidth-heavy CDN-y przed Hetzner overage charge.
"""
from app.api.stream_proxy import get_bandwidth_stats
@@ -308,7 +308,7 @@ def bandwidth_stats() -> BandwidthStats:
s_24h = get_bandwidth_stats(24)
s_7d = get_bandwidth_stats(168)
- # Hetzner stats — load from cache file (written by check_hetzner_traffic.py cron).
+ # Hetzner stats, load from cache file (written by check_hetzner_traffic.py cron).
hetzner_data = None
settings = get_settings()
if settings.hetzner_api_token and settings.hetzner_server_id:
diff --git a/app/api/admin_html.py b/app/api/admin_html.py
index 99514db..2090c6a 100644
--- a/app/api/admin_html.py
+++ b/app/api/admin_html.py
@@ -1,9 +1,9 @@
"""htmx + Jinja2 admin UI dla MergeCandidate triage.
Endpointy:
- GET /ui/ — lista pending (filter status)
- GET /ui/candidate/{id} — side-by-side scen
- POST /ui/candidate/{id}/resolve — htmx form submit (action=merge_keep_left|merge_keep_right|reject)
+ GET /ui/ lista pending (filter status)
+ GET /ui/candidate/{id} side-by-side scen
+ POST /ui/candidate/{id}/resolve, htmx form submit (action=merge_keep_left|merge_keep_right|reject)
zwraca fragment HTML z potwierdzeniem
"""
from __future__ import annotations
@@ -197,9 +197,9 @@ def resolve_form(
def mount_static(app) -> None: # pragma: no cover - dev convenience
- # APK MIME type — bez tego Android Browser nie traktuje pliku jako instalable APK
+ # APK MIME type, bez tego Android Browser nie traktuje pliku jako instalable APK
# (text/plain → "Plik został pobrany" zamiast prompta install). Rejestracja jest
- # idempotentna na poziomie procesu — bezpiecznie wywoływać przy każdym startup.
+ # idempotentna na poziomie procesu, bezpiecznie wywoływać przy każdym startup.
import mimetypes
mimetypes.add_type("application/vnd.android.package-archive", ".apk")
if _STATIC_DIR.exists():
diff --git a/app/api/blacklist.py b/app/api/blacklist.py
index 4975fe8..0cc5d76 100644
--- a/app/api/blacklist.py
+++ b/app/api/blacklist.py
@@ -1,12 +1,12 @@
-"""Blacklists — globalnie ukryte performerki/studia/tagi.
+"""Blacklists, globalnie ukryte performerki/studia/tagi.
Sceny które MAJĄ blacklisted entity wypadają z każdego /scenes (pełna lista, search,
performer scenes, tag scenes). Auto-apply w `app/api/scenes.py`.
Endpointy:
- GET /blacklist — wszystkie 3 listy w jednym response
- POST /blacklist/{kind}/{entity_id} — dodaj (idempotent)
- DELETE /blacklist/{kind}/{entity_id} — usuń
+ GET /blacklist wszystkie 3 listy w jednym response
+ POST /blacklist/{kind}/{entity_id} dodaj (idempotent)
+ DELETE /blacklist/{kind}/{entity_id} usuń
`kind` ∈ {performer, studio, tag}.
"""
diff --git a/app/api/bug_reports.py b/app/api/bug_reports.py
index 547eb5e..aba9cda 100644
--- a/app/api/bug_reports.py
+++ b/app/api/bug_reports.py
@@ -1,10 +1,10 @@
-"""Bug reports — mobile FAB → POST /bug-reports → admin lista przez admin_html.
+"""Bug reports, mobile FAB → POST /bug-reports → admin lista przez admin_html.
POST nie wymaga obecnego scene_id (user może raportować z FavoritesScreen,
-SearchScreen itp.). Screenshot opcjonalny — niektóre ekrany nie warto kapturować.
+SearchScreen itp.). Screenshot opcjonalny, niektóre ekrany nie warto kapturować.
Limit body 1.5MB (FastAPI default jest hojny, ale dla rozsądku ograniczamy).
-Screenshot to PNG/JPEG z react-native-view-shot, base64 — typowe rozmiary:
+Screenshot to PNG/JPEG z react-native-view-shot, base64, typowe rozmiary:
- mały ekran scene-list: ~200-400KB
- duży scene-detail z thumbnail: ~600KB-1MB
"""
@@ -92,7 +92,7 @@ def create_bug_report(
scene_id = payload.scene_id
elif session.get(Movie, payload.scene_id) is not None:
movie_id = payload.scene_id
- # else: ID nie istnieje już nigdzie (deleted) — drop oba na null
+ # else: ID nie istnieje już nigdzie (deleted), drop oba na null
br = BugReport(
id=uuid.uuid4(),
@@ -211,7 +211,7 @@ def get_bug_report_screenshot(
bug_id: uuid.UUID,
session: Annotated[Session, Depends(get_session)],
) -> dict[str, str | None]:
- """Zwraca base64-encoded screenshot (jeśli jest) — admin UI go renderuje."""
+ """Zwraca base64-encoded screenshot (jeśli jest), admin UI go renderuje."""
br = session.get(BugReport, bug_id)
if br is None:
raise HTTPException(status_code=404, detail="not found")
diff --git a/app/api/device.py b/app/api/device.py
index 2ea605f..bc70dbf 100644
--- a/app/api/device.py
+++ b/app/api/device.py
@@ -6,7 +6,7 @@ nowi użytkownicy widzieli/nadpisywali ulubione, watched-badge i blacklisty Jana
nagłówku `X-Device-Id`; backend scope'uje wszystkie tabele stanu po `device_id`.
Stare wiersze (sprzed migracji) mają `device_id = LEGACY_DEVICE`. Klient bez nagłówka
-(stara wersja apki przed OTA) trafia również na LEGACY_DEVICE — czyli dostaje dawną
+(stara wersja apki przed OTA) trafia również na LEGACY_DEVICE, czyli dostaje dawną
współdzieloną pulę, dopóki nie zaktualizuje bundla. Endpoint `/me/adopt-legacy`
przepina LEGACY rows na konkretne device (Jan robi to raz po update).
"""
diff --git a/app/api/expo_updates.py b/app/api/expo_updates.py
index 43b7415..849a4b4 100644
--- a/app/api/expo_updates.py
+++ b/app/api/expo_updates.py
@@ -8,9 +8,9 @@ Każdy update wgrany przez `scripts/publish_update.py` ląduje w
`app/static/expo-updates/]+(?:src|data-src|data-original|data-lazy-src|data-lazy)=["\']'
@@ -53,7 +53,7 @@ class BaseSearchScraper(BaseDirectTubeScraper):
#: Regex matchujący scene URL w search HTML. Wymagana grupa `url` (full scene URL),
#: opcjonalna grupa `slug` (do title derivation gdy dostępny w URL).
- _scene_url_re: re.Pattern[str] = re.compile(r"$^") # placeholder — subclass override
+ _scene_url_re: re.Pattern[str] = re.compile(r"$^") # placeholder, subclass override
#: Minimalna długość tokena query do filtrowania wyników (krótsze ignorujemy żeby
#: nie matchowały niezwiązanych slugów).
@@ -74,12 +74,12 @@ class BaseSearchScraper(BaseDirectTubeScraper):
})
#: Window (chars) wokół scene URL match, w którym szukamy `
` jako thumbnail.
- #: WordPress-like tubes mają thumb w `
` —
+ #: WordPress-like tubes mają thumb w `
`,
#: ±800 chars łapie ten pattern niezawodnie.
_thumbnail_window: int = 800
def _scene_url_from_match(self, m: re.Match[str]) -> str:
- """Domyślnie group(1) — subclass override gdy regex używa named groups inaczej."""
+ """Domyślnie group(1), subclass override gdy regex używa named groups inaczej."""
try:
return m.group("url")
except IndexError:
@@ -103,17 +103,17 @@ class BaseSearchScraper(BaseDirectTubeScraper):
def _format_query_for_url(self, query: str) -> str:
"""Default: URL-encode (spaces → `+`). Subclass override gdy tube wymaga
- innego formatu — np. KVS-style sites użyją slug (spaces → `-`).
+ innego formatu, np. KVS-style sites użyją slug (spaces → `-`).
"""
return urllib.parse.quote_plus(query.strip())
def _fetch_scene_metadata(
self, scene_url: str
) -> tuple[RawStudio | None, list[RawPerformer], list[RawTag]] | None:
- """Optional hook — subclass może override żeby fetch'ować scene detail page
+ """Optional hook, subclass może override żeby fetch'ować scene detail page
i wyciągnąć studio/performerów/tagi. Default zwraca None (skip detail fetch).
- Wywoływane PER SCENE w `search()` — dodaje +1 HTTP request per match. Subclass
+ Wywoływane PER SCENE w `search()`, dodaje +1 HTTP request per match. Subclass
powinien rzucić wyjątki swobodnie, base łapie i kontynuuje bez metadata.
Returns: (studio, performers, tags). Każde może być None / pusta lista.
@@ -153,7 +153,7 @@ class BaseSearchScraper(BaseDirectTubeScraper):
if scene_url.startswith("//"):
scene_url = "https:" + scene_url
elif scene_url.startswith("/"):
- # Relative URL — prefix host z search URL.
+ # Relative URL, prefix host z search URL.
base = urllib.parse.urlparse(url)
scene_url = f"{base.scheme}://{base.netloc}{scene_url}"
if scene_url in seen:
@@ -165,11 +165,11 @@ class BaseSearchScraper(BaseDirectTubeScraper):
if slug_lower in self._nav_slug_blacklist:
continue
# Strict: WSZYSTKIE query tokens muszą być w slug. Wcześniej `any()`
- # przepuszczał scenę gdy choć jeden token był w slug — dla performera
+ # przepuszczał scenę gdy choć jeden token był w slug, dla performera
# "Ava Koxxx" (query="ava koxxx") wszystkie sceny z "ava-*" slug
# (Ava Devine, Ava Addams itp.) były labelowane jako "Ava Koxxx",
# bo `any("ava" in slug)` =True. User reports: scena "ava devine
- # gangbanged..." miała Ava Koxxx w DB. Fix: `all()` — slug musi
+ # gangbanged..." miała Ava Koxxx w DB. Fix: `all()`, slug musi
# zawierać każdy ≥3-char token z imienia performera.
if query_tokens and not all(tok in slug_lower for tok in query_tokens):
continue
@@ -178,7 +178,7 @@ class BaseSearchScraper(BaseDirectTubeScraper):
# Thumbnail: search ±N chars around scene_url match for nearest .
# Większość tubes ma `
` lub flat
- # `
` — window 800 obejmuje oba.
+ # `
`, window 800 obejmuje oba.
window_start = max(0, m.start() - self._thumbnail_window)
window_end = min(len(r.text), m.end() + self._thumbnail_window)
window_html = r.text[window_start:window_end]
@@ -193,7 +193,7 @@ class BaseSearchScraper(BaseDirectTubeScraper):
thumb_url = f"{base.scheme}://{base.netloc}{thumb_url}"
# Opcjonalny metadata fetch (studio/dodatkowi performerzy/tagi). Default
- # zwraca None — większość tube'ów ma tylko search HTML bez metadata.
+ # zwraca None, większość tube'ów ma tylko search HTML bez metadata.
# PornHat ma `data-setup='{...}'` w `js-ajax-{dvd,model,tag}` divach.
studio: RawStudio | None = None
extra_performers: list[RawPerformer] = []
@@ -212,7 +212,7 @@ class BaseSearchScraper(BaseDirectTubeScraper):
description = meta[3]
# Performer z query zawsze obecny (driver scraping). Extra performers
- # z detail page dorzucamy — dedupe po slug/name w resolverze.
+ # z detail page dorzucamy, dedupe po slug/name w resolverze.
all_performers = [RawPerformer(name=query.strip()), *extra_performers]
yield RawScene(
diff --git a/app/connectors/direct_scrapers/base.py b/app/connectors/direct_scrapers/base.py
index aba2391..4561eb8 100644
--- a/app/connectors/direct_scrapers/base.py
+++ b/app/connectors/direct_scrapers/base.py
@@ -1,4 +1,4 @@
-"""BaseDirectTubeScraper — kontrakt dla bezpośrednich scraperów tube'ów."""
+"""BaseDirectTubeScraper, kontrakt dla bezpośrednich scraperów tube'ów."""
from __future__ import annotations
import abc
@@ -13,7 +13,7 @@ class BaseDirectTubeScraper(abc.ABC):
żeby dziedziczyć logikę resolvera + idempotent merge per external_id."""
sitetag: str
- """Stabilny ID tube'a — używany w external_id `f"{sitetag}:{url}"`. Zgodny
+ """Stabilny ID tube'a, używany w external_id `f"{sitetag}:{url}"`. Zgodny
z porn-app sitetag (hqpornercom, sxylandcom, itp.)."""
@abc.abstractmethod
diff --git a/app/connectors/direct_scrapers/eporner.py b/app/connectors/direct_scrapers/eporner.py
index 26b0ab7..2954642 100644
--- a/app/connectors/direct_scrapers/eporner.py
+++ b/app/connectors/direct_scrapers/eporner.py
@@ -1,4 +1,4 @@
-"""eporner.com — direct HTML scrape search results.
+"""eporner.com, direct HTML scrape search results.
Search: `https://www.eporner.com/search/
/
]*>\s*([^<]+?)\s*
")
-# `1785081937