Auto tag galleries?

Hey there

I have thousands of zip galleries and a lot of them have a performer name in the zip filename. Is there a way to scan galleries and automatically link them to a performer when that performer name appears in the zip filename? Something similar to what is done when scraping scenes with “auto tag”.

I searched the plugins for gallery related stuff but noting like that.

Thanks!

p.s.

I looked at the DB structure and I realized this could be done directly in SQL (or in python) as the filenames are there and there is that performers_galleries table also. Not sure how to do it though. Any help on this would be greatly appreciated.

So I wrote a python script to do it. I made 2 backups the DB, ran the script on one of those and replaced the “main” DB with the modified backup. It linked some ~13000 galleries to their performers!

The script takes the DB as parameter.
The script only considers performers whose names have at least 2 “words”, otherwise it was really messy.

Enjoy :slight_smile:

import sqlite3
from collections import defaultdict
import logging
import sys
import os

# Validate command-line arguments
if len(sys.argv) < 2:
    print("Usage: python link_performers.py <database_file>")
    sys.exit(1)

db_path = sys.argv[1]

if not os.path.exists(db_path):
    print(f"Error: Database file '{db_path}' not found.")
    sys.exit(1)

# Set up loggers
logger = logging.getLogger("PerformerGalleryLinker")
logger.setLevel(logging.INFO)

# File handler (log only insertions)
file_handler = logging.FileHandler("performer_gallery_matches.log", mode='w')
file_handler.setLevel(logging.INFO)
file_formatter = logging.Formatter("%(asctime)s - %(message)s")
file_handler.setFormatter(file_formatter)

# Console handler (log all matches)
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(logging.INFO)
console_formatter = logging.Formatter("%(message)s")
console_handler.setFormatter(console_formatter)

logger.addHandler(file_handler)
logger.addHandler(console_handler)

# Connect to the SQLite database
conn = sqlite3.connect(db_path)
cursor = conn.cursor()

# Step 1: Load all performers (with more than one word in their name)
cursor.execute("SELECT id, name FROM performers")
performers = [(pid, name) for pid, name in cursor.fetchall() if name and len(name.strip().split()) > 1]

# Step 2: Load all files and their associated galleries
cursor.execute("""
    SELECT gf.gallery_id, f.id AS file_id, f.basename
    FROM galleries_files gf
    JOIN files f ON gf.file_id = f.id
""")
gallery_file_links = cursor.fetchall()

# Step 3: Build a mapping from gallery_id to list of basenames
gallery_to_files = defaultdict(list)
for gallery_id, file_id, basename in gallery_file_links:
    gallery_to_files[gallery_id].append((file_id, basename))

# Step 4: Match performer names to file basenames and insert links
inserted_links = []
for performer_id, performer_name in performers:
    name_lower = performer_name.lower()

    for gallery_id, file_info_list in gallery_to_files.items():
        matched_file = None

        for file_id, basename in file_info_list:
            if basename and name_lower in basename.lower():
                matched_file = basename
                break

        if matched_file:
            # Check if the link already exists
            cursor.execute("""
                SELECT 1 FROM performers_galleries
                WHERE gallery_id = ? AND performer_id = ?
            """, (gallery_id, performer_id))
            if cursor.fetchone() is None:
                cursor.execute("""
                    INSERT INTO performers_galleries (gallery_id, performer_id)
                    VALUES (?, ?)
                """, (gallery_id, performer_id))
                inserted_links.append((gallery_id, performer_id))
                msg = (f"Inserted: Performer '{performer_name}' (ID {performer_id}) "
                       f"-> Gallery {gallery_id} (matched in file '{matched_file}')")
                logger.info(msg)  # Logged to both file and screen
            else:
                msg = (f"Skipped (already exists): Performer '{performer_name}' (ID {performer_id}) "
                       f"-> Gallery {gallery_id} (matched in file '{matched_file}')")
                console_handler.stream.write(msg + "\n")  # Log only to screen

# Finalize
conn.commit()
conn.close()

# Summary
logger.info(f"\nInserted {len(inserted_links)} performer-gallery links.")
if inserted_links:
    logger.info(f"Sample inserted links: {inserted_links[:10]}")
logger.info("Log written to performer_gallery_matches.log")

2 Likes

There is a plugin for it. It just wasn’t tagged properly.