mirror of
https://github.com/beetbox/beets.git
synced 2026-02-08 16:34:12 +01:00
Merge 3c1f696c5a into 680473b9e5
This commit is contained in:
commit
cd2c2a931b
13 changed files with 50 additions and 46 deletions
|
|
@ -37,11 +37,11 @@ class IncludeLazyConfig(confuse.LazyConfig):
|
|||
YAML files specified in an `include` setting.
|
||||
"""
|
||||
|
||||
def read(self, user=True, defaults=True):
|
||||
def read(self, user: bool = True, defaults: bool = True) -> None:
|
||||
super().read(user, defaults)
|
||||
|
||||
try:
|
||||
for view in self["include"]:
|
||||
for view in self["include"].sequence():
|
||||
self.set_file(view.as_filename())
|
||||
except confuse.NotFoundError:
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ from beets.util.deprecation import deprecate_for_maintainers, deprecate_for_user
|
|||
if TYPE_CHECKING:
|
||||
from collections.abc import Callable, Iterable, Iterator, Sequence
|
||||
|
||||
from confuse import ConfigView
|
||||
from confuse import Subview
|
||||
|
||||
from beets.dbcore import Query
|
||||
from beets.dbcore.db import FieldQueryType
|
||||
|
|
@ -162,7 +162,7 @@ class BeetsPlugin(metaclass=BeetsPluginMeta):
|
|||
album_template_fields: TFuncMap[Album]
|
||||
|
||||
name: str
|
||||
config: ConfigView
|
||||
config: Subview
|
||||
early_import_stages: list[ImportStageFunc]
|
||||
import_stages: list[ImportStageFunc]
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ import textwrap
|
|||
import traceback
|
||||
from difflib import SequenceMatcher
|
||||
from functools import cache
|
||||
from itertools import chain
|
||||
from typing import TYPE_CHECKING, Any, Literal
|
||||
|
||||
import confuse
|
||||
|
|
@ -551,18 +550,20 @@ def get_color_config() -> dict[ColorName, str]:
|
|||
legacy single-color format. Validates all color names against known codes
|
||||
and raises an error for any invalid entries.
|
||||
"""
|
||||
colors_by_color_name: dict[ColorName, list[str]] = {
|
||||
k: (v if isinstance(v, list) else LEGACY_COLORS.get(v, [v]))
|
||||
for k, v in config["ui"]["colors"].flatten().items()
|
||||
}
|
||||
|
||||
if invalid_colors := (
|
||||
set(chain.from_iterable(colors_by_color_name.values()))
|
||||
- CODE_BY_COLOR.keys()
|
||||
):
|
||||
raise UserError(
|
||||
f"Invalid color(s) in configuration: {', '.join(invalid_colors)}"
|
||||
template_dict: dict[ColorName, confuse.OneOf[str | list[str]]] = {
|
||||
n: confuse.OneOf(
|
||||
[
|
||||
confuse.Choice(sorted(LEGACY_COLORS)),
|
||||
confuse.Sequence(confuse.Choice(sorted(CODE_BY_COLOR))),
|
||||
]
|
||||
)
|
||||
for n in ColorName.__args__ # type: ignore[attr-defined]
|
||||
}
|
||||
template = confuse.MappingTemplate(template_dict)
|
||||
colors_by_color_name = {
|
||||
k: (v if isinstance(v, list) else LEGACY_COLORS.get(v, [v]))
|
||||
for k, v in config["ui"]["colors"].get(template).items()
|
||||
}
|
||||
|
||||
return {
|
||||
n: ";".join(str(CODE_BY_COLOR[c]) for c in colors)
|
||||
|
|
|
|||
|
|
@ -335,6 +335,7 @@ def _summary_judgment(rec):
|
|||
summary judgment is made.
|
||||
"""
|
||||
|
||||
action: importer.Action | None
|
||||
if config["import"]["quiet"]:
|
||||
if rec == Recommendation.strong:
|
||||
return importer.Action.APPLY
|
||||
|
|
|
|||
|
|
@ -355,10 +355,9 @@ class DiscogsPlugin(MetadataSourcePlugin):
|
|||
style = self.format(result.data.get("styles"))
|
||||
base_genre = self.format(result.data.get("genres"))
|
||||
|
||||
if self.config["append_style_genre"] and style:
|
||||
genre = self.config["separator"].as_str().join([base_genre, style])
|
||||
else:
|
||||
genre = base_genre
|
||||
genre = base_genre
|
||||
if self.config["append_style_genre"] and genre is not None and style:
|
||||
genre += f"{self.config['separator'].as_str()}{style}"
|
||||
|
||||
discogs_albumid = self._extract_id(result.data.get("uri"))
|
||||
|
||||
|
|
|
|||
|
|
@ -288,7 +288,8 @@ class Candidate:
|
|||
elif check == ImageAction.REFORMAT:
|
||||
self.path = ArtResizer.shared.reformat(
|
||||
self.path,
|
||||
plugin.cover_format,
|
||||
# TODO: fix this gnarly logic to remove the need for type ignore
|
||||
plugin.cover_format, # type: ignore[arg-type]
|
||||
deinterlaced=plugin.deinterlace,
|
||||
)
|
||||
|
||||
|
|
@ -1367,7 +1368,7 @@ class FetchArtPlugin(plugins.BeetsPlugin, RequestMixin):
|
|||
|
||||
# allow both pixel and percentage-based margin specifications
|
||||
self.enforce_ratio = self.config["enforce_ratio"].get(
|
||||
confuse.OneOf(
|
||||
confuse.OneOf[bool | str](
|
||||
[
|
||||
bool,
|
||||
confuse.String(pattern=self.PAT_PX),
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ if TYPE_CHECKING:
|
|||
import optparse
|
||||
from collections.abc import Callable
|
||||
|
||||
from beets.importer import ImportSession, ImportTask
|
||||
from beets.library import LibModel
|
||||
|
||||
LASTFM = pylast.LastFMNetwork(api_key=plugins.LASTFM_KEY)
|
||||
|
|
@ -178,14 +179,13 @@ class LastGenrePlugin(plugins.BeetsPlugin):
|
|||
"""A tuple of allowed genre sources. May contain 'track',
|
||||
'album', or 'artist.'
|
||||
"""
|
||||
source = self.config["source"].as_choice(("track", "album", "artist"))
|
||||
if source == "track":
|
||||
return "track", "album", "artist"
|
||||
if source == "album":
|
||||
return "album", "artist"
|
||||
if source == "artist":
|
||||
return ("artist",)
|
||||
return tuple()
|
||||
return self.config["source"].as_choice(
|
||||
{
|
||||
"track": ("track", "album", "artist"),
|
||||
"album": ("album", "artist"),
|
||||
"artist": ("artist",),
|
||||
}
|
||||
)
|
||||
|
||||
# More canonicalization and general helpers.
|
||||
|
||||
|
|
@ -603,10 +603,8 @@ class LastGenrePlugin(plugins.BeetsPlugin):
|
|||
lastgenre_cmd.func = lastgenre_func
|
||||
return [lastgenre_cmd]
|
||||
|
||||
def imported(
|
||||
self, session: library.Session, task: library.ImportTask
|
||||
) -> None:
|
||||
self._process(task.album if task.is_album else task.item, write=False)
|
||||
def imported(self, _: ImportSession, task: ImportTask) -> None:
|
||||
self._process(task.album if task.is_album else task.item, write=False) # type: ignore[attr-defined]
|
||||
|
||||
def _tags_for(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@ class LRCLib(Backend):
|
|||
for group in self.fetch_candidates(artist, title, album, length):
|
||||
candidates = [evaluate_item(item) for item in group]
|
||||
if item := self.pick_best_match(candidates):
|
||||
lyrics = item.get_text(self.config["synced"])
|
||||
lyrics = item.get_text(self.config["synced"].get(bool))
|
||||
return lyrics, f"{self.GET_URL}/{item.id}"
|
||||
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ class PlaylistQuery(InQuery[bytes]):
|
|||
relative_to = os.path.dirname(playlist_path)
|
||||
else:
|
||||
relative_to = config["relative_to"].as_filename()
|
||||
relative_to = beets.util.bytestring_path(relative_to)
|
||||
relative_to_bytes = beets.util.bytestring_path(relative_to)
|
||||
|
||||
for line in f:
|
||||
if line[0] == "#":
|
||||
|
|
@ -78,7 +78,7 @@ class PlaylistQuery(InQuery[bytes]):
|
|||
|
||||
paths.append(
|
||||
beets.util.normpath(
|
||||
os.path.join(relative_to, line.rstrip())
|
||||
os.path.join(relative_to_bytes, line.rstrip())
|
||||
)
|
||||
)
|
||||
f.close()
|
||||
|
|
|
|||
|
|
@ -262,8 +262,9 @@ class SmartPlaylistPlugin(BeetsPlugin):
|
|||
"Updating {} smart playlists...", len(self._matched_playlists)
|
||||
)
|
||||
|
||||
playlist_dir = self.config["playlist_dir"].as_filename()
|
||||
playlist_dir = bytestring_path(playlist_dir)
|
||||
playlist_dir = bytestring_path(
|
||||
self.config["playlist_dir"].as_filename()
|
||||
)
|
||||
tpl = self.config["uri_format"].get()
|
||||
prefix = bytestring_path(self.config["prefix"].as_str())
|
||||
relative_to = self.config["relative_to"].get()
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ class TitlecasePlugin(BeetsPlugin):
|
|||
|
||||
@cached_property
|
||||
def replace(self) -> list[tuple[str, str]]:
|
||||
return self.config["replace"].as_pairs()
|
||||
return self.config["replace"].as_pairs(default_value="")
|
||||
|
||||
@cached_property
|
||||
def the_artist(self) -> bool:
|
||||
|
|
|
|||
13
poetry.lock
generated
13
poetry.lock
generated
|
|
@ -747,18 +747,21 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "confuse"
|
||||
version = "2.1.0"
|
||||
version = "2.2.0"
|
||||
description = "Painless YAML config files"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
python-versions = ">=3.10"
|
||||
files = [
|
||||
{file = "confuse-2.1.0-py3-none-any.whl", hash = "sha256:502be1299aa6bf7c48f7719f56795720c073fb28550c0c7a37394366c9d30316"},
|
||||
{file = "confuse-2.1.0.tar.gz", hash = "sha256:abb9674a99c7a6efaef84e2fc84403ecd2dd304503073ff76ea18ed4176e218d"},
|
||||
{file = "confuse-2.2.0-py3-none-any.whl", hash = "sha256:470c6aa1a5008c8d740267f2ad574e3a715b6dd873c1e5f8778b7f7abb954722"},
|
||||
{file = "confuse-2.2.0.tar.gz", hash = "sha256:35c1b53e81be125f441bee535130559c935917b26aeaa61289010cd1f55c2b9e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pyyaml = "*"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx (>=7.4.7)", "sphinx-rtd-theme (>=3.0.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "coverage"
|
||||
version = "7.11.0"
|
||||
|
|
@ -4583,4 +4586,4 @@ web = ["flask", "flask-cors"]
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.10,<4"
|
||||
content-hash = "f8ce55ae74c5e3c5d1d330582f83dae30ef963a0b8dd8c8b79f16c3bcfdb525a"
|
||||
content-hash = "d00ffb911964e9943b08c5ae3de28867cd5636700bdfe4a70534b02843ea80d7"
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ Changelog = "https://github.com/beetbox/beets/blob/master/docs/changelog.rst"
|
|||
python = ">=3.10,<4"
|
||||
|
||||
colorama = { version = "*", markers = "sys_platform == 'win32'" }
|
||||
confuse = ">=2.1.0"
|
||||
confuse = ">=2.2.0"
|
||||
jellyfish = "*"
|
||||
lap = ">=0.5.12"
|
||||
mediafile = ">=0.12.0"
|
||||
|
|
|
|||
Loading…
Reference in a new issue