import subprocess import uuid import webbrowser from beets.plugins import BeetsPlugin from beets.ui import Subcommand, UserError MUSICBRAINZ_LOOKUP='https://musicbrainz.org/otherlookup/mbid?other-lookup.mbid=' FIELD_NAMES = ['albumartist', 'album', 'artist', 'releasegroup', 'releasetrack', 'track', 'work'] class BrowsePlugin(BeetsPlugin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def commands(self): return [BrowseCommand(self.config)] class BrowseCommand(Subcommand): explorer = 'thunar' def __init__(self, config): super().__init__('browse', parser=None, help='browse items on MusicBrainz or the file system') self.parser.add_option('-f', '--field', type='string', help='which field to look up on MusicBrainz, ' 'e.g. album, artist, track, work, ...') self.parser.add_option('-o', '--open', action='store_true', help='open in the file browser instead of MusicBrainz') self.parser.add_album_option() if 'explorer' in config: self.explorer = config['explorer'].get() # pylint: disable=no-self-use def browse_musicbrainz(self, item, field): mbid = item.get(f'mb_{field}id') if not mbid: raise UserError(f'\'mb_{field}id\' not available for: {item}') try: uuid.UUID(mbid) except ValueError: raise UserError(f'invalid UUID "{mbid}" for: {item}') from None webbrowser.open(MUSICBRAINZ_LOOKUP + mbid) def browse_filesystem(self, item, _): try: subprocess.Popen(self.explorer.split(' ') + [item.get('path')]) # pylint: disable=consider-using-with except OSError as err: raise UserError(err) from err def func(self, lib, opts, args): queryfun = lib.albums if opts.album else lib.items browsefun = self.browse_filesystem if opts.open else self.browse_musicbrainz field = opts.field or ('album' if opts.album else 'track') if field not in FIELD_NAMES: raise UserError(f'invalid field "{field}", try one of: {", ".join(FIELD_NAMES)}') if not args: raise UserError('empty query, refusing') items = queryfun(args) if not items: return if len(items) == 1: browsefun(items[0], field) return print('Query returned multiple matches, please disambiguate:') for index, item in enumerate(items): if index < 5: print(item) else: print(f'[{len(items) - index} more]') return