From a80a07f093c3a5f77446bd1b6e34bbc4d6d581e3 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 10 Jan 2017 14:42:15 +0000 Subject: [PATCH] playlist: Add playlist plugin Adds M3U playlist support as a query to beets and thus partially resolves issue #123. The implementation is heavily based on #2380 by Robin McCorkell. It supports referencing playlists by absolute path: $ beet ls playlist:/path/to/someplaylist.m3u It also supports referencing playlists by name. The playlist is then seached in the playlist_dir and the ".m3u" extension is appended to the name: $ beet ls playlist:anotherplaylist The configuration for the plugin looks like this: playlist: relative_to: library playlist_dir: /path/to/playlists The relative_to option specifies how relative paths in playlists are handled. By default, paths are relative to the "library" directory. It also possible to make them relative to the "playlist" or set the option or set it to a fixed path. --- beetsplug/playlist.py | 72 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 beetsplug/playlist.py diff --git a/beetsplug/playlist.py b/beetsplug/playlist.py new file mode 100644 index 0000000000..624791ee4a --- /dev/null +++ b/beetsplug/playlist.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +# This file is part of beets. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. + +import os +import beets + + +class PlaylistQuery(beets.dbcore.FieldQuery): + """Matches files listed by a playlist file. + """ + def __init__(self, field, pattern, fast=False): + super(PlaylistQuery, self).__init__(field, pattern, fast) + config = beets.config['playlist'] + + # Get the full path to the playlist + if os.path.isabs(beets.util.syspath(pattern)): + playlist_path = pattern + else: + playlist_path = os.path.abspath(os.path.join( + config['playlist_dir'].as_filename(), + '{0}.m3u'.format(pattern), + )) + + if config['relative_to'].get() == 'library': + relative_to = beets.config['directory'].as_filename() + elif config['relative_to'].get() == 'playlist': + relative_to = os.path.dirname(playlist_path) + else: + relative_to = config['relative_to'].as_filename() + relative_to = beets.util.bytestring_path(relative_to) + + self.paths = [] + with open(beets.util.syspath(playlist_path), 'rb') as f: + for line in f: + if line[0] == '#': + # ignore comments, and extm3u extension + continue + + self.paths.append(beets.util.normpath( + os.path.join(relative_to, line.rstrip()) + )) + + def match(self, item): + return item.path in self.paths + + +class PlaylistType(beets.dbcore.types.String): + """Custom type for playlist query. + """ + query = PlaylistQuery + + +class PlaylistPlugin(beets.plugins.BeetsPlugin): + item_types = {'playlist': PlaylistType()} + + def __init__(self): + super(PlaylistPlugin, self).__init__() + self.config.add({ + 'playlist_dir': '.', + 'relative_to': 'library', + })