mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 08:39:17 +01:00
playlist: Add playlist auto-update functionality
This commit is contained in:
parent
5b68d88346
commit
6d42028057
1 changed files with 93 additions and 0 deletions
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
import os
|
||||
import fnmatch
|
||||
import tempfile
|
||||
import beets
|
||||
|
||||
|
||||
|
|
@ -86,6 +87,98 @@ class PlaylistPlugin(beets.plugins.BeetsPlugin):
|
|||
def __init__(self):
|
||||
super(PlaylistPlugin, self).__init__()
|
||||
self.config.add({
|
||||
'auto': False,
|
||||
'playlist_dir': '.',
|
||||
'relative_to': 'library',
|
||||
})
|
||||
|
||||
self.playlist_dir = self.config['playlist_dir'].as_filename()
|
||||
self.changes = {}
|
||||
|
||||
if self.config['relative_to'].get() == 'library':
|
||||
self.relative_to = beets.util.bytestring_path(
|
||||
beets.config['directory'].as_filename())
|
||||
elif self.config['relative_to'].get() != 'playlist':
|
||||
print(repr(self.config['relative_to'].get()))
|
||||
self.relative_to = beets.util.bytestring_path(
|
||||
self.config['relative_to'].as_filename())
|
||||
else:
|
||||
self.relative_to = None
|
||||
|
||||
if self.config['auto'].get(bool):
|
||||
self.register_listener('item_moved', self.item_moved)
|
||||
self.register_listener('item_removed', self.item_removed)
|
||||
self.register_listener('cli_exit', self.cli_exit)
|
||||
|
||||
def item_moved(self, item, source, destination):
|
||||
self.changes[source] = destination
|
||||
|
||||
def item_removed(self, item):
|
||||
if not os.path.exists(beets.util.syspath(item.path)):
|
||||
self.changes[item.path] = None
|
||||
|
||||
def cli_exit(self, lib):
|
||||
for playlist in self.find_playlists():
|
||||
self._log.info('Updating playlist: {0}'.format(playlist))
|
||||
base_dir = beets.util.bytestring_path(
|
||||
self.relative_to if self.relative_to
|
||||
else os.path.dirname(playlist)
|
||||
)
|
||||
|
||||
try:
|
||||
self.update_playlist(playlist, base_dir)
|
||||
except beets.util.FilesystemError:
|
||||
self._log.error('Failed to update playlist: {0}'.format(
|
||||
beets.util.displayable_path(playlist)))
|
||||
|
||||
def find_playlists(self):
|
||||
"""Find M3U playlists in the playlist directory."""
|
||||
try:
|
||||
dir_contents = os.listdir(beets.util.syspath(self.playlist_dir))
|
||||
except OSError:
|
||||
self._log.warning('Unable to open playlist directory {0}'.format(
|
||||
beets.util.displayable_path(self.playlist_dir)))
|
||||
return
|
||||
|
||||
for filename in dir_contents:
|
||||
if fnmatch.fnmatch(filename, '*.[mM]3[uU]'):
|
||||
yield os.path.join(self.playlist_dir, filename)
|
||||
|
||||
def update_playlist(self, filename, base_dir):
|
||||
"""Find M3U playlists in the specified directory."""
|
||||
changes = 0
|
||||
deletions = 0
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='w+b') as tempfp:
|
||||
with open(filename, mode='rb') as fp:
|
||||
for line in fp:
|
||||
original_path = line.rstrip(b'\r\n')
|
||||
|
||||
# Ensure that path from playlist is absolute
|
||||
is_relative = not os.path.isabs(beets.util.syspath(line))
|
||||
if is_relative:
|
||||
lookup = os.path.join(base_dir, original_path)
|
||||
else:
|
||||
lookup = original_path
|
||||
|
||||
try:
|
||||
new_path = self.changes[lookup]
|
||||
except KeyError:
|
||||
tempfp.write(line)
|
||||
else:
|
||||
if new_path is None:
|
||||
# Item has been deleted
|
||||
deletions += 1
|
||||
continue
|
||||
|
||||
changes += 1
|
||||
if is_relative:
|
||||
new_path = os.path.relpath(new_path, base_dir)
|
||||
|
||||
tempfp.write(line.replace(original_path, new_path))
|
||||
if changes or deletions:
|
||||
self._log.info(
|
||||
'Updated playlist {0} ({1} changes, {2} deletions)'.format(
|
||||
filename, changes, deletions))
|
||||
tempfp.flush()
|
||||
beets.util.copy(tempfp.name, filename, replace=True)
|
||||
|
|
|
|||
Loading…
Reference in a new issue