Skip to content

[starIdentifier] image fetches fail with auth enabled — urllib calls don't pass session cookie #717

@Mavrx-Operations

Description

@Mavrx-Operations

Plugin

plugins/starIdentifierstar_identifier.py

Bug

The plugin fetches performer images and scene screenshots via raw urllib.request.urlopen():

# line ~189
image = face_recognition.load_image_file(urllib.request.urlopen(performer['image_path']))

# line ~202
image = urllib.request.urlopen(scene['paths']['screenshot'])

Neither call attaches the session cookie Stash hands plugins via json_input["server_connection"]["SessionCookie"]["Value"]. With Stash configured to require authentication (username + password set in config.yml), every urlopen returns the login page HTML instead of the image, and PIL raises:

ERRO [Plugin / Star Identifier] cannot identify image file <_io.BytesIO object at 0x...>

Export Performers writes no encodings file, and the subsequent identify task then fails with:

Encoding database not found at .../star-identifier-encodings/star-identifier-encodings.npz.
Run Export Performers and try again.

Without auth (the unsecured deployment case) this path works by accident.

The plugin's IdentifierStashInterface class already receives and stores the session cookie — it's used for the GraphQL POST in __callGraphQL, just not for the image fetches.

Repro

  1. Configure Stash with username + password in config.yml.
  2. Install Star Identifier (assume [starIdentifier] manifest exec path references non-existent py_plugins/ subdirectory #716 patched / manifest fixed so the plugin can actually launch).
  3. Run Export Performers — every performer hits cannot identify image file.

Suggested fix

Module-global the cookie (so ProcessPoolExecutor workers inherit it via fork() on Linux) and route the two image fetches through a helper. Minimal patch:

# near the top, after the existing imports:
SESSION_COOKIE = None

def _open_with_cookie(url):
    req = urllib.request.Request(url)
    if SESSION_COOKIE:
        req.add_header("Cookie", f"session={SESSION_COOKIE}")
    return urllib.request.urlopen(req)

# inside run(), right after `client = IdentifierStashInterface(...)`:
global SESSION_COOKIE
SESSION_COOKIE = client.cookies.get("session")

# encode_performer_from_url + get_recognized_ids_from_scene_screenshot:
#   replace `urllib.request.urlopen(...)` calls with `_open_with_cookie(...)`

Verified locally — Export Performers now actually processes images and writes the .npz.

Portability note

This works because Python's ProcessPoolExecutor uses fork as the default start-method on Linux, and forked workers inherit module-level state set before the fork point. On spawn/forkserver (Windows; or if a future CPython release changes the default) the global wouldn't propagate. Passing the cookie as an explicit arg via executor.submit(fn, item, SESSION_COOKIE) is more portable but requires changing the call sites and the execute_identification_list harness signature.

Environment

  • Stash v0.31.1 (4de2351e)
  • Container: stashapp/stash:latest (Alpine, Python 3.12.13)
  • Plugin version: 1.0
  • Stash auth: username + password set in config.yml

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions