beetbox/beets

Error in `%titlecase` documentation

已關閉

#6,697 建立於 2026年5月31日

 (0 則留言) (0 個反應) (0 位負責人)Python (1,837 個分叉)batch import
good first issuetitlecase

倉庫指標

星標
 (12,133 顆星)
PR 合併指標
 (平均合併 26天 4小時) (30 天內合併 51 個 PR)

描述

Problem

I think there's a typo in the documentation for the titlecase plugin's %titlecase template function. For every other template function it is documented as %func{arg,arg}.1 Titlecase also is not mentioned in the list of plugins providing templates.2

The documentation for the titlecase plugin specifies it with parentheses. https://github.com/beetbox/beets/blob/26ab6b26361e8c9d77cdf04ba9cf5ca64bbbc722/docs/plugins/titlecase.rst#L34-L40

I didn't catch this initially when I added the titlecase plugin to my config leading to results like %titlecase(Smiths, The) as part of the directory and file names.

Running this command in verbose (-vv) mode:

$ beet -vv import -q -L artist:"The Smiths"

Led to this problem:

user configuration: /home/tom/.config/beets/config.yaml
data directory: /home/tom/.config/beets
plugin paths: []
Loading plugins: chroma, convert, discogs, duplicates, edit, fuzzy, info, mbsync, musicbrainz, permissions, replace, spotify, the, titlecase, unimported, web
Sending event: pluginload
library database: /home/tom/.config/beets/musiclibrary.db
library directory: /home/tom/Music
Sending event: library_opened
Sending event: import_begin
Parsed query: AndQuery([SubstringQuery('artist', 'The Smiths', fast=True)])
Parsed sort: NullSort()
yielding album 1436: The Smiths - Hatful of Hollow
Sending event: import_task_created
Sending event: import_task_start
# [...] output of unrelated plugins cut
/home/tom/Music/Smiths, The/Hatful of Hollow (1 items)
Sending event: import_task_before_choice
Importing as-is.
Sending event: import_task_choice
Replacing item 6502: /home/tom/Music/Smiths, The/Hatful of Hollow/How Soon Is Now_.mp4
Sending event: database_change
Sending event: database_change
Sending event: album_removed
Sending event: item_removed
1 of 1 items replaced
Sending event: database_change
Sending event: database_change
Sending event: database_change
Sending event: database_change
Reimported album 1453. Preserving attribute ['added']. Path: /home/tom/Music/Smiths, The/Hatful of Hollow
Reimported album 1453. Preserving flexible attributes ['data_source', 'media']. Path: /home/tom/Music/Smiths, The/Hatful of Hollow
Reimported item 6538. Preserving attribute ['added']. Path: /home/tom/Music/Smiths, The/Hatful of Hollow/How Soon Is Now_.mp4
Reimported item 6538. Preserving flexible attributes ['data_source', 'spotify_time_signature', 'spotify_valence', 'spotify_danceability', 'spotify_artist_id', 'spotify_track_id', 'spotify_key', 'spotify_acousticness', 'spotify_liveness', 'spotify_energy', 'spotify_updated', 'spotify_speechiness', 'spotify_track_popularity', 'spotify_tempo', 'spotify_instrumentalness', 'track_alt', 'spotify_loudness', 'spotify_mode']. Path: /home/tom/Music/Smiths, The/Hatful of Hollow/How Soon Is Now_.mp4
Sending event: database_change
Parsed query: AndQuery([NoneQuery('album_id', True)])
Parsed sort: NullSort()
Parsed query: AndQuery([BooleanQuery('comp', 1, fast=True)])
Parsed sort: NullSort()
the: "The Smiths" -> "Smiths, The"
Sending event: before_item_moved
Sending event: item_moved
Sending event: database_change
Sending event: database_change
Sending event: database_change
Sending event: import_task_files
Sending event: album_imported
permissions: setting file permissions on /home/tom/Music/%titlecase(Smiths, The)/%titlecase(Hatful of Hollow)/%titlecase(How Soon Is Now_).mp4
permissions: setting directory permissions on /home/tom/Music/%titlecase(Smiths, The)/%titlecase(Hatful of Hollow)
permissions: setting directory permissions on /home/tom/Music/%titlecase(Smiths, The)
Sending event: import
Sending event: cli_exit

I was able to fix this and reimport my library automatically with beet import -q -m -L, which resolved the filename issues.

Setup

  • OS: Arch Linux
  • Python version: 3.14.5
  • beets version: 2.11.0
  • Turning off plugins made problem go away (yes/no): Not applicable

My configuration (output of beet config) is:

Related sections only
# --------------- Main ---------------

library: ~/.config/beets/musiclibrary.db
directory: ~/Music/
include: [secrets.yaml]
paths:
    default: '%titlecase{%the{$albumartist}}/%titlecase{$album}/%titlecase{$title}'
    singleton: '%titlecase{%the{$albumartist}}/%titlecase{$album}/%titlecase{$title}'

import:
    copy: yes
    quiet_fallback: asis
    incremental: yes
    incremental_skip_later: yes
    resume: ask
    languages: en
    log: ~/.config/beets/import.log
# [...]
# --------------- Plugins ---------------

plugins:
- chroma
- convert
- discogs
- duplicates
- edit
- fuzzy
- info
- mbsync
- musicbrainz
- permissions
- replace
- spotify
- the
- titlecase
- unimported
- web
# [...]
titlecase:
    auto: no
    preserve: []
    replace:
        "\u2013": '-'
        "\u2014": '-'
        "\u2026": '...'
        "\u2018": '''' # This is "'" in the file
        "\u2019": '''' # Not sure why `beet config`
        "\u201B": '''' # prints them as ''''
        "\u2039": ''''
        "\u203A": ''''
        "\u201A": ''''
        "\u275B": ''''
        "\u275C": ''''
        "\u275F": ''''
        "\u276E": ''''
        "\u276F": ''''
        "\uFF07": ''''
        "\xAB": '"'
        "\xBB": '"'
        "\u201C": '"'
        "\u201D": '"'
        "\u201E": '"'
        "\u201F": '"'
        "\u275D": '"'
        "\u275E": '"'
        "\u301E": '"'
        "\u301F": '"'
        "\u2E42": '"'
        "\uFF02": '"'
    fields: []
    separators: []
    force_lowercase: no
    small_first_last: yes
    the_artist: yes
    all_caps: no
    all_lowercase: no
    after_choice: no

Footnotes

  1. https://beets.readthedocs.io/en/v2.11.0/reference/pathformat.html#template-functions

  2. https://beets.readthedocs.io/en/v2.11.0/reference/pathformat.html#templ-plugins

貢獻者指南