Update vendored beets to 1.6.0

Updates colorama to 0.4.6
Adds confuse version 1.7.0
Updates jellyfish to 0.9.0
Adds mediafile 0.10.1
Updates munkres to 1.1.4
Updates musicbrainzngs to 0.7.1
Updates mutagen to 1.46.0
Updates pyyaml to 6.0
Updates unidecode to 1.3.6
This commit is contained in:
Labrys of Knossos 2022-11-28 18:02:40 -05:00
commit 56c6773c6b
385 changed files with 25143 additions and 18080 deletions

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# This file is part of beets.
# Copyright 2016, Peter Schnebel and Johann Klähn.
#
@ -13,11 +12,8 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import division, absolute_import, print_function
import mpd
import socket
import select
import time
import os
@ -45,14 +41,21 @@ def is_url(path):
return path.split('://', 1)[0] in ['http', 'https']
class MPDClientWrapper(object):
class MPDClientWrapper:
def __init__(self, log):
self._log = log
self.music_directory = (
mpd_config['music_directory'].as_str())
self.music_directory = mpd_config['music_directory'].as_str()
self.strip_path = mpd_config['strip_path'].as_str()
self.client = mpd.MPDClient(use_unicode=True)
# Ensure strip_path end with '/'
if not self.strip_path.endswith('/'):
self.strip_path += '/'
self._log.debug('music_directory: {0}', self.music_directory)
self._log.debug('strip_path: {0}', self.strip_path)
self.client = mpd.MPDClient()
def connect(self):
"""Connect to the MPD.
@ -63,11 +66,11 @@ class MPDClientWrapper(object):
if host[0] in ['/', '~']:
host = os.path.expanduser(host)
self._log.info(u'connecting to {0}:{1}', host, port)
self._log.info('connecting to {0}:{1}', host, port)
try:
self.client.connect(host, port)
except socket.error as e:
raise ui.UserError(u'could not connect to MPD: {0}'.format(e))
except OSError as e:
raise ui.UserError(f'could not connect to MPD: {e}')
password = mpd_config['password'].as_str()
if password:
@ -75,7 +78,7 @@ class MPDClientWrapper(object):
self.client.password(password)
except mpd.CommandError as e:
raise ui.UserError(
u'could not authenticate to MPD: {0}'.format(e)
f'could not authenticate to MPD: {e}'
)
def disconnect(self):
@ -90,12 +93,12 @@ class MPDClientWrapper(object):
"""
try:
return getattr(self.client, command)()
except (select.error, mpd.ConnectionError) as err:
self._log.error(u'{0}', err)
except (OSError, mpd.ConnectionError) as err:
self._log.error('{0}', err)
if retries <= 0:
# if we exited without breaking, we couldn't reconnect in time :(
raise ui.UserError(u'communication with MPD server failed')
raise ui.UserError('communication with MPD server failed')
time.sleep(RETRY_INTERVAL)
@ -107,18 +110,26 @@ class MPDClientWrapper(object):
self.connect()
return self.get(command, retries=retries - 1)
def playlist(self):
"""Return the currently active playlist. Prefixes paths with the
music_directory, to get the absolute path.
def currentsong(self):
"""Return the path to the currently playing song, along with its
songid. Prefixes paths with the music_directory, to get the absolute
path.
In some cases, we need to remove the local path from MPD server,
we replace 'strip_path' with ''.
`strip_path` defaults to ''.
"""
result = {}
for entry in self.get('playlistinfo'):
result = None
entry = self.get('currentsong')
if 'file' in entry:
if not is_url(entry['file']):
result[entry['id']] = os.path.join(
self.music_directory, entry['file'])
file = entry['file']
if file.startswith(self.strip_path):
file = file[len(self.strip_path):]
result = os.path.join(self.music_directory, file)
else:
result[entry['id']] = entry['file']
return result
result = entry['file']
self._log.debug('returning: {0}', result)
return result, entry.get('id')
def status(self):
"""Return the current status of the MPD.
@ -132,7 +143,7 @@ class MPDClientWrapper(object):
return self.get('idle')
class MPDStats(object):
class MPDStats:
def __init__(self, lib, log):
self.lib = lib
self._log = log
@ -164,7 +175,7 @@ class MPDStats(object):
if item:
return item
else:
self._log.info(u'item not found: {0}', displayable_path(path))
self._log.info('item not found: {0}', displayable_path(path))
def update_item(self, item, attribute, value=None, increment=None):
"""Update the beets item. Set attribute to value or increment the value
@ -182,7 +193,7 @@ class MPDStats(object):
item[attribute] = value
item.store()
self._log.debug(u'updated: {0} = {1} [{2}]',
self._log.debug('updated: {0} = {1} [{2}]',
attribute,
item[attribute],
displayable_path(item.path))
@ -229,29 +240,31 @@ class MPDStats(object):
"""Updates the play count of a song.
"""
self.update_item(song['beets_item'], 'play_count', increment=1)
self._log.info(u'played {0}', displayable_path(song['path']))
self._log.info('played {0}', displayable_path(song['path']))
def handle_skipped(self, song):
"""Updates the skip count of a song.
"""
self.update_item(song['beets_item'], 'skip_count', increment=1)
self._log.info(u'skipped {0}', displayable_path(song['path']))
self._log.info('skipped {0}', displayable_path(song['path']))
def on_stop(self, status):
self._log.info(u'stop')
self._log.info('stop')
if self.now_playing:
# if the current song stays the same it means that we stopped on the
# current track and should not record a skip.
if self.now_playing and self.now_playing['id'] != status.get('songid'):
self.handle_song_change(self.now_playing)
self.now_playing = None
def on_pause(self, status):
self._log.info(u'pause')
self._log.info('pause')
self.now_playing = None
def on_play(self, status):
playlist = self.mpd.playlist()
path = playlist.get(status['songid'])
path, songid = self.mpd.currentsong()
if not path:
return
@ -276,16 +289,17 @@ class MPDStats(object):
self.handle_song_change(self.now_playing)
if is_url(path):
self._log.info(u'playing stream {0}', displayable_path(path))
self._log.info('playing stream {0}', displayable_path(path))
self.now_playing = None
return
self._log.info(u'playing {0}', displayable_path(path))
self._log.info('playing {0}', displayable_path(path))
self.now_playing = {
'started': time.time(),
'remaining': remaining,
'path': path,
'started': time.time(),
'remaining': remaining,
'path': path,
'id': songid,
'beets_item': self.get_item(path),
}
@ -305,7 +319,7 @@ class MPDStats(object):
if handler:
handler(status)
else:
self._log.debug(u'unhandled status "{0}"', status)
self._log.debug('unhandled status "{0}"', status)
events = self.mpd.events()
@ -313,37 +327,38 @@ class MPDStats(object):
class MPDStatsPlugin(plugins.BeetsPlugin):
item_types = {
'play_count': types.INTEGER,
'skip_count': types.INTEGER,
'play_count': types.INTEGER,
'skip_count': types.INTEGER,
'last_played': library.DateType(),
'rating': types.FLOAT,
'rating': types.FLOAT,
}
def __init__(self):
super(MPDStatsPlugin, self).__init__()
super().__init__()
mpd_config.add({
'music_directory': config['directory'].as_filename(),
'rating': True,
'rating_mix': 0.75,
'host': os.environ.get('MPD_HOST', u'localhost'),
'port': 6600,
'password': u'',
'strip_path': '',
'rating': True,
'rating_mix': 0.75,
'host': os.environ.get('MPD_HOST', 'localhost'),
'port': int(os.environ.get('MPD_PORT', 6600)),
'password': '',
})
mpd_config['password'].redact = True
def commands(self):
cmd = ui.Subcommand(
'mpdstats',
help=u'run a MPD client to gather play statistics')
help='run a MPD client to gather play statistics')
cmd.parser.add_option(
u'--host', dest='host', type='string',
help=u'set the hostname of the server to connect to')
'--host', dest='host', type='string',
help='set the hostname of the server to connect to')
cmd.parser.add_option(
u'--port', dest='port', type='int',
help=u'set the port of the MPD server to connect to')
'--port', dest='port', type='int',
help='set the port of the MPD server to connect to')
cmd.parser.add_option(
u'--password', dest='password', type='string',
help=u'set the password of the MPD server to connect to')
'--password', dest='password', type='string',
help='set the password of the MPD server to connect to')
def func(lib, opts, args):
mpd_config.set_args(opts)