from __future__ import annotations
from typing import TYPE_CHECKING
from ..._shared import TTLCache
from ._shared import DiscogsResourceAPI
if TYPE_CHECKING:
from typing import Any
[docs]
class UsersAPI(DiscogsResourceAPI):
"""
User Identity, User Collection, User Wantlist, and User Lists API
endpoints for the Discogs API.
.. important::
This class is managed by
:class:`~minim.api.discogs.DiscogsAPIClient` and should not be
instantiated directly.
"""
_SORT_FIELDS = {
"added",
"artist",
"catno",
"format",
"label",
"rating",
"title",
"year",
}
__sort__ = ()
[docs]
@TTLCache.cached_method(ttl="static")
def get_my_identity(self) -> dict[str, Any]:
"""
`User Identity > Identity <https://www.discogs.com/developers
/#page:user-identity,header:user-identity-identity>`_: Get the
identity of the current user.
.. admonition:: User authentication
:class: entitlement
.. tab-set::
.. tab-item:: Required
User authentication
Access protected endpoints.
Returns
-------
identity : dict[str, Any]
Identity of the current user.
.. admonition:: Sample response
:class: response dropdown
.. code-block::
{
"consumer_name": <str>,
"id": <int>,
"resource_url": <str>,
"username": <str>
}
"""
self._client._require_authentication("users.get_my_identity")
return self._client._request("GET", "oauth/identity").json()
[docs]
@TTLCache.cached_method(ttl="user")
def get_user(self, username: str | None = None, /) -> dict[str, Any]:
"""
`User Identity > Profile > Get Profile <https://www.discogs.com
/developers/#page:user-identity,header:user-identity-profile>`_:
Get Discogs profile information for a user.
.. admonition:: User authentication
:class: entitlement dropdown
.. tab-set::
.. tab-item:: Optional
User authentication
Access the :code:`email`, :code:`num_list`,
:code:`num_collection`, and :code:`num_wantlist`
keys if authenticated as the requested user.
Parameters
----------
username : str; positional-only; optional
Username of the user. If not specified, the username of the
current user is used. Only optional when authenticated.
**Example**: :code:`"rodneyfool"`.
Returns
-------
user : dict[str, Any]
Discogs profile information for the user.
.. admonition:: Sample response
:class: response dropdown
.. code-block::
{
"activated": <bool>,
"avatar_url": <str>,
"banner_url": <str>,
"buyer_num_ratings": <int>,
"buyer_rating": <float>,
"buyer_rating_stars": <float>,
"collection_fields_url": <str>,
"collection_folders_url": <str>,
"curr_abbr": <str>,
"email": <str>,
"home_page": <str>,
"id": <int>,
"inventory_url": <str>,
"is_staff": <bool>,
"location": <str>,
"marketplace_suspended": <bool>,
"name": <str>,
"num_collection": <int>,
"num_for_sale": <int>,
"num_lists": <int>,
"num_pending": <int>,
"num_unread": <int>,
"num_wantlist": <int>,
"profile": <str>,
"rank": <float>,
"rating_avg": <float>,
"registered": <str>,
"releases_contributed": <int>,
"releases_rated": <int>,
"resource_url": <str>,
"seller_num_ratings": <int>,
"seller_rating": <float>,
"seller_rating_stars": <float>,
"uri": <str>,
"username": <str>,
"wantlist_url": <str>
}
"""
return self._client._request(
"GET", f"users/{self._resolve_username(username)}"
).json()
[docs]
def update_user_profile(
self,
*,
name: str | None = None,
website: str | None = None,
location: str | None = None,
bio: str | None = None,
currency: str | None = None,
username: str | None = None,
) -> dict[str, Any]:
"""
`User Identity > Profile > Edit Profile <https://www.discogs.com
/developers/#page:user-identity,
header:user-identity-profile-post>`_: Update the Deezer profile
information for a user.
.. admonition:: User authentication
:class: entitlement
.. tab-set::
.. tab-item:: Required
User authentication
Access protected endpoints.
.. important::
At least one of :code:`name`, :code:`website`,
:code:`location`, :code:`bio`, or :code:`currency` must be
specified.
Parameters
----------
name : str; keyword-only; optional
Full name.
**Example**: :code:`"Nicolas Cage"`.
website : str; keyword-only; optional
Home page or website.
**Example**: :code:`"www.discogs.com"`.
location : str; keyword-only; optional
Geographical location.
**Example**: :code:`"Portland"`.
bio : str; keyword-only; optional
Biographical information or tagline.
**Example**: :code:`"I am a Discogs user!"`.
currency : str; keyword-only; optional
Currency for marketplace data.
**Valid values**: :code:`"USD"`, :code:`"GBP"`,
:code:`"EUR"`, :code:`"CAD"`, :code:`"AUD"`, :code:`"JPY"`,
:code:`"CHF"`, :code:`"MXN"`, :code:`"BRL"`, :code:`"NZD"`,
:code:`"SEK"`, :code:`"ZAR"`.
username : str; keyword-only; optional
Username of the user. If not specified, the username of the
current user is used.
**Example**: :code:`"vreon"`.
Returns
-------
profile : dict[str, Any]
Updated Discogs profile information for the user.
.. admonition:: Sample resposne
:class: response dropdown
.. code-block::
{
"activated": <bool>,
"avatar_url": <str>,
"banner_url": <str>,
"buyer_num_ratings": <int>,
"buyer_rating": <float>,
"buyer_rating_stars": <float>,
"collection_fields_url": <str>,
"collection_folders_url": <str>,
"curr_abbr": <str>,
"email": <str>,
"home_page": <str>,
"id": <int>,
"inventory_url": <str>,
"is_staff": <bool>,
"location": <str>,
"marketplace_suspended": <bool>,
"name": <str>,
"num_collection": <int>,
"num_for_sale": <int>,
"num_lists": <int>,
"num_pending": <int>,
"num_unread": <int>,
"num_wantlist": <int>,
"profile": <str>,
"rank": <float>,
"rating_avg": <float>,
"registered": <str>,
"releases_contributed": <int>,
"releases_rated": <int>,
"resource_url": <str>,
"seller_num_ratings": <int>,
"seller_rating": <float>,
"seller_rating_stars": <float>,
"uri": <str>,
"username": <str>,
"wantlist_url": <str>
}
"""
self._client._require_authentication("users.update_user_profile")
payload = {}
if name is not None:
payload["name"] = self._prepare_string(
"name", name, allow_blank=True
)
if website is not None:
payload["home_page"] = self._prepare_string(
"website", website, allow_blank=True
)
if location is not None:
payload["location"] = self._prepare_string(
"location", location, allow_blank=True
)
if bio is not None:
self._validate_type("bio", bio, str)
payload["profile"] = bio
if currency is not None:
currency = self._prepare_string("currency", currency).upper()
if currency not in self._CURRENCIES:
raise ValueError(
f"Invalid currency {currency!r}. "
f"Valid values: {self._join_values(self._CURRENCIES)}."
)
payload["curr_abbr"] = currency
if not payload:
raise ValueError("At least one change must be specified.")
return self._client._request(
"POST", f"users/{self._resolve_username(username)}", json=payload
).json()
[docs]
@TTLCache.cached_method(ttl="user")
def get_user_edits(
self,
username: str | None = None,
*,
limit: int | None = None,
page: int | None = None,
) -> dict[str, Any]:
"""
`User Identity > User Submissions <https://www.discogs.com
/developers/#page:user-identity,
header:user-identity-user-submissions>`_: Get Discogs catalog
information for a user's edits to artists, labels, and releases.
Parameters
----------
username : str; optional
Username of the user. If not specified, the username of the
current user is used. Only optional when authenticated.
**Example**: :code:`"shooezgirl"`.
limit : int; keyword-only; optional
Maximum number of edits to return.
**Valid range**: :code:`1` to :code:`100`.
**API default**: :code:`50`.
page : int; keyword-only; optional
Page number. Use with `limit` to get the next page of edits.
**Minimum value**: :code:`1`.
**API default**: :code:`1`.
Returns
-------
edits : dict[str, Any]
Page of Discogs metadata for the user's edits.
.. admonition:: Sample response
:class: response dropdown
.. code-block::
{
"pagination": {
"items": <int>,
"page": <int>,
"pages": <int>,
"per_page": <int>,
"urls": {
"first": <str>,
"last": <str>,
"next": <str>,
"prev": <str>
}
},
"submissions": {
"artists": [
{
"data_quality": <str>,
"id": <int>,
"name": <str>,
"namevariations": <list[str]>,
"releases_url": <str>,
"resource_url": <str>,
"uri": <str>
}
],
"labels": [],
"releases": [
{
"artists": [
{
"anv": <str>,
"id": <int>,
"join": <str>,
"name": <str>,
"resource_url": <str>,
"role": <str>,
"tracks": <str>
}
],
"community": {
"contributors": [
{
"resource_url": <str>,
"username": <str>
}
],
"data_quality": <str>,
"have": <int>,
"rating": {
"average": <int>,
"count": <int>
},
"status": <str>,
"submitter": {
"resource_url": <str>,
"username": <str>
},
"want": <int>
},
"companies": [],
"country": <str>,
"data_quality": <str>,
"date_added": <str>,
"date_changed": <str>,
"estimated_weight": <int>,
"format_quantity": <int>,
"formats": [
{
"descriptions": <list[str]>,
"name": <str>,
"qty": <str>
}
],
"genres": <list[str]>,
"id": <int>,
"images": [
{
"height": <int>,
"resource_url": <str>,
"type": "primary",
"uri": <str>,
"uri150": <str>,
"width": <int>
}
],
"labels": [
{
"catno": <str>,
"entity_type": <str>,
"id": <int>,
"name": <str>,
"resource_url": <str>
}
],
"master_id": <int>,
"master_url": <str>,
"notes": <str>,
"released": <str>,
"released_formatted": <str>,
"resource_url": <str>,
"series": [],
"status": <str>,
"styles": <list[str]>,
"thumb": <str>,
"title": <str>,
"uri": <str>,
"videos": [
{
"description": <str>,
"duration": <int>,
"embed": <bool>,
"title": <str>,
"uri": <str>
}
],
"year": <int>
}
],
}
}
"""
return self._get_paginated_resources(
f"users/{self._resolve_username(username)}/submissions",
limit=limit,
page=page,
)
[docs]
@TTLCache.cached_method(ttl="user")
def get_user_contributions(
self,
username: str | None = None,
*,
limit: int | None = None,
page: int | None = None,
sort_by: str | None = None,
descending: bool | None = None,
) -> dict[str, Any]:
"""
`User Identity > User Contributions <https://www.discogs.com
/developers/#page:user-identity,
header:user-identity-user-contributions>`_: Get Discogs catalog
information for a user's contributions of artists, labels, and
releases.
Parameters
----------
username : str; optional
Username of the user. If not specified, the username of the
current user is used. Only optional when authenticated.
**Example**: :code:`"shooezgirl"`.
limit : int; keyword-only; optional
Maximum number of items to return.
**Valid range**: :code:`1` to :code:`100`.
**API default**: :code:`50`.
page : int; keyword-only; optional
Page number. Use with `limit` to get the next page of items.
**Minimum value**: :code:`1`.
**API default**: :code:`1`.
sort_by : str; keyword-only; optional
Field to sort the returned items by.
**Valid values**: :code:`"label"`, :code:`"artist"`,
:code:`"title"`, :code:`"catno"`, :code:`"format"`,
:code:`"rating"`, :code:`"year"`, :code:`"added"`.
descending : bool; keyword-only; optional
Whether to sort in descending order.
Returns
-------
contributions : dict[str, Any]
Page of Discogs metadata for the user's contributions.
.. admonition:: Sample response
:class: response dropdown
.. code-block::
{
"contributions": [
{
"artists": [
{
"anv": <str>,
"id": <int>,
"join": <str>,
"name": <str>,
"resource_url": <str>,
"role": <str>,
"tracks": <str>
}
],
"community": {
"contributors": [
{
"resource_url": <str>,
"username": <str>
}
],
"data_quality": <str>,
"have": <int>,
"rating": {
"average": <int>,
"count": <int>
},
"status": <str>,
"submitter": {
"resource_url": <str>,
"username": <str>
},
"want": <int>
},
"companies": [],
"country": <str>,
"data_quality": <str>,
"date_added": <str>,
"date_changed": <str>,
"estimated_weight": <int>,
"format_quantity": <int>,
"formats": [
{
"descriptions": <list[str]>,
"name": <str>,
"qty": <str>
}
],
"genres": <list[str]>,
"id": <int>,
"images": [
{
"height": <int>,
"resource_url": <str>,
"type": <str>,
"uri": <str>,
"uri150": <str>,
"width": <int>
}
],
"labels": [
{
"catno": <str>,
"entity_type": <str>,
"id": <int>,
"name": <str>,
"resource_url": <str>
}
],
"master_id": <int>,
"master_url": <str>,
"notes": <str>,
"released": <str>,
"released_formatted": <str>,
"resource_url": <str>,
"series": [],
"status": <str>,
"styles": <list[str]>,
"thumb": <str>,
"title": <str>,
"uri": <str>,
"videos": [
{
"description": <str>,
"duration": <int>,
"embed": <bool>,
"title": <str>,
"uri": <str>
}
],
"year": <int>
}
],
"pagination": {
"items": <int>,
"page": <int>,
"pages": <int>,
"per_page": <int>,
"urls": {
"first": <str>,
"last": <str>,
"next": <str>,
"prev": <str>
}
}
}
"""
params = {}
if sort_by is not None:
sort_by = self._prepare_string("sort_by", sort_by).lower()
if sort_by not in self._SORT_FIELDS:
raise ValueError(
f"Invalid sort field {sort_by!r}. "
f"Valid values: {self._join_values(self._SORT_FIELDS)}."
)
if descending is not None:
self._validate_type("descending", descending, bool)
params["sort_order"] = "desc" if descending else "asc"
return self._get_paginated_resources(
f"users/{self._resolve_username(username)}/contributions",
limit=limit,
page=page,
params=params,
)
[docs]
@TTLCache.cached_method(ttl="user")
def get_user_collection_folders(
self, username: str | None = None
) -> dict[str, Any]:
"""
`User Collection > Collection > Get Collection Folders
<https://www.discogs.com/developers/#page:user-collection,
header:user-collection-collection-get>`_: Get Discogs catalog
information for a user's collection folders.
.. admonition:: User authentication
:class: entitlement dropdown
.. tab-set::
.. tab-item:: Optional
User authentication
Access private collections if authenticated as the
requested user.
Parameters
----------
username : str; optional
Username of the user. If not specified, the username of the
current user is used. Only optional when authenticated.
**Example**: :code:`"rodneyfool"`.
Returns
-------
folders : dict[str, Any]
Discogs metadata for the user's collection folders.
.. admonition:: Sample response
:class: response dropdown
.. code-block::
{
"folders": [
{
"count": <int>,
"id": <int>,
"name": <str>,
"resource_url": <str>
}
]
}
"""
return self._client._request(
"GET",
f"users/{self._resolve_username(username)}/collection/folders",
).json()
[docs]
def create_user_collection_folder(
self, folder_name: str, *, username: str | None = None
) -> dict[str, Any]:
"""
`User Collection > Collection > Create Folder
<https://www.discogs.com/developers/#page:user-collection,
header:user-collection-collection-post>`_: Create a collection
folder.
.. admonition:: User authentication
:class: entitlement
.. tab-set::
.. tab-item:: Required
User authentication
Access protected endpoints.
Parameters
----------
folder_name : str
Folder name.
**Example**: :code:`"My favorites"`.
username : str; keyword-only; optional
Username of the user. If not specified, the username of the
current user is used.
**Example**: :code:`"rodneyfool"`.
Returns
-------
folder : dict[str, Any]
Discogs metadata for the newly created collection folder.
.. admonition:: Sample response
:class: response dropdown
.. code-block::
{
"count": <int>,
"id": <int>,
"name": <str>,
"resource_url": <str>
}
"""
self._client._require_authentication(
"users.create_user_collection_folder"
)
return self._client._request(
"POST",
f"users/{self._resolve_username(username)}/collection/folder",
params={"name": self._prepare_string("folder_name", folder_name)},
).json()
[docs]
@TTLCache.cached_method(ttl="user")
def get_user_collection_folder(
self, folder_id: int | str, /, username: str | None = None
) -> dict[str, Any]:
"""
`User Collection > Collection Folder > Get Folders
<https://www.discogs.com/developers/#page:user-collection,
header:user-collection-collection-folder-get>`_: Get Discogs
catalog information for a user's collection folder.
.. admonition:: User authentication
:class: entitlement dropdown
.. tab-set::
.. tab-item:: Conditional
User authentication
Access collection folders that do not have a
`folder_id` of :code:`0` if authenticated as the
requested user.
Parameters
----------
folder_id : int or str; positional-only
Discogs ID of the collection folder.
**Examples**: :code:`0`, :code:`"3"`.
username : str; optional
Username of the user. If not specified, the username of the
current user is used. Only optional when authenticated.
**Example**: :code:`"rodneyfool"`.
Returns
-------
folder : dict[str, Any]
Discogs metadata for the user's collection folder.
.. admonition:: Sample response
:class: response dropdown
.. code-block::
{
"count": <int>,
"id": <int>,
"name": <str>,
"resource_url": <str>
}
"""
self._validate_numeric("folder_id", folder_id, int, 0)
if int(folder_id) == 0:
self._client._require_authentication(
"users.get_user_collection_folder"
)
return self._client._request(
"GET",
f"users/{self._resolve_username(username)}/collection/folders/{folder_id}",
).json()
[docs]
def rename_user_collection_folder(
self,
folder_id: int | str,
/,
folder_name: str,
*,
username: str | None = None,
) -> dict[str, Any]:
"""
`User Collection > Collection Folder > Edit Folder
<https://www.discogs.com/developers/#page:user-collection,
header:user-collection-collection-folder-post>`_: Rename a
user's collection folder.
.. admonition:: User authentication
:class: entitlement
.. tab-set::
.. tab-item:: Required
User authentication
Access protected endpoints.
Parameters
----------
folder_id : int or str; positional-only
Discogs ID of the collection folder. The "All"
(:code:`folder_id=0`) and "Uncategorized"
(:code:`folder_id=1`) folders cannot be renamed.
**Examples**: :code:`2`, :code:`"3"`.
folder_name : str
New folder name.
**Example**: :code:`"My favorites"`.
username : str; keyword-only; optional
Username of the user. If not specified, the username of the
current user is used.
**Example**: :code:`"rodneyfool"`.
Returns
-------
folder : dict[str, Any]
Discogs metadata for the renamed collection folder.
.. admonition:: Sample response
:class: response dropdown
.. code-block::
{
"count": <int>,
"id": <int>,
"name": <str>,
"resource_url": <str>
}
"""
self._client._require_authentication(
"users.rename_user_collection_folder"
)
self._validate_numeric("folder_id", folder_id, int, 2)
return self._client._request(
"POST",
f"users/{self._resolve_username(username)}/collection/folders/{folder_id}",
json={"name": self._prepare_string("folder_name", folder_name)},
).json()
[docs]
def delete_user_collection_folder(
self, folder_id: int | str, /, username: str | None = None
) -> None:
"""
`User Collection > Collection Folder > Delete Folder
<https://www.discogs.com/developers/#page:user-collection,
header:user-collection-collection-folder-delete>`_: Delete a
user's collection folder.
.. admonition:: User authentication
:class: entitlement
.. tab-set::
.. tab-item:: Required
User authentication
Access protected endpoints.
Parameters
----------
folder_id : int or str; positional-only
Discogs ID of the collection folder.
**Examples**: :code:`2`, :code:`"3"`. The "All"
(:code:`folder_id=0`) and "Uncategorized"
(:code:`folder_id=1`) folders cannot be deleted.
username : str; optional
Username of the user. If not specified, the username of the
current user is used.
**Example**: :code:`"rodneyfool"`.
"""
self._client._require_authentication(
"users.delete_user_collection_folder"
)
self._validate_numeric("folder_id", folder_id, int, 2)
self._client._request(
"DELETE",
f"users/{self._resolve_username(username)}"
f"/collection/folders/{folder_id}",
)
[docs]
@TTLCache.cached_method(ttl="user")
def get_user_collection_release_instances(
self, release_id: int | str, /, username: str | None = None
) -> dict[str, Any]:
"""
`User Collection > Collection Items by Release
<https://www.discogs.com/developers/#page:user-collection,
header:user-collection-collection-items-by-release>`_: Get
Discogs catalog information for instances of a release in a
user's collection.
.. admonition:: User authentication
:class: entitlement dropdown
.. tab-set::
.. tab-item:: Optional
User authentication
Access private collections if authenticated as the
requested user.
Parameters
----------
release_id : int or str; positional-only
Discogs ID of the release.
**Examples**: :code:`772347`, :code:`"7781525"`.
username : str; optional
Username of the user. If not specified, the username of the
current user is used. Only optional when authenticated.
**Example**: :code:`"rodneyfool"`.
Returns
-------
instances : dict[str, Any]
Discogs metadata for the release instances in the user's
collection.
.. admonition:: Sample response
:class: response dropdown
.. code-block::
{
"pagination": {
"items": <int>,
"page": <int>,
"pages": <int>,
"per_page": <int>,
"urls": {
"first": <str>,
"last": <str>,
"next": <str>,
"prev": <str>
}
},
"releases": [
{
"basic_information": {
"artists": [
{
"anv": <str>,
"id": <int>,
"join": <str>,
"name": <str>,
"resource_url": <str>,
"role": <str>,
"tracks": <str>
}
],
"formats": [
{
"descriptions": <list[str]>,
"name": <str>,
"qty": <str>,
"text": <str>
}
],
"genres": <list[str]>,
"id": <int>,
"labels": [
{
"catno": <str>,
"entity_type": <str>,
"entity_type_name": <str>,
"id": <int>,
"name": <str>,
"resource_url": <str>,
}
],
"resource_url": <str>,
"styles": <list[str]>,
"thumb": <str>,
"title": <str>,
"year": <int>,
},
"date_added": <str>,
"folder_id": <int>,
"id": <int>,
"instance_id": <int>,
"notes": [
{
"field_id": <int>,
"value": <str>
}
]
"rating": <int>
},
]
}
"""
self._validate_numeric("release_id", release_id, int, 1)
return self._client._request(
"GET",
f"users/{self._resolve_username(username)}"
f"/collection/releases/{release_id}",
).json()
[docs]
@TTLCache.cached_method(ttl="user")
def get_user_collection_folder_releases(
self,
folder_id: int | str,
/,
username: str | None = None,
*,
limit: int | None = None,
page: int | None = None,
) -> dict[str, Any]:
"""
`User Collection > Collection Items by Folder
<https://www.discogs.com/developers/#page:user-collection,
header:user-collection-collection-items-by-folder>`_: Get
Discogs catalog information for releases in a user's collection
folder.
.. admonition:: User authentication
:class: entitlement dropdown
.. tab-set::
.. tab-item:: Conditional
User authentication
Access collection folders that do not have a
`folder_id` of :code:`0` if authenticated as the
requested user.
Parameters
----------
folder_id : int or str; positional-only
Discogs ID of the collection folder.
**Examples**: :code:`0`, :code:`"3"`.
username : str; optional
Username of the user. If not specified, the username of the
current user is used. Only optional when authenticated.
**Example**: :code:`"rodneyfool"`.
limit : int; keyword-only; optional
Maximum number of releases to return.
**Valid range**: :code:`1` to :code:`100`.
**API default**: :code:`50`.
page : int; keyword-only; optional
Page number. Use with `limit` to get the next page of
releases.
**Minimum value**: :code:`1`.
**API default**: :code:`1`.
Returns
-------
releases : dict[str, Any]
Page of Discogs metadata for the releases in the user's
collection folder.
.. admonition:: Sample response
:class: response dropdown
.. code-block::
{
"pagination": {
"items": <int>,
"page": <int>,
"pages": <int>,
"per_page": <int>,
"urls": {
"first": <str>,
"last": <str>,
"next": <str>,
"prev": <str>
}
},
"releases": [
{
"basic_information": {
"artists": [
{
"anv": <str>,
"id": <int>,
"join": <str>,
"name": <str>,
"resource_url": <str>,
"role": <str>,
"tracks": <str>
}
],
"formats": [
{
"descriptions": <list[str]>,
"name": <str>,
"qty": <str>,
"text": <str>
}
],
"genres": <list[str]>,
"id": <int>,
"labels": [
{
"catno": <str>,
"entity_type": <str>,
"entity_type_name": <str>,
"id": <int>,
"name": <str>,
"resource_url": <str>,
}
],
"resource_url": <str>,
"styles": <list[str]>,
"thumb": <str>,
"title": <str>,
"year": <int>,
},
"date_added": <str>,
"folder_id": <int>,
"id": <int>,
"instance_id": <int>,
"notes": [
{
"field_id": <int>,
"value": <str>
}
]
"rating": <int>
},
]
}
"""
self._validate_numeric("folder_id", folder_id, int, 0)
if int(folder_id) == 0:
self._client._require_authentication(
"users.get_user_collection_folder_releases"
)
return self._get_paginated_resources(
f"users/{self._resolve_username(username)}"
f"/collection/folders/{folder_id}/releases",
limit=limit,
page=page,
)
[docs]
def add_user_collection_release(
self,
folder_id: int | str,
release_id: int | str,
*,
username: str | None = None,
) -> dict[str, Any]:
"""
`User Collection > Add to Collection Folder
<https://www.discogs.com/developers/#page:user-collection,
header:user-collection-add-to-collection-folder>`_: Add a
release to a user's collection folder.
.. admonition:: User authentication
:class: entitlement
.. tab-set::
.. tab-item:: Required
User authentication
Access protected endpoints.
Parameters
----------
folder_id : int or str
Discogs ID of the collection folder. The "All" folder
(:code:`folder_id=0`) is not allowed, but the
"Uncategorized" folder (:code:`folder_id=1`) is.
**Examples**: :code:`1`, :code:`"3"`.
release_id : int or str
Discogs ID of the release.
**Examples**: :code:`772347`, :code:`"7781525"`.
username : str; keyword-only; optional
Username of the user. If not specified, the username of the
current user is used.
**Example**: :code:`"rodneyfool"`.
Returns
-------
instance : dict[str, Any]
Discogs metadata for the newly added release instance.
.. admonition:: Sample response
:class: response dropdown
.. code-block::
{
"instance_id": <int>,
"resource_url": <str>
}
"""
self._client._require_authentication(
"users.add_user_collection_release"
)
self._validate_numeric("folder_id", folder_id, int, 0)
self._validate_numeric("release_id", release_id, int, 1)
return self._client._request(
"POST",
f"users/{self._resolve_username(username)}"
f"/collection/folders/{folder_id}/releases/{release_id}",
).json()
[docs]
def update_user_collection_release_instance(
self,
from_folder_id: int | str,
release_id: int | str,
instance_id: int | str,
*,
to_folder_id: int | str | None = None,
rating: int | None = None,
username: str | None = None,
) -> None:
"""
`User Collection > Change Rating of Release
<https://www.discogs.com/developers/#page:user-collection,
header:user-collection-change-rating-of-release>`_: Update the
rating for a release and/or move a release instance to another
collection folder.
.. admonition:: User authentication
:class: entitlement
.. tab-set::
.. tab-item:: Required
User authentication
Access protected endpoints.
.. important::
Either :code:`to_folder_id` or :code:`rating` must be
specified.
Parameters
----------
from_folder_id : int or str
Discogs ID of the collection folder the release instance is
currently in.
**Examples**: :code:`0`, :code:`"3"`.
release_id : int or str
Discogs ID of the release.
**Examples**: :code:`772347`, :code:`"7781525"`.
instance_id : int or str
Discogs ID of the release instance.
**Examples**: :code:`130076`, :code:`"130077"`.
to_folder_id : int or str; keyword-only; optional
Discogs ID of the collection folder to move the release
instance to.
**Examples**: :code:`0`, :code:`"3"`.
rating : int; keyword-only; optional
Star rating for the release. Use :code:`0` to reset the
rating.
**Valid range**: :code:`0` to :code:`5`.
username : str; keyword-only; optional
Username of the user. If not specified, the username of the
current user is used.
**Example**: :code:`"rodneyfool"`.
"""
self._client._require_authentication(
"users.update_user_collection_release_instance"
)
self._validate_numeric("from_folder_id", from_folder_id, int, 0)
self._validate_numeric("release_id", release_id, int, 1)
self._validate_numeric("instance_id", instance_id, int, 1)
payload = {}
if to_folder_id is not None:
self._validate_numeric("to_folder_id", to_folder_id, int, 0)
payload["folder_id"] = to_folder_id
if rating is not None:
self._validate_number("rating", rating, int, 0, 5)
payload["rating"] = rating
if not payload:
raise RuntimeError("At least one change must be specified.")
return self._client._request(
"POST",
f"users/{self._resolve_username(username)}"
f"/collection/folders/{from_folder_id}"
f"/releases/{release_id}/instances/{instance_id}",
json=payload,
).json()
[docs]
def remove_user_collection_release_instance(
self,
folder_id: int | str,
release_id: int | str,
instance_id: int | str,
*,
username: str | None = None,
) -> None:
"""
`User Collection > Delete Instance from Folder
<https://www.discogs.com/developers/#page:user-collection,
header:user-collection-delete-instance-from-folder>`_: Remove a
release instance from a user's collection folder.
.. admonition:: User authentication
:class: entitlement
.. tab-set::
.. tab-item:: Required
User authentication
Access protected endpoints.
Parameters
----------
folder_id : int or str
Discogs ID of the collection folder.
**Examples**: :code:`0`, :code:`"3"`.
release_id : int or str
Discogs ID of the release.
**Examples**: :code:`772347`, :code:`"7781525"`.
instance_id : int or str
Discogs ID of the release instance.
**Examples**: :code:`130076`, :code:`"130077"`.
username : str; keyword-only; optional
Username of the user. If not specified, the username of the
current user is used.
**Example**: :code:`"rodneyfool"`.
"""
self._client._require_authentication(
"users.remove_user_collection_release_instance"
)
self._validate_numeric("folder_id", folder_id, int, 0)
self._validate_numeric("release_id", release_id, int, 1)
self._validate_numeric("instance_id", instance_id, int, 1)
return self._client._request(
"DELETE",
f"users/{self._resolve_username(username)}"
f"/collection/folders/{folder_id}/releases/{release_id}"
f"/instances/{instance_id}",
)
[docs]
@TTLCache.cached_method(ttl="user")
def get_user_collection_fields(
self, username: str | None = None, /
) -> dict[str, Any]:
"""
`User Collection > List Custom Fields <https://www.discogs.com
/developers/#page:user-collection,
header:user-collection-list-custom-fields>`_: Get
Discogs resource information for user-defined collection note
fields.
.. admonition:: User authentication
:class: entitlement dropdown
.. tab-set::
.. tab-item:: Optional
User authentication
Access private collections if authenticated as the
requested user.
Parameters
----------
username : str; optional
Username of the user. If not specified, the username of the
current user is used. Only optional when authenticated.
**Example**: :code:`"rodneyfool"`.
Returns
-------
fields : dict[str, Any]
Discogs metadata for the collection note fields.
.. admonition:: Sample response
:class: response dropdown
.. code-block::
{
"fields": [
{
"id": <int>,
"name": <str>,
"options": <list[str]>,
"position": <int>,
"public": <bool>,
"type": <str>
}
]
}
"""
return self._client._request(
"GET",
f"users/{self._resolve_username(username)}/collection/fields",
).json()
[docs]
def update_user_collection_release_field(
self,
folder_id: int | str,
release_id: int | str,
instance_id: int | str,
field_id: int | str,
value: str,
*,
username: str | None = None,
) -> None:
"""
`User Collection > Edit Fields Instance <https://www.discogs.com
/developers/#page:user-collection,
header:user-collection-edit-fields-instance>`_: Update a note
field for a release instance in a user's collection.
.. admonition:: User authentication
:class: entitlement
.. tab-set::
.. tab-item:: Required
User authentication
Access protected endpoints.
Parameters
----------
folder_id : int or str
Discogs ID of the collection folder.
**Examples**: :code:`0`, :code:`"3"`.
release_id : int or str
Discogs ID of the release.
**Examples**: :code:`772347`, :code:`"7781525"`.
instance_id : int or str
Discogs ID of the release instance.
**Examples**: :code:`130076`, :code:`"130077"`.
field_id : int or str
Discogs ID of the note field.
**Examples**: :code:`1`, :code:`"2"`.
username : str; keyword-only; optional
Username of the user. If not specified, the username of the
current user is used.
**Example**: :code:`"rodneyfool"`.
"""
self._client._require_authentication(
"users.update_user_collection_release_field"
)
self._validate_numeric("folder_id", folder_id, int, 0)
self._validate_numeric("release_id", release_id, int, 1)
self._validate_numeric("instance_id", instance_id, int, 1)
self._validate_numeric("field_id", field_id, int, 1)
self._validate_type("value", value, str)
self._client._request(
"POST",
f"users/{self._resolve_username(username)}/collection"
f"/folders/{folder_id}/releases/{release_id}"
f"/instances/{instance_id}/fields/{field_id}",
params={"value": value},
)
[docs]
@TTLCache.cached_method(ttl="user")
def get_user_collection_value(
self, username: str | None = None, /
) -> dict[str, Any]:
"""
`User Collection > Collection Value <https://www.discogs.com
/developers/#page:user-collection,
header:user-collection-collection-value>`_: Get the estimated
monetary value of a user's collection.
.. admonition:: User authentication
:class: entitlement
.. tab-set::
.. tab-item:: Required
User authentication
Access private endpoints.
Parameters
----------
username : str; optional
Username of the user. If not specified, the username of the
current user is used.
**Example**: :code:`"rodneyfool"`.
Returns
-------
value : dict[str, Any]
Estimated value of the user's collection.
.. admonition:: Sample response
:class: response dropdown
.. code-block::
{
"maximum": <str>,
"median": <str>,
"minimum": <str>
}
"""
return self._client._request(
"GET",
f"users/{self._resolve_username(username)}/collection/value",
).json()
[docs]
@TTLCache.cached_method(ttl="user")
def get_user_wantlist_releases(
self,
username: str | None = None,
/,
*,
limit: int | None = None,
page: int | None = None,
) -> dict[str, Any]:
"""
`User Wantlist > Wantlist <https://www.discogs.com/developers
/#page:user-wantlist,header:user-wantlist-wantlist>`_: Get
Discogs catalog information for releases in a user's wantlist.
.. admonition:: User authentication
:class: entitlement dropdown
.. tab-set::
.. tab-item:: Optional
User authentication
Access private collections if authenticated as the
requested user.
Parameters
----------
username : str; positional-only; optional
Username of the user. If not specified, the username of the
current user is used. Only optional when authenticated.
**Example**: :code:`"rodneyfool"`.
limit : int; keyword-only; optional
Maximum number of releases to return.
**Valid range**: :code:`1` to :code:`100`.
**API default**: :code:`50`.
page : int; keyword-only; optional
Page number. Use with `limit` to get the next page of
releases.
**Minimum value**: :code:`1`.
**API default**: :code:`1`.
Returns
-------
releases : dict[str, Any]
Page of Discogs metadata for the releases in the user's
wantlist.
.. admonition:: Sample response
:class: response dropdown
.. code-block::
{
"pagination": {
"items": <int>,
"page": <int>,
"pages": <int>,
"per_page": <int>,
"urls": {
"first": <str>,
"last": <str>,
"next": <str>,
"prev": <str>
}
},
"wants": [
{
"basic_information": {
"artists": [
{
"anv": <str>,
"id": <int>,
"join": <str>,
"name": <str>,
"resource_url": <str>,
"role": <str>,
"tracks": <str>
}
],
"formats": [
{
"descriptions": <list[str]>,
"name": <str>,
"qty": <str>,
"text": <str>
}
],
"genres": <list[str]>,
"id": <int>,
"labels": [
{
"catno": <str>,
"entity_type": <str>,
"entity_type_name": <str>,
"id": <int>,
"name": <str>,
"resource_url": <str>,
}
],
"resource_url": <str>,
"styles": <list[str]>,
"thumb": <str>,
"title": <str>,
"year": <int>,
},
"id": <int>,
"notes": <str>,
"rating": <int>
}
]
}
"""
return self._get_paginated_resources(
f"users/{self._resolve_username(username)}/wants",
limit=limit,
page=page,
)
[docs]
def add_user_wantlist_release(
self,
release_id: int | str,
/,
*,
username: str | None = None,
) -> dict[str, Any]:
"""
`User Wantlist > Add to Wantlist > Add to Wantlist
<https://www.discogs.com/developers/#page:user-wantlist,
header:user-wantlist-add-to-wantlist-put>`_: Add a release to a
user's wantlist.
.. admonition:: User authentication
:class: entitlement
.. tab-set::
.. tab-item:: Required
User authentication
Access protected endpoints.
Parameters
----------
release_id : int or str; positional-only
Discogs ID of the release.
**Examples**: :code:`772347`, :code:`"7781525"`.
username : str; keyword-only; optional
Username of the user. If not specified, the username of the
current user is used.
**Example**: :code:`"rodneyfool"`.
Returns
-------
release : dict[str, Any]
Discogs metadata for the newly added release.
.. admonition:: Sample response
:class: response dropdown
.. code-block::
{
"basic_information": {
"artists": [
{
"anv": <str>,
"id": <int>,
"join": <str>,
"name": <str>,
"resource_url": <str>,
"role": <str>,
"tracks": <str>
}
],
"formats": [
{
"descriptions": <list[str]>,
"name": <str>,
"qty": <str>,
"text": <str>
}
],
"genres": <list[str]>,
"id": <int>,
"labels": [
{
"catno": <str>,
"entity_type": <str>,
"entity_type_name": <str>,
"id": <int>,
"name": <str>,
"resource_url": <str>,
}
],
"resource_url": <str>,
"styles": <list[str]>,
"thumb": <str>,
"title": <str>,
"year": <int>,
},
"id": <int>,
"notes": <str>,
"rating": <int>
}
"""
self._client._require_authentication("users.add_user_wantlist_release")
self._validate_numeric("release_id", release_id, int, 1)
return self._client._request(
"PUT",
f"users/{self._resolve_username(username)}/wants/{release_id}",
).json()
[docs]
def update_user_wantlist_release(
self,
release_id: int | str,
/,
*,
notes: str | None = None,
rating: int | None = None,
username: str | None = None,
) -> dict[str, Any]:
"""
`User Wantlist > Add to Wantlist > Edit Release in Wantlist
<https://www.discogs.com/developers/#page:user-wantlist,
header:user-wantlist-add-to-wantlist-post>`_: Update the notes
or rating for a release in a user's wantlist.
.. admonition:: User authentication
:class: entitlement
.. tab-set::
.. tab-item:: Required
User authentication
Access protected endpoints.
Parameters
----------
release_id : int or str; positional-only
Discogs ID of the release.
**Examples**: :code:`772347`, :code:`"7781525"`.
notes : str; keyword-only; optional
User notes to associate with the release.
**Example**: :code:`"My favorite release"`.
rating : int; keyword-only; optional
Star rating for the release.
**Valid range**: :code:`0` to :code:`5`.
**API default**: :code:`0`.
username : str; keyword-only; optional
Username of the user. If not specified, the username of the
current user is used.
**Example**: :code:`"rodneyfool"`.
Returns
-------
release : dict[str, Any]
Discogs metadata for the updated release.
.. admonition:: Sample response
:class: response dropdown
.. code-block::
{
"basic_information": {
"artists": [
{
"anv": <str>,
"id": <int>,
"join": <str>,
"name": <str>,
"resource_url": <str>,
"role": <str>,
"tracks": <str>
}
],
"formats": [
{
"descriptions": <list[str]>,
"name": <str>,
"qty": <str>,
"text": <str>
}
],
"genres": <list[str]>,
"id": <int>,
"labels": [
{
"catno": <str>,
"entity_type": <str>,
"entity_type_name": <str>,
"id": <int>,
"name": <str>,
"resource_url": <str>,
}
],
"resource_url": <str>,
"styles": <list[str]>,
"thumb": <str>,
"title": <str>,
"year": <int>,
},
"id": <int>,
"notes": <str>,
"rating": <int>
}
"""
self._client._require_authentication(
"users.update_user_wantlist_release"
)
self._validate_numeric("release_id", release_id, int, 1)
payload = {}
if notes is not None:
payload["notes"] = self._prepare_string(
"notes", notes, allow_blank=True
)
if rating is not None:
self._validate_number("rating", rating, int, 0, 5)
payload["rating"] = rating
return self._client._request(
"POST",
f"users/{self._resolve_username(username)}/wants/{release_id}",
json=payload,
).json()
[docs]
def remove_user_wantlist_release(
self, release_id: int | str, /, *, username: str | None = None
) -> None:
"""
`User Wantlist > Add to Wantlist > Delete Release from Wantlist
<https://www.discogs.com/developers/#page:user-wantlist,
header:user-wantlist-add-to-wantlist-delete>`_: Remove a release
from a user's wantlist.
.. admonition:: User authentication
:class: entitlement
.. tab-set::
.. tab-item:: Required
User authentication
Access protected endpoints.
Parameters
----------
release_id : int or str; positional-only
Discogs ID of the release.
**Examples**: :code:`772347`, :code:`"7781525"`.
username : str; keyword-only; optional
Username of the user. If not specified, the username of the
current user is used.
**Example**: :code:`"rodneyfool"`.
"""
self._client._require_authentication(
"users.remove_user_wantlist_release"
)
self._client._request(
"DELETE",
f"users/{self._resolve_username(username)}/wants/{release_id}",
)
[docs]
@TTLCache.cached_method(ttl="user")
def get_user_lists(
self,
username: str | None = None,
/,
*,
limit: int | None = None,
page: int | None = None,
) -> dict[str, Any]:
"""
`User Lists > User Lists <https://www.discogs.com/developers
/#page:user-lists,header:user-lists-user-lists>`_: Get
Discogs catalog information for a user's lists.
.. admonition:: User authentication
:class: entitlement dropdown
.. tab-set::
.. tab-item:: Optional
User authentication
Access private collections if authenticated as the
requested user.
Parameters
----------
username : str; positional-only; optional
Username of the user. If not specified, the username of the
current user is used. Only optional when authenticated.
**Example**: :code:`"rodneyfool"`.
limit : int; keyword-only; optional
Maximum number of lists to return.
**Valid range**: :code:`1` to :code:`100`.
**API default**: :code:`50`.
page : int; keyword-only; optional
Page number. Use with `limit` to get the next page of lists.
**Minimum value**: :code:`1`.
**API default**: :code:`1`.
Returns
-------
lists : dict[str, Any]
Page of Discogs metadata for the user's lists.
.. admonition:: Sample response
:class: response dropdown
.. code-block::
{
"lists": [
{
"date_added": <str>,
"date_changed": <str>,
"description": <str>,
"id": <int>,
"image_url": <str>,
"name": <str>,
"public": <bool>,
"resource_url": <str>,
"uri": <str>,
"user": {
"avatar_url": <str>,
"id": <int>,
"resource_url": <str>,
"username": <str>
}
}
],
"pagination": {
"items": <int>,
"page": <int>,
"pages": <int>,
"per_page": <int>,
"urls": {
"first": <str>,
"last": <str>,
"next": <str>,
"prev": <str>
}
}
}
"""
return self._get_paginated_resources(
f"users/{self._resolve_username(username)}/lists",
limit=limit,
page=page,
)
[docs]
@TTLCache.cached_method(ttl="user")
def get_user_list(self, list_id: int | str, /) -> dict[str, Any]:
"""
`User Lists > List <https://www.discogs.com/developers
/#page:user-lists,header:user-lists-list>`_: Get Discogs catalog
information for a user's list and the releases in it.
.. admonition:: User authentication
:class: entitlement dropdown
.. tab-set::
.. tab-item:: Optional
User authentication
Access private collections if authenticated as the
list's owner.
Parameters
----------
list_id : int or str; positional-only
Discogs ID of the list.
**Examples**: :code:`123`, :code:`"321"`.
Returns
-------
list : dict[str, Any]
Discogs metadata for the user's list and the items in it.
.. admonition:: Sample response
:class: response dropdown
.. code-block::
{
"date_added": <str>,
"date_changed": <str>,
"description": <str>,
"id": <int>,
"image_url": <str>,
"items": [
{
"comment": <str>,
"display_title": <str>,
"id": <int>,
"image_url": <str>,
"resource_url": <str>,
"stats": {
"community": {
"in_collection": <int>,
"in_wantlist": <int>
},
"user": {
"in_collection": <int>,
"in_wantlist": <int>
}
},
"type": "release",
"uri": <str>
}
],
"name": <str>,
"public": <bool>,
"resource_url": <str>,
"uri": <str>,
"user": {
"avatar_url": <str>,
"id": <int>,
"resource_url": <str>,
"username": <str>
}
}
"""
self._validate_numeric("list_id", list_id, int, 1)
return self._client._request("GET", f"lists/{list_id}").json()