Merge pull request #4842 from arsaboo/deezer

Import additional fields from Deezer and add function to update rank
This commit is contained in:
Adrian Sampson 2023-07-14 14:29:44 -07:00 committed by GitHub
commit b19b961035
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 71 additions and 3 deletions

View file

@ -16,19 +16,28 @@
"""
import collections
import time
import unidecode
import requests
import unidecode
from beets import ui
from beets.autotag import AlbumInfo, TrackInfo
from beets.plugins import MetadataSourcePlugin, BeetsPlugin
from beets.dbcore import types
from beets.library import DateType
from beets.plugins import BeetsPlugin, MetadataSourcePlugin
from beets.util.id_extractors import deezer_id_regex
class DeezerPlugin(MetadataSourcePlugin, BeetsPlugin):
data_source = 'Deezer'
item_types = {
'deezer_track_rank': types.INTEGER,
'deezer_track_id': types.INTEGER,
'deezer_updated': DateType(),
}
# Base URLs for the Deezer API
# Documentation: https://developers.deezer.com/api/
search_url = 'https://api.deezer.com/search/'
@ -40,6 +49,19 @@ class DeezerPlugin(MetadataSourcePlugin, BeetsPlugin):
def __init__(self):
super().__init__()
def commands(self):
"""Add beet UI commands to interact with Deezer."""
deezer_update_cmd = ui.Subcommand(
'deezerupdate', help=f'Update {self.data_source} rank')
def func(lib, opts, args):
items = lib.items(ui.decargs(args))
self.deezerupdate(items, ui.should_write())
deezer_update_cmd.func = func
return [deezer_update_cmd]
def album_for_id(self, album_id):
"""Fetch an album by its Deezer ID or URL and return an
AlbumInfo object or None if the album is not found.
@ -54,7 +76,15 @@ class DeezerPlugin(MetadataSourcePlugin, BeetsPlugin):
return None
album_data = requests.get(self.album_url + deezer_id).json()
artist, artist_id = self.get_artist(album_data['contributors'])
if 'error' in album_data:
self._log.debug(f"Error fetching album {album_id}: "
f"{album_data['error']['message']}")
return None
contributors = album_data.get('contributors')
if contributors is not None:
artist, artist_id = self.get_artist(contributors)
else:
artist, artist_id = None, None
release_date = album_data['release_date']
date_parts = [int(part) for part in release_date.split('-')]
@ -113,6 +143,7 @@ class DeezerPlugin(MetadataSourcePlugin, BeetsPlugin):
mediums=max(medium_totals.keys()),
data_source=self.data_source,
data_url=album_data['link'],
cover_art_url=album_data.get('cover_xl'),
)
def _get_track(self, track_data):
@ -129,14 +160,18 @@ class DeezerPlugin(MetadataSourcePlugin, BeetsPlugin):
return TrackInfo(
title=track_data['title'],
track_id=track_data['id'],
deezer_track_id=track_data['id'],
isrc=track_data.get('isrc'),
artist=artist,
artist_id=artist_id,
length=track_data['duration'],
index=track_data.get('track_position'),
medium=track_data.get('disk_number'),
deezer_track_rank=track_data.get('rank'),
medium_index=track_data.get('track_position'),
data_source=self.data_source,
data_url=track_data['link'],
deezer_updated=time.time(),
)
def track_for_id(self, track_id=None, track_data=None):
@ -157,6 +192,10 @@ class DeezerPlugin(MetadataSourcePlugin, BeetsPlugin):
if deezer_id is None:
return None
track_data = requests.get(self.track_url + deezer_id).json()
if 'error' in track_data:
self._log.debug(f"Error fetching track {track_id}: "
f"{track_data['error']['message']}")
return None
track = self._get_track(track_data)
# Get album's tracks to set `track.index` (position on the entire
@ -232,3 +271,27 @@ class DeezerPlugin(MetadataSourcePlugin, BeetsPlugin):
query,
)
return response_data
def deezerupdate(self, items, write):
"""Obtain rank information from Deezer."""
for index, item in enumerate(items, start=1):
self._log.info('Processing {}/{} tracks - {} ',
index, len(items), item)
try:
deezer_track_id = item.deezer_track_id
except AttributeError:
self._log.debug('No deezer_track_id present for: {}', item)
continue
try:
rank = requests.get(
f"{self.track_url}{deezer_track_id}").json().get('rank')
self._log.debug('Deezer track: {} has {} rank',
deezer_track_id, rank)
except Exception as e:
self._log.debug('Invalid Deezer track_id: {}', e)
continue
item.deezer_track_rank = int(rank)
item.store()
item.deezer_updated = time.time()
if write:
item.try_write()

View file

@ -11,6 +11,8 @@ for Python 3.6).
New features:
* :doc:`/plugins/deezer`: Import rank and other attributes from Deezer during import and add a function to update the rank of existing items.
:bug:`4841`
* resolve transl-tracklisting relations for pseudo releases and merge data with the actual release
:bug:`654`
* Fetchart: Use the right field (`spotify_album_id`) to obtain the Spotify album id
@ -95,6 +97,7 @@ New features:
Bug fixes:
* :doc:`/plugins/deezer`: Fixed the error where Deezer plugin would crash if non-Deezer id is passed during import.
* :doc:`/plugins/fetchart`: Fix fetching from Cover Art Archive when the
`maxwidth` option is set to one of the supported Cover Art Archive widths.
* :doc:`/plugins/discogs`: Fix "Discogs plugin replacing Feat. or Ft. with

View file

@ -23,3 +23,5 @@ Configuration
-------------
This plugin can be configured like other metadata source plugins as described in :ref:`metadata-source-plugin-configuration`.
The ``deezer`` plugin provides an additional command ``deezerupdate`` to update the ``rank`` information from Deezer. The ``rank`` (ranges from 0 to 1M) is a global indicator of a song's popularity on Deezer that is updated daily based on streams. The higher the ``rank``, the more popular the track is.