diff --git a/qbittorrent_performer_sorter.html b/qbittorrent_performer_sorter.html
index 3b17e78..1649584 100644
--- a/qbittorrent_performer_sorter.html
+++ b/qbittorrent_performer_sorter.html
@@ -2658,17 +2658,17 @@
fileNames = torrent.innerFiles.map(f => f.name).slice(0, 15);
}
- const prompt = `Analyze the following adult video torrent title and internal files to identify ALL performers / actors.
+ const prompt = `Analyze the following adult video torrent title and internal files to identify ALL FEMALE performers / actresses.
Torrent Name: "${torrent.name}"
Internal Files: ${JSON.stringify(fileNames)}
CRITICAL INSTRUCTIONS:
-1. Extract EVERY distinct performer / actor mentioned.
-2. If multiple performers appear (e.g. "Alison Rey Reagan Foxx" or "Kendra Lust and Lisa Ann"), you MUST return EACH individual person as a separate entry in the "all_performers" array: ["Alison Rey", "Reagan Foxx"].
+1. Extract ONLY distinct FEMALE performers / actresses mentioned. Completely OMIT and ignore all male performers, male actors, and directors.
+2. If multiple female performers appear (e.g. "Alison Rey Reagan Foxx" or "Kendra Lust and Lisa Ann"), you MUST return EACH individual female as a separate entry in "all_performers": ["Alison Rey", "Reagan Foxx"].
3. NEVER combine multiple performers into one 4-word name (e.g. NEVER output "Alison Rey Reagan Foxx" as a single name).
4. Ignore studio names (Brazzers, NaughtyAmerica, Blacked, Vixen, Tushy, PureTaboo, RealityKings, BangBros, TeamSkeet, EvilAngel, MissaX, etc.), resolutions, release groups, and codecs.
-5. List all detected performers in "all_performers", pick the primary performer in "primary_performer", assign confidence ('high'|'medium'|'low'), and short reasoning.
+5. List all detected female performers in "all_performers", pick the primary performer in "primary_performer", assign confidence ('high'|'medium'|'low'), and short reasoning.
Return ONLY valid JSON matching this schema:
{
@@ -2719,15 +2719,16 @@ Return ONLY valid JSON matching this schema:
return `[Item ${idx + 1}] ID: "${t.hash}"\nName: "${t.name}"\nFiles: ${JSON.stringify(fileNames)}`;
}).join('\n\n');
- const prompt = `Analyze the following ${batchTorrents.length} adult video torrents and identify ALL performers / actors for EACH item.
+ const prompt = `Analyze the following ${batchTorrents.length} adult video torrents and identify ALL FEMALE performers / actresses for EACH item.
${itemsListStr}
CRITICAL INSTRUCTIONS:
-1. For each item, extract EVERY distinct performer / actor name. If multiple performers appear (e.g. "Alison Rey Reagan Foxx", "Kendra Lust and Lisa Ann"), list EACH person separately in "all_performers": ["Alison Rey", "Reagan Foxx"].
-2. NEVER combine two performers into a single 4-word string (e.g. NEVER output "Alison Rey Reagan Foxx").
-3. Ignore studio names (Brazzers, NaughtyAmerica, Blacked, Vixen, Tushy, PureTaboo, RealityKings, BangBros, TeamSkeet, EvilAngel, MissaX, etc.), scene numbers, resolutions, and codecs.
-4. List all detected performers in "all_performers", pick the primary performer in "primary_performer", assign confidence ('high'|'medium'|'low'), and short reasoning.
+1. For each item, extract ONLY distinct FEMALE performers / actresses. Completely OMIT and ignore all male performers, male actors, and directors.
+2. If multiple female performers appear (e.g. "Alison Rey Reagan Foxx", "Kendra Lust and Lisa Ann"), list EACH female person separately in "all_performers": ["Alison Rey", "Reagan Foxx"].
+3. NEVER combine two performers into a single 4-word string (e.g. NEVER output "Alison Rey Reagan Foxx").
+4. Ignore studio names (Brazzers, NaughtyAmerica, Blacked, Vixen, Tushy, PureTaboo, RealityKings, BangBros, TeamSkeet, EvilAngel, MissaX, etc.), scene numbers, resolutions, and codecs.
+5. List all detected female performers in "all_performers", pick the primary performer in "primary_performer", assign confidence ('high'|'medium'|'low'), and short reasoning.
Return ONLY valid JSON matching:
{
@@ -3346,16 +3347,16 @@ Return ONLY valid JSON matching:
async function analyzeSmbFileWithAI(fileItem) {
const destRoot = (smbDestRootInput ? smbDestRootInput.value.trim() : '/mnt/isolation/videos').replace(/\/+$/, '') || '/mnt/isolation/videos';
- const prompt = `Analyze the following adult video filename to identify ALL performers / actors.
+ const prompt = `Analyze the following adult video filename to identify ALL FEMALE performers / actresses.
Filename: "${fileItem.name}"
CRITICAL INSTRUCTIONS:
-1. Extract EVERY distinct video performer / actor mentioned.
-2. If multiple performers appear (e.g. "Alison Rey Reagan Foxx" or "Kendra Lust and Lisa Ann"), you MUST return EACH individual person as a separate entry in the "all_performers" array: ["Alison Rey", "Reagan Foxx"].
+1. Extract ONLY distinct FEMALE video performers / actresses mentioned. Completely OMIT and ignore all male performers, male actors, and directors.
+2. If multiple female performers appear (e.g. "Alison Rey Reagan Foxx" or "Kendra Lust and Lisa Ann"), you MUST return EACH individual female as a separate entry in "all_performers": ["Alison Rey", "Reagan Foxx"].
3. NEVER combine multiple performers into one 4-word name (e.g. NEVER output "Alison Rey Reagan Foxx" as a single name).
4. Ignore studio names (Brazzers, NaughtyAmerica, Blacked, Vixen, Tushy, PureTaboo, RealityKings, BangBros, TeamSkeet, EvilAngel, MissaX, Family Roleplay, Spy Fam, etc.), resolutions, release groups, and codecs.
-5. List all detected performers in "all_performers", pick the primary performer in "primary_performer", assign confidence ('high'|'medium'|'low'), and short reasoning.
+5. List all detected female performers in "all_performers", pick the primary performer in "primary_performer", assign confidence ('high'|'medium'|'low'), and short reasoning.
Return ONLY valid JSON matching this schema:
{
@@ -3400,15 +3401,16 @@ Return ONLY valid JSON matching this schema:
return `[Item ${idx + 1}] ID: "${f.path}"\nFilename: "${f.name}"`;
}).join('\n\n');
- const prompt = `Analyze the following ${batchFiles.length} adult video filenames and identify ALL performers / actors for EACH item.
+ const prompt = `Analyze the following ${batchFiles.length} adult video filenames and identify ALL FEMALE performers / actresses for EACH item.
${itemsListStr}
CRITICAL INSTRUCTIONS:
-1. For each item, extract EVERY distinct performer / actor name. If multiple performers appear (e.g. "Alison Rey Reagan Foxx", "Kendra Lust and Lisa Ann"), list EACH person separately in "all_performers": ["Alison Rey", "Reagan Foxx"].
-2. NEVER combine two performers into a single 4-word string (e.g. NEVER output "Alison Rey Reagan Foxx").
-3. Ignore studio names (Brazzers, NaughtyAmerica, Blacked, Vixen, Tushy, PureTaboo, RealityKings, BangBros, TeamSkeet, EvilAngel, MissaX, Family Roleplay, Spy Fam, etc.), scene numbers, resolutions, and codecs.
-4. List all detected performers in "all_performers", pick the primary performer in "primary_performer", assign confidence ('high'|'medium'|'low'), and short reasoning.
+1. For each item, extract ONLY distinct FEMALE performers / actresses. Completely OMIT and ignore all male performers, male actors, and directors.
+2. If multiple female performers appear (e.g. "Alison Rey Reagan Foxx", "Kendra Lust and Lisa Ann"), list EACH female person separately in "all_performers": ["Alison Rey", "Reagan Foxx"].
+3. NEVER combine two performers into a single 4-word string (e.g. NEVER output "Alison Rey Reagan Foxx").
+4. Ignore studio names (Brazzers, NaughtyAmerica, Blacked, Vixen, Tushy, PureTaboo, RealityKings, BangBros, TeamSkeet, EvilAngel, MissaX, Family Roleplay, Spy Fam, etc.), scene numbers, resolutions, and codecs.
+5. List all detected female performers in "all_performers", pick the primary performer in "primary_performer", assign confidence ('high'|'medium'|'low'), and short reasoning.
Return ONLY a valid JSON object with an array named "results":
{
diff --git a/server.py b/server.py
index ae9cd1c..f2ec2ce 100644
--- a/server.py
+++ b/server.py
@@ -180,22 +180,26 @@ def parse_stash_scene_data(scene, match_strategy='exact_path'):
if not performers:
return None
- females = [p['name'] for p in performers if p.get('gender') == 'FEMALE']
- males = [p['name'] for p in performers if p.get('gender') == 'MALE']
- others = [p['name'] for p in performers if p.get('gender') not in ('FEMALE', 'MALE')]
+ females = [p for p in performers if p.get('gender') == 'FEMALE']
+ non_males = [p for p in performers if p.get('gender') not in ('FEMALE', 'MALE')]
- # Priority: Females first as primary, then others, then males
- ordered_names = females + others + males
- if not ordered_names:
- ordered_names = [p['name'] for p in performers]
+ # Priority: NEVER include male performers if any female or non-male performers are present
+ eligible_performers = females if females else (non_males if non_males else performers)
formatted_candidates = []
seen = set()
- for name in ordered_names:
+ for p in eligible_performers:
+ name = p.get('name', '')
fmt = format_performer_slug(name)
if fmt and fmt not in seen:
seen.add(fmt)
- formatted_candidates.append({'raw': name, 'formatted': fmt})
+ formatted_candidates.append({
+ 'raw': name,
+ 'formatted': fmt,
+ 'id': p.get('id'),
+ 'gender': p.get('gender'),
+ 'image': p.get('image_path')
+ })
if not formatted_candidates:
return None
@@ -217,8 +221,8 @@ def parse_stash_scene_data(scene, match_strategy='exact_path'):
'studio': studio_name,
'primaryPerformer': primary_formatted,
'allPerformers': formatted_candidates,
- 'femalePerformers': [format_performer_slug(n) for n in females],
- 'malePerformers': [format_performer_slug(n) for n in males],
+ 'femalePerformers': [p['formatted'] for p in formatted_candidates if p.get('gender') == 'FEMALE'],
+ 'malePerformers': [],
'confidence': 'verified',
'reasoning': reasoning,
'matchStrategy': match_strategy
@@ -781,11 +785,11 @@ class RobustProxyHandler(http.server.SimpleHTTPRequestHandler):
except Exception as e:
print(f"Error merging performers from DB: {e}")
- # Also merge performers from Stash database if online
+ # Also merge female performers from Stash database if online
try:
- stash_q = '{ allPerformers { name } }'
- res = execute_stash_graphql(stash_q, timeout=2)
- for p in res.get('data', {}).get('allPerformers', []):
+ stash_q = '{ findPerformers(performer_filter: { gender: { value: FEMALE, modifier: EQUALS } }, filter: { per_page: -1 }) { performers { name } } }'
+ res = execute_stash_graphql(stash_q, timeout=3)
+ for p in res.get('data', {}).get('findPerformers', {}).get('performers', []):
slug = format_performer_slug(p.get('name'))
if slug:
performers_set.add(slug)
@@ -807,13 +811,22 @@ class RobustProxyHandler(http.server.SimpleHTTPRequestHandler):
p_id = params.get('id', [''])[0]
stash_url = params.get('url', [''])[0]
- content_type, img_bytes = fetch_performer_image_data(name, p_id, stash_url)
- self.send_response(200)
- self.send_header('Content-Type', content_type)
- self.send_header('Cache-Control', 'public, max-age=86400')
- self.send_cors_headers()
- self.end_headers()
- self.wfile.write(img_bytes)
+ try:
+ content_type, img_bytes = fetch_performer_image_data(name, p_id, stash_url)
+ self.send_response(200)
+ self.send_header('Content-Type', content_type)
+ self.send_header('Cache-Control', 'public, max-age=86400')
+ self.send_cors_headers()
+ self.end_headers()
+ self.wfile.write(img_bytes)
+ except (BrokenPipeError, ConnectionResetError):
+ pass
+ except Exception as e:
+ try:
+ self.send_response(500)
+ self.end_headers()
+ except Exception:
+ pass
# ==================== Stash Server API Handlers ====================
def handle_stash_status(self):