mirror of
https://github.com/beetbox/beets.git
synced 2026-01-08 08:56:56 +01:00
Merge pull request #1779 from diego-plan9/prompthook
mbsubmit: cleanup and completion
This commit is contained in:
commit
7ff999002a
5 changed files with 150 additions and 13 deletions
|
|
@ -16,8 +16,10 @@
|
|||
"""Aid in submitting information to MusicBrainz.
|
||||
|
||||
This plugin allows the user to print track information in a format that is
|
||||
parseable by the MusicBrainz track parser. Programmatic submitting is not
|
||||
parseable by the MusicBrainz track parser [1]. Programmatic submitting is not
|
||||
implemented by MusicBrainz yet.
|
||||
|
||||
[1] http://wiki.musicbrainz.org/History:How_To_Parse_Track_Listings
|
||||
"""
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
|
|
@ -25,7 +27,6 @@ from __future__ import (division, absolute_import, print_function,
|
|||
|
||||
|
||||
from beets.autotag import Recommendation
|
||||
from beets.importer import action
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.ui.commands import PromptChoice
|
||||
from beetsplug.info import print_data
|
||||
|
|
@ -35,21 +36,26 @@ class MBSubmitPlugin(BeetsPlugin):
|
|||
def __init__(self):
|
||||
super(MBSubmitPlugin, self).__init__()
|
||||
|
||||
self.config.add({
|
||||
'format': '$track. $title - $artist ($length)',
|
||||
'threshold': 'medium',
|
||||
})
|
||||
|
||||
# Validate and store threshold.
|
||||
self.threshold = self.config['threshold'].as_choice({
|
||||
'none': Recommendation.none,
|
||||
'low': Recommendation.low,
|
||||
'medium': Recommendation.medium,
|
||||
'strong': Recommendation.strong
|
||||
})
|
||||
|
||||
self.register_listener('before_choose_candidate',
|
||||
self.before_choose_candidate_event)
|
||||
|
||||
def before_choose_candidate_event(self, session, task):
|
||||
if not task.candidates or task.rec == Recommendation.none:
|
||||
return [PromptChoice('p', 'Print tracks', self.print_tracks),
|
||||
PromptChoice('k', 'print tracks and sKip',
|
||||
self.print_tracks_and_skip)]
|
||||
if task.rec <= self.threshold:
|
||||
return [PromptChoice('p', 'Print tracks', self.print_tracks)]
|
||||
|
||||
# Callbacks for choices.
|
||||
def print_tracks(self, session, task):
|
||||
for i in task.items:
|
||||
print_data(None, i, '$track. $artist - $title ($length)')
|
||||
|
||||
def print_tracks_and_skip(self, session, task):
|
||||
for i in task.items:
|
||||
print_data(None, i, '$track. $artist - $title ($length)')
|
||||
return action.SKIP
|
||||
print_data(None, i, self.config['format'].get())
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ New:
|
|||
:bug:`1778`
|
||||
* A new :doc:`/plugins/acousticbrainz` fetches acoustic-analysis information
|
||||
from the `AcousticBrainz`_ project. Thanks to :user:`opatel99`. :bug:`1784`
|
||||
* A new :doc:`/plugins/mbsubmit` lets you print the tracks of an album in a
|
||||
format parseable by MusicBrainz track parser during an interactive import
|
||||
session. :bug:`1779`
|
||||
|
||||
.. _AcousticBrainz: http://acousticbrainz.org/
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ Each plugin has its own set of options that can be defined in a section bearing
|
|||
lastimport
|
||||
lyrics
|
||||
mbcollection
|
||||
mbsubmit
|
||||
mbsync
|
||||
metasync
|
||||
missing
|
||||
|
|
@ -164,6 +165,7 @@ Miscellaneous
|
|||
* :doc:`ihate`: Automatically skip albums and tracks during the import process.
|
||||
* :doc:`info`: Print music files' tags to the console.
|
||||
* :doc:`mbcollection`: Maintain your MusicBrainz collection list.
|
||||
* :doc:`mbsubmit`: Print an album's tracks in a MusicBrainz-friendly format.
|
||||
* :doc:`missing`: List missing tracks.
|
||||
* :doc:`random`: Randomly choose albums and tracks from your library.
|
||||
* :doc:`filefilter`: Automatically skip files during the import process based
|
||||
|
|
|
|||
54
docs/plugins/mbsubmit.rst
Normal file
54
docs/plugins/mbsubmit.rst
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
MusicBrainz Submit Plugin
|
||||
=========================
|
||||
|
||||
The ``mbsubmit`` plugin provides an extra prompt choice during an import
|
||||
session that prints the tracks of the current album in a format that is
|
||||
parseable by MusicBrainz's `track parser`_.
|
||||
|
||||
.. _track parser: http://wiki.musicbrainz.org/History:How_To_Parse_Track_Listings
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Enable the ``mbsubmit`` plugin in your configuration (see :ref:`using-plugins`)
|
||||
and select the ``Print tracks`` choice which is by default displayed when no
|
||||
strong recommendations are found for the album::
|
||||
|
||||
No matching release found for 3 tracks.
|
||||
For help, see: http://beets.readthedocs.org/en/latest/faq.html#nomatch
|
||||
[U]se as-is, as Tracks, Group albums, Skip, Enter search, enter Id, aBort,
|
||||
Print tracks? p
|
||||
01. An Obscure Track - An Obscure Artist (3:37)
|
||||
02. Another Obscure Track - An Obscure Artist (2:05)
|
||||
03. The Third Track - Another Obscure Artist (3:02)
|
||||
|
||||
No matching release found for 3 tracks.
|
||||
For help, see: http://beets.readthedocs.org/en/latest/faq.html#nomatch
|
||||
[U]se as-is, as Tracks, Group albums, Skip, Enter search, enter Id, aBort,
|
||||
Print tracks?
|
||||
|
||||
As MusicBrainz currently does not support submitting albums programmatically,
|
||||
the recommended workflow is to copy the output of the ``Print tracks`` choice
|
||||
and paste it into the parser that can be found by clicking on the
|
||||
"Track Parser" button on MusicBrainz "Tracklist" tab.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
To configure the plugin, make a ``mbsubmit:`` section in your configuration
|
||||
file. The following options are available:
|
||||
|
||||
- **format**: The format used for printing the tracks, defined using the
|
||||
same template syntax as beets’ :doc:`path formats </reference/pathformat>`.
|
||||
Default: ``$track. $title - $artist ($length)``.
|
||||
- **threshold**: The minimum strength of the autotagger recommendation that
|
||||
will cause the ``Print tracks`` choice to be displayed on the prompt.
|
||||
Default: ``medium`` (causing the choice to be displayed for all albums that
|
||||
have a recommendation of medium strength or lower). Valid values: ``none``,
|
||||
``low``, ``medium``, ``strong``.
|
||||
|
||||
Please note that some values of the ``threshold`` configuration option might
|
||||
require other ``beets`` command line switches to be enabled in order to work as
|
||||
intended. In particular, setting a threshold of ``strong`` will only display
|
||||
the prompt if ``timid`` mode is enabled. You can find more information about
|
||||
how the recommendation system works at :ref:`match-config`.
|
||||
72
test/test_mbsubmit.py
Normal file
72
test/test_mbsubmit.py
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# This file is part of beets.
|
||||
# Copyright 2016, Adrian Sampson and Diego Moreda.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from test._common import unittest
|
||||
from test.helper import capture_stdout, control_stdin, TestHelper
|
||||
from test.test_importer import ImportHelper, AutotagStub
|
||||
from test.test_ui_importer import TerminalImportSessionSetup
|
||||
|
||||
|
||||
class MBSubmitPluginTest(TerminalImportSessionSetup, unittest.TestCase,
|
||||
ImportHelper, TestHelper):
|
||||
def setUp(self):
|
||||
self.setup_beets()
|
||||
self.load_plugins('mbsubmit')
|
||||
self._create_import_dir(2)
|
||||
self._setup_import_session()
|
||||
self.matcher = AutotagStub().install()
|
||||
|
||||
def tearDown(self):
|
||||
self.unload_plugins()
|
||||
self.teardown_beets()
|
||||
|
||||
def test_print_tracks_output(self):
|
||||
"""Test the output of the "print tracks" choice."""
|
||||
self.matcher.matching = AutotagStub.BAD
|
||||
|
||||
with capture_stdout() as output:
|
||||
with control_stdin('\n'.join(['p', 's'])):
|
||||
# Print tracks; Skip
|
||||
self.importer.run()
|
||||
|
||||
# Manually build the string for comparing the output.
|
||||
tracklist = ('Print tracks? '
|
||||
'01. Tag Title 1 - Tag Artist (0:01)\n'
|
||||
'02. Tag Title 2 - Tag Artist (0:01)')
|
||||
self.assertIn(tracklist, output.getvalue())
|
||||
|
||||
def test_print_tracks_output_as_tracks(self):
|
||||
"""Test the output of the "print tracks" choice, as singletons."""
|
||||
self.matcher.matching = AutotagStub.BAD
|
||||
|
||||
with capture_stdout() as output:
|
||||
with control_stdin('\n'.join(['t', 's', 'p', 's'])):
|
||||
# as Tracks; Skip; Print tracks; Skip
|
||||
self.importer.run()
|
||||
|
||||
# Manually build the string for comparing the output.
|
||||
tracklist = ('Print tracks? '
|
||||
'02. Tag Title 2 - Tag Artist (0:01)')
|
||||
self.assertIn(tracklist, output.getvalue())
|
||||
|
||||
|
||||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
Loading…
Reference in a new issue