diff --git a/docs/environment-variables.md b/docs/environment-variables.md index 71521ef..bd3a05b 100644 --- a/docs/environment-variables.md +++ b/docs/environment-variables.md @@ -14,6 +14,7 @@ This document lists all configuration options that can be set via environment va - [Network](#network) - [Advanced](#advanced) - [Prowlarr](#prowlarr) +- [Newznab](#newznab) - [AudiobookBay](#audiobookbay) - [IRC](#irc) - [Download Clients](#download-clients) @@ -124,6 +125,7 @@ Show the onboarding wizard on first run. Set to false to skip (useful for epheme | Variable | Description | Type | Default | |----------|-------------|------|---------| +| `SEARCH_PAGE_TITLE` | Title shown above the main search box on the homepage. | string | `Shelfmark` | | `CALIBRE_WEB_URL` | Adds a navigation button to your book library (Calibre-Web Automated, Grimmory, etc). | string | _none_ | | `AUDIOBOOK_LIBRARY_URL` | Adds a separate navigation button for your audiobook library (Audiobookshelf, Plex, etc). When both URLs are set, icons are shown instead of text. | string | _none_ | | `SUPPORTED_FORMATS` | Book formats to include in search results. ZIP/RAR archives are extracted automatically and book files are used if found. | string (comma-separated) | `epub,mobi,azw3,fb2,djvu,cbz,cbr` | @@ -133,6 +135,15 @@ Show the onboarding wizard on first run. Set to false to skip (useful for epheme
Detailed descriptions +#### `SEARCH_PAGE_TITLE` + +**Search Page Title** + +Title shown above the main search box on the homepage. + +- **Type:** string +- **Default:** `Shelfmark` + #### `CALIBRE_WEB_URL` **Library URL** @@ -294,8 +305,8 @@ The release source tab to open by default in the release modal for audiobooks. U | `BOOKS_OUTPUT_MODE` | Choose where completed book files are sent. | string (choice) | `folder` | | `INGEST_DIR` | Directory where downloaded files are saved. Use {User} for per-user folders (e.g. /books/{User}). | string | `/books` | | `FILE_ORGANIZATION` | Choose how downloaded book files are named and organized. | string (choice) | `rename` | -| `TEMPLATE_RENAME` | Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} (source filename without extension). Universal adds: {Series}, {SeriesPosition}, {Subtitle}. Use arbitrary prefix/suffix: {Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty. Rename templates are filename-only (no '/' or '\'); use Organize for folders. Applies to single-file downloads. | string | `{Author} - {Title} ({Year})` | -| `TEMPLATE_ORGANIZE` | Use / to create folders. Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} (source filename without extension). Universal adds: {Series}, {SeriesPosition}, {Subtitle}. Use arbitrary prefix/suffix: {Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty. | string | `{Author}/{Title} ({Year})` | +| `TEMPLATE_RENAME` | Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} (source filename without extension). Universal adds: {Series}, {SeriesPosition}, {Subtitle}, {PrimaryTitle}. Use arbitrary prefix/suffix: {Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty. Rename templates are filename-only (no '/' or '\'); use Organize for folders. Applies to single-file downloads. | string | `{Author} - {Title} ({Year})` | +| `TEMPLATE_ORGANIZE` | Use / to create folders. Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} (source filename without extension). Universal adds: {Series}, {SeriesPosition}, {Subtitle}, {PrimaryTitle}. Use arbitrary prefix/suffix: {Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty. | string | `{Author}/{Title} ({Year})` | | `HARDLINK_TORRENTS` | Create hardlinks instead of copying. Preserves seeding but archives won't be extracted. Don't use if destination is a library ingest folder. | boolean | `false` | | `BOOKLORE_HOST` | Base URL of your Grimmory instance | string | _none_ | | `BOOKLORE_USERNAME` | Grimmory account username | string | _none_ | @@ -311,13 +322,13 @@ The release source tab to open by default in the release modal for audiobooks. U | `EMAIL_SMTP_USERNAME` | SMTP username (leave empty for no authentication). | string | _none_ | | `EMAIL_SMTP_PASSWORD` | SMTP password (required if Username is set). | string (secret) | _none_ | | `EMAIL_FROM` | From address used for the email. You can include a display name (e.g., Shelfmark ). Leave blank to default to the SMTP username (when it is an email address). | string | _none_ | -| `EMAIL_SUBJECT_TEMPLATE` | Email subject. Variables: {Author}, {Title}, {Year}, {Series}, {SeriesPosition}, {Subtitle}, {Format}. | string | `{Title}` | +| `EMAIL_SUBJECT_TEMPLATE` | Email subject. Variables: {Author}, {Title}, {PrimaryTitle}, {Year}, {Series}, {SeriesPosition}, {Subtitle}, {Format}. | string | `{Title}` | | `EMAIL_SMTP_TIMEOUT_SECONDS` | How long to wait for SMTP operations before failing. | number | `60` | | `EMAIL_ALLOW_UNVERIFIED_TLS` | Disable TLS certificate verification (not recommended). | boolean | `false` | | `DESTINATION_AUDIOBOOK` | Directory where downloaded audiobook files are saved. Leave empty to use the Books destination. | string | _none_ | | `FILE_ORGANIZATION_AUDIOBOOK` | Choose how downloaded audiobook files are named and organized. | string (choice) | `rename` | -| `TEMPLATE_AUDIOBOOK_RENAME` | Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} (source filename without extension), {Series}, {SeriesPosition}, {Subtitle}, {PartNumber}. Use arbitrary prefix/suffix: {Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty. Rename templates are filename-only (no '/' or '\'); use Organize for folders. Applies to single-file downloads. | string | `{Author} - {Title}` | -| `TEMPLATE_AUDIOBOOK_ORGANIZE` | Use / to create folders. Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} (source filename without extension), {Series}, {SeriesPosition}, {Subtitle}, {PartNumber}. Use arbitrary prefix/suffix: {Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty. | string | `{Author}/{Title}` | +| `TEMPLATE_AUDIOBOOK_RENAME` | Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} (source filename without extension), {Series}, {SeriesPosition}, {Subtitle}, {PrimaryTitle}, {PartNumber}. Use arbitrary prefix/suffix: {Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty. Rename templates are filename-only (no '/' or '\'); use Organize for folders. Applies to single-file downloads. | string | `{Author} - {Title}` | +| `TEMPLATE_AUDIOBOOK_ORGANIZE` | Use / to create folders. Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} (source filename without extension), {Series}, {SeriesPosition}, {Subtitle}, {PrimaryTitle}, {PartNumber}. Use arbitrary prefix/suffix: {Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty. | string | `{Author}/{Title}/{Title}` | | `HARDLINK_TORRENTS_AUDIOBOOK` | Create hardlinks instead of copying. Preserves seeding but archives won't be extracted. Don't use if destination is a library ingest folder. | boolean | `true` | | `AUTO_OPEN_DOWNLOADS_SIDEBAR` | Automatically open the downloads sidebar when a new download is queued. | boolean | `false` | | `DOWNLOAD_TO_BROWSER_CONTENT_TYPES` | Automatically download completed files to your browser for the selected content types. | string (comma-separated) | _empty list_ | @@ -361,7 +372,7 @@ Choose how downloaded book files are named and organized. **Naming Template** -Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} (source filename without extension). Universal adds: {Series}, {SeriesPosition}, {Subtitle}. Use arbitrary prefix/suffix: {Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty. Rename templates are filename-only (no '/' or '\'); use Organize for folders. Applies to single-file downloads. +Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} (source filename without extension). Universal adds: {Series}, {SeriesPosition}, {Subtitle}, {PrimaryTitle}. Use arbitrary prefix/suffix: {Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty. Rename templates are filename-only (no '/' or '\'); use Organize for folders. Applies to single-file downloads. - **Type:** string - **Default:** `{Author} - {Title} ({Year})` @@ -370,7 +381,7 @@ Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} (source filename wi **Path Template** -Use / to create folders. Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} (source filename without extension). Universal adds: {Series}, {SeriesPosition}, {Subtitle}. Use arbitrary prefix/suffix: {Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty. +Use / to create folders. Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} (source filename without extension). Universal adds: {Series}, {SeriesPosition}, {Subtitle}, {PrimaryTitle}. Use arbitrary prefix/suffix: {Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty. - **Type:** string - **Default:** `{Author}/{Title} ({Year})` @@ -524,7 +535,7 @@ From address used for the email. You can include a display name (e.g., Shelfmark **Subject Template** -Email subject. Variables: {Author}, {Title}, {Year}, {Series}, {SeriesPosition}, {Subtitle}, {Format}. +Email subject. Variables: {Author}, {Title}, {PrimaryTitle}, {Year}, {Series}, {SeriesPosition}, {Subtitle}, {Format}. - **Type:** string - **Default:** `{Title}` @@ -571,7 +582,7 @@ Choose how downloaded audiobook files are named and organized. **Naming Template** -Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} (source filename without extension), {Series}, {SeriesPosition}, {Subtitle}, {PartNumber}. Use arbitrary prefix/suffix: {Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty. Rename templates are filename-only (no '/' or '\'); use Organize for folders. Applies to single-file downloads. +Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} (source filename without extension), {Series}, {SeriesPosition}, {Subtitle}, {PrimaryTitle}, {PartNumber}. Use arbitrary prefix/suffix: {Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty. Rename templates are filename-only (no '/' or '\'); use Organize for folders. Applies to single-file downloads. - **Type:** string - **Default:** `{Author} - {Title}` @@ -580,10 +591,10 @@ Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} (source filename wi **Path Template** -Use / to create folders. Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} (source filename without extension), {Series}, {SeriesPosition}, {Subtitle}, {PartNumber}. Use arbitrary prefix/suffix: {Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty. +Use / to create folders. Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} (source filename without extension), {Series}, {SeriesPosition}, {Subtitle}, {PrimaryTitle}, {PartNumber}. Use arbitrary prefix/suffix: {Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty. - **Type:** string -- **Default:** `{Author}/{Title}` +- **Default:** `{Author}/{Title}/{Title}` #### `HARDLINK_TORRENTS_AUDIOBOOK` @@ -639,7 +650,7 @@ How long to keep completed/failed downloads in the queue display. | Variable | Description | Type | Default | |----------|-------------|------|---------| -| `AUTH_METHOD` | Select the authentication method for accessing Shelfmark. | string (choice) | `none` | +| `AUTH_METHOD` | Select the authentication method for accessing Shelfmark. Restart container after changing Calibre-Web passwords. | string (choice) | `none` | | `PROXY_AUTH_USER_HEADER` | The HTTP header your proxy uses to pass the authenticated username. | string | `X-Auth-User` | | `PROXY_AUTH_LOGOUT_URL` | The URL to redirect users to for logging out. Leave empty to disable logout functionality. | string | _empty string_ | | `PROXY_AUTH_ADMIN_GROUP_HEADER` | Optional: header your proxy uses to pass user groups/roles. | string | `X-Auth-Groups` | @@ -661,7 +672,7 @@ How long to keep completed/failed downloads in the queue display. **Authentication Method** -Select the authentication method for accessing Shelfmark. +Select the authentication method for accessing Shelfmark. Restart container after changing Calibre-Web passwords. - **Type:** string (choice) - **Default:** `none` @@ -1115,6 +1126,57 @@ Automatically retry search without category filtering if no results are found
+## Newznab + +| Variable | Description | Type | Default | +|----------|-------------|------|---------| +| `NEWZNAB_ENABLED` | Enable searching for books via a Newznab-compatible indexer | boolean | `false` | +| `NEWZNAB_URL` | Base URL of your Newznab indexer or aggregator | string | _none_ | +| `NEWZNAB_API_KEY` | Your Newznab API key (leave blank if not required) | string (secret) | _none_ | +| `NEWZNAB_AUTO_EXPAND` | Automatically retry search without category filtering if no results are found | boolean | `false` | + +
+Detailed descriptions + +#### `NEWZNAB_ENABLED` + +**Enable Newznab source** + +Enable searching for books via a Newznab-compatible indexer + +- **Type:** boolean +- **Default:** `false` + +#### `NEWZNAB_URL` + +**Newznab URL** + +Base URL of your Newznab indexer or aggregator + +- **Type:** string +- **Default:** _none_ +- **Required:** Yes + +#### `NEWZNAB_API_KEY` + +**API Key** + +Your Newznab API key (leave blank if not required) + +- **Type:** string (secret) +- **Default:** _none_ + +#### `NEWZNAB_AUTO_EXPAND` + +**Auto-expand search on no results** + +Automatically retry search without category filtering if no results are found + +- **Type:** boolean +- **Default:** `false` + +
+ ## AudiobookBay | Variable | Description | Type | Default | diff --git a/scripts/generate_env_docs.py b/scripts/generate_env_docs.py index d0e6aac..2907166 100755 --- a/scripts/generate_env_docs.py +++ b/scripts/generate_env_docs.py @@ -310,7 +310,7 @@ def generate_env_docs() -> str: def _generate_tab_docs(tab: Any, group_prefix: str | None = None) -> list[str]: """Generate documentation for a single settings tab.""" - from shelfmark.core.settings_registry import ActionButton, CustomComponentField, HeadingField + from shelfmark.core.settings_registry import iter_value_fields lines = [] @@ -323,17 +323,9 @@ def _generate_tab_docs(tab: Any, group_prefix: str | None = None) -> list[str]: lines.append("") # Collect env-supported fields - env_fields = [] - for field in tab.fields: - # Skip non-value fields - if isinstance(field, (ActionButton, CustomComponentField, HeadingField)): - continue - - # Skip fields that don't support ENV vars - if not getattr(field, "env_supported", True): - continue - - env_fields.append(field) + env_fields = [ + field for field in iter_value_fields(tab) if getattr(field, "env_supported", True) + ] if not env_fields: lines.append("_No environment variables for this section._") diff --git a/shelfmark/config/settings.py b/shelfmark/config/settings.py index 3ebd38e..18da163 100644 --- a/shelfmark/config/settings.py +++ b/shelfmark/config/settings.py @@ -938,7 +938,7 @@ def download_settings() -> list[SettingsField]: SelectField( key="FILE_ORGANIZATION", label="File Organization", - description="Choose how downloaded book files are named and organized. ", + description="Choose how downloaded book files are named and organized.", options=[ { "value": "none", @@ -966,7 +966,14 @@ def download_settings() -> list[SettingsField]: _naming_template_field( key="TEMPLATE_RENAME", label="Naming Template", - description="Filename template for single-file book downloads.", + description=( + "Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} " + "(source filename without extension). Universal adds: {Series}, " + "{SeriesPosition}, {Subtitle}, {PrimaryTitle}. Use arbitrary prefix/suffix: " + "{Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty. " + "Rename templates are filename-only (no '/' or '\\'); use Organize for folders. " + "Applies to single-file downloads." + ), default="{Author} - {Title} ({Year})", placeholder="{Author} - {Title} ({Year})", show_when=[ @@ -978,7 +985,12 @@ def download_settings() -> list[SettingsField]: _naming_template_field( key="TEMPLATE_ORGANIZE", label="Path Template", - description="Folder and filename template for book downloads.", + description=( + "Use / to create folders. Variables: {Author}, {Title}, {Year}, {User}, " + "{OriginalName} (source filename without extension). Universal adds: {Series}, " + "{SeriesPosition}, {Subtitle}, {PrimaryTitle}. Use arbitrary prefix/suffix: " + "{Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty." + ), default="{Author}/{Title} ({Year})", placeholder="{Author}/{Series/}{Title} ({Year})", show_when=[ @@ -1236,7 +1248,14 @@ def download_settings() -> list[SettingsField]: _naming_template_field( key="TEMPLATE_AUDIOBOOK_RENAME", label="Naming Template", - description="Filename template for single-file audiobook downloads.", + description=( + "Variables: {Author}, {Title}, {Year}, {User}, {OriginalName} " + "(source filename without extension), {Series}, {SeriesPosition}, {Subtitle}, " + "{PrimaryTitle}, {PartNumber}. Use arbitrary prefix/suffix: " + "{Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty. " + "Rename templates are filename-only (no '/' or '\\'); use Organize for folders. " + "Applies to single-file downloads." + ), default="{Author} - {Title}", placeholder="{Author} - {Title}{ - Part }{PartNumber}", show_when={"field": "FILE_ORGANIZATION_AUDIOBOOK", "value": "rename"}, @@ -1246,8 +1265,13 @@ def download_settings() -> list[SettingsField]: _naming_template_field( key="TEMPLATE_AUDIOBOOK_ORGANIZE", label="Path Template", - description="Folder and filename template for audiobook downloads.", - default="{Author}/{Title}", + description=( + "Use / to create folders. Variables: {Author}, {Title}, {Year}, {User}, " + "{OriginalName} (source filename without extension), {Series}, {SeriesPosition}, " + "{Subtitle}, {PrimaryTitle}, {PartNumber}. Use arbitrary prefix/suffix: " + "{Vol. SeriesPosition - } outputs 'Vol. 2 - ' when set, nothing when empty." + ), + default="{Author}/{Title}/{Title}", placeholder="{Author}/{Series/}{Title}{ - Part }{PartNumber}", show_when={"field": "FILE_ORGANIZATION_AUDIOBOOK", "value": "organize"}, universal_only=True, diff --git a/shelfmark/core/settings_registry.py b/shelfmark/core/settings_registry.py index c8b6d3a..cc4e67a 100644 --- a/shelfmark/core/settings_registry.py +++ b/shelfmark/core/settings_registry.py @@ -333,7 +333,7 @@ def get_all_settings_tabs() -> list[SettingsTab]: return sorted(_SETTINGS_REGISTRY.values(), key=lambda t: (t.order, t.name)) -def _iter_value_fields(tab: SettingsTab) -> Iterator[FieldBase]: +def iter_value_fields(tab: SettingsTab) -> Iterator[FieldBase]: """Yield value-bearing fields for a tab.""" for settings_field in tab.fields: if isinstance(settings_field, CustomComponentField): @@ -360,7 +360,7 @@ def get_settings_field_map( field_map: dict[str, tuple[FieldBase, str]] = {} for tab in tabs: - for settings_field in _iter_value_fields(tab): + for settings_field in iter_value_fields(tab): field_map[settings_field.key] = (settings_field, tab.name) return field_map @@ -494,7 +494,7 @@ def initialize_default_configs() -> bool: # Collect default values for all fields defaults = {} - for field in _iter_value_fields(tab): + for field in iter_value_fields(tab): # Only include fields that have a non-None default if field.default is not None: defaults[field.key] = field.default @@ -536,7 +536,7 @@ def sync_env_to_config() -> None: for tab in get_all_settings_tabs(): values_to_sync = {} - for settings_field in _iter_value_fields(tab): + for settings_field in iter_value_fields(tab): # Skip fields that don't support ENV vars if not getattr(settings_field, "env_supported", True): continue diff --git a/src/frontend/src/components/settings/customFields/NamingTemplateField.tsx b/src/frontend/src/components/settings/customFields/NamingTemplateField.tsx index 5db7485..9b159f5 100644 --- a/src/frontend/src/components/settings/customFields/NamingTemplateField.tsx +++ b/src/frontend/src/components/settings/customFields/NamingTemplateField.tsx @@ -106,7 +106,6 @@ export const NamingTemplateField = ({ disabled={fieldDisabled} className="w-full rounded-lg border border-(--border-muted) bg-(--bg-soft) px-3 py-2 text-sm transition-colors focus:border-sky-500 focus:ring-2 focus:ring-sky-500/50 focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-60" /> - {boundField.description &&

{boundField.description}

} {(hasPathSeparatorInFilename || preview.unknownTokens.length > 0) && ( diff --git a/src/frontend/src/tests/namingTemplatePreview.test.ts b/src/frontend/src/tests/namingTemplatePreview.test.ts index 94a469c..7116a3e 100644 --- a/src/frontend/src/tests/namingTemplatePreview.test.ts +++ b/src/frontend/src/tests/namingTemplatePreview.test.ts @@ -2,11 +2,18 @@ import { describe, expect, it } from 'vitest'; import { buildNamingTemplatePreview, + NAMING_TEMPLATE_TOKENS, renderNamingTemplate, SAMPLE_NAMING_METADATA, } from '../utils/namingTemplatePreview'; describe('namingTemplatePreview', () => { + it('groups primary title with universal variables', () => { + expect(NAMING_TEMPLATE_TOKENS.find((token) => token.token === 'PrimaryTitle')?.group).toBe( + 'Universal', + ); + }); + it('renders primary title in path previews', () => { const preview = buildNamingTemplatePreview( '{Author}/{Series/}{SeriesPosition - }{PrimaryTitle} ({Year})', diff --git a/src/frontend/src/utils/namingTemplatePreview.ts b/src/frontend/src/utils/namingTemplatePreview.ts index 63c41b4..d1dc970 100644 --- a/src/frontend/src/utils/namingTemplatePreview.ts +++ b/src/frontend/src/utils/namingTemplatePreview.ts @@ -39,7 +39,7 @@ export const NAMING_TEMPLATE_TOKENS: NamingTemplateToken[] = [ label: 'Primary title', description: 'Title without the subtitle suffix', value: 'The Hound of the Baskervilles', - group: 'Core', + group: 'Universal', }, { token: 'Year', diff --git a/tests/config/test_download_settings.py b/tests/config/test_download_settings.py index 3f45aef..556b1a1 100644 --- a/tests/config/test_download_settings.py +++ b/tests/config/test_download_settings.py @@ -156,6 +156,21 @@ def test_download_settings_naming_templates_use_wrapped_custom_component(): assert value_key not in fields_by_key +def test_download_settings_naming_template_value_fields_are_registered(): + import shelfmark.config.settings # noqa: F401 + from shelfmark.core import settings_registry + + field_map = settings_registry.get_settings_field_map(tab_name="downloads") + + for value_key in ( + "TEMPLATE_RENAME", + "TEMPLATE_ORGANIZE", + "TEMPLATE_AUDIOBOOK_RENAME", + "TEMPLATE_AUDIOBOOK_ORGANIZE", + ): + assert value_key in field_map + + def test_download_settings_naming_template_serialization_keeps_value_fields_hidden(): from shelfmark.config.settings import download_settings from shelfmark.core import settings_registry diff --git a/tests/config/test_generate_env_docs.py b/tests/config/test_generate_env_docs.py index cbdccda..98e3525 100644 --- a/tests/config/test_generate_env_docs.py +++ b/tests/config/test_generate_env_docs.py @@ -38,3 +38,22 @@ def test_generated_env_docs_describe_mirror_lists_as_comma_separated_strings() - "| `LIBGEN_MIRROR_URLS` | Mirrors are tried in the order you add them until one works. | " "string (comma-separated) | _empty list_ |" ) in docs + + +def test_generated_env_docs_include_custom_component_value_fields() -> None: + docs = generate_env_docs() + + for env_var in ( + "TEMPLATE_RENAME", + "TEMPLATE_ORGANIZE", + "TEMPLATE_AUDIOBOOK_RENAME", + "TEMPLATE_AUDIOBOOK_ORGANIZE", + ): + assert f"`{env_var}`" in docs + + assert ( + "| `TEMPLATE_AUDIOBOOK_ORGANIZE` | Use / to create folders. Variables: " + "{Author}, {Title}, {Year}, {User}, {OriginalName} " + "(source filename without extension), {Series}, {SeriesPosition}, {Subtitle}, " + "{PrimaryTitle}, {PartNumber}. Use arbitrary prefix/suffix:" + ) in docs