Remove utils, rework from_plugin method in ArtistState to from_config

This commit is contained in:
Henry 2026-01-18 18:54:47 -08:00
parent 2cfd1df3c1
commit ff95ce5d20
4 changed files with 50 additions and 65 deletions

View file

@ -18,9 +18,11 @@ python3-discogs-client library.
from __future__ import annotations
import http.client
import json
import os
import re
import socket
import time
import traceback
from functools import cache
@ -30,6 +32,7 @@ from typing import TYPE_CHECKING
import confuse
from discogs_client import Client, Master, Release
from discogs_client.exceptions import DiscogsAPIError
from requests.exceptions import ConnectionError
import beets
import beets.ui
@ -38,8 +41,7 @@ from beets.autotag.distance import string_dist
from beets.autotag.hooks import AlbumInfo, TrackInfo
from beets.metadata_plugins import MetadataSourcePlugin
from .states import ArtistState, TracklistState
from .utils import CONNECTION_ERRORS, DISAMBIGUATION_RE, TRACK_INDEX_RE
from .states import DISAMBIGUATION_RE, ArtistState, TracklistState
if TYPE_CHECKING:
from collections.abc import Callable, Iterable, Sequence
@ -53,6 +55,31 @@ API_KEY = "rAzVUQYRaoFjeBjyWuWZ"
API_SECRET = "plxtUTqoCzwxZpqdPysCwGuBSmZNdZVy"
# Exceptions that discogs_client should really handle but does not.
CONNECTION_ERRORS = (
ConnectionError,
socket.error,
http.client.HTTPException,
ValueError, # JSON decoding raises a ValueError.
DiscogsAPIError,
)
TRACK_INDEX_RE = re.compile(
r"""
(.*?) # medium: everything before medium_index.
(\d*?) # medium_index: a number at the end of
# `position`, except if followed by a subtrack index.
# subtrack_index: can only be matched if medium
# or medium_index have been matched, and can be
(
(?<=\w)\.[\w]+ # a dot followed by a string (A.1, 2.A)
| (?<=\d)[A-Z]+ # a string that follows a number (1A, B2a)
)?
""",
re.VERBOSE,
)
class DiscogsPlugin(MetadataSourcePlugin):
def __init__(self):
super().__init__()
@ -304,8 +331,8 @@ class DiscogsPlugin(MetadataSourcePlugin):
artist_data = [a.data for a in result.artists]
# Information for the album artist
albumartist = ArtistState.from_plugin(
self, artist_data, for_album_artist=True
albumartist = ArtistState.from_config(
self.config, artist_data, for_album_artist=True
)
album = re.sub(r" +", " ", result.title)
@ -315,7 +342,8 @@ class DiscogsPlugin(MetadataSourcePlugin):
# information and leave us with skeleton `Artist` objects that will
# each make an API call just to get the same data back.
tracks = self.get_tracks(
result.data["tracklist"], ArtistState.from_plugin(self, artist_data)
result.data["tracklist"],
ArtistState.from_config(self.config, artist_data),
)
# Extract information for the optional AlbumInfo fields, if possible.
@ -611,8 +639,8 @@ class DiscogsPlugin(MetadataSourcePlugin):
length = self.get_track_length(track["duration"])
# If artists are found on the track, we will use those instead
artistinfo = ArtistState.from_plugin(
self,
artistinfo = ArtistState.from_config(
self.config,
[
*(track.get("artists") or albumartistinfo.raw_artists),
*track.get("extraartists", []),

View file

@ -16,6 +16,7 @@
from __future__ import annotations
import re
from dataclasses import asdict, dataclass, field
from functools import cached_property
from typing import TYPE_CHECKING, NamedTuple
@ -23,13 +24,16 @@ from typing import TYPE_CHECKING, NamedTuple
from beets import config
from .types import Artist, ArtistInfo, Track, TracklistInfo
from .utils import DISAMBIGUATION_RE
if TYPE_CHECKING:
from confuse import ConfigView
from beets.autotag.hooks import TrackInfo
from . import DiscogsPlugin
DISAMBIGUATION_RE = re.compile(r" \(\d+\)")
@dataclass
class ArtistState:
@ -170,20 +174,20 @@ class ArtistState:
return artist
@classmethod
def from_plugin(
def from_config(
cls,
plugin: DiscogsPlugin,
config: ConfigView,
artists: list[Artist],
for_album_artist: bool = False,
) -> ArtistState:
return cls(
artists,
plugin.config["anv"][
"album_artist" if for_album_artist else "artist"
].get(bool),
plugin.config["anv"]["artist_credit"].get(bool),
plugin.config["featured_string"].as_str(),
plugin.config["strip_disambiguation"].get(bool),
config["anv"]["album_artist" if for_album_artist else "artist"].get(
bool
),
config["anv"]["artist_credit"].get(bool),
config["featured_string"].as_str(),
config["strip_disambiguation"].get(bool),
)

View file

@ -1,47 +0,0 @@
# This file is part of beets.
# Copyright 2016, Adrian Sampson.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
"""Utility resources for the Discogs plugin."""
import http.client
import re
import socket
from discogs_client.exceptions import DiscogsAPIError
from requests.exceptions import ConnectionError
# Exceptions that discogs_client should really handle but does not.
CONNECTION_ERRORS = (
ConnectionError,
socket.error,
http.client.HTTPException,
ValueError, # JSON decoding raises a ValueError.
DiscogsAPIError,
)
DISAMBIGUATION_RE = re.compile(r" \(\d+\)")
TRACK_INDEX_RE = re.compile(
r"""
(.*?) # medium: everything before medium_index.
(\d*?) # medium_index: a number at the end of
# `position`, except if followed by a subtrack index.
# subtrack_index: can only be matched if medium
# or medium_index have been matched, and can be
(
(?<=\w)\.[\w]+ # a dot followed by a string (A.1, 2.A)
| (?<=\d)[A-Z]+ # a string that follows a number (1A, B2a)
)?
""",
re.VERBOSE,
)

View file

@ -674,7 +674,7 @@ def test_parse_featured_artists(track, expected_artist, expected_artists):
"""Tests the plugins ability to parse a featured artist.
Ignores artists that are not listed as featured."""
plugin = DiscogsPlugin()
artistinfo = ArtistState.from_plugin(plugin, [_artist("ARTIST")])
artistinfo = ArtistState.from_config(plugin.config, [_artist("ARTIST")])
t, _, _ = plugin.get_track_info(track, 1, 1, artistinfo)
assert t.artist == expected_artist
assert t.artists == expected_artists
@ -724,7 +724,7 @@ def test_get_media_and_albumtype(formats, expected_media, expected_albumtype):
def test_va_buildartistinfo(given_artists, expected_info, config_va_name):
config["va_name"] = config_va_name
assert (
ArtistState.from_plugin(DiscogsPlugin(), given_artists).info
ArtistState.from_config(DiscogsPlugin().config, given_artists).info
== expected_info
)