mirror of
https://github.com/beetbox/beets.git
synced 2026-02-11 18:02:10 +01:00
Added support for pre-tag selection stage
This commit is contained in:
parent
c89d0c1637
commit
a6bda748ce
3 changed files with 82 additions and 16 deletions
|
|
@ -22,6 +22,7 @@ from typing import Optional, Pattern
|
|||
from titlecase import titlecase
|
||||
|
||||
from beets import ui
|
||||
from beets.autotag.hooks import AlbumInfo, Info, TrackInfo
|
||||
from beets.importer import ImportSession, ImportTask
|
||||
from beets.library import Item
|
||||
from beets.plugins import BeetsPlugin
|
||||
|
|
@ -52,6 +53,7 @@ class TitlecasePlugin(BeetsPlugin):
|
|||
"force_lowercase": False,
|
||||
"small_first_last": True,
|
||||
"the_artist": True,
|
||||
"after_choice": False,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -77,7 +79,15 @@ class TitlecasePlugin(BeetsPlugin):
|
|||
|
||||
self.__get_config_file__()
|
||||
if self.config["auto"]:
|
||||
self.import_stages = [self.imported]
|
||||
if self.config["after_choice"].get(bool):
|
||||
self.import_stages = [self.imported]
|
||||
else:
|
||||
self.register_listener(
|
||||
"trackinfo_received", self.received_info_handler
|
||||
)
|
||||
self.register_listener(
|
||||
"albuminfo_received", self.received_info_handler
|
||||
)
|
||||
|
||||
def __get_config_file__(self):
|
||||
self.force_lowercase = self.config["force_lowercase"].get(bool)
|
||||
|
|
@ -92,11 +102,11 @@ class TitlecasePlugin(BeetsPlugin):
|
|||
"""Creates the set for fields to process in tagging."""
|
||||
if fields:
|
||||
self.fields_to_process = set(fields)
|
||||
self._log.info(
|
||||
self._log.debug(
|
||||
f"set fields to process: {', '.join(self.fields_to_process)}"
|
||||
)
|
||||
else:
|
||||
self._log.info("no fields specified!")
|
||||
self._log.debug("no fields specified!")
|
||||
|
||||
def __preserve_words__(self, preserve: list[str]) -> None:
|
||||
for word in preserve:
|
||||
|
|
@ -113,11 +123,17 @@ class TitlecasePlugin(BeetsPlugin):
|
|||
return preserved_word
|
||||
return None
|
||||
|
||||
def received_info_handler(self, info: AlbumInfo | TrackInfo):
|
||||
self.titlecase_fields(info)
|
||||
if isinstance(info, AlbumInfo):
|
||||
for track in info.tracks:
|
||||
self.titlecase_fields(track)
|
||||
|
||||
def commands(self) -> list[ui.Subcommand]:
|
||||
def func(lib, opts, args):
|
||||
write = ui.should_write()
|
||||
for item in lib.items(args):
|
||||
self._log.info(f"titlecasing {item.title}:")
|
||||
self._log.debug(f"titlecasing {item.title}:")
|
||||
self.titlecase_fields(item)
|
||||
item.store()
|
||||
if write:
|
||||
|
|
@ -126,7 +142,7 @@ class TitlecasePlugin(BeetsPlugin):
|
|||
self._command.func = func
|
||||
return [self._command]
|
||||
|
||||
def titlecase_fields(self, item: Item):
|
||||
def titlecase_fields(self, item: Item | Info):
|
||||
"""Applies titlecase to fields, except
|
||||
those excluded by the default exclusions and the
|
||||
set exclude lists.
|
||||
|
|
@ -141,20 +157,20 @@ class TitlecasePlugin(BeetsPlugin):
|
|||
self.titlecase(i) for i in init_field
|
||||
]
|
||||
setattr(item, field, cased_list)
|
||||
self._log.info(
|
||||
self._log.debug(
|
||||
(
|
||||
f"{field}: {', '.join(init_field)} -> "
|
||||
f"{', '.join(cased_list)}"
|
||||
)
|
||||
)
|
||||
elif isinstance(init_field, str):
|
||||
cased: str = self.titlecase(init_field)
|
||||
cased: str = self.titlecase(init_field, field)
|
||||
setattr(item, field, cased)
|
||||
self._log.info(f"{field}: {init_field} -> {cased}")
|
||||
self._log.debug(f"{field}: {init_field} -> {cased}")
|
||||
else:
|
||||
self._log.info(f"{field}: no string present")
|
||||
self._log.debug(f"{field}: no string present")
|
||||
else:
|
||||
self._log.info(f"{field}: does not exist on {item}")
|
||||
self._log.debug(f"{field}: does not exist on {type(item)}")
|
||||
|
||||
def titlecase(self, text: str, field: str = "") -> str:
|
||||
"""Titlecase the given text."""
|
||||
|
|
@ -180,8 +196,8 @@ class TitlecasePlugin(BeetsPlugin):
|
|||
"""Import hook for titlecasing on import."""
|
||||
for item in task.imported_items():
|
||||
try:
|
||||
self._log.info(f"titlecasing {item.title}:")
|
||||
self._log.debug(f"titlecasing {item.title}:")
|
||||
self.titlecase_fields(item)
|
||||
item.store()
|
||||
except Exception as e:
|
||||
self._log.info(f"titlecasing exception {e}")
|
||||
self._log.debug(f"titlecasing exception {e}")
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ Default
|
|||
force_lowercase: no
|
||||
small_first_last: yes
|
||||
the_artist: yes
|
||||
after_choice: no
|
||||
|
||||
.. conf:: auto
|
||||
:default: yes
|
||||
|
|
@ -99,9 +100,9 @@ Default
|
|||
|
||||
.. conf:: replace
|
||||
|
||||
The replace function takes place before any titlecasing occurs, and is intended to
|
||||
help normalize differences in puncuation styles. It accepts a list of tuples, with
|
||||
the first being the target, and the second being the replacement
|
||||
The replace function takes place before any titlecasing occurs, and is intended to
|
||||
help normalize differences in puncuation styles. It accepts a list of tuples, with
|
||||
the first being the target, and the second being the replacement
|
||||
|
||||
.. conf:: force_lowercase
|
||||
:default: no
|
||||
|
|
@ -121,6 +122,13 @@ Default
|
|||
capitalized. Useful for bands with `The` as part of the proper name,
|
||||
like ``Amyl and The Sniffers``.
|
||||
|
||||
.. conf:: after_choice
|
||||
|
||||
By default, titlecase runs on the candidates that are received, adjusting them before
|
||||
you make your selection and creating different weight calculations. If you'd rather
|
||||
see the data as recieved from the database, set this to true to run after you make
|
||||
your tag choice.
|
||||
|
||||
Dangerous Fields
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
import pytest
|
||||
|
||||
from beets.autotag.hooks import AlbumInfo, TrackInfo
|
||||
from beets.library import Item
|
||||
from beets.test.helper import PluginTestCase
|
||||
from beetsplug.titlecase import TitlecasePlugin
|
||||
|
|
@ -59,7 +60,7 @@ titlecase_test_cases = [
|
|||
title="Till It's Done (Tutu)",
|
||||
),
|
||||
"expected": Item(
|
||||
artist="D'Angelo and the Vanguard",
|
||||
artist="D'Angelo and The Vanguard",
|
||||
mb_albumid="Ab140e13-7b36-402a-A528-B69e3dee38a8",
|
||||
albumartist="D'Angelo",
|
||||
format="CD",
|
||||
|
|
@ -237,6 +238,47 @@ class TitlecasePluginTest(PluginTestCase):
|
|||
if isinstance(value, str):
|
||||
assert getattr(item, key) == getattr(expected, key)
|
||||
|
||||
def test_recieved_info_handler(self):
|
||||
test_track_info = TrackInfo(
|
||||
album="test album",
|
||||
artist_credit="test artist credit",
|
||||
artists=["artist one", "artist two"],
|
||||
)
|
||||
expected_track_info = TrackInfo(
|
||||
album="Test Album",
|
||||
artist_credit="Test Artist Credit",
|
||||
artists=["Artist One", "Artist Two"],
|
||||
)
|
||||
test_album_info = AlbumInfo(
|
||||
tracks=[test_track_info],
|
||||
album="test album",
|
||||
artist_credit="test artist credit",
|
||||
artists=["artist one", "artist two"],
|
||||
)
|
||||
expected_album_info = AlbumInfo(
|
||||
tracks=[expected_track_info],
|
||||
album="Test Album",
|
||||
artist_credit="Test Artist Credit",
|
||||
artists=["Artist One", "Artist Two"],
|
||||
)
|
||||
with self.configure_plugin(
|
||||
{"fields": ["album", "artist_credit", "artists"]}
|
||||
):
|
||||
TitlecasePlugin().received_info_handler(test_track_info)
|
||||
assert test_track_info.album == expected_track_info.album
|
||||
assert (
|
||||
test_track_info.artist_credit
|
||||
== expected_track_info.artist_credit
|
||||
)
|
||||
assert test_track_info.artists == expected_track_info.artists
|
||||
TitlecasePlugin().received_info_handler(test_album_info)
|
||||
assert test_album_info.album == expected_album_info.album
|
||||
assert (
|
||||
test_album_info.artist_credit
|
||||
== expected_album_info.artist_credit
|
||||
)
|
||||
assert test_album_info.artists == expected_album_info.artists
|
||||
|
||||
def test_cli(self):
|
||||
for tc in titlecase_test_cases:
|
||||
with self.configure_plugin(tc["config"]):
|
||||
|
|
|
|||
Loading…
Reference in a new issue