Fix/plex section id library identity - #1738
Conversation
85c1c96 to
51d5fe5
Compare
There was a problem hiding this comment.
Pull request overview
This PR improves how Plex libraries are identified and represented across the Quickstart UI and config-generation pipeline by moving from name-based identifiers to stable Plex section IDs, while also adding dev-quality-of-life support (Vite dev-server mode) and preserving significant whitespace in library names.
Changes:
- Switch library selection/storage/telemetry from library names to Plex section IDs, with migration of existing saved settings.
- Preserve leading/trailing whitespace in library names end-to-end (rendering, parsing, config/header output, resume hints).
- Add optional Vite dev-server support (
QS_VITE_DEV*) and UI tweaks for better dev ergonomics.
Reviewed changes
Copilot reviewed 40 out of 42 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| vite.config.js | Bind/dev-server configuration update. |
| uv.lock | Updates Python requirement for uv lock usage. |
| tests/test_vite_manifest.py | Adds coverage for new Vite dev-mode helpers and asset URL behavior. |
| tests/test_resume_hint.py | Adds coverage for whitespace-preserving resume and command parsing. |
| tests/test_importer_library_services.py | Updates expected importer payload for library toggles/IDs. |
| tests/test_importer_edge_cases.py | Updates expected importer payload for library toggles/IDs in edge cases. |
| tests/test_core_backend.py | Updates fake Plex sections + expected payload shape to include IDs. |
| templates/partials/_library_card.html | Switch include toggle value to boolean-ish and render whitespace-preserved names. |
| templates/900-kometa.html | Improves library label rendering + run-progress table whitespace handling. |
| templates/025-libraries.html | Update telemetry/library rendering and dropdown labels for whitespace-preserved names. |
| templates/010-plex.html | Adds hidden name-map field and changes db_cache minimum. |
| templates/000-base.html | Injects Vite dev client when dev origin is enabled. |
| static/local-js/modules/kometa/_util.js | Adds shared nbspLeadingSpaces helper. |
| static/local-js/modules/kometa/_runProgress.js | Uses nbspLeadingSpaces for progress table rendering. |
| static/local-js/905-analytics.js | Uses nbspLeadingSpaces to render snapshot names without collapsing spaces. |
| static/local-js/025-libraries.js | Preserves whitespace in picker labels and includes a local nbspLeadingSpaces. |
| static/local-js/010-plex.js | Stores library lists as ID CSV + JSON name map; improves db_cache mismatch warning logic. |
| static/css/styles.css | Ensures dropdown/progress labels preserve whitespace and use monospace where appropriate. |
| quickstart.py | Wires Vite dev origin + adds Jinja filter for whitespace preservation; adjusts library ID decoding usage. |
| PART | Build “part” marker update. |
| package.json | Adds a new production dependency. |
| package-lock.json | Lockfile update reflecting the new dependency tree. |
| modules/validations_services.py | Plex validation now returns ID/name objects and logs names only. |
| modules/process_run_context.py | Updates --run-libraries parsing to preserve whitespace. |
| modules/persistence.py | Adds library ID decoding, name-map storage, and migration from name-based keys to ID-based keys. |
| modules/output_yaml_header.py | Switch header library summaries to ID-based lookup. |
| modules/output_libraries_data.py | Prefer authoritative Plex name map when building output bundle. |
| modules/output_dump.py | Improves YAML header injection handling for quoted keys. |
| modules/logscan_resume.py | Preserves quoted whitespace and refines resume-scope normalization/quoting. |
| modules/logscan_progress.py | Preserves library-name whitespace and improves name/type lookup using ID→name mapping. |
| modules/logscan_library_stats.py | Adds exact-match precedence to avoid conflating whitespace-distinct names. |
| modules/logscan_incomplete_resume.py | Preserves whitespace in current library detection. |
| modules/importer.py | Imports library keys using Plex IDs when available; sets library toggles to "true". |
| modules/helpers/_vite_manifest.py | Adds Vite dev-mode helpers and dev-origin asset URL behavior. |
| modules/helpers/_plex.py | Switch Plex metadata indexing and summaries to use section IDs. |
| modules/helpers/_forms.py | Avoids stripping library fields in form building. |
| modules/helpers/_constants.py | Normalizes BASE_DIR to an absolute path. |
| blueprints/validation_routes.py | Runs library-key migration during Plex validation/refresh; stores name map. |
| blueprints/library_routes.py | Build library lists from decoded IDs + name map. |
| blueprints/import_config_routes.py | Uses helper to derive Plex library name sets under new storage format. |
| blueprints/import_config_helpers.py | Adds ID-aware Plex library name extraction helpers and whitespace-preserving parsing. |
| .pre-commit-config.yaml | Bumps ruff hook revision. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
In all cases, these are the two libraries checked for spacing throughout QS:
[ TestMovies-4kk] and [ TestTV Shows - 4k ]
Unreal, that even here in GH, when I put braces within a code block, GH removes the extra spaces.... basically TestMovies-4kk has about 5 prepended spaces and the TestTV Shows has about 10 prepended and appended.
Here we go:
1 - So it seems that appended spaces are in the header of the dropdown, but prepended spaces are not. They are shown when you expand the dropdown.
2 - Here is the issue with Importer in terms of spaces, the dropdown does not show the spaces on the plex server:

3 - Below is a strange message in the kometa final output page within the config where it cannot find it, but its there in the config so not sure why it cannot match the library name and produce the stats in the upper section of the output within the config?

Replaces normalised-name keys (e.g. mov-library_moviesl-*) with Plex
integer section IDs (mov-library_59-*) so that library identity is stable
regardless of display-name whitespace or special characters.
Key changes:
- persistence.py: decode_library_ids(), get_library_names(),
migrate_library_keys_to_plex_ids(); clean_form_data() no longer strips
library display-name values (leading/trailing spaces are significant)
- helpers/_forms.py: build_simple_dict() no longer strips -library or
libraries values
- output_dump.py: strip YAML quote characters from section-header names
so ruamel-quoted keys like ' Movies L': resolve correctly
- output_yaml_header.py: _sorted_library_display_names() preserves names
with spaces for the Plex metadata lookup; only strips for empty-check
and sort key
- quickstart.py: _nbsp_leading_spaces Jinja filter replaces leading
ASCII spaces with EM SPACE (U+2003) for visible indentation in
native OS select dropdowns
- 025-libraries.js: nbspLeadingSpaces() mirrors the Jinja filter so
refreshPickerLabels() does not overwrite EM-SPACE option text with
the raw data-label value
- validation_routes.py: triggers migration at Plex validation time
- validations_services.py, library_routes.py, import_config_helpers.py,
importer.py: updated to work with {id, name} dicts and integer IDs
- 010-plex.js / 010-plex.html: hidden inputs store Plex section IDs
- 248 tests passing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When visiting the libraries page, migrate_library_keys_to_plex_ids runs inside refresh_plex_libraries() at line 2278, renaming old name-based DB keys (e.g. mov-library_moviesl-*) to ID-based keys (mov-library_59-*). However, `data` was loaded at line 2234 before the migration ran, so configured_ids was built from stale name-based keys while movie_libraries was built from the new ID-based tmp_movie_libraries — zero intersection, all libraries appeared unconfigured. Fix: re-read `data` from the DB for the libraries page after the refresh so configured_ids reflects the post-migration key format. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
retrieve_settings(config_name) was called with the user's config name
(e.g. "nervous_johnson"). extract_names() splits on "-" and takes the
last segment, producing "johnson" — a nonexistent section — so the DB
read returned empty, libraries={}, and the migration returned 0 without
renaming any keys.
Fix: call retrieve_settings("025-libraries") so extract_names correctly
derives section="libraries" and reads the actual library settings.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The card header h4 was rendering {{ library.name }} without the filter,
so libraries with leading spaces (e.g. ' Movies') showed as 'Movies'
in the card title. Apply the same EM-SPACE filter used in the picker
options so the leading indentation is visible in the card heading.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Leading-only conversion left trailing spaces as regular ASCII, which browsers collapse in dropdown option text and HTML headings. Now both the Python Jinja filter and the JS nbspLeadingSpaces() helper convert leading AND trailing ASCII spaces to EM SPACE (U+2003) so names like 'Movies T ' display as 'Movies T⁃' rather than 'Movies T'. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: chazlarson <3865541+chazlarson@users.noreply.github.com>
Co-authored-by: chazlarson <3865541+chazlarson@users.noreply.github.com>
Co-authored-by: YozoraXCII <96386153+YozoraXCII@users.noreply.github.com> Co-authored-by: badja-dev <180163201+badja-dev@users.noreply.github.com>
Updated GitHub Actions workflows to use newer versions of actions and added a new step to run tests.
Updated the GitHub Actions workflow to improve permissions, concurrency handling, and environment variable usage. Enhanced error handling and output formatting for better clarity.
83cb56d to
70866d8
Compare
As I recall that was judged accpetable previously given that the name of the library with spaces is displayed immediately below the menu once selected, but I'll have a look. The solution is "fully custom dropdown replacement" or "wrap names in brackets in the dropdown". |
I can't load those images to see them clearly. What is that showing? If I import an existing config with spaces in names, everything is fine. However, I don't see a dialog that contains whatever that extra stuff is on the bottom, whether I merge or create a new one. Looks like you're choosing libraries to import, but I don't see any place to do that. I can't reproduce any problems here. |
Sure, maybe leave it. I found it peculiar that spaces appended showed properly but not prepended spaces and only in the header of the dropdown. |
To reproduce this import scenario. Case 1:
Case 2:
Case 3:
|
|
Honestly this seems like a really unlikely edge case, but I can see what is going on. If the user has renamed libraries in Plex, and presumably has an existing Quickstart setup for the pre-rename setup, why are they abandoning that and importing an old Quickstart config? The import only knows names, so if you change names and then try to import a config expecting Quickstart to match "Foo" to "Bar" I don't see how that can work. We have nothing to base the match on. What's the practical use case where this comes up? |
2 cases: |
|
Strange and not sure why this is happening however if you visually look at the command output, there are clearly spaces missing however when you copy using the button and paste elsewhere, you get:
Which has the spaces. I am puzzled. And even as I paste it here, in the edit I see the spaces...from the paste but not when I save it and GH displays it. |
Adding this to line 3385 of styles.css resolves the visual display issue in QuickStart: |
I'll add that, but hopefully it doesn't break anything else. |
I had never seen any "mapping" facility anywhere, so it seemed like this was expected to be some sort of automatic process. |
It's "semi" automatic. Because not everyone has the same set of library names. If you are creating different bundles against the same plex server with the same names, then the import is fully automatic. As long as the names of the libraries you import are the same as the libraries on the plex server you have, then the import is fully automatic |












What type of PR is this?
Description
A variety of changes related to spaces in names, using library IDs, and other QOL.
Which Environment Did You Test On?
python quickstart.py)