From 05d54b4f2322c1ef9c19bf0a79e4e1e9ad4ad825 Mon Sep 17 00:00:00 2001 From: Bruno Tournay Date: Sat, 8 Mar 2014 21:21:34 +0100 Subject: [PATCH 1/2] Added ability to also include in playlist result from query based on albums (album_query parameter). --- beetsplug/smartplaylist.py | 29 +++++++++++++++++++++-------- docs/plugins/smartplaylist.rst | 25 +++++++++++++++++-------- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/beetsplug/smartplaylist.py b/beetsplug/smartplaylist.py index 254671094..2a586a3c5 100644 --- a/beetsplug/smartplaylist.py +++ b/beetsplug/smartplaylist.py @@ -36,13 +36,25 @@ def update_playlists(lib): relative_to = normpath(relative_to) for playlist in playlists: - # Parse the query. If it's a list, join the queries with OR. - query_strings = playlist['query'] - if not isinstance(query_strings, (list, tuple)): - query_strings = [query_strings] - items = lib.items(dbcore.OrQuery( - [library.get_query(q, library.Item) for q in query_strings] - )) + items = [] + # Parse album quer(ies). If it's a list, join the queries with OR. + if playlist.has_key('album_query'): + query_strings = playlist['album_query'] + if not isinstance(query_strings, (list, tuple)): + query_strings = [query_strings] + matching_albums = lib.albums(dbcore.OrQuery( + [library.get_query(q, library.Album) for q in query_strings] + )) + for album in matching_albums: + items.extend(album.items()) + # Parse item quer(ies). If it's a list, join the queries with OR. + if playlist.has_key('query'): + query_strings = playlist['query'] + if not isinstance(query_strings, (list, tuple)): + query_strings = [query_strings] + items.extend(lib.items(dbcore.OrQuery( + [library.get_query(q, library.Item) for q in query_strings] + ))) m3us = {} basename = playlist['name'].encode('utf8') @@ -55,7 +67,8 @@ def update_playlists(lib): item_path = item.path if relative_to: item_path = os.path.relpath(item.path, relative_to) - m3us[m3u_name].append(item_path) + if not item_path in m3us[m3u_name]: + m3us[m3u_name].append(item_path) # Now iterate through the m3us that we need to generate for m3u in m3us: m3u_path = normpath(os.path.join(playlist_dir, m3u)) diff --git a/docs/plugins/smartplaylist.rst b/docs/plugins/smartplaylist.rst index 0ee62eb92..05a1c8c7a 100644 --- a/docs/plugins/smartplaylist.rst +++ b/docs/plugins/smartplaylist.rst @@ -15,11 +15,11 @@ following example:: relative_to: ~/Music playlist_dir: ~/.mpd/playlists playlists: - - query: '' - name: all.m3u + - name: all.m3u + query: '' - - query: 'artist:Beatles' - name: beatles.m3u + - name: beatles.m3u + query: 'artist:Beatles' If you intend to use this plugin to generate playlists for MPD, you should set ``relative_to`` to your MPD music directory (by default, ``relative_to`` is @@ -38,8 +38,8 @@ will be overwritten when the plugin runs. For more advanced usage, you can use template syntax (see :doc:`/reference/pathformat/`) in the ``name`` field. For example:: - - query: 'year::201(0|1)' - name: 'ReleasedIn$year.m3u' + - name: 'ReleasedIn$year.m3u' + query: 'year::201(0|1)' This will query all the songs in 2010 and 2011 and generate the two playlist files `ReleasedIn2010.m3u` and `ReleasedIn2011.m3u` using those songs. @@ -47,8 +47,17 @@ files `ReleasedIn2010.m3u` and `ReleasedIn2011.m3u` using those songs. You can also gather the results of several queries by putting them in a list. (Items that match both queries are not included twice.) For example:: - - query: ['artist:beatles', 'genre:"beatles cover"'] - name: 'BeatlesUniverse.m3u' + - name: 'BeatlesUniverse.m3u' + query: ['artist:beatles', 'genre:"beatles cover"'] + +For querying albums instead of items (mainly useful with extensible fields), +use the ``album_query`` field. ``query`` and ``album_query`` can be used at the +same time. The following example gathers single items but also items belonging +to albums that have a ``for_travel`` extensible field set to 1:: + + - name: 'MyTravelPlaylist.m3u' + album_query: 'for_travel:1' + query: 'for_travel:1' By default, all playlists are regenerated after every beets command that changes the library database. To force regeneration, you can invoke it manually From 8a73a173df69a4a5243710f3e28e0f2caa110e12 Mon Sep 17 00:00:00 2001 From: Bruno Tournay Date: Sun, 9 Mar 2014 20:15:51 +0100 Subject: [PATCH 2/2] Attempt to factorize duplicate code --- beetsplug/smartplaylist.py | 42 ++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/beetsplug/smartplaylist.py b/beetsplug/smartplaylist.py index 2a586a3c5..ff8d0ed11 100644 --- a/beetsplug/smartplaylist.py +++ b/beetsplug/smartplaylist.py @@ -27,6 +27,28 @@ import os database_changed = False +def query_from_parameter(lib, playlist, parameter, album=False): + if playlist.has_key(parameter): + # Parse quer(ies). If it's a list, join the queries with OR. + query_strings = playlist[parameter] + if not isinstance(query_strings, (list, tuple)): + query_strings = [query_strings] + model = library.Album if album else library.Item + query = dbcore.OrQuery( + [library.get_query(q, model) for q in query_strings] + ) + # Execute query, depending on type + if album: + result = [] + for album in lib.albums(query): + result.extend(album.items()) + return result + else: + return lib.items(query) + else: + return [] + + def update_playlists(lib): ui.print_("Updating smart playlists...") playlists = config['smartplaylist']['playlists'].get(list) @@ -37,24 +59,8 @@ def update_playlists(lib): for playlist in playlists: items = [] - # Parse album quer(ies). If it's a list, join the queries with OR. - if playlist.has_key('album_query'): - query_strings = playlist['album_query'] - if not isinstance(query_strings, (list, tuple)): - query_strings = [query_strings] - matching_albums = lib.albums(dbcore.OrQuery( - [library.get_query(q, library.Album) for q in query_strings] - )) - for album in matching_albums: - items.extend(album.items()) - # Parse item quer(ies). If it's a list, join the queries with OR. - if playlist.has_key('query'): - query_strings = playlist['query'] - if not isinstance(query_strings, (list, tuple)): - query_strings = [query_strings] - items.extend(lib.items(dbcore.OrQuery( - [library.get_query(q, library.Item) for q in query_strings] - ))) + items.extend(query_from_parameter(lib, playlist, 'album_query', True)) + items.extend(query_from_parameter(lib, playlist, 'query', False)) m3us = {} basename = playlist['name'].encode('utf8')