mirror of
https://github.com/beetbox/beets.git
synced 2025-12-28 03:22:39 +01:00
fixes
This commit is contained in:
parent
2f88ca0101
commit
2bb072fde1
3 changed files with 80 additions and 30 deletions
|
|
@ -17,7 +17,7 @@ Title case logic is derived from the python-titlecase library.
|
|||
Provides a template function and a tag modification function."""
|
||||
|
||||
import re
|
||||
from typing import Pattern
|
||||
from typing import Pattern, Optional
|
||||
|
||||
from titlecase import titlecase
|
||||
|
||||
|
|
@ -32,8 +32,7 @@ __version__ = "1.0"
|
|||
# These fields are excluded to avoid modifying anything
|
||||
# that may be case sensistive, or important to database
|
||||
# function
|
||||
EXCLUDED_INFO_FIELDS = set(
|
||||
[
|
||||
EXCLUDED_INFO_FIELDS: set[str] = {
|
||||
"acoustid_fingerprint",
|
||||
"acoustid_id",
|
||||
"artists_ids",
|
||||
|
|
@ -54,15 +53,14 @@ EXCLUDED_INFO_FIELDS = set(
|
|||
"bitrate_mode",
|
||||
"encoder_info",
|
||||
"encoder_settings",
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class TitlecasePlugin(BeetsPlugin):
|
||||
preserve: dict[str, str] = {}
|
||||
preserve_phrases: dict[str, Pattern[str]] = {}
|
||||
force_lowercase: bool = True
|
||||
fields_to_process: set[str] = set([])
|
||||
fields_to_process: set[str] = {}
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
|
@ -111,9 +109,10 @@ class TitlecasePlugin(BeetsPlugin):
|
|||
Only uses fields included.
|
||||
Last, the EXCLUDED_INFO_FIELDS are removed to prevent unitentional modification.
|
||||
"""
|
||||
initial_field_list = set(fields)
|
||||
initial_field_list -= set(EXCLUDED_INFO_FIELDS)
|
||||
self.fields_to_process = initial_field_list
|
||||
if fields:
|
||||
initial_field_list = set(fields)
|
||||
initial_field_list -= set(EXCLUDED_INFO_FIELDS)
|
||||
self.fields_to_process = initial_field_list
|
||||
|
||||
def __preserve_words__(self, preserve: list[str]) -> None:
|
||||
for word in preserve:
|
||||
|
|
@ -124,7 +123,7 @@ class TitlecasePlugin(BeetsPlugin):
|
|||
else:
|
||||
self.preserve[word.upper()] = word
|
||||
|
||||
def __preserved__(self, word, **kwargs) -> str | None:
|
||||
def __preserved__(self, word, **kwargs) -> Optional[str]:
|
||||
"""Callback function for words to preserve case of."""
|
||||
if preserved_word := self.preserve.get(word.upper(), ""):
|
||||
return preserved_word
|
||||
|
|
@ -150,20 +149,18 @@ class TitlecasePlugin(BeetsPlugin):
|
|||
"""
|
||||
for field in self.fields_to_process:
|
||||
init_field = getattr(item, field, "")
|
||||
if isinstance(init_field, list):
|
||||
cased_list: list[str] = [self.titlecase(i) for i in init_field]
|
||||
self._log.info(
|
||||
f"""
|
||||
{field}: {", ".join(init_field)} ->
|
||||
{", ".join(cased_list)}"""
|
||||
)
|
||||
setattr(item, field, cased_list)
|
||||
elif init_field and isinstance(init_field, str):
|
||||
cased: str = self.titlecase(init_field)
|
||||
self._log.info(f"{field}: {init_field} -> {cased}")
|
||||
setattr(item, field, cased)
|
||||
else:
|
||||
self._log.info(f"{field}: no string present")
|
||||
if init_field:
|
||||
if isinstance(init_field, list) and isinstance(init_field[0], str):
|
||||
cased_list: list[str] = [self.titlecase(i) for i in init_field]
|
||||
self._log.info((f"{field}: {', '.join(init_field)} -> "
|
||||
f"{', '.join(cased_list)}"))
|
||||
setattr(item, field, cased_list)
|
||||
elif isinstance(init_field, str):
|
||||
cased: str = self.titlecase(init_field)
|
||||
self._log.info(f"{field}: {init_field} -> {cased}")
|
||||
setattr(item, field, cased)
|
||||
else:
|
||||
self._log.info(f"{field}: no string present")
|
||||
|
||||
def titlecase(self, text: str) -> str:
|
||||
"""Titlecase the given text."""
|
||||
|
|
@ -179,6 +176,9 @@ class TitlecasePlugin(BeetsPlugin):
|
|||
def imported(self, session: ImportSession, task: ImportTask) -> None:
|
||||
"""Import hook for titlecasing on import."""
|
||||
for item in task.imported_items():
|
||||
self._log.info(f"titlecasing {item.title}:")
|
||||
self.titlecase_fields(item)
|
||||
item.store()
|
||||
try:
|
||||
self._log.info(f"titlecasing {item.title}:")
|
||||
self.titlecase_fields(item)
|
||||
item.store()
|
||||
except Exception as e:
|
||||
self._log.info(f"titlecasing exception {e}")
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ The ``titlecase`` plugin lets you format tags and paths in accordance with the
|
|||
titlecase guidelines in the `New York Times Manual of Style`_ and uses the
|
||||
`python titlecase library`_.
|
||||
|
||||
Motiviation for this plugin comes from a desire to resolve differences in style
|
||||
Motivation for this plugin comes from a desire to resolve differences in style
|
||||
between databases sources. For example, `MusicBrainz style`_ follows standard
|
||||
title case rules, except in the case of terms that are deemed generic, like
|
||||
"mix" and "remix". On the other hand, `Discogs guidlines`_ recommend
|
||||
capitalizing the first letter of each word, even for small words like "of" and
|
||||
"a". This plugin aims to achieve a middleground between disparate approaches to
|
||||
casing, and bring more consistency to titlecasing in your library.
|
||||
"a". This plugin aims to achieve a middle ground between disparate approaches to
|
||||
casing, and bring more consistency to titles in your library.
|
||||
|
||||
.. _discogs style: https://support.discogs.com/hc/en-us/articles/360005006334-Database-Guidelines-1-General-Rules#Capitalization_And_Grammar
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,55 @@ titlecase_test_cases = [
|
|||
album="the black messiah",
|
||||
title="Till It's Done (Tutu)",
|
||||
),
|
||||
},
|
||||
{
|
||||
"config": {
|
||||
"preserve": [""],
|
||||
"fields": ["artist", "albumartist",
|
||||
"title",
|
||||
"album",
|
||||
"mb_albumd", "year"],
|
||||
"force_lowercase": True,
|
||||
"small_first_last": True,
|
||||
},
|
||||
"item": Item(
|
||||
artist="OPHIDIAN",
|
||||
albumartist="ophiDIAN",
|
||||
format="CD",
|
||||
year=2003,
|
||||
album="BLACKBOX",
|
||||
title="KhAmElEoN",
|
||||
),
|
||||
"expected": Item(
|
||||
artist="Ophidian",
|
||||
albumartist="Ophidian",
|
||||
format="CD",
|
||||
year=2003,
|
||||
album="Blackbox",
|
||||
title="Khameleon",
|
||||
),
|
||||
},
|
||||
{
|
||||
"config": {
|
||||
"preserve": [""],
|
||||
"fields": [
|
||||
"artists",
|
||||
"artists_ids",
|
||||
"discogs_artistid"
|
||||
],
|
||||
"force_lowercase": False,
|
||||
"small_first_last": True,
|
||||
},
|
||||
"item": Item(
|
||||
artists=["artist_one", "artist_two"],
|
||||
artists_ids=["aBcDeF32", "aBcDeF12"],
|
||||
discogs_artistid=21
|
||||
),
|
||||
"expected": Item(
|
||||
artists=["Artist_One", "Artist_Two"],
|
||||
artists_ids=["aBcDeF32", "aBcDeF12"],
|
||||
discogs_artistid=21
|
||||
),
|
||||
}
|
||||
]
|
||||
|
||||
|
|
@ -146,3 +195,4 @@ class TitlecasePluginTest(PluginTestCase):
|
|||
output
|
||||
== f"{expected.artist} - {expected.album} - {expected.title}\n"
|
||||
)
|
||||
self.run_command(f"remove", expected.artist, "-f")
|
||||
|
|
|
|||
Loading…
Reference in a new issue