From 6ff26d2bbfc7ade30ee0c3e38682ef689b73bda6 Mon Sep 17 00:00:00 2001 From: Wolfgang Müller Date: Tue, 22 Feb 2022 11:35:39 +0100 Subject: Initial commit --- beetsplug/browse.py | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 beetsplug/browse.py (limited to 'beetsplug/browse.py') diff --git a/beetsplug/browse.py b/beetsplug/browse.py new file mode 100644 index 0000000..72999b9 --- /dev/null +++ b/beetsplug/browse.py @@ -0,0 +1,82 @@ +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 -- cgit v1.2.3-2-gb3c3