mirror of
https://github.com/beetbox/beets.git
synced 2026-02-17 12:56:05 +01:00
Implement and test attach command
This commit is contained in:
parent
8852bd24d0
commit
acf9e21dc3
4 changed files with 148 additions and 3 deletions
|
|
@ -15,8 +15,10 @@
|
|||
|
||||
import re
|
||||
import urlparse
|
||||
import optparse
|
||||
from argparse import ArgumentParser
|
||||
|
||||
from beets.plugins import find_plugins
|
||||
from beets import dbcore
|
||||
from beets.dbcore.query import Query, AndQuery
|
||||
|
||||
|
|
@ -232,9 +234,12 @@ class AttachmentFactory(object):
|
|||
"""
|
||||
self._collectors.append(collector)
|
||||
|
||||
def register_plugin(self, plugin):
|
||||
self.register_discoverer(plugin.attachment_discoverer)
|
||||
self.register_collector(plugin.attachment_collector)
|
||||
def register_plugins(self, plugins):
|
||||
for plugin in plugins:
|
||||
if hasattr(plugin, 'attachment_discoverer'):
|
||||
self.register_discoverer(plugin.attachment_discoverer)
|
||||
if hasattr(plugin, 'attachment_collector'):
|
||||
self.register_collector(plugin.attachment_collector)
|
||||
|
||||
def _discover_types(self, path):
|
||||
types = []
|
||||
|
|
@ -252,6 +257,8 @@ class AttachmentFactory(object):
|
|||
all_meta = {}
|
||||
for collector in self._collectors:
|
||||
try:
|
||||
# TODO maybe we should provide file handle for checking
|
||||
# content
|
||||
meta = collector(type, path)
|
||||
if isinstance(meta, dict):
|
||||
all_meta.update(meta)
|
||||
|
|
@ -300,7 +307,54 @@ class AttachmentCommand(ArgumentParser):
|
|||
pass
|
||||
|
||||
|
||||
class AttachCommand(object):
|
||||
"""Duck type for ui.Subcommand
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.name = 'attach'
|
||||
self.parser = optparse.OptionParser()
|
||||
self.aliases = ()
|
||||
self.help = 'create an attachment for an album or a ' \
|
||||
'track and move the attachment'
|
||||
self.hide = False
|
||||
|
||||
self.parser.add_option(
|
||||
'-c', '--copy', action='store_true', dest='copy',
|
||||
help='copy attachment intead of moving them'
|
||||
)
|
||||
self.parser.add_option(
|
||||
'--track', action='store_true', dest='track',
|
||||
help='attach path to the tracks matched by the query'
|
||||
)
|
||||
self.parser.add_option(
|
||||
'-t', '--type', dest='type',
|
||||
help='create one attachment with this type',
|
||||
)
|
||||
|
||||
def func(self, lib, opts, args):
|
||||
# FIXME prevents circular dependency
|
||||
from beets.ui import decargs
|
||||
factory = AttachmentFactory(lib)
|
||||
factory.register_plugins(find_plugins())
|
||||
path = args.pop(0)
|
||||
|
||||
if opts.track:
|
||||
entities = lib.items(decargs(args))
|
||||
else:
|
||||
entities = lib.albums(decargs(args))
|
||||
|
||||
for entity in entities:
|
||||
if opts.type:
|
||||
factory.create(path, opts.type, entity).add()
|
||||
else:
|
||||
for attachment in factory.discover(path, entity):
|
||||
attachment.add()
|
||||
|
||||
|
||||
class AttachmentRefQuery(Query):
|
||||
"""Matches any attachment whose entity is `entity`.
|
||||
"""
|
||||
|
||||
def __init__(self, entity):
|
||||
self.entity = entity
|
||||
|
|
@ -314,6 +368,8 @@ class AttachmentRefQuery(Query):
|
|||
|
||||
|
||||
class AttachmentEntityQuery(Query):
|
||||
"""Matches any attachment whose entity matches `entity_query`.
|
||||
"""
|
||||
|
||||
def __init__(self, entity_query):
|
||||
self.query = entity_query
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ from beets.util import syspath, normpath, ancestry, displayable_path
|
|||
from beets.util.functemplate import Template
|
||||
from beets import library
|
||||
from beets import config
|
||||
from beets import attachments
|
||||
from beets.util.confit import _package_path
|
||||
|
||||
VARIOUS_ARTISTS = u'Various Artists'
|
||||
|
|
@ -78,6 +79,9 @@ def _do_query(lib, query, album, also_items=True):
|
|||
return items, albums
|
||||
|
||||
|
||||
default_commands.append(attachments.AttachCommand())
|
||||
|
||||
|
||||
# fields: Shows a list of available fields for queries and format strings.
|
||||
|
||||
def fields_func(lib, opts, args):
|
||||
|
|
|
|||
|
|
@ -170,6 +170,14 @@ class TestHelper(object):
|
|||
beets.plugins.load_plugins(plugins)
|
||||
beets.plugins.find_plugins()
|
||||
|
||||
def add_plugin(self, plugin):
|
||||
"""Add a plugin instance to the list returned by
|
||||
`plugins.find_plugins()`.
|
||||
"""
|
||||
def create_plugin():
|
||||
return plugin
|
||||
beets.plugins._classes.add(create_plugin)
|
||||
|
||||
def unload_plugins(self):
|
||||
"""Unload all plugins and remove the from the configuration.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -13,8 +13,13 @@
|
|||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
|
||||
import os
|
||||
from tempfile import mkstemp
|
||||
from _common import unittest
|
||||
from helper import TestHelper
|
||||
|
||||
import beets.ui
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.attachments import AttachmentFactory
|
||||
from beets.library import Library, Album, Item
|
||||
|
||||
|
|
@ -87,6 +92,78 @@ class EntityAttachmentsTest(unittest.TestCase):
|
|||
[attachment.id])
|
||||
|
||||
|
||||
class AttachCommandTest(unittest.TestCase, TestHelper):
|
||||
|
||||
def setUp(self):
|
||||
self.setup_beets()
|
||||
self.setup_log_attachment_plugin()
|
||||
self.tmp_files = []
|
||||
|
||||
def tearDown(self):
|
||||
self.teardown_beets()
|
||||
self.unload_plugins()
|
||||
for p in self.tmp_files:
|
||||
os.remove(p)
|
||||
|
||||
def test_attach_to_album(self):
|
||||
album = Album(album='albumtitle')
|
||||
self.lib.add(album)
|
||||
|
||||
attachment_path = self.mkstemp('.log')
|
||||
self.runcli('attach', attachment_path, 'albumtitle')
|
||||
attachment = album.attachments().get()
|
||||
self.assertEqual(attachment.type, 'log')
|
||||
|
||||
def test_attach_to_album_and_move(self):
|
||||
self.skipTest('Not implemented')
|
||||
|
||||
def test_file_relative_to_album_dir(self):
|
||||
self.skipTest('Not implemented')
|
||||
|
||||
def test_attach_to_item(self):
|
||||
item = Item(title='tracktitle')
|
||||
self.lib.add(item)
|
||||
|
||||
attachment_path = self.mkstemp('.log')
|
||||
self.runcli('attach', '--track', attachment_path, 'tracktitle')
|
||||
attachment = item.attachments().get()
|
||||
self.assertEqual(attachment.type, 'log')
|
||||
|
||||
def test_attach_to_item_and_move(self):
|
||||
self.skipTest('Not implemented')
|
||||
|
||||
def test_user_type(self):
|
||||
album = Album(album='albumtitle')
|
||||
self.lib.add(album)
|
||||
|
||||
attachment_path = self.mkstemp()
|
||||
self.runcli('attach', '-t', 'customtype', attachment_path, 'albumtitle')
|
||||
attachment = album.attachments().get()
|
||||
self.assertEqual(attachment.type, 'customtype')
|
||||
|
||||
def test_unknown_warning(self):
|
||||
self.skipTest('Not implemented')
|
||||
|
||||
# Helpers
|
||||
|
||||
def runcli(self, *args):
|
||||
beets.ui._raw_main(list(args), self.lib)
|
||||
|
||||
def mkstemp(self, suffix=''):
|
||||
(handle, path) = mkstemp(suffix)
|
||||
os.close(handle)
|
||||
self.tmp_files.append(path)
|
||||
return path
|
||||
|
||||
def setup_log_attachment_plugin(self):
|
||||
def log_discoverer(path):
|
||||
if path.endswith('.log'):
|
||||
return 'log'
|
||||
log_plugin = BeetsPlugin()
|
||||
log_plugin.attachment_discoverer = log_discoverer
|
||||
self.add_plugin(log_plugin)
|
||||
|
||||
|
||||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue