diff --git a/app/api/scenes.py b/app/api/scenes.py
index 4a75c8f..48922e4 100644
--- a/app/api/scenes.py
+++ b/app/api/scenes.py
@@ -83,6 +83,13 @@ def list_scenes(
"po PlaybackSource.quality (string typu '720p' / '1080p Full HD')."
),
),
+ origin: str | None = Query(
+ default=None,
+ description=(
+ "Filtruj po playback origin (np. 'tube:hqpornercom'). Substring match — "
+ "'hqporner' złapie tube:hqpornercom. Diagnostyka per-hoster."
+ ),
+ ),
include_stubs: bool = Query(
default=False,
description=(
@@ -164,6 +171,18 @@ def list_scenes(
)
)
+ if origin:
+ # Substring match na origin — 'hqporner' złapie 'tube:hqpornercom'.
+ base = base.where(
+ exists(
+ select(1).where(
+ PlaybackSource.scene_id == Scene.id,
+ PlaybackSource.dead_at.is_(None),
+ PlaybackSource.origin.ilike(f"%{origin}%"),
+ )
+ )
+ )
+
# Blacklisty — globalne wykluczenia. Jeśli scena ma JAKIEGOKOLWIEK blacklisted
# performera, jest na blacklisted studio, lub ma JAKIKOLWIEK blacklisted tag → out.
from app.models.blacklist import (
diff --git a/mobile/src/api.ts b/mobile/src/api.ts
index 9cbae96..c8de20f 100644
--- a/mobile/src/api.ts
+++ b/mobile/src/api.ts
@@ -116,6 +116,7 @@ export class GoonClient {
qs.set('released_within_days', String(params.released_within_days));
if (params.min_quality_p !== undefined) qs.set('min_quality_p', String(params.min_quality_p));
if (params.include_stubs !== undefined) qs.set('include_stubs', String(params.include_stubs));
+ if (params.origin) qs.set('origin', params.origin);
if (params.sort) qs.set('sort', params.sort);
qs.set('page', String(params.page ?? 1));
qs.set('per_page', String(params.per_page ?? 50));
diff --git a/mobile/src/screens/ScenesFilterModal.tsx b/mobile/src/screens/ScenesFilterModal.tsx
index 6b6b2bf..bd66af0 100644
--- a/mobile/src/screens/ScenesFilterModal.tsx
+++ b/mobile/src/screens/ScenesFilterModal.tsx
@@ -24,6 +24,7 @@ export interface FilterState {
sort: ScenesSort;
hasPlayback: boolean;
includeStubs: boolean;
+ origin: string;
}
export const DEFAULT_FILTER: FilterState = {
@@ -33,6 +34,7 @@ export const DEFAULT_FILTER: FilterState = {
sort: 'created_at',
hasPlayback: true, // default: ukryj sceny bez playback linka (kompletność > świeżość)
includeStubs: false, // default: ukryj 5-10min hqporner trailery bez release_date
+ origin: '', // pusty = wszystkie źródła; substring match np. 'hqporner'
};
const SORT_OPTIONS: { value: ScenesSort; label: string }[] = [
@@ -161,6 +163,18 @@ export function ScenesFilterModal({
+
+ setDraft({ ...draft, origin: v })}
+ placeholder="np. hqporner, porntrex, xnxx — puste = wszystkie"
+ placeholderTextColor={theme.muted}
+ autoCapitalize="none"
+ autoCorrect={false}
+ />
+
+
diff --git a/mobile/src/types.ts b/mobile/src/types.ts
index 823a32c..5421a47 100644
--- a/mobile/src/types.ts
+++ b/mobile/src/types.ts
@@ -118,6 +118,7 @@ export interface ScenesListParams {
released_within_days?: number;
min_quality_p?: number;
include_stubs?: boolean;
+ origin?: string;
sort?: ScenesSort;
page?: number;
per_page?: number;