Merge pull request #80 from dangmai/smartplaylist

Smart Playlist plugin
This commit is contained in:
Adrian Sampson 2013-01-31 09:45:40 -08:00
commit 615b0decfa
3 changed files with 144 additions and 0 deletions

View file

@ -0,0 +1,91 @@
# This file is part of beets.
# Copyright 2013, Dang Mai <contact@dangmai.net>.
#
# 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.
"""Generates smart playlists based on beets queries.
"""
from __future__ import print_function
from beets.plugins import BeetsPlugin
from beets import config, ui
from beets.util import normpath, syspath
import os
# Global variables so that smartplaylist can detect database changes and run
# only once before beets exits.
database_changed = False
library = None
def update_playlists(lib):
from beets.util.functemplate import Template
print("Updating smart playlists...")
playlists = config['smartplaylist']['playlists'].get(list)
playlist_dir = config['smartplaylist']['playlist_dir'].get(unicode)
relative_to = config['smartplaylist']['relative_to'].get()
if relative_to:
relative_to = normpath(relative_to)
for playlist in playlists:
items = lib.items(playlist['query'])
m3us = {}
basename = playlist['name'].encode('utf8')
# As we allow tags in the m3u names, we'll need to iterate through
# the items and generate the correct m3u file names.
for item in items:
m3u_name = item.evaluate_template(Template(basename), lib=lib)
if not (m3u_name in m3us):
m3us[m3u_name] = []
if relative_to:
m3us[m3u_name].append(os.path.relpath(item.path, relative_to))
else:
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))
with open(syspath(m3u_path), 'w') as f:
for path in m3us[m3u]:
f.write(path + '\n')
print("... Done")
class SmartPlaylistPlugin(BeetsPlugin):
def __init__(self):
super(SmartPlaylistPlugin, self).__init__()
self.config.add({
'relative_to': None,
'playlist_dir': u'.',
'playlists': []
})
def commands(self):
def update(lib, opts, args):
update_playlists(lib)
spl_update = ui.Subcommand('splupdate',
help='update the smart playlists')
spl_update.func = update
return [spl_update]
@SmartPlaylistPlugin.listen('database_change')
def handle_change(lib):
global library
global database_changed
library = lib
database_changed = True
@SmartPlaylistPlugin.listen('cli_exit')
def update():
if database_changed:
update_playlists(library)

View file

@ -59,6 +59,7 @@ disabled by default, but you can turn them on as described above.
ihate
convert
info
smartplaylist
Autotagger Extensions
''''''''''''''''''''''
@ -92,6 +93,7 @@ Interoperability
* :doc:`mpdupdate`: Automatically notifies `MPD`_ whenever the beets library
changes.
* :doc:`importfeeds`: Keep track of imported files via ``.m3u`` playlist file(s) or symlinks.
* :doc:`smartplaylist`: Generate smart playlists based on beets queries.
Miscellaneous
'''''''''''''

View file

@ -0,0 +1,51 @@
Smart Playlist Plugin
=====================
``smartplaylist`` is a plugin to generate smart playlists in m3u format based on
beets queries every time your library changes. This plugin is specifically
created to work well with `MPD`_'s playlist functionality.
.. _MPD: http://mpd.wikia.com/wiki/Music_Player_Daemon_Wiki
To use it, enable the plugin by putting ``smartplaylist`` in the ``plugins``
section in your ``config.yaml``. Then configure your smart playlists like the
following example::
smartplaylist:
relative_to: ~/Music
playlist_dir: ~/.mpd/playlists
playlists:
- query: ''
name: all.m3u
- query: 'artist:Beatles'
name: beatles.m3u
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
``None``, and the absolute paths to your music files will be generated).
``playlist_dir`` is where the generated playlist files will be put.
You can generate as many playlists as you want by adding them to the
``playlists`` section, using the normal querying format (see
:doc:`/reference/query`) for ``query`` and the file name to be generated for
``name`` (*note*: if you have existing files with the same names, you should
back them up, as they will be overwritten when the plugin runs).
For more advanced usage, you can also specify metadata (see
:doc:`/reference/pathformat/`) in the ``name`` field, for example::
- query: 'year::201(0|1)'
name: 'ReleasedIn$year.m3u'
This will query all the songs in 2010 and 2011, and generate the 2 playlist
files `ReleasedIn2010.m3u` and `ReleasedIn2011.m3u` using those songs.
If you add a smart playlist to your ``config.yaml`` file and don't want to wait
until the next time your library changes for ``smartplugin`` to run, you can
invoke it manually from the command-line::
$ beet splupdate
which will generate your new smart playlists.