mirror of
https://github.com/beetbox/beets.git
synced 2026-03-30 10:14:02 +02:00
Add discogs.extra_tags and updated documentation
This commit is contained in:
parent
6af84bcfb6
commit
0d8d3bfadf
3 changed files with 113 additions and 3 deletions
|
|
@ -25,7 +25,7 @@ import re
|
|||
import socket
|
||||
import time
|
||||
import traceback
|
||||
from functools import cache
|
||||
from functools import cache, cached_property
|
||||
from string import ascii_lowercase
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ from requests.exceptions import ConnectionError
|
|||
|
||||
import beets
|
||||
import beets.ui
|
||||
from beets import config
|
||||
from beets import config, util
|
||||
from beets.autotag.distance import string_dist
|
||||
from beets.autotag.hooks import AlbumInfo, TrackInfo
|
||||
from beets.metadata_plugins import IDResponse, SearchApiMetadataSourcePlugin
|
||||
|
|
@ -80,6 +80,15 @@ TRACK_INDEX_RE = re.compile(
|
|||
re.VERBOSE,
|
||||
)
|
||||
|
||||
FIELDS_TO_DISCOGS_KEYS = {
|
||||
"barcode": "barcode",
|
||||
"catalognum": "catno",
|
||||
"country": "country",
|
||||
"label": "label",
|
||||
"media": "format",
|
||||
"year": "year",
|
||||
}
|
||||
|
||||
|
||||
class DiscogsPlugin(SearchApiMetadataSourcePlugin[IDResponse]):
|
||||
def __init__(self):
|
||||
|
|
@ -95,6 +104,7 @@ class DiscogsPlugin(SearchApiMetadataSourcePlugin[IDResponse]):
|
|||
"append_style_genre": False,
|
||||
"strip_disambiguation": True,
|
||||
"featured_string": "Feat.",
|
||||
"extra_tags": [],
|
||||
"anv": {
|
||||
"artist_credit": True,
|
||||
"artist": False,
|
||||
|
|
@ -107,6 +117,25 @@ class DiscogsPlugin(SearchApiMetadataSourcePlugin[IDResponse]):
|
|||
self.config["user_token"].redact = True
|
||||
self.setup()
|
||||
|
||||
@cached_property
|
||||
def extra_discogs_field_by_tag(self) -> dict[str, str]:
|
||||
"""Map configured extra tags to Discogs API search parameters.
|
||||
|
||||
Process user configuration to determine which additional Discogs
|
||||
fields should be included in search queries.
|
||||
"""
|
||||
field_by_tag = {
|
||||
tag: FIELDS_TO_DISCOGS_KEYS[tag]
|
||||
for tag in self.config["extra_tags"].as_str_seq()
|
||||
if tag in FIELDS_TO_DISCOGS_KEYS
|
||||
}
|
||||
if field_by_tag:
|
||||
self._log.debug(
|
||||
"Discogs additional search filters from tags: {}", field_by_tag
|
||||
)
|
||||
|
||||
return field_by_tag
|
||||
|
||||
def setup(self, session=None) -> None:
|
||||
"""Create the `discogs_client` field. Authenticate if necessary."""
|
||||
c_key = self.config["apikey"].as_str()
|
||||
|
|
@ -256,7 +285,26 @@ class DiscogsPlugin(SearchApiMetadataSourcePlugin[IDResponse]):
|
|||
# can also negate an otherwise positive result.
|
||||
query = re.sub(r"(?i)\b(CD|disc|vinyl)\s*\d+", "", query)
|
||||
|
||||
return query, {"type": "release"}
|
||||
filters: dict[str, str] = {"type": "release"}
|
||||
|
||||
for tag, api_field in self.extra_discogs_field_by_tag.items():
|
||||
# The Discogs search API does not provide direct equivalents for
|
||||
# MusicBrainz "alias" or "tracks" search fields, so we ignore
|
||||
# those tags if configured.
|
||||
if tag in {"alias", "tracks"}:
|
||||
continue
|
||||
|
||||
most_common, _count = util.plurality(item.get(tag) for item in items)
|
||||
if most_common is None:
|
||||
continue
|
||||
|
||||
value = str(most_common)
|
||||
if tag == "catalognum":
|
||||
value = value.replace(" ", "")
|
||||
|
||||
filters[api_field] = value
|
||||
|
||||
return query, filters
|
||||
|
||||
def get_search_response(self, params: SearchParams) -> Sequence[IDResponse]:
|
||||
"""Search Discogs releases and return raw result mappings with IDs."""
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ Default
|
|||
separator: ', '
|
||||
strip_disambiguation: yes
|
||||
featured_string: Feat.
|
||||
extra_tags: []
|
||||
anv:
|
||||
artist_credit: yes
|
||||
artist: no
|
||||
|
|
@ -144,6 +145,31 @@ Default
|
|||
|
||||
Configure the string used for noting featured artists. Useful if you prefer ``Featuring`` or ``ft.``.
|
||||
|
||||
.. conf:: extra_tags
|
||||
:default: []
|
||||
|
||||
By default, beets will only use the artist and album information to query Discogs. Additional tags to be queried can be supplied with the
|
||||
``extra_tags`` setting.
|
||||
|
||||
This setting should improve the autotagger results if the metadata with the
|
||||
given tags match the metadata returned by Discogs.
|
||||
|
||||
Tags supported by this setting:
|
||||
|
||||
* ``barcode``
|
||||
* ``catalognum``
|
||||
* ``country``
|
||||
* ``label``
|
||||
* ``media``
|
||||
* ``year``
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
discogs:
|
||||
extra_tags: [barcode, catalognum, country, label, media, year]
|
||||
|
||||
.. conf:: anv
|
||||
|
||||
This configuration option is dedicated to handling Artist Name
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ from unittest.mock import Mock, patch
|
|||
import pytest
|
||||
|
||||
from beets import config
|
||||
from beets.library import Item
|
||||
from beets.test._common import Bag
|
||||
from beets.test.helper import BeetsTestCase, capture_log
|
||||
from beetsplug.discogs import ArtistState, DiscogsPlugin
|
||||
|
|
@ -357,6 +358,41 @@ class DGAlbumInfoTest(BeetsTestCase):
|
|||
assert d is None
|
||||
assert "Release does not contain the required fields" in logs[0]
|
||||
|
||||
|
||||
@patch("beetsplug.discogs.DiscogsPlugin.setup", Mock())
|
||||
class DGSearchQueryTest(BeetsTestCase):
|
||||
def test_default_search_filters_without_extra_tags(self):
|
||||
"""Discogs search uses only the type filter when no extra_tags are set."""
|
||||
plugin = DiscogsPlugin()
|
||||
items = [Item()]
|
||||
|
||||
query, filters = plugin.get_search_query_with_filters(
|
||||
"album", items, "Artist", "Album", False
|
||||
)
|
||||
|
||||
assert "Album" in query
|
||||
assert filters == {"type": "release"}
|
||||
|
||||
def test_extra_tags_populate_discogs_filters(self):
|
||||
"""Configured extra_tags should populate Discogs search filters."""
|
||||
config["discogs"]["extra_tags"] = ["label", "catalognum"]
|
||||
plugin = DiscogsPlugin()
|
||||
|
||||
items = [
|
||||
Item(catalognum="ABC 123", label="abc"),
|
||||
Item(catalognum="ABC 123", label="abc"),
|
||||
Item(catalognum="ABC 123", label="def"),
|
||||
]
|
||||
|
||||
_query, filters = plugin.get_search_query_with_filters(
|
||||
"album", items, "Artist", "Album", False
|
||||
)
|
||||
|
||||
assert filters["type"] == "release"
|
||||
assert filters["label"] == "abc"
|
||||
# Catalog number should have whitespace removed.
|
||||
assert filters["catno"] == "ABC123"
|
||||
|
||||
def test_default_genre_style_settings(self):
|
||||
"""Test genre default settings, genres to genre, styles to style"""
|
||||
release = self._make_release_from_positions(["1", "2"])
|
||||
|
|
|
|||
Loading…
Reference in a new issue